LCOV - code coverage report
Current view: top level - proxy/src/auth - password_hack.rs (source / functions) Coverage Total Hit
Test: 2aa98e37cd3250b9a68c97ef6050b16fe702ab33.info Lines: 100.0 % 73 73
Test Date: 2024-08-29 11:33:10 Functions: 100.0 % 7 7

            Line data    Source code
       1              : //! Payload for ad hoc authentication method for clients that don't support SNI.
       2              : //! See the `impl` for [`super::backend::Backend<ClientCredentials>`].
       3              : //! Read more: <https://github.com/neondatabase/cloud/issues/1620#issuecomment-1165332290>.
       4              : //! UPDATE (Mon Aug  8 13:20:34 UTC 2022): the payload format has been simplified.
       5              : 
       6              : use bstr::ByteSlice;
       7              : 
       8              : use crate::EndpointId;
       9              : 
      10              : pub(crate) struct PasswordHackPayload {
      11              :     pub(crate) endpoint: EndpointId,
      12              :     pub(crate) password: Vec<u8>,
      13              : }
      14              : 
      15              : impl PasswordHackPayload {
      16           78 :     pub(crate) fn parse(bytes: &[u8]) -> Option<Self> {
      17           78 :         // The format is `project=<utf-8>;<password-bytes>` or `project=<utf-8>$<password-bytes>`.
      18           78 :         let separators = [";", "$"];
      19          162 :         for sep in separators {
      20          126 :             if let Some((endpoint, password)) = bytes.split_once_str(sep) {
      21           42 :                 let endpoint = endpoint.to_str().ok()?;
      22              :                 return Some(Self {
      23           42 :                     endpoint: parse_endpoint_param(endpoint)?.into(),
      24           42 :                     password: password.to_owned(),
      25              :                 });
      26           84 :             }
      27              :         }
      28              : 
      29           36 :         None
      30           78 :     }
      31              : }
      32              : 
      33          264 : pub(crate) fn parse_endpoint_param(bytes: &str) -> Option<&str> {
      34          264 :     bytes
      35          264 :         .strip_prefix("project=")
      36          264 :         .or_else(|| bytes.strip_prefix("endpoint="))
      37          264 : }
      38              : 
      39              : #[cfg(test)]
      40              : mod tests {
      41              :     use super::*;
      42              : 
      43              :     #[test]
      44            6 :     fn parse_endpoint_param_fn() {
      45            6 :         let input = "";
      46            6 :         assert!(parse_endpoint_param(input).is_none());
      47              : 
      48            6 :         let input = "project=";
      49            6 :         assert_eq!(parse_endpoint_param(input), Some(""));
      50              : 
      51            6 :         let input = "project=foobar";
      52            6 :         assert_eq!(parse_endpoint_param(input), Some("foobar"));
      53              : 
      54            6 :         let input = "endpoint=";
      55            6 :         assert_eq!(parse_endpoint_param(input), Some(""));
      56              : 
      57            6 :         let input = "endpoint=foobar";
      58            6 :         assert_eq!(parse_endpoint_param(input), Some("foobar"));
      59              : 
      60            6 :         let input = "other_option=foobar";
      61            6 :         assert!(parse_endpoint_param(input).is_none());
      62            6 :     }
      63              : 
      64              :     #[test]
      65            6 :     fn parse_password_hack_payload_project() {
      66            6 :         let bytes = b"";
      67            6 :         assert!(PasswordHackPayload::parse(bytes).is_none());
      68              : 
      69            6 :         let bytes = b"project=";
      70            6 :         assert!(PasswordHackPayload::parse(bytes).is_none());
      71              : 
      72            6 :         let bytes = b"project=;";
      73            6 :         let payload: PasswordHackPayload =
      74            6 :             PasswordHackPayload::parse(bytes).expect("parsing failed");
      75            6 :         assert_eq!(payload.endpoint, "");
      76            6 :         assert_eq!(payload.password, b"");
      77              : 
      78            6 :         let bytes = b"project=foobar;pass;word";
      79            6 :         let payload = PasswordHackPayload::parse(bytes).expect("parsing failed");
      80            6 :         assert_eq!(payload.endpoint, "foobar");
      81            6 :         assert_eq!(payload.password, b"pass;word");
      82            6 :     }
      83              : 
      84              :     #[test]
      85            6 :     fn parse_password_hack_payload_endpoint() {
      86            6 :         let bytes = b"";
      87            6 :         assert!(PasswordHackPayload::parse(bytes).is_none());
      88              : 
      89            6 :         let bytes = b"endpoint=";
      90            6 :         assert!(PasswordHackPayload::parse(bytes).is_none());
      91              : 
      92            6 :         let bytes = b"endpoint=;";
      93            6 :         let payload = PasswordHackPayload::parse(bytes).expect("parsing failed");
      94            6 :         assert_eq!(payload.endpoint, "");
      95            6 :         assert_eq!(payload.password, b"");
      96              : 
      97            6 :         let bytes = b"endpoint=foobar;pass;word";
      98            6 :         let payload = PasswordHackPayload::parse(bytes).expect("parsing failed");
      99            6 :         assert_eq!(payload.endpoint, "foobar");
     100            6 :         assert_eq!(payload.password, b"pass;word");
     101            6 :     }
     102              : 
     103              :     #[test]
     104            6 :     fn parse_password_hack_payload_dollar() {
     105            6 :         let bytes = b"";
     106            6 :         assert!(PasswordHackPayload::parse(bytes).is_none());
     107              : 
     108            6 :         let bytes = b"endpoint=";
     109            6 :         assert!(PasswordHackPayload::parse(bytes).is_none());
     110              : 
     111            6 :         let bytes = b"endpoint=$";
     112            6 :         let payload = PasswordHackPayload::parse(bytes).expect("parsing failed");
     113            6 :         assert_eq!(payload.endpoint, "");
     114            6 :         assert_eq!(payload.password, b"");
     115              : 
     116            6 :         let bytes = b"endpoint=foobar$pass$word";
     117            6 :         let payload = PasswordHackPayload::parse(bytes).expect("parsing failed");
     118            6 :         assert_eq!(payload.endpoint, "foobar");
     119            6 :         assert_eq!(payload.password, b"pass$word");
     120            6 :     }
     121              : }
        

Generated by: LCOV version 2.1-beta