LCOV - code coverage report
Current view: top level - proxy/src/auth - password_hack.rs (source / functions) Coverage Total Hit
Test: 8ac049b474321fdc72ddcb56d7165153a1a900e8.info Lines: 100.0 % 77 77
Test Date: 2023-09-06 10:18:01 Functions: 100.0 % 11 11

            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::BackendType<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              : pub struct PasswordHackPayload {
       9              :     pub endpoint: String,
      10              :     pub password: Vec<u8>,
      11              : }
      12              : 
      13              : impl PasswordHackPayload {
      14           15 :     pub fn parse(bytes: &[u8]) -> Option<Self> {
      15           15 :         // The format is `project=<utf-8>;<password-bytes>` or `project=<utf-8>$<password-bytes>`.
      16           15 :         let separators = [";", "$"];
      17           31 :         for sep in separators {
      18           24 :             if let Some((endpoint, password)) = bytes.split_once_str(sep) {
      19            8 :                 let endpoint = endpoint.to_str().ok()?;
      20              :                 return Some(Self {
      21            8 :                     endpoint: parse_endpoint_param(endpoint)?.to_owned(),
      22            8 :                     password: password.to_owned(),
      23              :                 });
      24           16 :             }
      25              :         }
      26              : 
      27            7 :         None
      28           15 :     }
      29              : }
      30              : 
      31          129 : pub fn parse_endpoint_param(bytes: &str) -> Option<&str> {
      32          129 :     bytes
      33          129 :         .strip_prefix("project=")
      34          129 :         .or_else(|| bytes.strip_prefix("endpoint="))
      35          129 : }
      36              : 
      37              : #[cfg(test)]
      38              : mod tests {
      39              :     use super::*;
      40              : 
      41            1 :     #[test]
      42            1 :     fn parse_endpoint_param_fn() {
      43            1 :         let input = "";
      44            1 :         assert!(parse_endpoint_param(input).is_none());
      45              : 
      46            1 :         let input = "project=";
      47            1 :         assert_eq!(parse_endpoint_param(input), Some(""));
      48              : 
      49            1 :         let input = "project=foobar";
      50            1 :         assert_eq!(parse_endpoint_param(input), Some("foobar"));
      51              : 
      52            1 :         let input = "endpoint=";
      53            1 :         assert_eq!(parse_endpoint_param(input), Some(""));
      54              : 
      55            1 :         let input = "endpoint=foobar";
      56            1 :         assert_eq!(parse_endpoint_param(input), Some("foobar"));
      57              : 
      58            1 :         let input = "other_option=foobar";
      59            1 :         assert!(parse_endpoint_param(input).is_none());
      60            1 :     }
      61              : 
      62            1 :     #[test]
      63            1 :     fn parse_password_hack_payload_project() {
      64            1 :         let bytes = b"";
      65            1 :         assert!(PasswordHackPayload::parse(bytes).is_none());
      66              : 
      67            1 :         let bytes = b"project=";
      68            1 :         assert!(PasswordHackPayload::parse(bytes).is_none());
      69              : 
      70            1 :         let bytes = b"project=;";
      71            1 :         let payload: PasswordHackPayload =
      72            1 :             PasswordHackPayload::parse(bytes).expect("parsing failed");
      73            1 :         assert_eq!(payload.endpoint, "");
      74            1 :         assert_eq!(payload.password, b"");
      75              : 
      76            1 :         let bytes = b"project=foobar;pass;word";
      77            1 :         let payload = PasswordHackPayload::parse(bytes).expect("parsing failed");
      78            1 :         assert_eq!(payload.endpoint, "foobar");
      79            1 :         assert_eq!(payload.password, b"pass;word");
      80            1 :     }
      81              : 
      82            1 :     #[test]
      83            1 :     fn parse_password_hack_payload_endpoint() {
      84            1 :         let bytes = b"";
      85            1 :         assert!(PasswordHackPayload::parse(bytes).is_none());
      86              : 
      87            1 :         let bytes = b"endpoint=";
      88            1 :         assert!(PasswordHackPayload::parse(bytes).is_none());
      89              : 
      90            1 :         let bytes = b"endpoint=;";
      91            1 :         let payload = PasswordHackPayload::parse(bytes).expect("parsing failed");
      92            1 :         assert_eq!(payload.endpoint, "");
      93            1 :         assert_eq!(payload.password, b"");
      94              : 
      95            1 :         let bytes = b"endpoint=foobar;pass;word";
      96            1 :         let payload = PasswordHackPayload::parse(bytes).expect("parsing failed");
      97            1 :         assert_eq!(payload.endpoint, "foobar");
      98            1 :         assert_eq!(payload.password, b"pass;word");
      99            1 :     }
     100              : 
     101            1 :     #[test]
     102            1 :     fn parse_password_hack_payload_dollar() {
     103            1 :         let bytes = b"";
     104            1 :         assert!(PasswordHackPayload::parse(bytes).is_none());
     105              : 
     106            1 :         let bytes = b"endpoint=";
     107            1 :         assert!(PasswordHackPayload::parse(bytes).is_none());
     108              : 
     109            1 :         let bytes = b"endpoint=$";
     110            1 :         let payload = PasswordHackPayload::parse(bytes).expect("parsing failed");
     111            1 :         assert_eq!(payload.endpoint, "");
     112            1 :         assert_eq!(payload.password, b"");
     113              : 
     114            1 :         let bytes = b"endpoint=foobar$pass$word";
     115            1 :         let payload = PasswordHackPayload::parse(bytes).expect("parsing failed");
     116            1 :         assert_eq!(payload.endpoint, "foobar");
     117            1 :         assert_eq!(payload.password, b"pass$word");
     118            1 :     }
     119              : }
        

Generated by: LCOV version 2.1-beta