LCOV - differential code coverage report
Current view: top level - proxy/src/auth - password_hack.rs (source / functions) Coverage Total Hit CBC
Current: f6946e90941b557c917ac98cd5a7e9506d180f3e.info Lines: 100.0 % 77 77 77
Current Date: 2023-10-19 02:04:12 Functions: 100.0 % 11 11 11
Baseline: c8637f37369098875162f194f92736355783b050.info
Baseline Date: 2023-10-18 20:25:20

           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                 : 
       8                 : pub struct PasswordHackPayload {
       9                 :     pub endpoint: String,
      10                 :     pub password: Vec<u8>,
      11                 : }
      12                 : 
      13                 : impl PasswordHackPayload {
      14 CBC          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             133 : pub fn parse_endpoint_param(bytes: &str) -> Option<&str> {
      32             133 :     bytes
      33             133 :         .strip_prefix("project=")
      34             133 :         .or_else(|| bytes.strip_prefix("endpoint="))
      35             133 : }
      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