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

Generated by: LCOV version 2.1-beta