+10
-4
crates/atproto-client/src/com_atproto_repo.rs
+10
-4
crates/atproto-client/src/com_atproto_repo.rs
···
213
213
/// A paginated list of records from the collection
214
214
pub async fn list_records<T: DeserializeOwned>(
215
215
http_client: &reqwest::Client,
216
-
dpop_auth: &DPoPAuth,
216
+
dpop_auth: Option<&DPoPAuth>,
217
217
base_url: &str,
218
218
repo: String,
219
219
collection: String,
···
240
240
241
241
let url = url_builder.build();
242
242
243
-
get_dpop_json(http_client, dpop_auth, &url)
244
-
.await
245
-
.and_then(|value| serde_json::from_value(value).map_err(|err| err.into()))
243
+
if let Some(dpop_auth) = dpop_auth {
244
+
get_dpop_json(http_client, dpop_auth, &url)
245
+
.await
246
+
.and_then(|value| serde_json::from_value(value).map_err(|err| err.into()))
247
+
} else {
248
+
get_json(http_client, &url)
249
+
.await
250
+
.and_then(|value| serde_json::from_value(value).map_err(|err| err.into()))
251
+
}
246
252
}
247
253
248
254
/// Request to create a new record in an AT Protocol repository.
+292
-146
crates/atproto-identity/src/validation.rs
+292
-146
crates/atproto-identity/src/validation.rs
···
52
52
const RESERVED_TLDS: [&str; 4] = [".localhost", ".internal", ".arpa", ".local"];
53
53
54
54
/// Validates if a string is a valid hostname according to RFC 1035.
55
-
///
55
+
///
56
56
/// A valid hostname must:
57
57
/// - Be between 1 and 253 characters in length
58
58
/// - Not use reserved top-level domains (.localhost, .internal, .arpa, .local)
59
59
/// - Not be an IPv4 or IPv6 address
60
60
/// - Contain only valid hostname characters (letters, digits, hyphens, dots)
61
61
/// - Have valid DNS labels (no leading/trailing hyphens, max 63 chars per label)
62
-
///
62
+
///
63
63
/// # Arguments
64
-
///
64
+
///
65
65
/// * `hostname` - The hostname string to validate
66
-
///
66
+
///
67
67
/// # Returns
68
-
///
68
+
///
69
69
/// `true` if the hostname is valid according to RFC 1035, `false` otherwise
70
-
///
70
+
///
71
71
/// # Examples
72
-
///
72
+
///
73
73
/// ```
74
74
/// use atproto_identity::validation::is_valid_hostname;
75
-
///
75
+
///
76
76
/// // Valid hostnames
77
77
/// assert!(is_valid_hostname("example.com"));
78
78
/// assert!(is_valid_hostname("sub.example.com"));
79
79
/// assert!(is_valid_hostname("test-host.example.com"));
80
80
/// assert!(is_valid_hostname("localhost"));
81
-
///
81
+
///
82
82
/// // Invalid hostnames
83
83
/// assert!(!is_valid_hostname("192.168.1.1")); // IPv4 address
84
84
/// assert!(!is_valid_hostname("example.localhost")); // Reserved TLD
···
135
135
}
136
136
137
137
/// Checks if a string is a valid IPv4 address.
138
-
///
138
+
///
139
139
/// Validates that the string consists of exactly four decimal numbers
140
140
/// separated by dots, where each number is between 0 and 255.
141
-
///
141
+
///
142
142
/// # Arguments
143
-
///
143
+
///
144
144
/// * `s` - The string to validate as an IPv4 address
145
-
///
145
+
///
146
146
/// # Returns
147
-
///
147
+
///
148
148
/// `true` if the string is a valid IPv4 address, `false` otherwise
149
-
///
149
+
///
150
150
/// # Examples
151
-
///
151
+
///
152
152
/// ```
153
153
/// use atproto_identity::validation::is_ipv4;
154
-
///
154
+
///
155
155
/// // Valid IPv4 addresses
156
156
/// assert!(is_ipv4("192.168.1.1"));
157
157
/// assert!(is_ipv4("127.0.0.1"));
158
158
/// assert!(is_ipv4("255.255.255.255"));
159
159
/// assert!(is_ipv4("0.0.0.0"));
160
-
///
160
+
///
161
161
/// // Invalid IPv4 addresses
162
162
/// assert!(!is_ipv4("256.1.1.1")); // Number too large
163
163
/// assert!(!is_ipv4("192.168.1")); // Missing octet
···
174
174
}
175
175
176
176
/// Checks if a string is a valid IPv6 address.
177
-
///
177
+
///
178
178
/// Performs basic IPv6 validation including:
179
179
/// - Must contain colons (distinguishing from IPv4)
180
180
/// - Supports brackets for URLs (e.g., `[2001:db8::1]`)
181
181
/// - Validates compressed notation with `::` (at most one occurrence)
182
182
/// - Each segment must be valid hexadecimal (1-4 characters)
183
183
/// - At most 8 segments total
184
-
///
184
+
///
185
185
/// # Arguments
186
-
///
186
+
///
187
187
/// * `s` - The string to validate as an IPv6 address
188
-
///
188
+
///
189
189
/// # Returns
190
-
///
190
+
///
191
191
/// `true` if the string is a valid IPv6 address, `false` otherwise
192
-
///
192
+
///
193
193
/// # Examples
194
-
///
194
+
///
195
195
/// ```
196
196
/// use atproto_identity::validation::is_ipv6;
197
-
///
197
+
///
198
198
/// // Valid IPv6 addresses
199
199
/// assert!(is_ipv6("2001:db8::1"));
200
200
/// assert!(is_ipv6("::1"));
201
201
/// assert!(is_ipv6("fe80::1"));
202
202
/// assert!(is_ipv6("[2001:db8::1]")); // With brackets
203
203
/// assert!(is_ipv6("2001:0db8:0000:0000:0000:ff00:0042:8329"));
204
-
///
204
+
///
205
205
/// // Invalid IPv6 addresses
206
206
/// assert!(!is_ipv6("192.168.1.1")); // IPv4, not IPv6
207
207
/// assert!(!is_ipv6("example.com")); // No colons
···
241
241
}
242
242
243
243
/// Validates and normalizes an AT Protocol handle.
244
-
///
244
+
///
245
245
/// A valid AT Protocol handle must:
246
246
/// - Be a valid hostname (after stripping prefixes)
247
247
/// - Contain at least one period (to distinguish from simple hostnames)
248
248
/// - Follow all hostname validation rules (RFC 1035)
249
-
///
249
+
///
250
250
/// The function automatically strips common prefixes (`at://` and `@`) before validation.
251
-
///
251
+
///
252
252
/// # Arguments
253
-
///
253
+
///
254
254
/// * `handle` - The handle string to validate and normalize
255
-
///
255
+
///
256
256
/// # Returns
257
-
///
257
+
///
258
258
/// `Some(String)` containing the normalized handle if valid, `None` if invalid
259
-
///
259
+
///
260
260
/// # Examples
261
-
///
261
+
///
262
262
/// ```
263
263
/// use atproto_identity::validation::is_valid_handle;
264
-
///
264
+
///
265
265
/// // Valid handles
266
266
/// assert_eq!(is_valid_handle("alice.bsky.social"), Some("alice.bsky.social".to_string()));
267
267
/// assert_eq!(is_valid_handle("@bob.example.com"), Some("bob.example.com".to_string()));
268
268
/// assert_eq!(is_valid_handle("at://charlie.test.com"), Some("charlie.test.com".to_string()));
269
-
///
269
+
///
270
270
/// // Invalid handles
271
271
/// assert_eq!(is_valid_handle("localhost"), None); // No period
272
272
/// assert_eq!(is_valid_handle("192.168.1.1"), None); // IPv4 address
···
285
285
}
286
286
287
287
/// Strips common AT Protocol handle prefixes from a handle string.
288
-
///
288
+
///
289
289
/// Removes the `at://` or `@` prefix if present, returning the clean handle.
290
290
/// This is useful for normalizing handle input from various sources.
291
-
///
291
+
///
292
292
/// # Arguments
293
-
///
293
+
///
294
294
/// * `handle` - The handle string that may contain prefixes
295
-
///
295
+
///
296
296
/// # Returns
297
-
///
297
+
///
298
298
/// The handle string with prefixes removed
299
-
///
299
+
///
300
300
/// # Examples
301
-
///
301
+
///
302
302
/// ```
303
303
/// use atproto_identity::validation::strip_handle_prefixes;
304
-
///
304
+
///
305
305
/// assert_eq!(strip_handle_prefixes("@alice.bsky.social"), "alice.bsky.social");
306
306
/// assert_eq!(strip_handle_prefixes("at://bob.example.com"), "bob.example.com");
307
307
/// assert_eq!(strip_handle_prefixes("charlie.test.com"), "charlie.test.com");
···
317
317
}
318
318
319
319
/// Validates if a string is a properly formatted PLC DID.
320
-
///
320
+
///
321
321
/// A valid PLC DID must:
322
322
/// - Start with the prefix `did:plc:`
323
323
/// - Be followed by exactly 24 characters of base32 encoding (lowercase letters a-z and digits 2-7)
324
-
///
324
+
///
325
325
/// # Arguments
326
-
///
326
+
///
327
327
/// * `did` - The DID string to validate
328
-
///
328
+
///
329
329
/// # Returns
330
-
///
330
+
///
331
331
/// `true` if the DID is a valid PLC DID, `false` otherwise
332
-
///
332
+
///
333
333
/// # Examples
334
-
///
334
+
///
335
335
/// ```
336
336
/// use atproto_identity::validation::is_valid_did_method_plc;
337
-
///
337
+
///
338
338
/// // Valid PLC DIDs
339
339
/// assert!(is_valid_did_method_plc("did:plc:z3f2222fa222f5c33c2f27ez"));
340
340
/// assert!(is_valid_did_method_plc("did:plc:abcdefghijklmnopqrstuvwx"));
341
-
///
341
+
///
342
342
/// // Invalid PLC DIDs
343
343
/// assert!(!is_valid_did_method_plc("did:web:example.com"));
344
344
/// assert!(!is_valid_did_method_plc("did:plc:invalid0length"));
···
358
358
}
359
359
360
360
/// Validates if a string is a properly formatted Web DID.
361
-
///
361
+
///
362
362
/// A valid Web DID must start with the prefix `did:web:` followed by content that
363
363
/// depends on the strictness mode:
364
-
///
364
+
///
365
365
/// # Strict Mode (`strict = true`)
366
366
/// - Only a valid hostname is allowed after `did:web:`
367
367
/// - No additional path segments permitted
368
-
///
368
+
///
369
369
/// # Non-Strict Mode (`strict = false`)
370
370
/// - First segment must be a valid hostname
371
371
/// - Additional colon-separated segments are allowed
372
372
/// - Each additional segment must be non-empty and alphanumeric
373
-
///
373
+
///
374
374
/// # Arguments
375
-
///
375
+
///
376
376
/// * `did` - The DID string to validate
377
377
/// * `strict` - Whether to use strict hostname-only validation
378
-
///
378
+
///
379
379
/// # Returns
380
-
///
380
+
///
381
381
/// `true` if the DID is a valid Web DID according to the specified mode, `false` otherwise
382
-
///
382
+
///
383
383
/// # Examples
384
-
///
384
+
///
385
385
/// ```
386
386
/// use atproto_identity::validation::is_valid_did_method_web;
387
-
///
387
+
///
388
388
/// // Valid in both modes
389
389
/// assert!(is_valid_did_method_web("did:web:example.com", true));
390
390
/// assert!(is_valid_did_method_web("did:web:example.com", false));
391
-
///
391
+
///
392
392
/// // Valid only in non-strict mode
393
393
/// assert!(!is_valid_did_method_web("did:web:example.com:path", true));
394
394
/// assert!(is_valid_did_method_web("did:web:example.com:path", false));
395
395
/// assert!(is_valid_did_method_web("did:web:example.com:path:subpath", false));
396
-
///
396
+
///
397
397
/// // Invalid in both modes
398
398
/// assert!(!is_valid_did_method_web("did:web:192.168.1.1", true));
399
399
/// assert!(!is_valid_did_method_web("did:web:example.com:", false));
···
429
429
}
430
430
431
431
/// Validates if a string is a properly formatted WebVH DID.
432
-
///
432
+
///
433
433
/// A WebVH DID extends the Web DID format by adding a SCIM (Self-Controlled Identity Marker)
434
434
/// segment immediately after the `did:webvh:` prefix.
435
-
///
435
+
///
436
436
/// # Format
437
-
///
437
+
///
438
438
/// ```text
439
439
/// did:webvh:<scim>:<content>
440
440
/// ```
441
-
///
441
+
///
442
442
/// Where:
443
443
/// - `<scim>` must contain only base58-btc alphabet characters (`123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`)
444
444
/// - `<content>` follows the same validation rules as `did:web` content
445
-
///
445
+
///
446
446
/// # Strict vs Non-Strict Mode
447
-
///
447
+
///
448
448
/// **Strict Mode (`strict = true`)**:
449
449
/// - `<content>` must be a valid hostname only
450
450
/// - No additional path segments permitted
451
-
///
451
+
///
452
452
/// **Non-Strict Mode (`strict = false`)**:
453
453
/// - First segment of `<content>` must be a valid hostname
454
454
/// - Additional colon-separated segments are allowed
455
455
/// - Each additional segment must be non-empty and alphanumeric
456
-
///
456
+
///
457
457
/// # Arguments
458
-
///
458
+
///
459
459
/// * `did` - The DID string to validate
460
460
/// * `strict` - Whether to use strict hostname-only validation for the content portion
461
-
///
461
+
///
462
462
/// # Returns
463
-
///
463
+
///
464
464
/// `true` if the DID is a valid WebVH DID according to the specified mode, `false` otherwise
465
-
///
465
+
///
466
466
/// # Examples
467
-
///
467
+
///
468
468
/// ```
469
469
/// use atproto_identity::validation::is_valid_did_method_webvh;
470
-
///
470
+
///
471
471
/// // Valid WebVH DIDs in both modes
472
472
/// assert!(is_valid_did_method_webvh("did:webvh:abc123:example.com", true));
473
473
/// assert!(is_valid_did_method_webvh("did:webvh:XYZ789:sub.example.com", false));
474
-
///
474
+
///
475
475
/// // Valid only in non-strict mode (has path segments)
476
476
/// assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com:path", true));
477
477
/// assert!(is_valid_did_method_webvh("did:webvh:abc123:example.com:path", false));
478
478
/// assert!(is_valid_did_method_webvh("did:webvh:def456:example.com:path:subpath", false));
479
-
///
479
+
///
480
480
/// // Invalid - SCIM contains excluded base58 characters (0, O, I, l)
481
481
/// assert!(!is_valid_did_method_webvh("did:webvh:0abc:example.com", true));
482
482
/// assert!(!is_valid_did_method_webvh("did:webvh:Oabc:example.com", false));
483
483
/// assert!(!is_valid_did_method_webvh("did:webvh:Iabc:example.com", true));
484
484
/// assert!(!is_valid_did_method_webvh("did:webvh:labc:example.com", false));
485
-
///
485
+
///
486
486
/// // Invalid - wrong format or missing components
487
487
/// assert!(!is_valid_did_method_webvh("did:web:abc123:example.com", true)); // Wrong prefix
488
488
/// assert!(!is_valid_did_method_webvh("did:webvh:abc123", true)); // Missing content
···
496
496
497
497
// Split by the first colon to separate scim from content
498
498
let parts: Vec<&str> = did_value.splitn(2, ':').collect();
499
-
499
+
500
500
// Must have exactly 2 parts: scim and content
501
501
if parts.len() != 2 {
502
502
return false;
503
503
}
504
-
504
+
505
505
let scim = parts[0];
506
506
let content = parts[1];
507
-
507
+
508
508
// Validate scim - must be non-empty and contain only base58-btc alphabet characters
509
509
if scim.is_empty() || !is_valid_base58_btc(scim) {
510
510
return false;
511
511
}
512
-
512
+
513
513
// Validate content using the same rules as did:web
514
514
if strict {
515
515
// In strict mode, only a valid hostname is allowed
···
536
536
}
537
537
538
538
/// Checks if a string contains only base58-btc alphabet characters.
539
-
///
539
+
///
540
540
/// The base58-btc alphabet is used in Bitcoin and other cryptocurrency systems.
541
541
/// It includes all alphanumeric characters except those that are easily confused:
542
542
/// - Excludes: `0` (zero), `O` (capital O), `I` (capital I), `l` (lowercase L)
543
543
/// - Includes: `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`
544
-
///
544
+
///
545
545
/// # Arguments
546
-
///
546
+
///
547
547
/// * `s` - The string to validate for base58-btc character compliance
548
-
///
548
+
///
549
549
/// # Returns
550
-
///
550
+
///
551
551
/// `true` if the string is non-empty and contains only valid base58-btc characters, `false` otherwise
552
-
///
552
+
///
553
553
/// # Examples
554
-
///
554
+
///
555
555
/// ```
556
556
/// use atproto_identity::validation::is_valid_base58_btc;
557
-
///
557
+
///
558
558
/// // Valid base58-btc strings
559
559
/// assert!(is_valid_base58_btc("123456789"));
560
560
/// assert!(is_valid_base58_btc("ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz"));
561
561
/// assert!(is_valid_base58_btc("abc123XYZ"));
562
-
///
562
+
///
563
563
/// // Invalid - contains excluded characters
564
564
/// assert!(!is_valid_base58_btc("abc0def")); // Contains 0
565
565
/// assert!(!is_valid_base58_btc("abcOdef")); // Contains O
566
566
/// assert!(!is_valid_base58_btc("abcIdef")); // Contains I
567
567
/// assert!(!is_valid_base58_btc("abcldef")); // Contains l
568
-
///
568
+
///
569
569
/// // Invalid - empty or non-alphanumeric
570
570
/// assert!(!is_valid_base58_btc(""));
571
571
/// assert!(!is_valid_base58_btc("abc-def"));
···
795
795
#[test]
796
796
fn test_is_valid_did_method_webvh() {
797
797
// Test strict mode - valid cases
798
-
assert!(is_valid_did_method_webvh("did:webvh:abc123:example.com", true));
799
-
assert!(is_valid_did_method_webvh("did:webvh:XYZ789:sub.example.com", true));
800
-
assert!(is_valid_did_method_webvh("did:webvh:ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz123456789:example.com", true));
798
+
assert!(is_valid_did_method_webvh(
799
+
"did:webvh:abc123:example.com",
800
+
true
801
+
));
802
+
assert!(is_valid_did_method_webvh(
803
+
"did:webvh:XYZ789:sub.example.com",
804
+
true
805
+
));
806
+
assert!(is_valid_did_method_webvh(
807
+
"did:webvh:ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz123456789:example.com",
808
+
true
809
+
));
801
810
assert!(is_valid_did_method_webvh("did:webvh:1:example.com", true)); // single char scim
802
-
assert!(is_valid_did_method_webvh("did:webvh:zzzzzz:localhost", true));
811
+
assert!(is_valid_did_method_webvh(
812
+
"did:webvh:zzzzzz:localhost",
813
+
true
814
+
));
803
815
804
816
// Test strict mode - invalid cases with path segments
805
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com:path", true));
806
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com:path:subpath", true));
817
+
assert!(!is_valid_did_method_webvh(
818
+
"did:webvh:abc123:example.com:path",
819
+
true
820
+
));
821
+
assert!(!is_valid_did_method_webvh(
822
+
"did:webvh:abc123:example.com:path:subpath",
823
+
true
824
+
));
807
825
808
826
// Test non-strict mode - valid cases
809
-
assert!(is_valid_did_method_webvh("did:webvh:abc123:example.com", false));
810
-
assert!(is_valid_did_method_webvh("did:webvh:abc123:example.com:path", false));
811
-
assert!(is_valid_did_method_webvh("did:webvh:abc123:example.com:path:subpath", false));
812
-
assert!(is_valid_did_method_webvh("did:webvh:abc123:example.com:123", false));
813
-
assert!(is_valid_did_method_webvh("did:webvh:abc123:example.com:ABC123", false));
827
+
assert!(is_valid_did_method_webvh(
828
+
"did:webvh:abc123:example.com",
829
+
false
830
+
));
831
+
assert!(is_valid_did_method_webvh(
832
+
"did:webvh:abc123:example.com:path",
833
+
false
834
+
));
835
+
assert!(is_valid_did_method_webvh(
836
+
"did:webvh:abc123:example.com:path:subpath",
837
+
false
838
+
));
839
+
assert!(is_valid_did_method_webvh(
840
+
"did:webvh:abc123:example.com:123",
841
+
false
842
+
));
843
+
assert!(is_valid_did_method_webvh(
844
+
"did:webvh:abc123:example.com:ABC123",
845
+
false
846
+
));
814
847
815
848
// Invalid - wrong prefix
816
-
assert!(!is_valid_did_method_webvh("did:web:abc123:example.com", true));
817
-
assert!(!is_valid_did_method_webvh("did:web:abc123:example.com", false));
818
-
assert!(!is_valid_did_method_webvh("did:plc:abc123:example.com", true));
849
+
assert!(!is_valid_did_method_webvh(
850
+
"did:web:abc123:example.com",
851
+
true
852
+
));
853
+
assert!(!is_valid_did_method_webvh(
854
+
"did:web:abc123:example.com",
855
+
false
856
+
));
857
+
assert!(!is_valid_did_method_webvh(
858
+
"did:plc:abc123:example.com",
859
+
true
860
+
));
819
861
assert!(!is_valid_did_method_webvh("webvh:abc123:example.com", true));
820
862
assert!(!is_valid_did_method_webvh("abc123:example.com", true));
821
863
···
827
869
assert!(!is_valid_did_method_webvh("did:webvh:example.com", true)); // no scim separator
828
870
829
871
// Invalid - scim contains invalid base58 characters
830
-
assert!(!is_valid_did_method_webvh("did:webvh:0abc:example.com", true)); // contains 0
831
-
assert!(!is_valid_did_method_webvh("did:webvh:Oabc:example.com", true)); // contains O
832
-
assert!(!is_valid_did_method_webvh("did:webvh:Iabc:example.com", true)); // contains I
833
-
assert!(!is_valid_did_method_webvh("did:webvh:labc:example.com", true)); // contains l
834
-
assert!(!is_valid_did_method_webvh("did:webvh:abc-123:example.com", true)); // contains -
835
-
assert!(!is_valid_did_method_webvh("did:webvh:abc_123:example.com", true)); // contains _
836
-
assert!(!is_valid_did_method_webvh("did:webvh:abc.123:example.com", true)); // contains .
837
-
assert!(!is_valid_did_method_webvh("did:webvh:abc@123:example.com", true)); // contains @
838
-
assert!(!is_valid_did_method_webvh("did:webvh:abc 123:example.com", true)); // contains space
839
-
assert!(!is_valid_did_method_webvh("did:webvh:abc!123:example.com", true)); // contains !
840
-
assert!(!is_valid_did_method_webvh("did:webvh:abc#123:example.com", true)); // contains #
841
-
assert!(!is_valid_did_method_webvh("did:webvh:abc$123:example.com", true)); // contains $
872
+
assert!(!is_valid_did_method_webvh(
873
+
"did:webvh:0abc:example.com",
874
+
true
875
+
)); // contains 0
876
+
assert!(!is_valid_did_method_webvh(
877
+
"did:webvh:Oabc:example.com",
878
+
true
879
+
)); // contains O
880
+
assert!(!is_valid_did_method_webvh(
881
+
"did:webvh:Iabc:example.com",
882
+
true
883
+
)); // contains I
884
+
assert!(!is_valid_did_method_webvh(
885
+
"did:webvh:labc:example.com",
886
+
true
887
+
)); // contains l
888
+
assert!(!is_valid_did_method_webvh(
889
+
"did:webvh:abc-123:example.com",
890
+
true
891
+
)); // contains -
892
+
assert!(!is_valid_did_method_webvh(
893
+
"did:webvh:abc_123:example.com",
894
+
true
895
+
)); // contains _
896
+
assert!(!is_valid_did_method_webvh(
897
+
"did:webvh:abc.123:example.com",
898
+
true
899
+
)); // contains .
900
+
assert!(!is_valid_did_method_webvh(
901
+
"did:webvh:abc@123:example.com",
902
+
true
903
+
)); // contains @
904
+
assert!(!is_valid_did_method_webvh(
905
+
"did:webvh:abc 123:example.com",
906
+
true
907
+
)); // contains space
908
+
assert!(!is_valid_did_method_webvh(
909
+
"did:webvh:abc!123:example.com",
910
+
true
911
+
)); // contains !
912
+
assert!(!is_valid_did_method_webvh(
913
+
"did:webvh:abc#123:example.com",
914
+
true
915
+
)); // contains #
916
+
assert!(!is_valid_did_method_webvh(
917
+
"did:webvh:abc$123:example.com",
918
+
true
919
+
)); // contains $
842
920
843
921
// Invalid - bad hostname in content
844
922
assert!(!is_valid_did_method_webvh("did:webvh:abc123:", false)); // empty hostname
845
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:..example.com", true));
846
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:.example.com", true));
847
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com.", true));
848
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:-example.com", true));
849
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.localhost", true)); // reserved TLD
850
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:192.168.1.1", true)); // IPv4
851
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:2001:db8::1", true)); // IPv6
923
+
assert!(!is_valid_did_method_webvh(
924
+
"did:webvh:abc123:..example.com",
925
+
true
926
+
));
927
+
assert!(!is_valid_did_method_webvh(
928
+
"did:webvh:abc123:.example.com",
929
+
true
930
+
));
931
+
assert!(!is_valid_did_method_webvh(
932
+
"did:webvh:abc123:example.com.",
933
+
true
934
+
));
935
+
assert!(!is_valid_did_method_webvh(
936
+
"did:webvh:abc123:-example.com",
937
+
true
938
+
));
939
+
assert!(!is_valid_did_method_webvh(
940
+
"did:webvh:abc123:example.localhost",
941
+
true
942
+
)); // reserved TLD
943
+
assert!(!is_valid_did_method_webvh(
944
+
"did:webvh:abc123:192.168.1.1",
945
+
true
946
+
)); // IPv4
947
+
assert!(!is_valid_did_method_webvh(
948
+
"did:webvh:abc123:2001:db8::1",
949
+
true
950
+
)); // IPv6
852
951
853
952
// Invalid in non-strict mode - empty path segments
854
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com:", false));
855
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com::", false));
856
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com:path:", false));
857
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com::path", false));
953
+
assert!(!is_valid_did_method_webvh(
954
+
"did:webvh:abc123:example.com:",
955
+
false
956
+
));
957
+
assert!(!is_valid_did_method_webvh(
958
+
"did:webvh:abc123:example.com::",
959
+
false
960
+
));
961
+
assert!(!is_valid_did_method_webvh(
962
+
"did:webvh:abc123:example.com:path:",
963
+
false
964
+
));
965
+
assert!(!is_valid_did_method_webvh(
966
+
"did:webvh:abc123:example.com::path",
967
+
false
968
+
));
858
969
859
970
// Invalid in non-strict mode - non-alphanumeric in path segments
860
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com:path/subpath", false));
861
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com:path-name", false));
862
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com:path_name", false));
863
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com:path.name", false));
864
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com:path@name", false));
865
-
assert!(!is_valid_did_method_webvh("did:webvh:abc123:example.com:path name", false));
971
+
assert!(!is_valid_did_method_webvh(
972
+
"did:webvh:abc123:example.com:path/subpath",
973
+
false
974
+
));
975
+
assert!(!is_valid_did_method_webvh(
976
+
"did:webvh:abc123:example.com:path-name",
977
+
false
978
+
));
979
+
assert!(!is_valid_did_method_webvh(
980
+
"did:webvh:abc123:example.com:path_name",
981
+
false
982
+
));
983
+
assert!(!is_valid_did_method_webvh(
984
+
"did:webvh:abc123:example.com:path.name",
985
+
false
986
+
));
987
+
assert!(!is_valid_did_method_webvh(
988
+
"did:webvh:abc123:example.com:path@name",
989
+
false
990
+
));
991
+
assert!(!is_valid_did_method_webvh(
992
+
"did:webvh:abc123:example.com:path name",
993
+
false
994
+
));
866
995
867
996
// Edge cases with base58 characters
868
-
assert!(is_valid_did_method_webvh("did:webvh:111111:example.com", true)); // all 1s
869
-
assert!(is_valid_did_method_webvh("did:webvh:999999:example.com", true)); // all 9s
870
-
assert!(is_valid_did_method_webvh("did:webvh:AAAAAA:example.com", true)); // all As
871
-
assert!(is_valid_did_method_webvh("did:webvh:zzzzzz:example.com", true)); // all zs
872
-
assert!(is_valid_did_method_webvh("did:webvh:HJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz:example.com", true)); // no excluded letters
997
+
assert!(is_valid_did_method_webvh(
998
+
"did:webvh:111111:example.com",
999
+
true
1000
+
)); // all 1s
1001
+
assert!(is_valid_did_method_webvh(
1002
+
"did:webvh:999999:example.com",
1003
+
true
1004
+
)); // all 9s
1005
+
assert!(is_valid_did_method_webvh(
1006
+
"did:webvh:AAAAAA:example.com",
1007
+
true
1008
+
)); // all As
1009
+
assert!(is_valid_did_method_webvh(
1010
+
"did:webvh:zzzzzz:example.com",
1011
+
true
1012
+
)); // all zs
1013
+
assert!(is_valid_did_method_webvh(
1014
+
"did:webvh:HJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz:example.com",
1015
+
true
1016
+
)); // no excluded letters
873
1017
}
874
1018
875
1019
#[test]
876
1020
fn test_is_valid_base58_btc() {
877
1021
// Valid base58 strings
878
1022
assert!(is_valid_base58_btc("123456789"));
879
-
assert!(is_valid_base58_btc("ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz"));
1023
+
assert!(is_valid_base58_btc(
1024
+
"ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz"
1025
+
));
880
1026
assert!(is_valid_base58_btc("1"));
881
1027
assert!(is_valid_base58_btc("z"));
882
1028
assert!(is_valid_base58_btc("ABC123xyz"));