diff options
Diffstat (limited to 'tests/state_authorization.rs')
| -rw-r--r-- | tests/state_authorization.rs | 242 |
1 files changed, 119 insertions, 123 deletions
diff --git a/tests/state_authorization.rs b/tests/state_authorization.rs index a5dfa2d..d443005 100644 --- a/tests/state_authorization.rs +++ b/tests/state_authorization.rs | |||
| @@ -13,30 +13,27 @@ use nostr_sdk::prelude::*; | |||
| 13 | async fn test_reject_state_without_announcement() { | 13 | async fn test_reject_state_without_announcement() { |
| 14 | // Start test relay | 14 | // Start test relay |
| 15 | let relay = TestRelay::start().await; | 15 | let relay = TestRelay::start().await; |
| 16 | 16 | ||
| 17 | // Create test keypair | 17 | // Create test keypair |
| 18 | let keys = Keys::generate(); | 18 | let keys = Keys::generate(); |
| 19 | 19 | ||
| 20 | // Create a state event without any announcement | 20 | // Create a state event without any announcement |
| 21 | let state_event = EventBuilder::new( | 21 | let state_event = EventBuilder::new(Kind::RepoState, "") |
| 22 | Kind::RepoState, | 22 | .tags([ |
| 23 | "", | 23 | Tag::custom(TagKind::custom("d"), ["test-repo"]), |
| 24 | ) | 24 | Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]), |
| 25 | .tags([ | 25 | ]) |
| 26 | Tag::custom(TagKind::custom("d"), ["test-repo"]), | 26 | .sign_with_keys(&keys) |
| 27 | Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]), | 27 | .unwrap(); |
| 28 | ]) | 28 | |
| 29 | .sign_with_keys(&keys) | ||
| 30 | .unwrap(); | ||
| 31 | |||
| 32 | // Connect to relay | 29 | // Connect to relay |
| 33 | let client = Client::default(); | 30 | let client = Client::default(); |
| 34 | client.add_relay(relay.url()).await.unwrap(); | 31 | client.add_relay(relay.url()).await.unwrap(); |
| 35 | client.connect().await; | 32 | client.connect().await; |
| 36 | 33 | ||
| 37 | // Try to send state event | 34 | // Try to send state event |
| 38 | let result = client.send_event(&state_event).await; | 35 | let result = client.send_event(&state_event).await; |
| 39 | 36 | ||
| 40 | // Should be rejected | 37 | // Should be rejected |
| 41 | match result { | 38 | match result { |
| 42 | Ok(output) => { | 39 | Ok(output) => { |
| @@ -45,22 +42,26 @@ async fn test_reject_state_without_announcement() { | |||
| 45 | "Event should be processed" | 42 | "Event should be processed" |
| 46 | ); | 43 | ); |
| 47 | // Check if any relay rejected it | 44 | // Check if any relay rejected it |
| 48 | let rejected = output.failed.values().any(|err| { | 45 | let rejected = output |
| 49 | err.to_string().contains("no announcement exists") | 46 | .failed |
| 50 | }); | 47 | .values() |
| 51 | assert!(rejected, "Event should be rejected due to missing announcement"); | 48 | .any(|err| err.to_string().contains("no announcement exists")); |
| 49 | assert!( | ||
| 50 | rejected, | ||
| 51 | "Event should be rejected due to missing announcement" | ||
| 52 | ); | ||
| 52 | } | 53 | } |
| 53 | Err(e) => { | 54 | Err(e) => { |
| 54 | // Also acceptable - relay rejected the event | 55 | // Also acceptable - relay rejected the event |
| 55 | assert!( | 56 | assert!( |
| 56 | e.to_string().contains("no announcement exists") || | 57 | e.to_string().contains("no announcement exists") |
| 57 | e.to_string().contains("rejected"), | 58 | || e.to_string().contains("rejected"), |
| 58 | "Error should indicate missing announcement: {}", | 59 | "Error should indicate missing announcement: {}", |
| 59 | e | 60 | e |
| 60 | ); | 61 | ); |
| 61 | } | 62 | } |
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | relay.stop().await; | 65 | relay.stop().await; |
| 65 | } | 66 | } |
| 66 | 67 | ||
| @@ -68,67 +69,67 @@ async fn test_reject_state_without_announcement() { | |||
| 68 | async fn test_reject_state_from_unauthorized_author() { | 69 | async fn test_reject_state_from_unauthorized_author() { |
| 69 | // Start test relay | 70 | // Start test relay |
| 70 | let relay = TestRelay::start().await; | 71 | let relay = TestRelay::start().await; |
| 71 | 72 | ||
| 72 | // Create two keypairs: one for announcement, one for unauthorized state | 73 | // Create two keypairs: one for announcement, one for unauthorized state |
| 73 | let announcement_keys = Keys::generate(); | 74 | let announcement_keys = Keys::generate(); |
| 74 | let unauthorized_keys = Keys::generate(); | 75 | let unauthorized_keys = Keys::generate(); |
| 75 | 76 | ||
| 76 | // Create announcement | 77 | // Create announcement |
| 77 | let announcement = EventBuilder::new( | 78 | let announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "") |
| 78 | Kind::GitRepoAnnouncement, | 79 | .tags([ |
| 79 | "", | 80 | Tag::custom(TagKind::custom("d"), ["test-repo"]), |
| 80 | ) | 81 | Tag::custom( |
| 81 | .tags([ | 82 | TagKind::custom("clone"), |
| 82 | Tag::custom(TagKind::custom("d"), ["test-repo"]), | 83 | [format!("https://{}/test.git", relay.domain())], |
| 83 | Tag::custom(TagKind::custom("clone"), [format!("https://{}/test.git", relay.domain())]), | 84 | ), |
| 84 | Tag::custom(TagKind::custom("relays"), [relay.url()]), | 85 | Tag::custom(TagKind::custom("relays"), [relay.url()]), |
| 85 | ]) | 86 | ]) |
| 86 | .sign_with_keys(&announcement_keys) | 87 | .sign_with_keys(&announcement_keys) |
| 87 | .unwrap(); | 88 | .unwrap(); |
| 88 | 89 | ||
| 89 | // Connect to relay | 90 | // Connect to relay |
| 90 | let client = Client::default(); | 91 | let client = Client::default(); |
| 91 | client.add_relay(relay.url()).await.unwrap(); | 92 | client.add_relay(relay.url()).await.unwrap(); |
| 92 | client.connect().await; | 93 | client.connect().await; |
| 93 | 94 | ||
| 94 | // Send announcement | 95 | // Send announcement |
| 95 | client.send_event(&announcement).await.unwrap(); | 96 | client.send_event(&announcement).await.unwrap(); |
| 96 | 97 | ||
| 97 | // Wait for announcement to be processed | 98 | // Wait for announcement to be processed |
| 98 | tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; | 99 | tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; |
| 99 | 100 | ||
| 100 | // Try to send state event from unauthorized author | 101 | // Try to send state event from unauthorized author |
| 101 | let state_event = EventBuilder::new( | 102 | let state_event = EventBuilder::new(Kind::RepoState, "") |
| 102 | Kind::RepoState, | 103 | .tags([ |
| 103 | "", | 104 | Tag::custom(TagKind::custom("d"), ["test-repo"]), |
| 104 | ) | 105 | Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]), |
| 105 | .tags([ | 106 | ]) |
| 106 | Tag::custom(TagKind::custom("d"), ["test-repo"]), | 107 | .sign_with_keys(&unauthorized_keys) |
| 107 | Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]), | 108 | .unwrap(); |
| 108 | ]) | 109 | |
| 109 | .sign_with_keys(&unauthorized_keys) | ||
| 110 | .unwrap(); | ||
| 111 | |||
| 112 | let result = client.send_event(&state_event).await; | 110 | let result = client.send_event(&state_event).await; |
| 113 | 111 | ||
| 114 | // Should be rejected | 112 | // Should be rejected |
| 115 | match result { | 113 | match result { |
| 116 | Ok(output) => { | 114 | Ok(output) => { |
| 117 | let rejected = output.failed.values().any(|err| { | 115 | let rejected = output |
| 118 | err.to_string().contains("not authorized") | 116 | .failed |
| 119 | }); | 117 | .values() |
| 120 | assert!(rejected, "Event should be rejected due to unauthorized author"); | 118 | .any(|err| err.to_string().contains("not authorized")); |
| 119 | assert!( | ||
| 120 | rejected, | ||
| 121 | "Event should be rejected due to unauthorized author" | ||
| 122 | ); | ||
| 121 | } | 123 | } |
| 122 | Err(e) => { | 124 | Err(e) => { |
| 123 | assert!( | 125 | assert!( |
| 124 | e.to_string().contains("not authorized") || | 126 | e.to_string().contains("not authorized") || e.to_string().contains("rejected"), |
| 125 | e.to_string().contains("rejected"), | ||
| 126 | "Error should indicate unauthorized author: {}", | 127 | "Error should indicate unauthorized author: {}", |
| 127 | e | 128 | e |
| 128 | ); | 129 | ); |
| 129 | } | 130 | } |
| 130 | } | 131 | } |
| 131 | 132 | ||
| 132 | relay.stop().await; | 133 | relay.stop().await; |
| 133 | } | 134 | } |
| 134 | 135 | ||
| @@ -136,48 +137,45 @@ async fn test_reject_state_from_unauthorized_author() { | |||
| 136 | async fn test_accept_state_from_announcement_author() { | 137 | async fn test_accept_state_from_announcement_author() { |
| 137 | // Start test relay | 138 | // Start test relay |
| 138 | let relay = TestRelay::start().await; | 139 | let relay = TestRelay::start().await; |
| 139 | 140 | ||
| 140 | // Create keypair | 141 | // Create keypair |
| 141 | let keys = Keys::generate(); | 142 | let keys = Keys::generate(); |
| 142 | 143 | ||
| 143 | // Create announcement | 144 | // Create announcement |
| 144 | let announcement = EventBuilder::new( | 145 | let announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "") |
| 145 | Kind::GitRepoAnnouncement, | 146 | .tags([ |
| 146 | "", | 147 | Tag::custom(TagKind::custom("d"), ["test-repo"]), |
| 147 | ) | 148 | Tag::custom( |
| 148 | .tags([ | 149 | TagKind::custom("clone"), |
| 149 | Tag::custom(TagKind::custom("d"), ["test-repo"]), | 150 | [format!("https://{}/test.git", relay.domain())], |
| 150 | Tag::custom(TagKind::custom("clone"), [format!("https://{}/test.git", relay.domain())]), | 151 | ), |
| 151 | Tag::custom(TagKind::custom("relays"), [relay.url()]), | 152 | Tag::custom(TagKind::custom("relays"), [relay.url()]), |
| 152 | ]) | 153 | ]) |
| 153 | .sign_with_keys(&keys) | 154 | .sign_with_keys(&keys) |
| 154 | .unwrap(); | 155 | .unwrap(); |
| 155 | 156 | ||
| 156 | // Connect to relay | 157 | // Connect to relay |
| 157 | let client = Client::default(); | 158 | let client = Client::default(); |
| 158 | client.add_relay(relay.url()).await.unwrap(); | 159 | client.add_relay(relay.url()).await.unwrap(); |
| 159 | client.connect().await; | 160 | client.connect().await; |
| 160 | 161 | ||
| 161 | // Send announcement | 162 | // Send announcement |
| 162 | client.send_event(&announcement).await.unwrap(); | 163 | client.send_event(&announcement).await.unwrap(); |
| 163 | 164 | ||
| 164 | // Wait for announcement to be processed | 165 | // Wait for announcement to be processed |
| 165 | tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; | 166 | tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; |
| 166 | 167 | ||
| 167 | // Send state event from same author (should be accepted or go to purgatory) | 168 | // Send state event from same author (should be accepted or go to purgatory) |
| 168 | let state_event = EventBuilder::new( | 169 | let state_event = EventBuilder::new(Kind::RepoState, "") |
| 169 | Kind::RepoState, | 170 | .tags([ |
| 170 | "", | 171 | Tag::custom(TagKind::custom("d"), ["test-repo"]), |
| 171 | ) | 172 | Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]), |
| 172 | .tags([ | 173 | ]) |
| 173 | Tag::custom(TagKind::custom("d"), ["test-repo"]), | 174 | .sign_with_keys(&keys) |
| 174 | Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]), | 175 | .unwrap(); |
| 175 | ]) | 176 | |
| 176 | .sign_with_keys(&keys) | ||
| 177 | .unwrap(); | ||
| 178 | |||
| 179 | let result = client.send_event(&state_event).await; | 177 | let result = client.send_event(&state_event).await; |
| 180 | 178 | ||
| 181 | // Should be accepted or go to purgatory (not permanently rejected) | 179 | // Should be accepted or go to purgatory (not permanently rejected) |
| 182 | match result { | 180 | match result { |
| 183 | Ok(output) => { | 181 | Ok(output) => { |
| @@ -194,14 +192,13 @@ async fn test_accept_state_from_announcement_author() { | |||
| 194 | Err(e) => { | 192 | Err(e) => { |
| 195 | // Purgatory is acceptable | 193 | // Purgatory is acceptable |
| 196 | assert!( | 194 | assert!( |
| 197 | e.to_string().contains("purgatory") || | 195 | e.to_string().contains("purgatory") || e.to_string().contains("waiting for git"), |
| 198 | e.to_string().contains("waiting for git"), | ||
| 199 | "Error should be about purgatory, not authorization: {}", | 196 | "Error should be about purgatory, not authorization: {}", |
| 200 | e | 197 | e |
| 201 | ); | 198 | ); |
| 202 | } | 199 | } |
| 203 | } | 200 | } |
| 204 | 201 | ||
| 205 | relay.stop().await; | 202 | relay.stop().await; |
| 206 | } | 203 | } |
| 207 | 204 | ||
| @@ -209,50 +206,50 @@ async fn test_accept_state_from_announcement_author() { | |||
| 209 | async fn test_accept_state_from_maintainer() { | 206 | async fn test_accept_state_from_maintainer() { |
| 210 | // Start test relay | 207 | // Start test relay |
| 211 | let relay = TestRelay::start().await; | 208 | let relay = TestRelay::start().await; |
| 212 | 209 | ||
| 213 | // Create two keypairs: owner and maintainer | 210 | // Create two keypairs: owner and maintainer |
| 214 | let owner_keys = Keys::generate(); | 211 | let owner_keys = Keys::generate(); |
| 215 | let maintainer_keys = Keys::generate(); | 212 | let maintainer_keys = Keys::generate(); |
| 216 | 213 | ||
| 217 | // Create announcement with maintainer | 214 | // Create announcement with maintainer |
| 218 | let announcement = EventBuilder::new( | 215 | let announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "") |
| 219 | Kind::GitRepoAnnouncement, | 216 | .tags([ |
| 220 | "", | 217 | Tag::custom(TagKind::custom("d"), ["test-repo"]), |
| 221 | ) | 218 | Tag::custom( |
| 222 | .tags([ | 219 | TagKind::custom("clone"), |
| 223 | Tag::custom(TagKind::custom("d"), ["test-repo"]), | 220 | [format!("https://{}/test.git", relay.domain())], |
| 224 | Tag::custom(TagKind::custom("clone"), [format!("https://{}/test.git", relay.domain())]), | 221 | ), |
| 225 | Tag::custom(TagKind::custom("relays"), [relay.url()]), | 222 | Tag::custom(TagKind::custom("relays"), [relay.url()]), |
| 226 | Tag::custom(TagKind::custom("maintainers"), [maintainer_keys.public_key().to_hex()]), | 223 | Tag::custom( |
| 227 | ]) | 224 | TagKind::custom("maintainers"), |
| 228 | .sign_with_keys(&owner_keys) | 225 | [maintainer_keys.public_key().to_hex()], |
| 229 | .unwrap(); | 226 | ), |
| 230 | 227 | ]) | |
| 228 | .sign_with_keys(&owner_keys) | ||
| 229 | .unwrap(); | ||
| 230 | |||
| 231 | // Connect to relay | 231 | // Connect to relay |
| 232 | let client = Client::default(); | 232 | let client = Client::default(); |
| 233 | client.add_relay(relay.url()).await.unwrap(); | 233 | client.add_relay(relay.url()).await.unwrap(); |
| 234 | client.connect().await; | 234 | client.connect().await; |
| 235 | 235 | ||
| 236 | // Send announcement | 236 | // Send announcement |
| 237 | client.send_event(&announcement).await.unwrap(); | 237 | client.send_event(&announcement).await.unwrap(); |
| 238 | 238 | ||
| 239 | // Wait for announcement to be processed | 239 | // Wait for announcement to be processed |
| 240 | tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; | 240 | tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; |
| 241 | 241 | ||
| 242 | // Send state event from maintainer | 242 | // Send state event from maintainer |
| 243 | let state_event = EventBuilder::new( | 243 | let state_event = EventBuilder::new(Kind::RepoState, "") |
| 244 | Kind::RepoState, | 244 | .tags([ |
| 245 | "", | 245 | Tag::custom(TagKind::custom("d"), ["test-repo"]), |
| 246 | ) | 246 | Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]), |
| 247 | .tags([ | 247 | ]) |
| 248 | Tag::custom(TagKind::custom("d"), ["test-repo"]), | 248 | .sign_with_keys(&maintainer_keys) |
| 249 | Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]), | 249 | .unwrap(); |
| 250 | ]) | 250 | |
| 251 | .sign_with_keys(&maintainer_keys) | ||
| 252 | .unwrap(); | ||
| 253 | |||
| 254 | let result = client.send_event(&state_event).await; | 251 | let result = client.send_event(&state_event).await; |
| 255 | 252 | ||
| 256 | // Should be accepted or go to purgatory (not permanently rejected) | 253 | // Should be accepted or go to purgatory (not permanently rejected) |
| 257 | match result { | 254 | match result { |
| 258 | Ok(output) => { | 255 | Ok(output) => { |
| @@ -268,13 +265,12 @@ async fn test_accept_state_from_maintainer() { | |||
| 268 | Err(e) => { | 265 | Err(e) => { |
| 269 | // Purgatory is acceptable | 266 | // Purgatory is acceptable |
| 270 | assert!( | 267 | assert!( |
| 271 | e.to_string().contains("purgatory") || | 268 | e.to_string().contains("purgatory") || e.to_string().contains("waiting for git"), |
| 272 | e.to_string().contains("waiting for git"), | ||
| 273 | "Error should be about purgatory, not authorization: {}", | 269 | "Error should be about purgatory, not authorization: {}", |
| 274 | e | 270 | e |
| 275 | ); | 271 | ); |
| 276 | } | 272 | } |
| 277 | } | 273 | } |
| 278 | 274 | ||
| 279 | relay.stop().await; | 275 | relay.stop().await; |
| 280 | } | 276 | } |