LCOV - differential code coverage report
Current view: top level - proxy/src/auth - password_hack.rs (source / functions) Coverage Total Hit CBC
Current: cd44433dd675caa99df17a61b18949c8387e2242.info Lines: 100.0 % 77 77 77
Current Date: 2024-01-09 02:06:09 Functions: 100.0 % 11 11 11
Baseline: 66c52a629a0f4a503e193045e0df4c77139e344b.info
Baseline Date: 2024-01-08 15:34:46

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

Generated by: LCOV version 2.1-beta