lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

server_state_machine.rs (5136B)


      1 use radroots_nostr_connect::message::{RequestId, RequestMessage};
      2 use radroots_nostr_connect::permission::{Permission, Permissions};
      3 use radroots_nostr_connect::server::SERVER_MESSAGE_MAX_BYTES;
      4 use radroots_nostr_connect::{Error, Method, Request, Response, Server};
      5 use std::str::FromStr;
      6 
      7 fn request_json(id: &str, request: Request) -> String {
      8     serde_json::to_string(&RequestMessage::try_new(id, request).expect("request"))
      9         .expect("request JSON")
     10 }
     11 
     12 #[test]
     13 fn server_exposes_permission_evaluation_without_owning_policy() {
     14     let mut server = Server::new();
     15     let request = server
     16         .parse(
     17             "event-permission",
     18             &request_json(
     19                 "request-permission",
     20                 Request::Nip44Encrypt {
     21                     public_key: radroots_identity::PublicKey::from_hex(
     22                         "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
     23                     )
     24                     .expect("public key"),
     25                     plaintext: "payload".to_owned(),
     26                 },
     27             ),
     28         )
     29         .expect("server request");
     30     assert_eq!(
     31         request.required_permission(),
     32         Some(&Permission::new(Method::Nip44Encrypt))
     33     );
     34     assert!(!request.is_allowed_by(&Permissions::new()));
     35     assert!(
     36         request.is_allowed_by(
     37             &Permissions::try_from_vec(vec![Permission::new(Method::Nip44Encrypt)])
     38                 .expect("permissions")
     39         )
     40     );
     41 }
     42 
     43 #[test]
     44 fn server_rejects_unsupported_extensions_and_malformed_requests() {
     45     let mut server = Server::new();
     46     let extension = Method::from_str("vendor_action").expect("extension");
     47     assert_eq!(
     48         server
     49             .parse(
     50                 "event-extension",
     51                 &request_json(
     52                     "request-extension",
     53                     Request::Custom {
     54                         method: extension.clone(),
     55                         params: Vec::new(),
     56                     },
     57                 ),
     58             )
     59             .expect_err("unsupported extension"),
     60         Error::UnsupportedMethod(extension)
     61     );
     62     assert!(matches!(
     63         server.parse("event-malformed", "not JSON"),
     64         Err(Error::Json(_))
     65     ));
     66 }
     67 
     68 #[test]
     69 fn server_rejects_invalid_configuration_message_and_fingerprint_bounds() {
     70     assert!(matches!(
     71         Server::with_supported_extensions([Method::Ping]),
     72         Err(Error::InvalidServerState { .. })
     73     ));
     74     let mut server = Server::default();
     75     assert!(matches!(
     76         server.parse("event", &"x".repeat(SERVER_MESSAGE_MAX_BYTES + 1)),
     77         Err(Error::InvalidServerRequest { .. })
     78     ));
     79     for fingerprint in ["", "line\nbreak"] {
     80         assert!(matches!(
     81             server.parse(fingerprint, &request_json("request", Request::Ping)),
     82             Err(Error::InvalidServerRequest { .. })
     83         ));
     84     }
     85     assert!(matches!(
     86         server.parse("x".repeat(129), &request_json("request", Request::Ping)),
     87         Err(Error::InvalidServerRequest { .. })
     88     ));
     89 }
     90 
     91 #[test]
     92 fn configured_extension_is_admitted_with_a_permission_input() {
     93     let extension = Method::from_str("vendor_action").expect("extension");
     94     let mut server = Server::with_supported_extensions([extension.clone()]).expect("server");
     95     let request = server
     96         .parse(
     97             "event-extension",
     98             &request_json(
     99                 "request-extension",
    100                 Request::Custom {
    101                     method: extension.clone(),
    102                     params: Vec::new(),
    103                 },
    104             ),
    105         )
    106         .expect("extension request");
    107     assert_eq!(
    108         request.required_permission(),
    109         Some(&Permission::new(extension))
    110     );
    111 }
    112 
    113 #[test]
    114 fn server_constructs_correlated_plaintext_for_host_signing() {
    115     let mut server = Server::new();
    116     let request = server
    117         .parse(
    118             "event-response",
    119             &request_json("request-response", Request::Ping),
    120         )
    121         .expect("request");
    122     assert_eq!(
    123         request.request_id(),
    124         &RequestId::parse("request-response").expect("request id")
    125     );
    126     assert_eq!(request.request(), &Request::Ping);
    127     let response = request.respond(Response::Pong).expect("response");
    128     assert_eq!(
    129         response.envelope().request_id().expect("response id"),
    130         RequestId::parse("request-response").expect("request id")
    131     );
    132     assert!(response.as_json().contains("\"pong\""));
    133     assert_eq!(format!("{response:?}"), "ServerResponse(<redacted>)");
    134 }
    135 
    136 #[test]
    137 fn server_rejects_fingerprint_and_request_id_replays() {
    138     let mut server = Server::new();
    139     let first = request_json("request-replay", Request::Ping);
    140     server.parse("event-replay", &first).expect("first request");
    141     assert_eq!(
    142         server
    143             .parse(
    144                 "event-replay",
    145                 &request_json("request-other", Request::Ping)
    146             )
    147             .expect_err("fingerprint replay"),
    148         Error::ReplayedRequest
    149     );
    150     assert_eq!(
    151         server
    152             .parse("event-other", &first)
    153             .expect_err("request id replay"),
    154         Error::ReplayedRequest
    155     );
    156 }