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 }