+279
AUTH.md
+279
AUTH.md
···
1
+
# PDS Gatekeeper Authentication Middleware
2
+
3
+
This document describes the authentication middleware system for pds-gatekeeper, which provides flexible authorization rules based on DIDs, handles, and OAuth scopes.
4
+
5
+
## Overview
6
+
7
+
The auth middleware validates incoming requests by:
8
+
9
+
1. **Extracting** the DID and scopes from a JWT Bearer token
10
+
2. **Resolving** the DID to a handle using jacquard-identity
11
+
3. **Validating** against configured authorization rules
12
+
4. **Returning** appropriate HTTP errors (401/403) on failure
13
+
14
+
## Quick Start
15
+
16
+
```rust
17
+
use axum::middleware::from_fn_with_state;
18
+
use crate::auth::{auth_middleware, handle_ends_with, scope_equals, with_rules, AuthRules};
19
+
20
+
let app = Router::new()
21
+
// Simple: require handle from specific domain
22
+
.route("/xrpc/community.blacksky.feed.get",
23
+
get(handler).layer(from_fn_with_state(
24
+
handle_ends_with(".blacksky.team", &state),
25
+
auth_middleware
26
+
)))
27
+
28
+
// Simple: require specific OAuth scope
29
+
.route("/xrpc/com.atproto.repo.createRecord",
30
+
post(handler).layer(from_fn_with_state(
31
+
scope_equals("repo:app.bsky.feed.post", &state),
32
+
auth_middleware
33
+
)))
34
+
35
+
.with_state(state);
36
+
```
37
+
38
+
## ATProto OAuth Scopes Reference
39
+
40
+
| Scope | Description |
41
+
|-------|-------------|
42
+
| `atproto` | Base scope, required for all OAuth clients |
43
+
| `transition:generic` | Full repository access (equivalent to app passwords) |
44
+
| `repo:<collection>` | Access to specific collection (e.g., `repo:app.bsky.feed.post`) |
45
+
| `identity:handle` | Permits handle changes |
46
+
| `identity:*` | Full DID document control |
47
+
| `account:email` | Read email addresses |
48
+
| `account:repo?action=manage` | Import repository data |
49
+
| `blob:*/*` | Upload any blob type |
50
+
| `blob?accept=image/*` | Upload only images |
51
+
52
+
See [Marvin's Guide to OAuth Scopes](https://marvins-guide.leaflet.pub/3mbfvey7sok26) for complete details.
53
+
54
+
## Helper Functions
55
+
56
+
### Identity Helpers
57
+
58
+
| Function | Description |
59
+
|----------|-------------|
60
+
| `handle_ends_with(suffix, state)` | Handle must end with suffix |
61
+
| `handle_ends_with_any(suffixes, state)` | Handle must end with any suffix (OR) |
62
+
| `did_equals(did, state)` | DID must match exactly |
63
+
| `did_equals_any(dids, state)` | DID must match any value (OR) |
64
+
65
+
### Scope Helpers
66
+
67
+
| Function | Description |
68
+
|----------|-------------|
69
+
| `scope_equals(scope, state)` | Must have specific scope |
70
+
| `scope_any(scopes, state)` | Must have any of the scopes (OR) |
71
+
| `scope_all(scopes, state)` | Must have all scopes (AND) |
72
+
73
+
### Combined Helpers (Identity + Scope)
74
+
75
+
| Function | Description |
76
+
|----------|-------------|
77
+
| `handle_ends_with_and_scope(suffix, scope, state)` | Handle suffix AND scope |
78
+
| `handle_ends_with_and_scopes(suffix, scopes, state)` | Handle suffix AND all scopes |
79
+
| `did_with_scope(did, scope, state)` | DID match AND scope |
80
+
| `did_with_scopes(did, scopes, state)` | DID match AND all scopes |
81
+
82
+
### Custom Rules
83
+
84
+
For complex authorization logic, use `with_rules()`:
85
+
86
+
```rust
87
+
with_rules(AuthRules::Any(vec![
88
+
AuthRules::DidEquals("did:plc:rnpkyqnmsw4ipey6eotbdnnf".into()),
89
+
AuthRules::All(vec![
90
+
AuthRules::HandleEndsWith(".mod.team".into()),
91
+
AuthRules::ScopeEquals("account:email".into()),
92
+
]),
93
+
]), &state)
94
+
```
95
+
96
+
## Realistic PDS Endpoint Examples
97
+
98
+
### Admin Endpoints
99
+
100
+
Based on `com.atproto.admin.*` endpoints from the ATProto PDS:
101
+
102
+
```rust
103
+
// com.atproto.admin.deleteAccount
104
+
// Admin-only: specific DID with full access scope
105
+
.route("/xrpc/com.atproto.admin.deleteAccount",
106
+
post(delete_account).layer(from_fn_with_state(
107
+
did_with_scope("did:plc:rnpkyqnmsw4ipey6eotbdnnf", "transition:generic", &state),
108
+
auth_middleware
109
+
)))
110
+
111
+
// com.atproto.admin.getAccountInfo
112
+
// Either admin DID OR (moderator handle + account scope)
113
+
.route("/xrpc/com.atproto.admin.getAccountInfo",
114
+
get(get_account_info).layer(from_fn_with_state(
115
+
with_rules(AuthRules::Any(vec![
116
+
AuthRules::DidEquals("did:plc:rnpkyqnmsw4ipey6eotbdnnf".into()),
117
+
AuthRules::All(vec![
118
+
AuthRules::HandleEndsWith(".mod.team".into()),
119
+
AuthRules::ScopeEquals("account:email".into()),
120
+
]),
121
+
]), &state),
122
+
auth_middleware
123
+
)))
124
+
125
+
// com.atproto.admin.updateAccountEmail
126
+
// Admin DID with account management scope
127
+
.route("/xrpc/com.atproto.admin.updateAccountEmail",
128
+
post(update_email).layer(from_fn_with_state(
129
+
did_with_scopes(
130
+
"did:plc:rnpkyqnmsw4ipey6eotbdnnf",
131
+
["account:email", "account:repo?action=manage"],
132
+
&state
133
+
),
134
+
auth_middleware
135
+
)))
136
+
137
+
// com.atproto.admin.updateAccountHandle
138
+
// Admin with identity control
139
+
.route("/xrpc/com.atproto.admin.updateAccountHandle",
140
+
post(update_handle).layer(from_fn_with_state(
141
+
did_with_scope("did:plc:rnpkyqnmsw4ipey6eotbdnnf", "identity:*", &state),
142
+
auth_middleware
143
+
)))
144
+
```
145
+
146
+
### Repository Endpoints
147
+
148
+
```rust
149
+
// com.atproto.repo.createRecord
150
+
// Scoped write access to specific collection
151
+
.route("/xrpc/com.atproto.repo.createRecord",
152
+
post(create_record).layer(from_fn_with_state(
153
+
scope_equals("repo:app.bsky.feed.post", &state),
154
+
auth_middleware
155
+
)))
156
+
157
+
// com.atproto.repo.putRecord
158
+
// Either specific collection scope OR full access
159
+
.route("/xrpc/com.atproto.repo.putRecord",
160
+
post(put_record).layer(from_fn_with_state(
161
+
scope_any(["repo:app.bsky.feed.post", "transition:generic"], &state),
162
+
auth_middleware
163
+
)))
164
+
165
+
// com.atproto.repo.uploadBlob
166
+
// Blob upload with media type restriction (scope-based)
167
+
.route("/xrpc/com.atproto.repo.uploadBlob",
168
+
post(upload_blob).layer(from_fn_with_state(
169
+
scope_any(["blob:*/*", "blob?accept=image/*", "transition:generic"], &state),
170
+
auth_middleware
171
+
)))
172
+
```
173
+
174
+
### Community/Custom Endpoints
175
+
176
+
```rust
177
+
// Community feed generator - restricted to team members with full access
178
+
.route("/xrpc/community.blacksky.feed.generator",
179
+
post(generator).layer(from_fn_with_state(
180
+
handle_ends_with_and_scope(".blacksky.team", "transition:generic", &state),
181
+
auth_middleware
182
+
)))
183
+
184
+
// Multi-community endpoint
185
+
.route("/xrpc/community.shared.moderation.report",
186
+
post(report).layer(from_fn_with_state(
187
+
with_rules(AuthRules::All(vec![
188
+
AuthRules::HandleEndsWithAny(vec![
189
+
".blacksky.team".into(),
190
+
".bsky.team".into(),
191
+
".mod.social".into(),
192
+
]),
193
+
AuthRules::ScopeEquals("atproto".into()),
194
+
]), &state),
195
+
auth_middleware
196
+
)))
197
+
198
+
// VIP access - specific DIDs only
199
+
.route("/xrpc/community.blacksky.vip.access",
200
+
get(vip_handler).layer(from_fn_with_state(
201
+
did_equals_any([
202
+
"did:plc:rnpkyqnmsw4ipey6eotbdnnf",
203
+
"did:plc:abc123def456ghi789jklmno",
204
+
"did:plc:xyz987uvw654rst321qponml",
205
+
], &state),
206
+
auth_middleware
207
+
)))
208
+
```
209
+
210
+
## Building Complex Authorization Rules
211
+
212
+
The `AuthRules` enum supports arbitrary nesting:
213
+
214
+
```rust
215
+
// Complex: Admin OR (Team member with write scope) OR (Moderator with read-only)
216
+
let rules = AuthRules::Any(vec![
217
+
// Admin bypass
218
+
AuthRules::DidEquals("did:plc:rnpkyqnmsw4ipey6eotbdnnf".into()),
219
+
220
+
// Team member with write access
221
+
AuthRules::All(vec![
222
+
AuthRules::HandleEndsWith(".blacksky.team".into()),
223
+
AuthRules::ScopeEquals("transition:generic".into()),
224
+
]),
225
+
226
+
// Moderator with limited scope
227
+
AuthRules::All(vec![
228
+
AuthRules::HandleEndsWith(".mod.team".into()),
229
+
AuthRules::ScopeEqualsAny(vec![
230
+
"account:email".into(),
231
+
"atproto".into(),
232
+
]),
233
+
]),
234
+
]);
235
+
```
236
+
237
+
## Error Responses
238
+
239
+
| Status | Error Code | Description |
240
+
|--------|------------|-------------|
241
+
| `401` | `AuthRequired` | No Authorization header provided |
242
+
| `401` | `InvalidToken` | JWT validation failed (expired, invalid signature, malformed) |
243
+
| `403` | `AccessDenied` | Valid authentication but authorization rules rejected |
244
+
| `500` | `ResolutionError` | Failed to resolve DID to handle |
245
+
246
+
Response format:
247
+
```json
248
+
{
249
+
"error": "AccessDenied",
250
+
"message": "Access denied by authorization rules"
251
+
}
252
+
```
253
+
254
+
## JWT Token Format
255
+
256
+
The middleware expects JWT tokens with these claims:
257
+
258
+
```json
259
+
{
260
+
"sub": "did:plc:rnpkyqnmsw4ipey6eotbdnnf",
261
+
"scope": "atproto transition:generic repo:app.bsky.feed.post",
262
+
"iat": 1704067200,
263
+
"exp": 1704153600
264
+
}
265
+
```
266
+
267
+
- `sub` (required): The user's DID
268
+
- `scope` (optional): Space-separated OAuth scopes per [RFC 6749](https://tools.ietf.org/html/rfc6749)
269
+
270
+
## Handle Resolution
271
+
272
+
DIDs are resolved to handles using the jacquard-identity `PublicResolver`:
273
+
274
+
1. Check the `HandleCache` for a cached result
275
+
2. If miss, resolve the DID document via PLC directory
276
+
3. Extract handle from `alsoKnownAs` field (format: `at://handle.example.com`)
277
+
4. Cache the result (1 hour TTL default)
278
+
279
+
This allows rules like `HandleEndsWith(".blacksky.team")` to work even though the JWT only contains the DID.
+759
-605
Cargo.lock
+759
-605
Cargo.lock
···
22
22
]
23
23
24
24
[[package]]
25
-
name = "addr2line"
26
-
version = "0.24.2"
27
-
source = "registry+https://github.com/rust-lang/crates.io-index"
28
-
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
29
-
dependencies = [
30
-
"gimli",
31
-
]
32
-
33
-
[[package]]
34
25
name = "adler2"
35
26
version = "2.0.1"
36
27
source = "registry+https://github.com/rust-lang/crates.io-index"
···
50
41
51
42
[[package]]
52
43
name = "aho-corasick"
53
-
version = "1.1.3"
44
+
version = "1.1.4"
54
45
source = "registry+https://github.com/rust-lang/crates.io-index"
55
-
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
46
+
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
56
47
dependencies = [
57
48
"memchr",
58
49
]
···
80
71
81
72
[[package]]
82
73
name = "anyhow"
83
-
version = "1.0.99"
74
+
version = "1.0.100"
75
+
source = "registry+https://github.com/rust-lang/crates.io-index"
76
+
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
77
+
78
+
[[package]]
79
+
name = "ar_archive_writer"
80
+
version = "0.2.0"
84
81
source = "registry+https://github.com/rust-lang/crates.io-index"
85
-
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
82
+
checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a"
83
+
dependencies = [
84
+
"object",
85
+
]
86
86
87
87
[[package]]
88
88
name = "async-compression"
89
-
version = "0.4.27"
89
+
version = "0.4.36"
90
90
source = "registry+https://github.com/rust-lang/crates.io-index"
91
-
checksum = "ddb939d66e4ae03cee6091612804ba446b12878410cfa17f785f4dd67d4014e8"
91
+
checksum = "98ec5f6c2f8bc326c994cb9e241cc257ddaba9afa8555a43cffbb5dd86efaa37"
92
92
dependencies = [
93
-
"flate2",
93
+
"compression-codecs",
94
+
"compression-core",
94
95
"futures-core",
95
-
"memchr",
96
96
"pin-project-lite",
97
97
"tokio",
98
-
"zstd",
99
-
"zstd-safe",
100
98
]
101
99
102
100
[[package]]
···
107
105
dependencies = [
108
106
"proc-macro2",
109
107
"quote",
110
-
"syn 2.0.105",
108
+
"syn 2.0.112",
111
109
]
112
110
113
111
[[package]]
···
120
118
]
121
119
122
120
[[package]]
121
+
name = "atomic-polyfill"
122
+
version = "1.0.3"
123
+
source = "registry+https://github.com/rust-lang/crates.io-index"
124
+
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
125
+
dependencies = [
126
+
"critical-section",
127
+
]
128
+
129
+
[[package]]
123
130
name = "atomic-waker"
124
131
version = "1.1.2"
125
132
source = "registry+https://github.com/rust-lang/crates.io-index"
···
133
140
134
141
[[package]]
135
142
name = "aws-lc-rs"
136
-
version = "1.13.3"
143
+
version = "1.15.2"
137
144
source = "registry+https://github.com/rust-lang/crates.io-index"
138
-
checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba"
145
+
checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288"
139
146
dependencies = [
140
147
"aws-lc-sys",
141
148
"untrusted 0.7.1",
···
144
151
145
152
[[package]]
146
153
name = "aws-lc-sys"
147
-
version = "0.30.0"
154
+
version = "0.35.0"
148
155
source = "registry+https://github.com/rust-lang/crates.io-index"
149
-
checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff"
156
+
checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1"
150
157
dependencies = [
151
-
"bindgen",
152
158
"cc",
153
159
"cmake",
154
160
"dunce",
···
157
163
158
164
[[package]]
159
165
name = "axum"
160
-
version = "0.8.4"
166
+
version = "0.8.8"
161
167
source = "registry+https://github.com/rust-lang/crates.io-index"
162
-
checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5"
168
+
checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
163
169
dependencies = [
164
170
"axum-core",
165
171
"axum-macros",
···
177
183
"mime",
178
184
"percent-encoding",
179
185
"pin-project-lite",
180
-
"rustversion",
181
-
"serde",
186
+
"serde_core",
182
187
"serde_json",
183
188
"serde_path_to_error",
184
189
"serde_urlencoded",
···
192
197
193
198
[[package]]
194
199
name = "axum-core"
195
-
version = "0.5.2"
200
+
version = "0.5.6"
196
201
source = "registry+https://github.com/rust-lang/crates.io-index"
197
-
checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6"
202
+
checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1"
198
203
dependencies = [
199
204
"bytes",
200
205
"futures-core",
···
203
208
"http-body-util",
204
209
"mime",
205
210
"pin-project-lite",
206
-
"rustversion",
207
211
"sync_wrapper",
208
212
"tower-layer",
209
213
"tower-service",
···
218
222
dependencies = [
219
223
"proc-macro2",
220
224
"quote",
221
-
"syn 2.0.105",
225
+
"syn 2.0.112",
222
226
]
223
227
224
228
[[package]]
···
230
234
"axum",
231
235
"handlebars",
232
236
"serde",
233
-
"thiserror 2.0.14",
234
-
]
235
-
236
-
[[package]]
237
-
name = "backtrace"
238
-
version = "0.3.75"
239
-
source = "registry+https://github.com/rust-lang/crates.io-index"
240
-
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
241
-
dependencies = [
242
-
"addr2line",
243
-
"cfg-if",
244
-
"libc",
245
-
"miniz_oxide",
246
-
"object",
247
-
"rustc-demangle",
248
-
"windows-targets 0.52.6",
237
+
"thiserror 2.0.17",
249
238
]
250
239
251
240
[[package]]
···
278
267
279
268
[[package]]
280
269
name = "base64ct"
281
-
version = "1.8.0"
270
+
version = "1.8.1"
282
271
source = "registry+https://github.com/rust-lang/crates.io-index"
283
-
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
284
-
285
-
[[package]]
286
-
name = "bindgen"
287
-
version = "0.69.5"
288
-
source = "registry+https://github.com/rust-lang/crates.io-index"
289
-
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
290
-
dependencies = [
291
-
"bitflags",
292
-
"cexpr",
293
-
"clang-sys",
294
-
"itertools",
295
-
"lazy_static",
296
-
"lazycell",
297
-
"log",
298
-
"prettyplease",
299
-
"proc-macro2",
300
-
"quote",
301
-
"regex",
302
-
"rustc-hash 1.1.0",
303
-
"shlex",
304
-
"syn 2.0.105",
305
-
"which",
306
-
]
272
+
checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a"
307
273
308
274
[[package]]
309
275
name = "bitflags"
310
-
version = "2.9.1"
276
+
version = "2.10.0"
311
277
source = "registry+https://github.com/rust-lang/crates.io-index"
312
-
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
278
+
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
313
279
dependencies = [
314
-
"serde",
280
+
"serde_core",
315
281
]
316
282
317
283
[[package]]
···
345
311
"proc-macro2",
346
312
"quote",
347
313
"rustversion",
348
-
"syn 2.0.105",
314
+
"syn 2.0.112",
349
315
]
350
316
351
317
[[package]]
···
359
325
360
326
[[package]]
361
327
name = "bstr"
362
-
version = "1.12.0"
328
+
version = "1.12.1"
363
329
source = "registry+https://github.com/rust-lang/crates.io-index"
364
-
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
330
+
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
365
331
dependencies = [
366
332
"memchr",
367
333
"serde",
···
393
359
394
360
[[package]]
395
361
name = "bumpalo"
396
-
version = "3.19.0"
362
+
version = "3.19.1"
397
363
source = "registry+https://github.com/rust-lang/crates.io-index"
398
-
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
364
+
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
399
365
400
366
[[package]]
401
367
name = "byteorder"
···
405
371
406
372
[[package]]
407
373
name = "bytes"
408
-
version = "1.10.1"
374
+
version = "1.11.0"
409
375
source = "registry+https://github.com/rust-lang/crates.io-index"
410
-
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
376
+
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
411
377
dependencies = [
412
378
"serde",
413
379
]
···
423
389
424
390
[[package]]
425
391
name = "cc"
426
-
version = "1.2.32"
392
+
version = "1.2.51"
427
393
source = "registry+https://github.com/rust-lang/crates.io-index"
428
-
checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e"
394
+
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
429
395
dependencies = [
396
+
"find-msvc-tools",
430
397
"jobserver",
431
398
"libc",
432
399
"shlex",
···
442
409
]
443
410
444
411
[[package]]
445
-
name = "cexpr"
446
-
version = "0.6.0"
447
-
source = "registry+https://github.com/rust-lang/crates.io-index"
448
-
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
449
-
dependencies = [
450
-
"nom 7.1.3",
451
-
]
452
-
453
-
[[package]]
454
412
name = "cfg-if"
455
-
version = "1.0.1"
413
+
version = "1.0.4"
456
414
source = "registry+https://github.com/rust-lang/crates.io-index"
457
-
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
415
+
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
458
416
459
417
[[package]]
460
418
name = "cfg_aliases"
···
473
431
"num-traits",
474
432
"serde",
475
433
"wasm-bindgen",
476
-
"windows-link 0.2.1",
434
+
"windows-link",
477
435
]
478
436
479
437
[[package]]
···
538
496
]
539
497
540
498
[[package]]
541
-
name = "clang-sys"
542
-
version = "1.8.1"
499
+
name = "cmake"
500
+
version = "0.1.57"
501
+
source = "registry+https://github.com/rust-lang/crates.io-index"
502
+
checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
503
+
dependencies = [
504
+
"cc",
505
+
]
506
+
507
+
[[package]]
508
+
name = "cobs"
509
+
version = "0.3.0"
543
510
source = "registry+https://github.com/rust-lang/crates.io-index"
544
-
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
511
+
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
545
512
dependencies = [
546
-
"glob",
547
-
"libc",
548
-
"libloading",
513
+
"thiserror 2.0.17",
549
514
]
550
515
551
516
[[package]]
552
-
name = "cmake"
553
-
version = "0.1.54"
517
+
name = "compression-codecs"
518
+
version = "0.4.35"
554
519
source = "registry+https://github.com/rust-lang/crates.io-index"
555
-
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
520
+
checksum = "b0f7ac3e5b97fdce45e8922fb05cae2c37f7bbd63d30dd94821dacfd8f3f2bf2"
556
521
dependencies = [
557
-
"cc",
522
+
"compression-core",
523
+
"flate2",
524
+
"memchr",
525
+
"zstd",
526
+
"zstd-safe",
558
527
]
528
+
529
+
[[package]]
530
+
name = "compression-core"
531
+
version = "0.4.31"
532
+
source = "registry+https://github.com/rust-lang/crates.io-index"
533
+
checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d"
559
534
560
535
[[package]]
561
536
name = "concurrent-queue"
···
579
554
checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3"
580
555
581
556
[[package]]
557
+
name = "cordyceps"
558
+
version = "0.3.4"
559
+
source = "registry+https://github.com/rust-lang/crates.io-index"
560
+
checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a"
561
+
dependencies = [
562
+
"loom",
563
+
"tracing",
564
+
]
565
+
566
+
[[package]]
582
567
name = "core-foundation"
583
568
version = "0.9.4"
584
569
source = "registry+https://github.com/rust-lang/crates.io-index"
···
614
599
615
600
[[package]]
616
601
name = "crc"
617
-
version = "3.3.0"
602
+
version = "3.4.0"
618
603
source = "registry+https://github.com/rust-lang/crates.io-index"
619
-
checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675"
604
+
checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
620
605
dependencies = [
621
606
"crc-catalog",
622
607
]
···
635
620
dependencies = [
636
621
"cfg-if",
637
622
]
623
+
624
+
[[package]]
625
+
name = "critical-section"
626
+
version = "1.2.0"
627
+
source = "registry+https://github.com/rust-lang/crates.io-index"
628
+
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
638
629
639
630
[[package]]
640
631
name = "crossbeam-queue"
···
671
662
672
663
[[package]]
673
664
name = "crypto-common"
674
-
version = "0.1.6"
665
+
version = "0.1.7"
675
666
source = "registry+https://github.com/rust-lang/crates.io-index"
676
-
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
667
+
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
677
668
dependencies = [
678
669
"generic-array",
679
670
"typenum",
···
710
701
"proc-macro2",
711
702
"quote",
712
703
"strsim",
713
-
"syn 2.0.105",
704
+
"syn 2.0.112",
714
705
]
715
706
716
707
[[package]]
···
724
715
"proc-macro2",
725
716
"quote",
726
717
"strsim",
727
-
"syn 2.0.105",
718
+
"syn 2.0.112",
728
719
]
729
720
730
721
[[package]]
···
735
726
dependencies = [
736
727
"darling_core 0.20.11",
737
728
"quote",
738
-
"syn 2.0.105",
729
+
"syn 2.0.112",
739
730
]
740
731
741
732
[[package]]
···
746
737
dependencies = [
747
738
"darling_core 0.21.3",
748
739
"quote",
749
-
"syn 2.0.105",
740
+
"syn 2.0.112",
750
741
]
751
742
752
743
[[package]]
···
786
777
checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976"
787
778
dependencies = [
788
779
"data-encoding",
789
-
"syn 2.0.105",
780
+
"syn 2.0.112",
790
781
]
791
782
792
783
[[package]]
···
828
819
"darling 0.20.11",
829
820
"proc-macro2",
830
821
"quote",
831
-
"syn 2.0.105",
822
+
"syn 2.0.112",
832
823
]
833
824
834
825
[[package]]
···
838
829
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
839
830
dependencies = [
840
831
"derive_builder_core",
841
-
"syn 2.0.105",
832
+
"syn 2.0.112",
842
833
]
834
+
835
+
[[package]]
836
+
name = "derive_more"
837
+
version = "1.0.0"
838
+
source = "registry+https://github.com/rust-lang/crates.io-index"
839
+
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
840
+
dependencies = [
841
+
"derive_more-impl",
842
+
]
843
+
844
+
[[package]]
845
+
name = "derive_more-impl"
846
+
version = "1.0.0"
847
+
source = "registry+https://github.com/rust-lang/crates.io-index"
848
+
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
849
+
dependencies = [
850
+
"proc-macro2",
851
+
"quote",
852
+
"syn 2.0.112",
853
+
"unicode-xid",
854
+
]
855
+
856
+
[[package]]
857
+
name = "diatomic-waker"
858
+
version = "0.2.3"
859
+
source = "registry+https://github.com/rust-lang/crates.io-index"
860
+
checksum = "ab03c107fafeb3ee9f5925686dbb7a73bc76e3932abb0d2b365cb64b169cf04c"
843
861
844
862
[[package]]
845
863
name = "digest"
···
861
879
dependencies = [
862
880
"proc-macro2",
863
881
"quote",
864
-
"syn 2.0.105",
882
+
"syn 2.0.112",
865
883
]
866
884
867
885
[[package]]
···
942
960
checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449"
943
961
944
962
[[package]]
963
+
name = "embedded-io"
964
+
version = "0.4.0"
965
+
source = "registry+https://github.com/rust-lang/crates.io-index"
966
+
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
967
+
968
+
[[package]]
969
+
name = "embedded-io"
970
+
version = "0.6.1"
971
+
source = "registry+https://github.com/rust-lang/crates.io-index"
972
+
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
973
+
974
+
[[package]]
945
975
name = "encoding_rs"
946
976
version = "0.8.35"
947
977
source = "registry+https://github.com/rust-lang/crates.io-index"
···
958
988
959
989
[[package]]
960
990
name = "errno"
961
-
version = "0.3.13"
991
+
version = "0.3.14"
962
992
source = "registry+https://github.com/rust-lang/crates.io-index"
963
-
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
993
+
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
964
994
dependencies = [
965
995
"libc",
966
996
"windows-sys 0.59.0",
···
1005
1035
]
1006
1036
1007
1037
[[package]]
1038
+
name = "find-msvc-tools"
1039
+
version = "0.1.6"
1040
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1041
+
checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
1042
+
1043
+
[[package]]
1008
1044
name = "flate2"
1009
1045
version = "1.1.5"
1010
1046
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1022
1058
dependencies = [
1023
1059
"futures-core",
1024
1060
"futures-sink",
1025
-
"spin",
1061
+
"spin 0.9.8",
1026
1062
]
1027
1063
1028
1064
[[package]]
···
1038
1074
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
1039
1075
1040
1076
[[package]]
1077
+
name = "foldhash"
1078
+
version = "0.2.0"
1079
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1080
+
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
1081
+
1082
+
[[package]]
1041
1083
name = "foreign-types"
1042
1084
version = "0.3.2"
1043
1085
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1054
1096
1055
1097
[[package]]
1056
1098
name = "form_urlencoded"
1057
-
version = "1.2.1"
1099
+
version = "1.2.2"
1058
1100
source = "registry+https://github.com/rust-lang/crates.io-index"
1059
-
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
1101
+
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
1060
1102
dependencies = [
1061
1103
"percent-encoding",
1062
1104
]
···
1078
1120
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
1079
1121
1080
1122
[[package]]
1123
+
name = "futures-buffered"
1124
+
version = "0.2.12"
1125
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1126
+
checksum = "a8e0e1f38ec07ba4abbde21eed377082f17ccb988be9d988a5adbf4bafc118fd"
1127
+
dependencies = [
1128
+
"cordyceps",
1129
+
"diatomic-waker",
1130
+
"futures-core",
1131
+
"pin-project-lite",
1132
+
"spin 0.10.0",
1133
+
]
1134
+
1135
+
[[package]]
1081
1136
name = "futures-channel"
1082
1137
version = "0.3.31"
1083
1138
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1122
1177
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
1123
1178
1124
1179
[[package]]
1180
+
name = "futures-lite"
1181
+
version = "2.6.1"
1182
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1183
+
checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
1184
+
dependencies = [
1185
+
"fastrand",
1186
+
"futures-core",
1187
+
"futures-io",
1188
+
"parking",
1189
+
"pin-project-lite",
1190
+
]
1191
+
1192
+
[[package]]
1125
1193
name = "futures-macro"
1126
1194
version = "0.3.31"
1127
1195
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1129
1197
dependencies = [
1130
1198
"proc-macro2",
1131
1199
"quote",
1132
-
"syn 2.0.105",
1200
+
"syn 2.0.112",
1133
1201
]
1134
1202
1135
1203
[[package]]
···
1168
1236
]
1169
1237
1170
1238
[[package]]
1239
+
name = "generator"
1240
+
version = "0.8.8"
1241
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1242
+
checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9"
1243
+
dependencies = [
1244
+
"cc",
1245
+
"cfg-if",
1246
+
"libc",
1247
+
"log",
1248
+
"rustversion",
1249
+
"windows-link",
1250
+
"windows-result",
1251
+
]
1252
+
1253
+
[[package]]
1171
1254
name = "generic-array"
1172
1255
version = "0.14.7"
1173
1256
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1206
1289
]
1207
1290
1208
1291
[[package]]
1209
-
name = "gimli"
1210
-
version = "0.31.1"
1211
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1212
-
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
1213
-
1214
-
[[package]]
1215
-
name = "glob"
1216
-
version = "0.3.3"
1217
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1218
-
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
1219
-
1220
-
[[package]]
1221
1292
name = "globset"
1222
-
version = "0.4.16"
1293
+
version = "0.4.18"
1223
1294
source = "registry+https://github.com/rust-lang/crates.io-index"
1224
-
checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5"
1295
+
checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
1225
1296
dependencies = [
1226
1297
"aho-corasick",
1227
1298
"bstr",
1228
1299
"log",
1229
-
"regex-automata 0.4.13",
1230
-
"regex-syntax 0.8.5",
1300
+
"regex-automata",
1301
+
"regex-syntax",
1231
1302
]
1232
1303
1233
1304
[[package]]
1234
1305
name = "governor"
1235
-
version = "0.10.1"
1306
+
version = "0.10.4"
1236
1307
source = "registry+https://github.com/rust-lang/crates.io-index"
1237
-
checksum = "444405bbb1a762387aa22dd569429533b54a1d8759d35d3b64cb39b0293eaa19"
1308
+
checksum = "9efcab3c1958580ff1f25a2a41be1668f7603d849bb63af523b208a3cc1223b8"
1238
1309
dependencies = [
1239
1310
"cfg-if",
1240
1311
"dashmap",
···
1242
1313
"futures-timer",
1243
1314
"futures-util",
1244
1315
"getrandom 0.3.4",
1245
-
"hashbrown 0.15.5",
1316
+
"hashbrown 0.16.1",
1246
1317
"nonzero_ext",
1247
1318
"parking_lot",
1248
1319
"portable-atomic",
···
1276
1347
"futures-core",
1277
1348
"futures-sink",
1278
1349
"http",
1279
-
"indexmap 2.10.0",
1350
+
"indexmap 2.12.1",
1280
1351
"slab",
1281
1352
"tokio",
1282
1353
"tokio-util",
···
1285
1356
1286
1357
[[package]]
1287
1358
name = "half"
1288
-
version = "2.6.0"
1359
+
version = "2.7.1"
1289
1360
source = "registry+https://github.com/rust-lang/crates.io-index"
1290
-
checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
1361
+
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
1291
1362
dependencies = [
1292
1363
"cfg-if",
1293
1364
"crunchy",
1365
+
"zerocopy",
1294
1366
]
1295
1367
1296
1368
[[package]]
1297
1369
name = "handlebars"
1298
-
version = "6.3.2"
1370
+
version = "6.4.0"
1299
1371
source = "registry+https://github.com/rust-lang/crates.io-index"
1300
-
checksum = "759e2d5aea3287cb1190c8ec394f42866cb5bf74fcbf213f354e3c856ea26098"
1372
+
checksum = "9b3f9296c208515b87bd915a2f5d1163d4b3f863ba83337d7713cf478055948e"
1301
1373
dependencies = [
1302
1374
"derive_builder",
1303
1375
"log",
···
1307
1379
"rust-embed",
1308
1380
"serde",
1309
1381
"serde_json",
1310
-
"thiserror 2.0.14",
1382
+
"thiserror 2.0.17",
1383
+
]
1384
+
1385
+
[[package]]
1386
+
name = "hash32"
1387
+
version = "0.2.1"
1388
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1389
+
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
1390
+
dependencies = [
1391
+
"byteorder",
1311
1392
]
1312
1393
1313
1394
[[package]]
···
1334
1415
dependencies = [
1335
1416
"allocator-api2",
1336
1417
"equivalent",
1337
-
"foldhash",
1418
+
"foldhash 0.1.5",
1419
+
]
1420
+
1421
+
[[package]]
1422
+
name = "hashbrown"
1423
+
version = "0.16.1"
1424
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1425
+
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
1426
+
dependencies = [
1427
+
"allocator-api2",
1428
+
"equivalent",
1429
+
"foldhash 0.2.0",
1338
1430
]
1339
1431
1340
1432
[[package]]
···
1347
1439
]
1348
1440
1349
1441
[[package]]
1442
+
name = "heapless"
1443
+
version = "0.7.17"
1444
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1445
+
checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
1446
+
dependencies = [
1447
+
"atomic-polyfill",
1448
+
"hash32",
1449
+
"rustc_version",
1450
+
"serde",
1451
+
"spin 0.9.8",
1452
+
"stable_deref_trait",
1453
+
]
1454
+
1455
+
[[package]]
1350
1456
name = "heck"
1351
1457
version = "0.4.1"
1352
1458
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1390
1496
1391
1497
[[package]]
1392
1498
name = "home"
1393
-
version = "0.5.11"
1499
+
version = "0.5.12"
1394
1500
source = "registry+https://github.com/rust-lang/crates.io-index"
1395
-
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
1501
+
checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
1396
1502
dependencies = [
1397
-
"windows-sys 0.59.0",
1503
+
"windows-sys 0.61.2",
1398
1504
]
1399
1505
1400
1506
[[package]]
···
1408
1514
1409
1515
[[package]]
1410
1516
name = "http"
1411
-
version = "1.3.1"
1517
+
version = "1.4.0"
1412
1518
source = "registry+https://github.com/rust-lang/crates.io-index"
1413
-
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
1519
+
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
1414
1520
dependencies = [
1415
1521
"bytes",
1416
-
"fnv",
1417
1522
"itoa",
1418
1523
]
1419
1524
···
1454
1559
1455
1560
[[package]]
1456
1561
name = "hyper"
1457
-
version = "1.6.0"
1562
+
version = "1.8.1"
1458
1563
source = "registry+https://github.com/rust-lang/crates.io-index"
1459
-
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
1564
+
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
1460
1565
dependencies = [
1566
+
"atomic-waker",
1461
1567
"bytes",
1462
1568
"futures-channel",
1463
-
"futures-util",
1569
+
"futures-core",
1464
1570
"h2",
1465
1571
"http",
1466
1572
"http-body",
···
1468
1574
"httpdate",
1469
1575
"itoa",
1470
1576
"pin-project-lite",
1577
+
"pin-utils",
1471
1578
"smallvec",
1472
1579
"tokio",
1473
1580
"want",
···
1487
1594
"tokio",
1488
1595
"tokio-rustls",
1489
1596
"tower-service",
1490
-
"webpki-roots 1.0.2",
1597
+
"webpki-roots 1.0.5",
1491
1598
]
1492
1599
1493
1600
[[package]]
···
1505
1612
1506
1613
[[package]]
1507
1614
name = "hyper-util"
1508
-
version = "0.1.16"
1615
+
version = "0.1.19"
1509
1616
source = "registry+https://github.com/rust-lang/crates.io-index"
1510
-
checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
1617
+
checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
1511
1618
dependencies = [
1512
1619
"base64",
1513
1620
"bytes",
···
1531
1638
1532
1639
[[package]]
1533
1640
name = "iana-time-zone"
1534
-
version = "0.1.63"
1641
+
version = "0.1.64"
1535
1642
source = "registry+https://github.com/rust-lang/crates.io-index"
1536
-
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
1643
+
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
1537
1644
dependencies = [
1538
1645
"android_system_properties",
1539
1646
"core-foundation-sys",
···
1555
1662
1556
1663
[[package]]
1557
1664
name = "icu_collections"
1558
-
version = "2.0.0"
1665
+
version = "2.1.1"
1559
1666
source = "registry+https://github.com/rust-lang/crates.io-index"
1560
-
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
1667
+
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
1561
1668
dependencies = [
1562
1669
"displaydoc",
1563
1670
"potential_utf",
···
1568
1675
1569
1676
[[package]]
1570
1677
name = "icu_locale_core"
1571
-
version = "2.0.0"
1678
+
version = "2.1.1"
1572
1679
source = "registry+https://github.com/rust-lang/crates.io-index"
1573
-
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
1680
+
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
1574
1681
dependencies = [
1575
1682
"displaydoc",
1576
1683
"litemap",
···
1581
1688
1582
1689
[[package]]
1583
1690
name = "icu_normalizer"
1584
-
version = "2.0.0"
1691
+
version = "2.1.1"
1585
1692
source = "registry+https://github.com/rust-lang/crates.io-index"
1586
-
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
1693
+
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
1587
1694
dependencies = [
1588
-
"displaydoc",
1589
1695
"icu_collections",
1590
1696
"icu_normalizer_data",
1591
1697
"icu_properties",
···
1596
1702
1597
1703
[[package]]
1598
1704
name = "icu_normalizer_data"
1599
-
version = "2.0.0"
1705
+
version = "2.1.1"
1600
1706
source = "registry+https://github.com/rust-lang/crates.io-index"
1601
-
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
1707
+
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
1602
1708
1603
1709
[[package]]
1604
1710
name = "icu_properties"
1605
-
version = "2.0.1"
1711
+
version = "2.1.2"
1606
1712
source = "registry+https://github.com/rust-lang/crates.io-index"
1607
-
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
1713
+
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
1608
1714
dependencies = [
1609
-
"displaydoc",
1610
1715
"icu_collections",
1611
1716
"icu_locale_core",
1612
1717
"icu_properties_data",
1613
1718
"icu_provider",
1614
-
"potential_utf",
1615
1719
"zerotrie",
1616
1720
"zerovec",
1617
1721
]
1618
1722
1619
1723
[[package]]
1620
1724
name = "icu_properties_data"
1621
-
version = "2.0.1"
1725
+
version = "2.1.2"
1622
1726
source = "registry+https://github.com/rust-lang/crates.io-index"
1623
-
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
1727
+
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
1624
1728
1625
1729
[[package]]
1626
1730
name = "icu_provider"
1627
-
version = "2.0.0"
1731
+
version = "2.1.1"
1628
1732
source = "registry+https://github.com/rust-lang/crates.io-index"
1629
-
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
1733
+
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
1630
1734
dependencies = [
1631
1735
"displaydoc",
1632
1736
"icu_locale_core",
1633
-
"stable_deref_trait",
1634
-
"tinystr",
1635
1737
"writeable",
1636
1738
"yoke",
1637
1739
"zerofrom",
···
1647
1749
1648
1750
[[package]]
1649
1751
name = "idna"
1650
-
version = "1.0.3"
1752
+
version = "1.1.0"
1651
1753
source = "registry+https://github.com/rust-lang/crates.io-index"
1652
-
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
1754
+
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
1653
1755
dependencies = [
1654
1756
"idna_adapter",
1655
1757
"smallvec",
···
1679
1781
1680
1782
[[package]]
1681
1783
name = "indexmap"
1682
-
version = "2.10.0"
1784
+
version = "2.12.1"
1683
1785
source = "registry+https://github.com/rust-lang/crates.io-index"
1684
-
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
1786
+
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
1685
1787
dependencies = [
1686
1788
"equivalent",
1687
-
"hashbrown 0.15.5",
1789
+
"hashbrown 0.16.1",
1688
1790
"serde",
1791
+
"serde_core",
1689
1792
]
1690
1793
1691
1794
[[package]]
···
1716
1819
]
1717
1820
1718
1821
[[package]]
1719
-
name = "io-uring"
1720
-
version = "0.7.9"
1721
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1722
-
checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4"
1723
-
dependencies = [
1724
-
"bitflags",
1725
-
"cfg-if",
1726
-
"libc",
1727
-
]
1728
-
1729
-
[[package]]
1730
1822
name = "ipld-core"
1731
1823
version = "0.4.2"
1732
1824
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1745
1837
1746
1838
[[package]]
1747
1839
name = "iri-string"
1748
-
version = "0.7.9"
1840
+
version = "0.7.10"
1749
1841
source = "registry+https://github.com/rust-lang/crates.io-index"
1750
-
checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397"
1842
+
checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
1751
1843
dependencies = [
1752
1844
"memchr",
1753
1845
"serde",
1754
1846
]
1755
1847
1756
1848
[[package]]
1757
-
name = "itertools"
1758
-
version = "0.12.1"
1759
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1760
-
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
1761
-
dependencies = [
1762
-
"either",
1763
-
]
1764
-
1765
-
[[package]]
1766
1849
name = "itoa"
1767
-
version = "1.0.15"
1850
+
version = "1.0.17"
1768
1851
source = "registry+https://github.com/rust-lang/crates.io-index"
1769
-
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
1852
+
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
1770
1853
1771
1854
[[package]]
1772
1855
name = "jacquard-api"
1773
-
version = "0.9.2"
1856
+
version = "0.9.5"
1774
1857
source = "registry+https://github.com/rust-lang/crates.io-index"
1775
-
checksum = "bbbfd6e2b10fa1731f4d4e40c8f791956b0d4f804fb3efef891afec903f20597"
1858
+
checksum = "4979fb1848c1dd7ac8fd12745bc71f56f6da61374407d5f9b06005467a954e5a"
1776
1859
dependencies = [
1777
1860
"bon",
1778
1861
"bytes",
···
1782
1865
"miette",
1783
1866
"rustversion",
1784
1867
"serde",
1868
+
"serde_bytes",
1785
1869
"serde_ipld_dagcbor",
1786
-
"thiserror 2.0.14",
1870
+
"thiserror 2.0.17",
1787
1871
"unicode-segmentation",
1788
1872
]
1789
1873
1790
1874
[[package]]
1791
1875
name = "jacquard-common"
1792
-
version = "0.9.2"
1876
+
version = "0.9.5"
1793
1877
source = "registry+https://github.com/rust-lang/crates.io-index"
1794
-
checksum = "df86cb117d9f1c2b0251ba67c3f0e3f963fd22abc6cf8de0e02a7fc846c288ca"
1878
+
checksum = "1751921e0bdae5e0077afade6161545e9ef7698306c868f800916e99ecbcaae9"
1795
1879
dependencies = [
1796
1880
"base64",
1797
1881
"bon",
···
1809
1893
"multihash",
1810
1894
"ouroboros",
1811
1895
"p256",
1896
+
"postcard",
1812
1897
"rand 0.9.2",
1813
1898
"regex",
1814
1899
"regex-lite",
1815
1900
"reqwest",
1816
1901
"serde",
1902
+
"serde_bytes",
1817
1903
"serde_html_form",
1818
1904
"serde_ipld_dagcbor",
1819
1905
"serde_json",
1820
1906
"signature",
1821
1907
"smol_str",
1822
-
"thiserror 2.0.14",
1908
+
"thiserror 2.0.17",
1823
1909
"tokio",
1824
1910
"tokio-util",
1825
1911
"trait-variant",
···
1828
1914
1829
1915
[[package]]
1830
1916
name = "jacquard-derive"
1831
-
version = "0.9.2"
1917
+
version = "0.9.5"
1832
1918
source = "registry+https://github.com/rust-lang/crates.io-index"
1833
-
checksum = "42ca61a69dc7aa8fb2d7163416514ff7df5d79f2e8b22e269f4610afa85572fe"
1919
+
checksum = "9c8d73dfee07943fdab93569ed1c28b06c6921ed891c08b415c4a323ff67e593"
1834
1920
dependencies = [
1835
1921
"heck 0.5.0",
1836
1922
"jacquard-lexicon",
1837
1923
"proc-macro2",
1838
1924
"quote",
1839
-
"syn 2.0.105",
1925
+
"syn 2.0.112",
1840
1926
]
1841
1927
1842
1928
[[package]]
1843
1929
name = "jacquard-identity"
1844
-
version = "0.9.2"
1930
+
version = "0.9.5"
1845
1931
source = "registry+https://github.com/rust-lang/crates.io-index"
1846
-
checksum = "1ef714cacebfca486558a9f8e205daf466bfba0466c4d0c450fd6d0252400a53"
1932
+
checksum = "e7aaefa819fa4213cf59f180dba932f018a7cd0599582fd38474ee2a38c16cf2"
1847
1933
dependencies = [
1848
1934
"bon",
1849
1935
"bytes",
···
1852
1938
"jacquard-common",
1853
1939
"jacquard-lexicon",
1854
1940
"miette",
1941
+
"n0-future",
1855
1942
"percent-encoding",
1856
1943
"reqwest",
1857
1944
"serde",
1858
1945
"serde_html_form",
1859
1946
"serde_json",
1860
-
"thiserror 2.0.14",
1947
+
"thiserror 2.0.17",
1861
1948
"tokio",
1862
1949
"trait-variant",
1863
1950
"url",
···
1866
1953
1867
1954
[[package]]
1868
1955
name = "jacquard-lexicon"
1869
-
version = "0.9.2"
1956
+
version = "0.9.5"
1870
1957
source = "registry+https://github.com/rust-lang/crates.io-index"
1871
-
checksum = "de87f2c938faea1b1f1b32d5b9e0c870e7b5bb5efbf96e3692ae2d8f6b2beb7a"
1958
+
checksum = "8411aff546569b0a1e0ef669bed2380cec1c00d48f02f3fcd57a71545321b3d8"
1872
1959
dependencies = [
1873
1960
"cid",
1874
1961
"dashmap",
···
1886
1973
"serde_repr",
1887
1974
"serde_with",
1888
1975
"sha2",
1889
-
"syn 2.0.105",
1890
-
"thiserror 2.0.14",
1976
+
"syn 2.0.112",
1977
+
"thiserror 2.0.17",
1891
1978
"unicode-segmentation",
1892
1979
]
1893
1980
1894
1981
[[package]]
1895
1982
name = "jobserver"
1896
-
version = "0.1.33"
1983
+
version = "0.1.34"
1897
1984
source = "registry+https://github.com/rust-lang/crates.io-index"
1898
-
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
1985
+
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
1899
1986
dependencies = [
1900
1987
"getrandom 0.3.4",
1901
1988
"libc",
···
1914
2001
"regex",
1915
2002
"serde",
1916
2003
"serde_json",
1917
-
"thiserror 2.0.14",
2004
+
"thiserror 2.0.17",
1918
2005
"time",
1919
2006
]
1920
2007
1921
2008
[[package]]
1922
2009
name = "js-sys"
1923
-
version = "0.3.77"
2010
+
version = "0.3.83"
1924
2011
source = "registry+https://github.com/rust-lang/crates.io-index"
1925
-
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
2012
+
checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
1926
2013
dependencies = [
1927
2014
"once_cell",
1928
2015
"wasm-bindgen",
···
1979
2066
source = "registry+https://github.com/rust-lang/crates.io-index"
1980
2067
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
1981
2068
dependencies = [
1982
-
"spin",
2069
+
"spin 0.9.8",
1983
2070
]
1984
2071
1985
2072
[[package]]
1986
-
name = "lazycell"
1987
-
version = "1.3.0"
1988
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1989
-
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
1990
-
1991
-
[[package]]
1992
2073
name = "lettre"
1993
-
version = "0.11.18"
2074
+
version = "0.11.19"
1994
2075
source = "registry+https://github.com/rust-lang/crates.io-index"
1995
-
checksum = "5cb54db6ff7a89efac87dba5baeac57bb9ccd726b49a9b6f21fb92b3966aaf56"
2076
+
checksum = "9e13e10e8818f8b2a60f52cb127041d388b89f3a96a62be9ceaffa22262fef7f"
1996
2077
dependencies = [
1997
2078
"async-trait",
1998
2079
"base64",
···
2013
2094
"tokio",
2014
2095
"tokio-rustls",
2015
2096
"url",
2016
-
"webpki-roots 1.0.2",
2097
+
"webpki-roots 1.0.5",
2017
2098
]
2018
2099
2019
2100
[[package]]
2020
2101
name = "libc"
2021
-
version = "0.2.175"
2022
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2023
-
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
2024
-
2025
-
[[package]]
2026
-
name = "libloading"
2027
-
version = "0.8.8"
2102
+
version = "0.2.178"
2028
2103
source = "registry+https://github.com/rust-lang/crates.io-index"
2029
-
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
2030
-
dependencies = [
2031
-
"cfg-if",
2032
-
"windows-targets 0.52.6",
2033
-
]
2104
+
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
2034
2105
2035
2106
[[package]]
2036
2107
name = "libm"
···
2040
2111
2041
2112
[[package]]
2042
2113
name = "libredox"
2043
-
version = "0.1.9"
2114
+
version = "0.1.12"
2044
2115
source = "registry+https://github.com/rust-lang/crates.io-index"
2045
-
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
2116
+
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
2046
2117
dependencies = [
2047
2118
"bitflags",
2048
2119
"libc",
2049
-
"redox_syscall",
2120
+
"redox_syscall 0.7.0",
2050
2121
]
2051
2122
2052
2123
[[package]]
···
2059
2130
"pkg-config",
2060
2131
"vcpkg",
2061
2132
]
2062
-
2063
-
[[package]]
2064
-
name = "linux-raw-sys"
2065
-
version = "0.4.15"
2066
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2067
-
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
2068
2133
2069
2134
[[package]]
2070
2135
name = "litemap"
2071
-
version = "0.8.0"
2136
+
version = "0.8.1"
2072
2137
source = "registry+https://github.com/rust-lang/crates.io-index"
2073
-
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
2138
+
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
2074
2139
2075
2140
[[package]]
2076
2141
name = "lock_api"
2077
-
version = "0.4.13"
2142
+
version = "0.4.14"
2078
2143
source = "registry+https://github.com/rust-lang/crates.io-index"
2079
-
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
2144
+
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
2080
2145
dependencies = [
2081
-
"autocfg",
2082
2146
"scopeguard",
2083
2147
]
2084
2148
2085
2149
[[package]]
2086
2150
name = "log"
2087
-
version = "0.4.27"
2151
+
version = "0.4.29"
2088
2152
source = "registry+https://github.com/rust-lang/crates.io-index"
2089
-
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
2153
+
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
2154
+
2155
+
[[package]]
2156
+
name = "loom"
2157
+
version = "0.7.2"
2158
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2159
+
checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
2160
+
dependencies = [
2161
+
"cfg-if",
2162
+
"generator",
2163
+
"scoped-tls",
2164
+
"tracing",
2165
+
"tracing-subscriber",
2166
+
]
2090
2167
2091
2168
[[package]]
2092
2169
name = "lru-slab"
···
2107
2184
2108
2185
[[package]]
2109
2186
name = "matchers"
2110
-
version = "0.1.0"
2187
+
version = "0.2.0"
2111
2188
source = "registry+https://github.com/rust-lang/crates.io-index"
2112
-
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
2189
+
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
2113
2190
dependencies = [
2114
-
"regex-automata 0.1.10",
2191
+
"regex-automata",
2115
2192
]
2116
2193
2117
2194
[[package]]
···
2132
2209
2133
2210
[[package]]
2134
2211
name = "memchr"
2135
-
version = "2.7.5"
2212
+
version = "2.7.6"
2136
2213
source = "registry+https://github.com/rust-lang/crates.io-index"
2137
-
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
2214
+
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
2138
2215
2139
2216
[[package]]
2140
2217
name = "miette"
···
2155
2232
dependencies = [
2156
2233
"proc-macro2",
2157
2234
"quote",
2158
-
"syn 2.0.105",
2235
+
"syn 2.0.112",
2159
2236
]
2160
2237
2161
2238
[[package]]
···
2182
2259
2183
2260
[[package]]
2184
2261
name = "mio"
2185
-
version = "1.0.4"
2262
+
version = "1.1.1"
2186
2263
source = "registry+https://github.com/rust-lang/crates.io-index"
2187
-
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
2264
+
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
2188
2265
dependencies = [
2189
2266
"libc",
2190
2267
"wasi",
2191
-
"windows-sys 0.59.0",
2268
+
"windows-sys 0.61.2",
2192
2269
]
2193
2270
2194
2271
[[package]]
···
2215
2292
]
2216
2293
2217
2294
[[package]]
2295
+
name = "n0-future"
2296
+
version = "0.1.3"
2297
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2298
+
checksum = "7bb0e5d99e681ab3c938842b96fcb41bf8a7bb4bfdb11ccbd653a7e83e06c794"
2299
+
dependencies = [
2300
+
"cfg_aliases",
2301
+
"derive_more",
2302
+
"futures-buffered",
2303
+
"futures-lite",
2304
+
"futures-util",
2305
+
"js-sys",
2306
+
"pin-project",
2307
+
"send_wrapper",
2308
+
"tokio",
2309
+
"tokio-util",
2310
+
"wasm-bindgen",
2311
+
"wasm-bindgen-futures",
2312
+
"web-time",
2313
+
]
2314
+
2315
+
[[package]]
2218
2316
name = "nom"
2219
2317
version = "7.1.3"
2220
2318
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2247
2345
2248
2346
[[package]]
2249
2347
name = "nu-ansi-term"
2250
-
version = "0.46.0"
2348
+
version = "0.50.3"
2251
2349
source = "registry+https://github.com/rust-lang/crates.io-index"
2252
-
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
2350
+
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
2253
2351
dependencies = [
2254
-
"overload",
2255
-
"winapi",
2352
+
"windows-sys 0.59.0",
2256
2353
]
2257
2354
2258
2355
[[package]]
2259
2356
name = "num-bigint-dig"
2260
-
version = "0.8.4"
2357
+
version = "0.8.6"
2261
2358
source = "registry+https://github.com/rust-lang/crates.io-index"
2262
-
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
2359
+
checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7"
2263
2360
dependencies = [
2264
-
"byteorder",
2265
2361
"lazy_static",
2266
2362
"libm",
2267
2363
"num-integer",
···
2325
2421
2326
2422
[[package]]
2327
2423
name = "object"
2328
-
version = "0.36.7"
2424
+
version = "0.32.2"
2329
2425
source = "registry+https://github.com/rust-lang/crates.io-index"
2330
-
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
2426
+
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
2331
2427
dependencies = [
2332
2428
"memchr",
2333
2429
]
···
2361
2457
dependencies = [
2362
2458
"proc-macro2",
2363
2459
"quote",
2364
-
"syn 2.0.105",
2460
+
"syn 2.0.112",
2365
2461
]
2366
2462
2367
2463
[[package]]
···
2397
2493
"proc-macro2",
2398
2494
"proc-macro2-diagnostics",
2399
2495
"quote",
2400
-
"syn 2.0.105",
2496
+
"syn 2.0.112",
2401
2497
]
2402
2498
2403
2499
[[package]]
2404
-
name = "overload"
2405
-
version = "0.1.1"
2406
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2407
-
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
2408
-
2409
-
[[package]]
2410
2500
name = "p256"
2411
2501
version = "0.13.2"
2412
2502
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2426
2516
2427
2517
[[package]]
2428
2518
name = "parking_lot"
2429
-
version = "0.12.4"
2519
+
version = "0.12.5"
2430
2520
source = "registry+https://github.com/rust-lang/crates.io-index"
2431
-
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
2521
+
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
2432
2522
dependencies = [
2433
2523
"lock_api",
2434
2524
"parking_lot_core",
···
2436
2526
2437
2527
[[package]]
2438
2528
name = "parking_lot_core"
2439
-
version = "0.9.11"
2529
+
version = "0.9.12"
2440
2530
source = "registry+https://github.com/rust-lang/crates.io-index"
2441
-
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
2531
+
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
2442
2532
dependencies = [
2443
2533
"cfg-if",
2444
2534
"libc",
2445
-
"redox_syscall",
2535
+
"redox_syscall 0.5.18",
2446
2536
"smallvec",
2447
-
"windows-targets 0.52.6",
2537
+
"windows-link",
2448
2538
]
2449
2539
2450
2540
[[package]]
···
2477
2567
"axum",
2478
2568
"axum-template",
2479
2569
"chrono",
2570
+
"dashmap",
2480
2571
"dotenvy",
2481
2572
"handlebars",
2482
2573
"hex",
···
2498
2589
"sha2",
2499
2590
"sqlx",
2500
2591
"tokio",
2592
+
"tower",
2501
2593
"tower-http",
2502
2594
"tower_governor",
2503
2595
"tracing",
···
2516
2608
2517
2609
[[package]]
2518
2610
name = "percent-encoding"
2519
-
version = "2.3.1"
2611
+
version = "2.3.2"
2520
2612
source = "registry+https://github.com/rust-lang/crates.io-index"
2521
-
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
2613
+
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
2522
2614
2523
2615
[[package]]
2524
2616
name = "pest"
2525
-
version = "2.8.1"
2617
+
version = "2.8.4"
2526
2618
source = "registry+https://github.com/rust-lang/crates.io-index"
2527
-
checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323"
2619
+
checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22"
2528
2620
dependencies = [
2529
2621
"memchr",
2530
-
"thiserror 2.0.14",
2531
2622
"ucd-trie",
2532
2623
]
2533
2624
2534
2625
[[package]]
2535
2626
name = "pest_derive"
2536
-
version = "2.8.1"
2627
+
version = "2.8.4"
2537
2628
source = "registry+https://github.com/rust-lang/crates.io-index"
2538
-
checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc"
2629
+
checksum = "51f72981ade67b1ca6adc26ec221be9f463f2b5839c7508998daa17c23d94d7f"
2539
2630
dependencies = [
2540
2631
"pest",
2541
2632
"pest_generator",
···
2543
2634
2544
2635
[[package]]
2545
2636
name = "pest_generator"
2546
-
version = "2.8.1"
2637
+
version = "2.8.4"
2547
2638
source = "registry+https://github.com/rust-lang/crates.io-index"
2548
-
checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966"
2639
+
checksum = "dee9efd8cdb50d719a80088b76f81aec7c41ed6d522ee750178f83883d271625"
2549
2640
dependencies = [
2550
2641
"pest",
2551
2642
"pest_meta",
2552
2643
"proc-macro2",
2553
2644
"quote",
2554
-
"syn 2.0.105",
2645
+
"syn 2.0.112",
2555
2646
]
2556
2647
2557
2648
[[package]]
2558
2649
name = "pest_meta"
2559
-
version = "2.8.1"
2650
+
version = "2.8.4"
2560
2651
source = "registry+https://github.com/rust-lang/crates.io-index"
2561
-
checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5"
2652
+
checksum = "bf1d70880e76bdc13ba52eafa6239ce793d85c8e43896507e43dd8984ff05b82"
2562
2653
dependencies = [
2563
2654
"pest",
2564
2655
"sha2",
···
2581
2672
dependencies = [
2582
2673
"proc-macro2",
2583
2674
"quote",
2584
-
"syn 2.0.105",
2675
+
"syn 2.0.112",
2585
2676
]
2586
2677
2587
2678
[[package]]
···
2625
2716
2626
2717
[[package]]
2627
2718
name = "portable-atomic"
2628
-
version = "1.11.1"
2719
+
version = "1.13.0"
2629
2720
source = "registry+https://github.com/rust-lang/crates.io-index"
2630
-
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
2721
+
checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
2722
+
2723
+
[[package]]
2724
+
name = "postcard"
2725
+
version = "1.1.3"
2726
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2727
+
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
2728
+
dependencies = [
2729
+
"cobs",
2730
+
"embedded-io 0.4.0",
2731
+
"embedded-io 0.6.1",
2732
+
"heapless",
2733
+
"serde",
2734
+
]
2631
2735
2632
2736
[[package]]
2633
2737
name = "potential_utf"
2634
-
version = "0.1.2"
2738
+
version = "0.1.4"
2635
2739
source = "registry+https://github.com/rust-lang/crates.io-index"
2636
-
checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
2740
+
checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
2637
2741
dependencies = [
2638
2742
"zerovec",
2639
2743
]
···
2655
2759
2656
2760
[[package]]
2657
2761
name = "prettyplease"
2658
-
version = "0.2.35"
2762
+
version = "0.2.37"
2659
2763
source = "registry+https://github.com/rust-lang/crates.io-index"
2660
-
checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a"
2764
+
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
2661
2765
dependencies = [
2662
2766
"proc-macro2",
2663
-
"syn 2.0.105",
2767
+
"syn 2.0.112",
2664
2768
]
2665
2769
2666
2770
[[package]]
···
2698
2802
2699
2803
[[package]]
2700
2804
name = "proc-macro2"
2701
-
version = "1.0.97"
2805
+
version = "1.0.104"
2702
2806
source = "registry+https://github.com/rust-lang/crates.io-index"
2703
-
checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1"
2807
+
checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0"
2704
2808
dependencies = [
2705
2809
"unicode-ident",
2706
2810
]
···
2713
2817
dependencies = [
2714
2818
"proc-macro2",
2715
2819
"quote",
2716
-
"syn 2.0.105",
2820
+
"syn 2.0.112",
2717
2821
"version_check",
2718
2822
"yansi",
2719
2823
]
2720
2824
2721
2825
[[package]]
2722
2826
name = "psm"
2723
-
version = "0.1.26"
2827
+
version = "0.1.28"
2724
2828
source = "registry+https://github.com/rust-lang/crates.io-index"
2725
-
checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f"
2829
+
checksum = "d11f2fedc3b7dafdc2851bc52f277377c5473d378859be234bc7ebb593144d01"
2726
2830
dependencies = [
2831
+
"ar_archive_writer",
2727
2832
"cc",
2728
2833
]
2729
2834
···
2753
2858
"pin-project-lite",
2754
2859
"quinn-proto",
2755
2860
"quinn-udp",
2756
-
"rustc-hash 2.1.1",
2861
+
"rustc-hash",
2757
2862
"rustls",
2758
2863
"socket2",
2759
-
"thiserror 2.0.14",
2864
+
"thiserror 2.0.17",
2760
2865
"tokio",
2761
2866
"tracing",
2762
2867
"web-time",
···
2773
2878
"lru-slab",
2774
2879
"rand 0.9.2",
2775
2880
"ring",
2776
-
"rustc-hash 2.1.1",
2881
+
"rustc-hash",
2777
2882
"rustls",
2778
2883
"rustls-pki-types",
2779
2884
"slab",
2780
-
"thiserror 2.0.14",
2885
+
"thiserror 2.0.17",
2781
2886
"tinyvec",
2782
2887
"tracing",
2783
2888
"web-time",
···
2799
2904
2800
2905
[[package]]
2801
2906
name = "quote"
2802
-
version = "1.0.40"
2907
+
version = "1.0.42"
2803
2908
source = "registry+https://github.com/rust-lang/crates.io-index"
2804
-
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
2909
+
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
2805
2910
dependencies = [
2806
2911
"proc-macro2",
2807
2912
]
···
2885
2990
2886
2991
[[package]]
2887
2992
name = "raw-cpuid"
2888
-
version = "11.5.0"
2993
+
version = "11.6.0"
2994
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2995
+
checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
2996
+
dependencies = [
2997
+
"bitflags",
2998
+
]
2999
+
3000
+
[[package]]
3001
+
name = "redox_syscall"
3002
+
version = "0.5.18"
2889
3003
source = "registry+https://github.com/rust-lang/crates.io-index"
2890
-
checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146"
3004
+
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
2891
3005
dependencies = [
2892
3006
"bitflags",
2893
3007
]
2894
3008
2895
3009
[[package]]
2896
3010
name = "redox_syscall"
2897
-
version = "0.5.17"
3011
+
version = "0.7.0"
2898
3012
source = "registry+https://github.com/rust-lang/crates.io-index"
2899
-
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
3013
+
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
2900
3014
dependencies = [
2901
3015
"bitflags",
2902
3016
]
···
2918
3032
dependencies = [
2919
3033
"proc-macro2",
2920
3034
"quote",
2921
-
"syn 2.0.105",
3035
+
"syn 2.0.112",
2922
3036
]
2923
3037
2924
3038
[[package]]
···
2929
3043
dependencies = [
2930
3044
"aho-corasick",
2931
3045
"memchr",
2932
-
"regex-automata 0.4.13",
2933
-
"regex-syntax 0.8.5",
2934
-
]
2935
-
2936
-
[[package]]
2937
-
name = "regex-automata"
2938
-
version = "0.1.10"
2939
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2940
-
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
2941
-
dependencies = [
2942
-
"regex-syntax 0.6.29",
3046
+
"regex-automata",
3047
+
"regex-syntax",
2943
3048
]
2944
3049
2945
3050
[[package]]
···
2950
3055
dependencies = [
2951
3056
"aho-corasick",
2952
3057
"memchr",
2953
-
"regex-syntax 0.8.5",
3058
+
"regex-syntax",
2954
3059
]
2955
3060
2956
3061
[[package]]
···
2961
3066
2962
3067
[[package]]
2963
3068
name = "regex-syntax"
2964
-
version = "0.6.29"
3069
+
version = "0.8.8"
2965
3070
source = "registry+https://github.com/rust-lang/crates.io-index"
2966
-
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
2967
-
2968
-
[[package]]
2969
-
name = "regex-syntax"
2970
-
version = "0.8.5"
2971
-
source = "registry+https://github.com/rust-lang/crates.io-index"
2972
-
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
3071
+
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
2973
3072
2974
3073
[[package]]
2975
3074
name = "reqwest"
2976
-
version = "0.12.24"
3075
+
version = "0.12.28"
2977
3076
source = "registry+https://github.com/rust-lang/crates.io-index"
2978
-
checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f"
3077
+
checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
2979
3078
dependencies = [
2980
-
"async-compression",
2981
3079
"base64",
2982
3080
"bytes",
2983
3081
"encoding_rs",
2984
3082
"futures-core",
2985
-
"futures-util",
2986
3083
"h2",
2987
3084
"http",
2988
3085
"http-body",
···
3004
3101
"sync_wrapper",
3005
3102
"tokio",
3006
3103
"tokio-rustls",
3007
-
"tokio-util",
3008
3104
"tower",
3009
3105
"tower-http",
3010
3106
"tower-service",
3011
3107
"url",
3012
3108
"wasm-bindgen",
3013
3109
"wasm-bindgen-futures",
3014
-
"wasm-streams",
3015
3110
"web-sys",
3016
-
"webpki-roots 1.0.2",
3111
+
"webpki-roots 1.0.5",
3017
3112
]
3018
3113
3019
3114
[[package]]
···
3042
3137
3043
3138
[[package]]
3044
3139
name = "rsa"
3045
-
version = "0.9.8"
3140
+
version = "0.9.9"
3046
3141
source = "registry+https://github.com/rust-lang/crates.io-index"
3047
-
checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b"
3142
+
checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88"
3048
3143
dependencies = [
3049
3144
"const-oid",
3050
3145
"digest",
···
3062
3157
3063
3158
[[package]]
3064
3159
name = "rust-embed"
3065
-
version = "8.7.2"
3160
+
version = "8.9.0"
3066
3161
source = "registry+https://github.com/rust-lang/crates.io-index"
3067
-
checksum = "025908b8682a26ba8d12f6f2d66b987584a4a87bc024abc5bbc12553a8cd178a"
3162
+
checksum = "947d7f3fad52b283d261c4c99a084937e2fe492248cb9a68a8435a861b8798ca"
3068
3163
dependencies = [
3069
3164
"rust-embed-impl",
3070
3165
"rust-embed-utils",
···
3073
3168
3074
3169
[[package]]
3075
3170
name = "rust-embed-impl"
3076
-
version = "8.7.2"
3171
+
version = "8.9.0"
3077
3172
source = "registry+https://github.com/rust-lang/crates.io-index"
3078
-
checksum = "6065f1a4392b71819ec1ea1df1120673418bf386f50de1d6f54204d836d4349c"
3173
+
checksum = "5fa2c8c9e8711e10f9c4fd2d64317ef13feaab820a4c51541f1a8c8e2e851ab2"
3079
3174
dependencies = [
3080
3175
"proc-macro2",
3081
3176
"quote",
3082
3177
"rust-embed-utils",
3083
-
"syn 2.0.105",
3178
+
"syn 2.0.112",
3084
3179
"walkdir",
3085
3180
]
3086
3181
3087
3182
[[package]]
3088
3183
name = "rust-embed-utils"
3089
-
version = "8.7.2"
3184
+
version = "8.9.0"
3090
3185
source = "registry+https://github.com/rust-lang/crates.io-index"
3091
-
checksum = "f6cc0c81648b20b70c491ff8cce00c1c3b223bb8ed2b5d41f0e54c6c4c0a3594"
3186
+
checksum = "60b161f275cb337fe0a44d924a5f4df0ed69c2c39519858f931ce61c779d3475"
3092
3187
dependencies = [
3093
3188
"globset",
3094
3189
"sha2",
···
3096
3191
]
3097
3192
3098
3193
[[package]]
3099
-
name = "rustc-demangle"
3100
-
version = "0.1.26"
3101
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3102
-
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
3103
-
3104
-
[[package]]
3105
-
name = "rustc-hash"
3106
-
version = "1.1.0"
3107
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3108
-
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
3109
-
3110
-
[[package]]
3111
3194
name = "rustc-hash"
3112
3195
version = "2.1.1"
3113
3196
source = "registry+https://github.com/rust-lang/crates.io-index"
3114
3197
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
3115
3198
3116
3199
[[package]]
3117
-
name = "rustix"
3118
-
version = "0.38.44"
3200
+
name = "rustc_version"
3201
+
version = "0.4.1"
3119
3202
source = "registry+https://github.com/rust-lang/crates.io-index"
3120
-
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
3203
+
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
3121
3204
dependencies = [
3122
-
"bitflags",
3123
-
"errno",
3124
-
"libc",
3125
-
"linux-raw-sys",
3126
-
"windows-sys 0.59.0",
3205
+
"semver",
3127
3206
]
3128
3207
3129
3208
[[package]]
3130
3209
name = "rustls"
3131
-
version = "0.23.31"
3210
+
version = "0.23.35"
3132
3211
source = "registry+https://github.com/rust-lang/crates.io-index"
3133
-
checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc"
3212
+
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
3134
3213
dependencies = [
3135
3214
"aws-lc-rs",
3136
3215
"log",
···
3144
3223
3145
3224
[[package]]
3146
3225
name = "rustls-pki-types"
3147
-
version = "1.12.0"
3226
+
version = "1.13.2"
3148
3227
source = "registry+https://github.com/rust-lang/crates.io-index"
3149
-
checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
3228
+
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
3150
3229
dependencies = [
3151
3230
"web-time",
3152
3231
"zeroize",
···
3154
3233
3155
3234
[[package]]
3156
3235
name = "rustls-webpki"
3157
-
version = "0.103.4"
3236
+
version = "0.103.8"
3158
3237
source = "registry+https://github.com/rust-lang/crates.io-index"
3159
-
checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
3238
+
checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
3160
3239
dependencies = [
3161
3240
"aws-lc-rs",
3162
3241
"ring",
···
3172
3251
3173
3252
[[package]]
3174
3253
name = "ryu"
3175
-
version = "1.0.20"
3254
+
version = "1.0.22"
3176
3255
source = "registry+https://github.com/rust-lang/crates.io-index"
3177
-
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
3256
+
checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
3178
3257
3179
3258
[[package]]
3180
3259
name = "salsa20"
···
3208
3287
3209
3288
[[package]]
3210
3289
name = "schemars"
3211
-
version = "1.1.0"
3290
+
version = "1.2.0"
3212
3291
source = "registry+https://github.com/rust-lang/crates.io-index"
3213
-
checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289"
3292
+
checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2"
3214
3293
dependencies = [
3215
3294
"dyn-clone",
3216
3295
"ref-cast",
···
3219
3298
]
3220
3299
3221
3300
[[package]]
3301
+
name = "scoped-tls"
3302
+
version = "1.0.1"
3303
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3304
+
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
3305
+
3306
+
[[package]]
3222
3307
name = "scopeguard"
3223
3308
version = "1.2.0"
3224
3309
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3269
3354
]
3270
3355
3271
3356
[[package]]
3357
+
name = "semver"
3358
+
version = "1.0.27"
3359
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3360
+
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
3361
+
3362
+
[[package]]
3363
+
name = "send_wrapper"
3364
+
version = "0.6.0"
3365
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3366
+
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
3367
+
3368
+
[[package]]
3272
3369
name = "serde"
3273
3370
version = "1.0.228"
3274
3371
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3305
3402
dependencies = [
3306
3403
"proc-macro2",
3307
3404
"quote",
3308
-
"syn 2.0.105",
3405
+
"syn 2.0.112",
3309
3406
]
3310
3407
3311
3408
[[package]]
···
3315
3412
checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f"
3316
3413
dependencies = [
3317
3414
"form_urlencoded",
3318
-
"indexmap 2.10.0",
3415
+
"indexmap 2.12.1",
3319
3416
"itoa",
3320
3417
"ryu",
3321
3418
"serde_core",
···
3335
3432
3336
3433
[[package]]
3337
3434
name = "serde_json"
3338
-
version = "1.0.145"
3435
+
version = "1.0.148"
3339
3436
source = "registry+https://github.com/rust-lang/crates.io-index"
3340
-
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
3437
+
checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da"
3341
3438
dependencies = [
3342
-
"indexmap 2.10.0",
3439
+
"indexmap 2.12.1",
3343
3440
"itoa",
3344
3441
"memchr",
3345
-
"ryu",
3346
3442
"serde",
3347
3443
"serde_core",
3444
+
"zmij",
3348
3445
]
3349
3446
3350
3447
[[package]]
3351
3448
name = "serde_path_to_error"
3352
-
version = "0.1.17"
3449
+
version = "0.1.20"
3353
3450
source = "registry+https://github.com/rust-lang/crates.io-index"
3354
-
checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
3451
+
checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
3355
3452
dependencies = [
3356
3453
"itoa",
3357
3454
"serde",
3455
+
"serde_core",
3358
3456
]
3359
3457
3360
3458
[[package]]
···
3365
3463
dependencies = [
3366
3464
"proc-macro2",
3367
3465
"quote",
3368
-
"syn 2.0.105",
3466
+
"syn 2.0.112",
3369
3467
]
3370
3468
3371
3469
[[package]]
···
3382
3480
3383
3481
[[package]]
3384
3482
name = "serde_with"
3385
-
version = "3.16.0"
3483
+
version = "3.16.1"
3386
3484
source = "registry+https://github.com/rust-lang/crates.io-index"
3387
-
checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1"
3485
+
checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7"
3388
3486
dependencies = [
3389
3487
"base64",
3390
3488
"chrono",
3391
3489
"hex",
3392
3490
"indexmap 1.9.3",
3393
-
"indexmap 2.10.0",
3491
+
"indexmap 2.12.1",
3394
3492
"schemars 0.9.0",
3395
-
"schemars 1.1.0",
3493
+
"schemars 1.2.0",
3396
3494
"serde_core",
3397
3495
"serde_json",
3398
3496
"serde_with_macros",
···
3401
3499
3402
3500
[[package]]
3403
3501
name = "serde_with_macros"
3404
-
version = "3.16.0"
3502
+
version = "3.16.1"
3405
3503
source = "registry+https://github.com/rust-lang/crates.io-index"
3406
-
checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b"
3504
+
checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c"
3407
3505
dependencies = [
3408
3506
"darling 0.21.3",
3409
3507
"proc-macro2",
3410
3508
"quote",
3411
-
"syn 2.0.105",
3509
+
"syn 2.0.112",
3412
3510
]
3413
3511
3414
3512
[[package]]
···
3450
3548
3451
3549
[[package]]
3452
3550
name = "signal-hook-registry"
3453
-
version = "1.4.6"
3551
+
version = "1.4.8"
3454
3552
source = "registry+https://github.com/rust-lang/crates.io-index"
3455
-
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
3553
+
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
3456
3554
dependencies = [
3555
+
"errno",
3457
3556
"libc",
3458
3557
]
3459
3558
···
3469
3568
3470
3569
[[package]]
3471
3570
name = "simd-adler32"
3472
-
version = "0.3.7"
3571
+
version = "0.3.8"
3473
3572
source = "registry+https://github.com/rust-lang/crates.io-index"
3474
-
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
3573
+
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
3475
3574
3476
3575
[[package]]
3477
3576
name = "slab"
···
3500
3599
3501
3600
[[package]]
3502
3601
name = "socket2"
3503
-
version = "0.6.0"
3602
+
version = "0.6.1"
3504
3603
source = "registry+https://github.com/rust-lang/crates.io-index"
3505
-
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
3604
+
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
3506
3605
dependencies = [
3507
3606
"libc",
3508
-
"windows-sys 0.59.0",
3607
+
"windows-sys 0.60.2",
3509
3608
]
3510
3609
3511
3610
[[package]]
···
3518
3617
]
3519
3618
3520
3619
[[package]]
3620
+
name = "spin"
3621
+
version = "0.10.0"
3622
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3623
+
checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591"
3624
+
3625
+
[[package]]
3521
3626
name = "spinning_top"
3522
3627
version = "0.3.0"
3523
3628
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3568
3673
"futures-util",
3569
3674
"hashbrown 0.15.5",
3570
3675
"hashlink",
3571
-
"indexmap 2.10.0",
3676
+
"indexmap 2.12.1",
3572
3677
"log",
3573
3678
"memchr",
3574
3679
"once_cell",
···
3578
3683
"serde_json",
3579
3684
"sha2",
3580
3685
"smallvec",
3581
-
"thiserror 2.0.14",
3686
+
"thiserror 2.0.17",
3582
3687
"tokio",
3583
3688
"tokio-stream",
3584
3689
"tracing",
···
3596
3701
"quote",
3597
3702
"sqlx-core",
3598
3703
"sqlx-macros-core",
3599
-
"syn 2.0.105",
3704
+
"syn 2.0.112",
3600
3705
]
3601
3706
3602
3707
[[package]]
···
3619
3724
"sqlx-mysql",
3620
3725
"sqlx-postgres",
3621
3726
"sqlx-sqlite",
3622
-
"syn 2.0.105",
3727
+
"syn 2.0.112",
3623
3728
"tokio",
3624
3729
"url",
3625
3730
]
···
3662
3767
"smallvec",
3663
3768
"sqlx-core",
3664
3769
"stringprep",
3665
-
"thiserror 2.0.14",
3770
+
"thiserror 2.0.17",
3666
3771
"tracing",
3667
3772
"whoami",
3668
3773
]
···
3700
3805
"smallvec",
3701
3806
"sqlx-core",
3702
3807
"stringprep",
3703
-
"thiserror 2.0.14",
3808
+
"thiserror 2.0.17",
3704
3809
"tracing",
3705
3810
"whoami",
3706
3811
]
···
3725
3830
"serde",
3726
3831
"serde_urlencoded",
3727
3832
"sqlx-core",
3728
-
"thiserror 2.0.14",
3833
+
"thiserror 2.0.17",
3729
3834
"tracing",
3730
3835
"url",
3731
3836
]
3732
3837
3733
3838
[[package]]
3734
3839
name = "stable_deref_trait"
3735
-
version = "1.2.0"
3840
+
version = "1.2.1"
3736
3841
source = "registry+https://github.com/rust-lang/crates.io-index"
3737
-
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
3842
+
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
3738
3843
3739
3844
[[package]]
3740
3845
name = "stacker"
3741
-
version = "0.1.21"
3846
+
version = "0.1.22"
3742
3847
source = "registry+https://github.com/rust-lang/crates.io-index"
3743
-
checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b"
3848
+
checksum = "e1f8b29fb42aafcea4edeeb6b2f2d7ecd0d969c48b4cf0d2e64aafc471dd6e59"
3744
3849
dependencies = [
3745
3850
"cc",
3746
3851
"cfg-if",
···
3765
3870
"quote",
3766
3871
"serde",
3767
3872
"sha2",
3768
-
"syn 2.0.105",
3873
+
"syn 2.0.112",
3769
3874
"thiserror 1.0.69",
3770
3875
]
3771
3876
···
3811
3916
3812
3917
[[package]]
3813
3918
name = "syn"
3814
-
version = "2.0.105"
3919
+
version = "2.0.112"
3815
3920
source = "registry+https://github.com/rust-lang/crates.io-index"
3816
-
checksum = "7bc3fcb250e53458e712715cf74285c1f889686520d79294a9ef3bd7aa1fc619"
3921
+
checksum = "21f182278bf2d2bcb3c88b1b08a37df029d71ce3d3ae26168e3c653b213b99d4"
3817
3922
dependencies = [
3818
3923
"proc-macro2",
3819
3924
"quote",
···
3837
3942
dependencies = [
3838
3943
"proc-macro2",
3839
3944
"quote",
3840
-
"syn 2.0.105",
3945
+
"syn 2.0.112",
3841
3946
]
3842
3947
3843
3948
[[package]]
···
3872
3977
3873
3978
[[package]]
3874
3979
name = "thiserror"
3875
-
version = "2.0.14"
3980
+
version = "2.0.17"
3876
3981
source = "registry+https://github.com/rust-lang/crates.io-index"
3877
-
checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e"
3982
+
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
3878
3983
dependencies = [
3879
-
"thiserror-impl 2.0.14",
3984
+
"thiserror-impl 2.0.17",
3880
3985
]
3881
3986
3882
3987
[[package]]
···
3887
3992
dependencies = [
3888
3993
"proc-macro2",
3889
3994
"quote",
3890
-
"syn 2.0.105",
3995
+
"syn 2.0.112",
3891
3996
]
3892
3997
3893
3998
[[package]]
3894
3999
name = "thiserror-impl"
3895
-
version = "2.0.14"
4000
+
version = "2.0.17"
3896
4001
source = "registry+https://github.com/rust-lang/crates.io-index"
3897
-
checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227"
4002
+
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
3898
4003
dependencies = [
3899
4004
"proc-macro2",
3900
4005
"quote",
3901
-
"syn 2.0.105",
4006
+
"syn 2.0.112",
3902
4007
]
3903
4008
3904
4009
[[package]]
···
3943
4048
3944
4049
[[package]]
3945
4050
name = "tinystr"
3946
-
version = "0.8.1"
4051
+
version = "0.8.2"
3947
4052
source = "registry+https://github.com/rust-lang/crates.io-index"
3948
-
checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
4053
+
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
3949
4054
dependencies = [
3950
4055
"displaydoc",
3951
4056
"zerovec",
···
3953
4058
3954
4059
[[package]]
3955
4060
name = "tinyvec"
3956
-
version = "1.9.0"
4061
+
version = "1.10.0"
3957
4062
source = "registry+https://github.com/rust-lang/crates.io-index"
3958
-
checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71"
4063
+
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
3959
4064
dependencies = [
3960
4065
"tinyvec_macros",
3961
4066
]
···
3968
4073
3969
4074
[[package]]
3970
4075
name = "tokio"
3971
-
version = "1.47.1"
4076
+
version = "1.48.0"
3972
4077
source = "registry+https://github.com/rust-lang/crates.io-index"
3973
-
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
4078
+
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
3974
4079
dependencies = [
3975
-
"backtrace",
3976
4080
"bytes",
3977
-
"io-uring",
3978
4081
"libc",
3979
4082
"mio",
3980
4083
"pin-project-lite",
3981
4084
"signal-hook-registry",
3982
-
"slab",
3983
4085
"socket2",
3984
4086
"tokio-macros",
3985
-
"windows-sys 0.59.0",
4087
+
"windows-sys 0.61.2",
3986
4088
]
3987
4089
3988
4090
[[package]]
3989
4091
name = "tokio-macros"
3990
-
version = "2.5.0"
4092
+
version = "2.6.0"
3991
4093
source = "registry+https://github.com/rust-lang/crates.io-index"
3992
-
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
4094
+
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
3993
4095
dependencies = [
3994
4096
"proc-macro2",
3995
4097
"quote",
3996
-
"syn 2.0.105",
4098
+
"syn 2.0.112",
3997
4099
]
3998
4100
3999
4101
[[package]]
4000
4102
name = "tokio-rustls"
4001
-
version = "0.26.2"
4103
+
version = "0.26.4"
4002
4104
source = "registry+https://github.com/rust-lang/crates.io-index"
4003
-
checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
4105
+
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
4004
4106
dependencies = [
4005
4107
"rustls",
4006
4108
"tokio",
···
4026
4128
"bytes",
4027
4129
"futures-core",
4028
4130
"futures-sink",
4131
+
"futures-util",
4029
4132
"pin-project-lite",
4030
4133
"tokio",
4031
4134
]
4032
4135
4033
4136
[[package]]
4034
4137
name = "tonic"
4035
-
version = "0.14.1"
4138
+
version = "0.14.2"
4036
4139
source = "registry+https://github.com/rust-lang/crates.io-index"
4037
-
checksum = "67ac5a8627ada0968acec063a4746bf79588aa03ccb66db2f75d7dce26722a40"
4140
+
checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203"
4038
4141
dependencies = [
4039
4142
"async-trait",
4040
4143
"axum",
···
4067
4170
dependencies = [
4068
4171
"futures-core",
4069
4172
"futures-util",
4070
-
"indexmap 2.10.0",
4173
+
"indexmap 2.12.1",
4071
4174
"pin-project-lite",
4072
4175
"slab",
4073
4176
"sync_wrapper",
···
4080
4183
4081
4184
[[package]]
4082
4185
name = "tower-http"
4083
-
version = "0.6.6"
4186
+
version = "0.6.8"
4084
4187
source = "registry+https://github.com/rust-lang/crates.io-index"
4085
-
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
4188
+
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
4086
4189
dependencies = [
4087
4190
"async-compression",
4088
4191
"bitflags",
···
4091
4194
"futures-util",
4092
4195
"http",
4093
4196
"http-body",
4197
+
"http-body-util",
4094
4198
"iri-string",
4095
4199
"pin-project-lite",
4096
4200
"tokio",
···
4123
4227
"governor",
4124
4228
"http",
4125
4229
"pin-project",
4126
-
"thiserror 2.0.14",
4230
+
"thiserror 2.0.17",
4127
4231
"tonic",
4128
4232
"tower",
4129
4233
"tracing",
···
4131
4235
4132
4236
[[package]]
4133
4237
name = "tracing"
4134
-
version = "0.1.41"
4238
+
version = "0.1.44"
4135
4239
source = "registry+https://github.com/rust-lang/crates.io-index"
4136
-
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
4240
+
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
4137
4241
dependencies = [
4138
4242
"log",
4139
4243
"pin-project-lite",
···
4143
4247
4144
4248
[[package]]
4145
4249
name = "tracing-attributes"
4146
-
version = "0.1.30"
4250
+
version = "0.1.31"
4147
4251
source = "registry+https://github.com/rust-lang/crates.io-index"
4148
-
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
4252
+
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
4149
4253
dependencies = [
4150
4254
"proc-macro2",
4151
4255
"quote",
4152
-
"syn 2.0.105",
4256
+
"syn 2.0.112",
4153
4257
]
4154
4258
4155
4259
[[package]]
4156
4260
name = "tracing-core"
4157
-
version = "0.1.34"
4261
+
version = "0.1.36"
4158
4262
source = "registry+https://github.com/rust-lang/crates.io-index"
4159
-
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
4263
+
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
4160
4264
dependencies = [
4161
4265
"once_cell",
4162
4266
"valuable",
···
4175
4279
4176
4280
[[package]]
4177
4281
name = "tracing-subscriber"
4178
-
version = "0.3.19"
4282
+
version = "0.3.22"
4179
4283
source = "registry+https://github.com/rust-lang/crates.io-index"
4180
-
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
4284
+
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
4181
4285
dependencies = [
4182
4286
"matchers",
4183
4287
"nu-ansi-term",
4184
4288
"once_cell",
4185
-
"regex",
4289
+
"regex-automata",
4186
4290
"sharded-slab",
4187
4291
"smallvec",
4188
4292
"thread_local",
···
4199
4303
dependencies = [
4200
4304
"proc-macro2",
4201
4305
"quote",
4202
-
"syn 2.0.105",
4306
+
"syn 2.0.112",
4203
4307
]
4204
4308
4205
4309
[[package]]
···
4210
4314
4211
4315
[[package]]
4212
4316
name = "typenum"
4213
-
version = "1.18.0"
4317
+
version = "1.19.0"
4214
4318
source = "registry+https://github.com/rust-lang/crates.io-index"
4215
-
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
4319
+
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
4216
4320
4217
4321
[[package]]
4218
4322
name = "ucd-trie"
···
4228
4332
4229
4333
[[package]]
4230
4334
name = "unicode-ident"
4231
-
version = "1.0.18"
4335
+
version = "1.0.22"
4232
4336
source = "registry+https://github.com/rust-lang/crates.io-index"
4233
-
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
4337
+
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
4234
4338
4235
4339
[[package]]
4236
4340
name = "unicode-normalization"
4237
-
version = "0.1.24"
4341
+
version = "0.1.25"
4238
4342
source = "registry+https://github.com/rust-lang/crates.io-index"
4239
-
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
4343
+
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
4240
4344
dependencies = [
4241
4345
"tinyvec",
4242
4346
]
4243
4347
4244
4348
[[package]]
4245
4349
name = "unicode-properties"
4246
-
version = "0.1.3"
4350
+
version = "0.1.4"
4247
4351
source = "registry+https://github.com/rust-lang/crates.io-index"
4248
-
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
4352
+
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
4249
4353
4250
4354
[[package]]
4251
4355
name = "unicode-segmentation"
···
4260
4364
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
4261
4365
4262
4366
[[package]]
4367
+
name = "unicode-xid"
4368
+
version = "0.2.6"
4369
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4370
+
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
4371
+
4372
+
[[package]]
4263
4373
name = "unsigned-varint"
4264
4374
version = "0.8.0"
4265
4375
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4279
4389
4280
4390
[[package]]
4281
4391
name = "url"
4282
-
version = "2.5.4"
4392
+
version = "2.5.7"
4283
4393
source = "registry+https://github.com/rust-lang/crates.io-index"
4284
-
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
4394
+
checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
4285
4395
dependencies = [
4286
4396
"form_urlencoded",
4287
4397
"idna",
···
4367
4477
4368
4478
[[package]]
4369
4479
name = "wasm-bindgen"
4370
-
version = "0.2.100"
4480
+
version = "0.2.106"
4371
4481
source = "registry+https://github.com/rust-lang/crates.io-index"
4372
-
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
4482
+
checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
4373
4483
dependencies = [
4374
4484
"cfg-if",
4375
4485
"once_cell",
4376
4486
"rustversion",
4377
4487
"wasm-bindgen-macro",
4378
-
]
4379
-
4380
-
[[package]]
4381
-
name = "wasm-bindgen-backend"
4382
-
version = "0.2.100"
4383
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4384
-
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
4385
-
dependencies = [
4386
-
"bumpalo",
4387
-
"log",
4388
-
"proc-macro2",
4389
-
"quote",
4390
-
"syn 2.0.105",
4391
4488
"wasm-bindgen-shared",
4392
4489
]
4393
4490
4394
4491
[[package]]
4395
4492
name = "wasm-bindgen-futures"
4396
-
version = "0.4.50"
4493
+
version = "0.4.56"
4397
4494
source = "registry+https://github.com/rust-lang/crates.io-index"
4398
-
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
4495
+
checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
4399
4496
dependencies = [
4400
4497
"cfg-if",
4401
4498
"js-sys",
···
4406
4503
4407
4504
[[package]]
4408
4505
name = "wasm-bindgen-macro"
4409
-
version = "0.2.100"
4506
+
version = "0.2.106"
4410
4507
source = "registry+https://github.com/rust-lang/crates.io-index"
4411
-
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
4508
+
checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
4412
4509
dependencies = [
4413
4510
"quote",
4414
4511
"wasm-bindgen-macro-support",
···
4416
4513
4417
4514
[[package]]
4418
4515
name = "wasm-bindgen-macro-support"
4419
-
version = "0.2.100"
4516
+
version = "0.2.106"
4420
4517
source = "registry+https://github.com/rust-lang/crates.io-index"
4421
-
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
4518
+
checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
4422
4519
dependencies = [
4520
+
"bumpalo",
4423
4521
"proc-macro2",
4424
4522
"quote",
4425
-
"syn 2.0.105",
4426
-
"wasm-bindgen-backend",
4523
+
"syn 2.0.112",
4427
4524
"wasm-bindgen-shared",
4428
4525
]
4429
4526
4430
4527
[[package]]
4431
4528
name = "wasm-bindgen-shared"
4432
-
version = "0.2.100"
4529
+
version = "0.2.106"
4433
4530
source = "registry+https://github.com/rust-lang/crates.io-index"
4434
-
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
4531
+
checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
4435
4532
dependencies = [
4436
4533
"unicode-ident",
4437
4534
]
4438
4535
4439
4536
[[package]]
4440
-
name = "wasm-streams"
4441
-
version = "0.4.2"
4442
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4443
-
checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
4444
-
dependencies = [
4445
-
"futures-util",
4446
-
"js-sys",
4447
-
"wasm-bindgen",
4448
-
"wasm-bindgen-futures",
4449
-
"web-sys",
4450
-
]
4451
-
4452
-
[[package]]
4453
4537
name = "web-sys"
4454
-
version = "0.3.77"
4538
+
version = "0.3.83"
4455
4539
source = "registry+https://github.com/rust-lang/crates.io-index"
4456
-
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
4540
+
checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
4457
4541
dependencies = [
4458
4542
"js-sys",
4459
4543
"wasm-bindgen",
···
4475
4559
source = "registry+https://github.com/rust-lang/crates.io-index"
4476
4560
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
4477
4561
dependencies = [
4478
-
"webpki-roots 1.0.2",
4562
+
"webpki-roots 1.0.5",
4479
4563
]
4480
4564
4481
4565
[[package]]
4482
4566
name = "webpki-roots"
4483
-
version = "1.0.2"
4567
+
version = "1.0.5"
4484
4568
source = "registry+https://github.com/rust-lang/crates.io-index"
4485
-
checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2"
4569
+
checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c"
4486
4570
dependencies = [
4487
4571
"rustls-pki-types",
4488
-
]
4489
-
4490
-
[[package]]
4491
-
name = "which"
4492
-
version = "4.4.2"
4493
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4494
-
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
4495
-
dependencies = [
4496
-
"either",
4497
-
"home",
4498
-
"once_cell",
4499
-
"rustix",
4500
4572
]
4501
4573
4502
4574
[[package]]
···
4527
4599
4528
4600
[[package]]
4529
4601
name = "winapi-util"
4530
-
version = "0.1.9"
4602
+
version = "0.1.11"
4531
4603
source = "registry+https://github.com/rust-lang/crates.io-index"
4532
-
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
4604
+
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
4533
4605
dependencies = [
4534
-
"windows-sys 0.59.0",
4606
+
"windows-sys 0.48.0",
4535
4607
]
4536
4608
4537
4609
[[package]]
···
4542
4614
4543
4615
[[package]]
4544
4616
name = "windows-core"
4545
-
version = "0.61.2"
4617
+
version = "0.62.2"
4546
4618
source = "registry+https://github.com/rust-lang/crates.io-index"
4547
-
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
4619
+
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
4548
4620
dependencies = [
4549
4621
"windows-implement",
4550
4622
"windows-interface",
4551
-
"windows-link 0.1.3",
4623
+
"windows-link",
4552
4624
"windows-result",
4553
4625
"windows-strings",
4554
4626
]
4555
4627
4556
4628
[[package]]
4557
4629
name = "windows-implement"
4558
-
version = "0.60.0"
4630
+
version = "0.60.2"
4559
4631
source = "registry+https://github.com/rust-lang/crates.io-index"
4560
-
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
4632
+
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
4561
4633
dependencies = [
4562
4634
"proc-macro2",
4563
4635
"quote",
4564
-
"syn 2.0.105",
4636
+
"syn 2.0.112",
4565
4637
]
4566
4638
4567
4639
[[package]]
4568
4640
name = "windows-interface"
4569
-
version = "0.59.1"
4641
+
version = "0.59.3"
4570
4642
source = "registry+https://github.com/rust-lang/crates.io-index"
4571
-
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
4643
+
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
4572
4644
dependencies = [
4573
4645
"proc-macro2",
4574
4646
"quote",
4575
-
"syn 2.0.105",
4647
+
"syn 2.0.112",
4576
4648
]
4577
4649
4578
4650
[[package]]
4579
4651
name = "windows-link"
4580
-
version = "0.1.3"
4581
-
source = "registry+https://github.com/rust-lang/crates.io-index"
4582
-
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
4583
-
4584
-
[[package]]
4585
-
name = "windows-link"
4586
4652
version = "0.2.1"
4587
4653
source = "registry+https://github.com/rust-lang/crates.io-index"
4588
4654
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
4589
4655
4590
4656
[[package]]
4591
4657
name = "windows-registry"
4592
-
version = "0.5.3"
4658
+
version = "0.6.1"
4593
4659
source = "registry+https://github.com/rust-lang/crates.io-index"
4594
-
checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
4660
+
checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
4595
4661
dependencies = [
4596
-
"windows-link 0.1.3",
4662
+
"windows-link",
4597
4663
"windows-result",
4598
4664
"windows-strings",
4599
4665
]
4600
4666
4601
4667
[[package]]
4602
4668
name = "windows-result"
4603
-
version = "0.3.4"
4669
+
version = "0.4.1"
4604
4670
source = "registry+https://github.com/rust-lang/crates.io-index"
4605
-
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
4671
+
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
4606
4672
dependencies = [
4607
-
"windows-link 0.1.3",
4673
+
"windows-link",
4608
4674
]
4609
4675
4610
4676
[[package]]
4611
4677
name = "windows-strings"
4612
-
version = "0.4.2"
4678
+
version = "0.5.1"
4613
4679
source = "registry+https://github.com/rust-lang/crates.io-index"
4614
-
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
4680
+
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
4615
4681
dependencies = [
4616
-
"windows-link 0.1.3",
4682
+
"windows-link",
4617
4683
]
4618
4684
4619
4685
[[package]]
···
4644
4710
]
4645
4711
4646
4712
[[package]]
4713
+
name = "windows-sys"
4714
+
version = "0.60.2"
4715
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4716
+
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
4717
+
dependencies = [
4718
+
"windows-targets 0.53.5",
4719
+
]
4720
+
4721
+
[[package]]
4722
+
name = "windows-sys"
4723
+
version = "0.61.2"
4724
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4725
+
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
4726
+
dependencies = [
4727
+
"windows-link",
4728
+
]
4729
+
4730
+
[[package]]
4647
4731
name = "windows-targets"
4648
4732
version = "0.48.5"
4649
4733
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4667
4751
"windows_aarch64_gnullvm 0.52.6",
4668
4752
"windows_aarch64_msvc 0.52.6",
4669
4753
"windows_i686_gnu 0.52.6",
4670
-
"windows_i686_gnullvm",
4754
+
"windows_i686_gnullvm 0.52.6",
4671
4755
"windows_i686_msvc 0.52.6",
4672
4756
"windows_x86_64_gnu 0.52.6",
4673
4757
"windows_x86_64_gnullvm 0.52.6",
···
4675
4759
]
4676
4760
4677
4761
[[package]]
4762
+
name = "windows-targets"
4763
+
version = "0.53.5"
4764
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4765
+
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
4766
+
dependencies = [
4767
+
"windows-link",
4768
+
"windows_aarch64_gnullvm 0.53.1",
4769
+
"windows_aarch64_msvc 0.53.1",
4770
+
"windows_i686_gnu 0.53.1",
4771
+
"windows_i686_gnullvm 0.53.1",
4772
+
"windows_i686_msvc 0.53.1",
4773
+
"windows_x86_64_gnu 0.53.1",
4774
+
"windows_x86_64_gnullvm 0.53.1",
4775
+
"windows_x86_64_msvc 0.53.1",
4776
+
]
4777
+
4778
+
[[package]]
4678
4779
name = "windows_aarch64_gnullvm"
4679
4780
version = "0.48.5"
4680
4781
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4687
4788
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
4688
4789
4689
4790
[[package]]
4791
+
name = "windows_aarch64_gnullvm"
4792
+
version = "0.53.1"
4793
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4794
+
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
4795
+
4796
+
[[package]]
4690
4797
name = "windows_aarch64_msvc"
4691
4798
version = "0.48.5"
4692
4799
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4699
4806
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
4700
4807
4701
4808
[[package]]
4809
+
name = "windows_aarch64_msvc"
4810
+
version = "0.53.1"
4811
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4812
+
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
4813
+
4814
+
[[package]]
4702
4815
name = "windows_i686_gnu"
4703
4816
version = "0.48.5"
4704
4817
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4711
4824
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
4712
4825
4713
4826
[[package]]
4827
+
name = "windows_i686_gnu"
4828
+
version = "0.53.1"
4829
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4830
+
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
4831
+
4832
+
[[package]]
4714
4833
name = "windows_i686_gnullvm"
4715
4834
version = "0.52.6"
4716
4835
source = "registry+https://github.com/rust-lang/crates.io-index"
4717
4836
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
4837
+
4838
+
[[package]]
4839
+
name = "windows_i686_gnullvm"
4840
+
version = "0.53.1"
4841
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4842
+
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
4718
4843
4719
4844
[[package]]
4720
4845
name = "windows_i686_msvc"
···
4729
4854
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
4730
4855
4731
4856
[[package]]
4857
+
name = "windows_i686_msvc"
4858
+
version = "0.53.1"
4859
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4860
+
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
4861
+
4862
+
[[package]]
4732
4863
name = "windows_x86_64_gnu"
4733
4864
version = "0.48.5"
4734
4865
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4741
4872
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
4742
4873
4743
4874
[[package]]
4875
+
name = "windows_x86_64_gnu"
4876
+
version = "0.53.1"
4877
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4878
+
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
4879
+
4880
+
[[package]]
4744
4881
name = "windows_x86_64_gnullvm"
4745
4882
version = "0.48.5"
4746
4883
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4753
4890
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
4754
4891
4755
4892
[[package]]
4893
+
name = "windows_x86_64_gnullvm"
4894
+
version = "0.53.1"
4895
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4896
+
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
4897
+
4898
+
[[package]]
4756
4899
name = "windows_x86_64_msvc"
4757
4900
version = "0.48.5"
4758
4901
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4765
4908
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
4766
4909
4767
4910
[[package]]
4911
+
name = "windows_x86_64_msvc"
4912
+
version = "0.53.1"
4913
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4914
+
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
4915
+
4916
+
[[package]]
4768
4917
name = "wit-bindgen"
4769
4918
version = "0.46.0"
4770
4919
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4772
4921
4773
4922
[[package]]
4774
4923
name = "writeable"
4775
-
version = "0.6.1"
4924
+
version = "0.6.2"
4776
4925
source = "registry+https://github.com/rust-lang/crates.io-index"
4777
-
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
4926
+
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
4778
4927
4779
4928
[[package]]
4780
4929
name = "yansi"
···
4784
4933
4785
4934
[[package]]
4786
4935
name = "yoke"
4787
-
version = "0.8.0"
4936
+
version = "0.8.1"
4788
4937
source = "registry+https://github.com/rust-lang/crates.io-index"
4789
-
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
4938
+
checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
4790
4939
dependencies = [
4791
-
"serde",
4792
4940
"stable_deref_trait",
4793
4941
"yoke-derive",
4794
4942
"zerofrom",
···
4796
4944
4797
4945
[[package]]
4798
4946
name = "yoke-derive"
4799
-
version = "0.8.0"
4947
+
version = "0.8.1"
4800
4948
source = "registry+https://github.com/rust-lang/crates.io-index"
4801
-
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
4949
+
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
4802
4950
dependencies = [
4803
4951
"proc-macro2",
4804
4952
"quote",
4805
-
"syn 2.0.105",
4953
+
"syn 2.0.112",
4806
4954
"synstructure",
4807
4955
]
4808
4956
4809
4957
[[package]]
4810
4958
name = "zerocopy"
4811
-
version = "0.8.26"
4959
+
version = "0.8.31"
4812
4960
source = "registry+https://github.com/rust-lang/crates.io-index"
4813
-
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
4961
+
checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
4814
4962
dependencies = [
4815
4963
"zerocopy-derive",
4816
4964
]
4817
4965
4818
4966
[[package]]
4819
4967
name = "zerocopy-derive"
4820
-
version = "0.8.26"
4968
+
version = "0.8.31"
4821
4969
source = "registry+https://github.com/rust-lang/crates.io-index"
4822
-
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
4970
+
checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
4823
4971
dependencies = [
4824
4972
"proc-macro2",
4825
4973
"quote",
4826
-
"syn 2.0.105",
4974
+
"syn 2.0.112",
4827
4975
]
4828
4976
4829
4977
[[package]]
···
4843
4991
dependencies = [
4844
4992
"proc-macro2",
4845
4993
"quote",
4846
-
"syn 2.0.105",
4994
+
"syn 2.0.112",
4847
4995
"synstructure",
4848
4996
]
4849
4997
4850
4998
[[package]]
4851
4999
name = "zeroize"
4852
-
version = "1.8.1"
5000
+
version = "1.8.2"
4853
5001
source = "registry+https://github.com/rust-lang/crates.io-index"
4854
-
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
5002
+
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
4855
5003
dependencies = [
4856
5004
"zeroize_derive",
4857
5005
]
4858
5006
4859
5007
[[package]]
4860
5008
name = "zeroize_derive"
4861
-
version = "1.4.2"
5009
+
version = "1.4.3"
4862
5010
source = "registry+https://github.com/rust-lang/crates.io-index"
4863
-
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
5011
+
checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e"
4864
5012
dependencies = [
4865
5013
"proc-macro2",
4866
5014
"quote",
4867
-
"syn 2.0.105",
5015
+
"syn 2.0.112",
4868
5016
]
4869
5017
4870
5018
[[package]]
4871
5019
name = "zerotrie"
4872
-
version = "0.2.2"
5020
+
version = "0.2.3"
4873
5021
source = "registry+https://github.com/rust-lang/crates.io-index"
4874
-
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
5022
+
checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
4875
5023
dependencies = [
4876
5024
"displaydoc",
4877
5025
"yoke",
···
4880
5028
4881
5029
[[package]]
4882
5030
name = "zerovec"
4883
-
version = "0.11.4"
5031
+
version = "0.11.5"
4884
5032
source = "registry+https://github.com/rust-lang/crates.io-index"
4885
-
checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
5033
+
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
4886
5034
dependencies = [
4887
5035
"yoke",
4888
5036
"zerofrom",
···
4891
5039
4892
5040
[[package]]
4893
5041
name = "zerovec-derive"
4894
-
version = "0.11.1"
5042
+
version = "0.11.2"
4895
5043
source = "registry+https://github.com/rust-lang/crates.io-index"
4896
-
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
5044
+
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
4897
5045
dependencies = [
4898
5046
"proc-macro2",
4899
5047
"quote",
4900
-
"syn 2.0.105",
5048
+
"syn 2.0.112",
4901
5049
]
4902
5050
4903
5051
[[package]]
5052
+
name = "zmij"
5053
+
version = "1.0.8"
5054
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5055
+
checksum = "317f17ff091ac4515f17cc7a190d2769a8c9a96d227de5d64b500b01cda8f2cd"
5056
+
5057
+
[[package]]
4904
5058
name = "zstd"
4905
5059
version = "0.13.3"
4906
5060
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4920
5074
4921
5075
[[package]]
4922
5076
name = "zstd-sys"
4923
-
version = "2.0.15+zstd.1.5.7"
5077
+
version = "2.0.16+zstd.1.5.7"
4924
5078
source = "registry+https://github.com/rust-lang/crates.io-index"
4925
-
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
5079
+
checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
4926
5080
dependencies = [
4927
5081
"cc",
4928
5082
"pkg-config",
+11
-9
Cargo.toml
+11
-9
Cargo.toml
···
5
5
license = "MIT"
6
6
7
7
[dependencies]
8
-
axum = { version = "0.8.4", features = ["macros", "json"] }
9
-
tokio = { version = "1.47.1", features = ["rt-multi-thread", "macros", "signal"] }
8
+
axum = { version = "0.8.8", features = ["macros", "json"] }
9
+
tokio = { version = "1.48.0", features = ["rt-multi-thread", "macros", "signal"] }
10
10
sqlx = { version = "0.8.6", features = ["runtime-tokio-rustls", "sqlite", "migrate", "chrono"] }
11
11
dotenvy = "0.15.7"
12
12
serde = { version = "1.0", features = ["derive"] }
13
13
serde_json = "1.0"
14
14
tracing = "0.1"
15
15
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
16
-
hyper-util = { version = "0.1.16", features = ["client", "client-legacy"] }
16
+
hyper-util = { version = "0.1.19", features = ["client", "client-legacy"] }
17
17
tower-http = { version = "0.6", features = ["cors", "compression-zstd"] }
18
18
tower_governor = { version = "0.8.0", features = ["axum", "tracing"] }
19
19
hex = "0.4"
20
20
jwt-compact = { version = "0.8.0", features = ["es256k"] }
21
21
scrypt = "0.11"
22
22
#Leaveing these two cause I think it is needed by the email crate for ssl
23
-
aws-lc-rs = "1.13.0"
23
+
aws-lc-rs = "1.15.2"
24
24
rustls = { version = "0.23", default-features = false, features = ["tls12", "std", "logging", "aws_lc_rs"] }
25
25
lettre = { version = "0.11", default-features = false, features = ["builder", "webpki-roots", "rustls", "aws-lc-rs", "smtp-transport", "tokio1", "tokio1-rustls"] }
26
-
handlebars = { version = "6.3.2", features = ["rust-embed"] }
27
-
rust-embed = "8.7.2"
26
+
handlebars = { version = "6.4.0", features = ["rust-embed"] }
27
+
rust-embed = "8.9.0"
28
28
axum-template = { version = "3.0.0", features = ["handlebars"] }
29
29
rand = "0.9.2"
30
-
anyhow = "1.0.99"
30
+
anyhow = "1.0.100"
31
31
chrono = { version = "0.4.42", features = ["default", "serde"] }
32
32
sha2 = "0.10"
33
-
jacquard-common = "0.9.2"
34
-
jacquard-identity = "0.9.2"
33
+
jacquard-common = "0.9.5"
34
+
jacquard-identity = "0.9.5"
35
35
multibase = "0.9.2"
36
36
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
37
37
urlencoding = "2.1"
38
38
html-escape = "0.2.13"
39
39
josekit = "0.10.3"
40
+
dashmap = "6.1"
41
+
tower = "0.5"
+101
src/auth/cache.rs
+101
src/auth/cache.rs
···
1
+
use dashmap::DashMap;
2
+
use std::sync::Arc;
3
+
use std::time::{Duration, Instant};
4
+
5
+
#[derive(Clone, Debug)]
6
+
struct CachedHandle {
7
+
handle: String,
8
+
cached_at: Instant,
9
+
}
10
+
11
+
/// A thread-safe cache for DID-to-handle resolutions with TTL expiration.
12
+
#[derive(Clone)]
13
+
pub struct HandleCache {
14
+
cache: Arc<DashMap<String, CachedHandle>>,
15
+
ttl: Duration,
16
+
}
17
+
18
+
impl Default for HandleCache {
19
+
fn default() -> Self {
20
+
Self::new()
21
+
}
22
+
}
23
+
24
+
impl HandleCache {
25
+
/// Creates a new HandleCache with a default TTL of 1 hour.
26
+
pub fn new() -> Self {
27
+
Self::with_ttl(Duration::from_secs(3600))
28
+
}
29
+
30
+
/// Creates a new HandleCache with a custom TTL.
31
+
pub fn with_ttl(ttl: Duration) -> Self {
32
+
Self {
33
+
cache: Arc::new(DashMap::new()),
34
+
ttl,
35
+
}
36
+
}
37
+
38
+
/// Gets a cached handle for the given DID, if it exists and hasn't expired.
39
+
pub fn get(&self, did: &str) -> Option<String> {
40
+
let entry = self.cache.get(did)?;
41
+
if entry.cached_at.elapsed() > self.ttl {
42
+
drop(entry);
43
+
self.cache.remove(did);
44
+
return None;
45
+
}
46
+
Some(entry.handle.clone())
47
+
}
48
+
49
+
/// Inserts a DID-to-handle mapping into the cache.
50
+
pub fn insert(&self, did: String, handle: String) {
51
+
self.cache.insert(
52
+
did,
53
+
CachedHandle {
54
+
handle,
55
+
cached_at: Instant::now(),
56
+
},
57
+
);
58
+
}
59
+
60
+
/// Removes expired entries from the cache.
61
+
/// Call this periodically to prevent memory growth.
62
+
pub fn cleanup(&self) {
63
+
self.cache.retain(|_, v| v.cached_at.elapsed() <= self.ttl);
64
+
}
65
+
66
+
/// Returns the number of entries in the cache.
67
+
pub fn len(&self) -> usize {
68
+
self.cache.len()
69
+
}
70
+
71
+
/// Returns true if the cache is empty.
72
+
pub fn is_empty(&self) -> bool {
73
+
self.cache.is_empty()
74
+
}
75
+
}
76
+
77
+
#[cfg(test)]
78
+
mod tests {
79
+
use super::*;
80
+
81
+
#[test]
82
+
fn test_cache_insert_and_get() {
83
+
let cache = HandleCache::new();
84
+
cache.insert("did:plc:test".into(), "test.handle.com".into());
85
+
assert_eq!(cache.get("did:plc:test"), Some("test.handle.com".into()));
86
+
}
87
+
88
+
#[test]
89
+
fn test_cache_miss() {
90
+
let cache = HandleCache::new();
91
+
assert_eq!(cache.get("did:plc:nonexistent"), None);
92
+
}
93
+
94
+
#[test]
95
+
fn test_cache_expiration() {
96
+
let cache = HandleCache::with_ttl(Duration::from_millis(1));
97
+
cache.insert("did:plc:test".into(), "test.handle.com".into());
98
+
std::thread::sleep(Duration::from_millis(10));
99
+
assert_eq!(cache.get("did:plc:test"), None);
100
+
}
101
+
}
+456
src/auth/middleware.rs
+456
src/auth/middleware.rs
···
1
+
use super::{AuthRules, HandleCache, SessionData};
2
+
use crate::helpers::json_error_response;
3
+
use crate::AppState;
4
+
use axum::extract::{Request, State};
5
+
use axum::http::{HeaderMap, StatusCode};
6
+
use axum::middleware::Next;
7
+
use axum::response::{IntoResponse, Response};
8
+
use jacquard_identity::resolver::IdentityResolver;
9
+
use jacquard_identity::PublicResolver;
10
+
use jwt_compact::alg::{Hs256, Hs256Key};
11
+
use jwt_compact::{AlgorithmExt, Claims, Token, UntrustedToken, ValidationError};
12
+
use serde::{Deserialize, Serialize};
13
+
use std::env;
14
+
use std::sync::Arc;
15
+
use tracing::log;
16
+
17
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18
+
pub enum AuthScheme {
19
+
Bearer,
20
+
DPoP,
21
+
}
22
+
23
+
#[derive(Serialize, Deserialize)]
24
+
pub struct TokenClaims {
25
+
pub sub: String,
26
+
/// OAuth scopes as space-separated string (per OAuth 2.0 spec)
27
+
#[serde(default)]
28
+
pub scope: Option<String>,
29
+
}
30
+
31
+
/// State passed to the auth middleware containing both AppState and auth rules.
32
+
#[derive(Clone)]
33
+
pub struct AuthMiddlewareState {
34
+
pub app_state: AppState,
35
+
pub rules: AuthRules,
36
+
}
37
+
38
+
/// Core middleware function that validates authentication and applies auth rules.
39
+
///
40
+
/// Use this with `axum::middleware::from_fn_with_state`:
41
+
/// ```ignore
42
+
/// use axum::middleware::from_fn_with_state;
43
+
///
44
+
/// let mw_state = AuthMiddlewareState {
45
+
/// app_state: state.clone(),
46
+
/// rules: AuthRules::HandleEndsWith(".blacksky.team".into()),
47
+
/// };
48
+
///
49
+
/// .route("/protected", get(handler).layer(from_fn_with_state(mw_state, auth_middleware)))
50
+
/// ```
51
+
pub async fn auth_middleware(
52
+
State(mw_state): State<AuthMiddlewareState>,
53
+
req: Request,
54
+
next: Next,
55
+
) -> Response {
56
+
let AuthMiddlewareState { app_state, rules } = mw_state;
57
+
58
+
// 1. Extract DID and scopes from JWT (Bearer token)
59
+
let extracted = match extract_auth_from_request(req.headers()) {
60
+
Ok(Some(auth)) => auth,
61
+
Ok(None) => {
62
+
return json_error_response(StatusCode::UNAUTHORIZED, "AuthRequired", "Authentication required")
63
+
.unwrap_or_else(|_| StatusCode::UNAUTHORIZED.into_response());
64
+
}
65
+
Err(e) => {
66
+
log::error!("Token extraction error: {}", e);
67
+
return json_error_response(StatusCode::UNAUTHORIZED, "InvalidToken", &e)
68
+
.unwrap_or_else(|_| StatusCode::UNAUTHORIZED.into_response());
69
+
}
70
+
};
71
+
72
+
// 2. Resolve DID to handle (check cache first)
73
+
let handle = match resolve_did_to_handle(&app_state.resolver, &app_state.handle_cache, &extracted.did).await {
74
+
Ok(handle) => handle,
75
+
Err(e) => {
76
+
log::error!("Failed to resolve DID {} to handle: {}", extracted.did, e);
77
+
return json_error_response(
78
+
StatusCode::INTERNAL_SERVER_ERROR,
79
+
"ResolutionError",
80
+
"Failed to resolve identity",
81
+
)
82
+
.unwrap_or_else(|_| StatusCode::INTERNAL_SERVER_ERROR.into_response());
83
+
}
84
+
};
85
+
86
+
// 3. Build session data and validate rules
87
+
let session = SessionData {
88
+
did: extracted.did,
89
+
handle,
90
+
scopes: extracted.scopes,
91
+
};
92
+
93
+
if !rules.validate(&session) {
94
+
return json_error_response(StatusCode::FORBIDDEN, "AccessDenied", "Access denied by authorization rules")
95
+
.unwrap_or_else(|_| StatusCode::FORBIDDEN.into_response());
96
+
}
97
+
98
+
// 4. Pass through on success
99
+
next.run(req).await
100
+
}
101
+
102
+
/// Extracted authentication data from JWT
103
+
struct ExtractedAuth {
104
+
did: String,
105
+
scopes: Vec<String>,
106
+
}
107
+
108
+
/// Extracts the DID and scopes from the Authorization header (Bearer JWT).
109
+
fn extract_auth_from_request(headers: &HeaderMap) -> Result<Option<ExtractedAuth>, String> {
110
+
let auth = extract_auth(headers)?;
111
+
112
+
match auth {
113
+
None => Ok(None),
114
+
Some((scheme, token_str)) => {
115
+
match scheme {
116
+
AuthScheme::Bearer => {
117
+
let token = UntrustedToken::new(&token_str)
118
+
.map_err(|_| "Invalid token format".to_string())?;
119
+
120
+
let _claims: Claims<TokenClaims> = token
121
+
.deserialize_claims_unchecked()
122
+
.map_err(|_| "Failed to parse token claims".to_string())?;
123
+
124
+
let key = Hs256Key::new(
125
+
env::var("PDS_JWT_SECRET")
126
+
.map_err(|_| "PDS_JWT_SECRET not configured".to_string())?,
127
+
);
128
+
129
+
let validated: Token<TokenClaims> = Hs256
130
+
.validator(&key)
131
+
.validate(&token)
132
+
.map_err(|e: ValidationError| format!("Token validation failed: {:?}", e))?;
133
+
134
+
let custom = &validated.claims().custom;
135
+
136
+
// Parse scopes from space-separated string (OAuth 2.0 spec)
137
+
let scopes: Vec<String> = custom.scope
138
+
.as_ref()
139
+
.map(|s| s.split_whitespace().map(|s| s.to_string()).collect())
140
+
.unwrap_or_default();
141
+
142
+
Ok(Some(ExtractedAuth {
143
+
did: custom.sub.clone(),
144
+
scopes,
145
+
}))
146
+
}
147
+
AuthScheme::DPoP => {
148
+
// DPoP tokens are not validated here; pass through without auth data
149
+
Ok(None)
150
+
}
151
+
}
152
+
}
153
+
}
154
+
}
155
+
156
+
/// Extracts the authentication scheme and token from the Authorization header.
157
+
fn extract_auth(headers: &HeaderMap) -> Result<Option<(AuthScheme, String)>, String> {
158
+
match headers.get(axum::http::header::AUTHORIZATION) {
159
+
None => Ok(None),
160
+
Some(hv) => {
161
+
let s = hv
162
+
.to_str()
163
+
.map_err(|_| "Authorization header is not valid UTF-8".to_string())?;
164
+
165
+
let mut parts = s.splitn(2, ' ');
166
+
match (parts.next(), parts.next()) {
167
+
(Some("Bearer"), Some(tok)) if !tok.is_empty() => {
168
+
Ok(Some((AuthScheme::Bearer, tok.to_string())))
169
+
}
170
+
(Some("DPoP"), Some(tok)) if !tok.is_empty() => {
171
+
Ok(Some((AuthScheme::DPoP, tok.to_string())))
172
+
}
173
+
_ => Err(
174
+
"Authorization header must be in format 'Bearer <token>' or 'DPoP <token>'"
175
+
.to_string(),
176
+
),
177
+
}
178
+
}
179
+
}
180
+
}
181
+
182
+
/// Resolves a DID to its handle using the PublicResolver, with caching.
183
+
async fn resolve_did_to_handle(
184
+
resolver: &Arc<PublicResolver>,
185
+
cache: &HandleCache,
186
+
did: &str,
187
+
) -> Result<String, String> {
188
+
// Check cache first
189
+
if let Some(handle) = cache.get(did) {
190
+
return Ok(handle);
191
+
}
192
+
193
+
// Parse the DID
194
+
let did_parsed = jacquard_common::types::did::Did::new(did)
195
+
.map_err(|e| format!("Invalid DID: {:?}", e))?;
196
+
197
+
// Resolve the DID document
198
+
let did_doc_response = resolver
199
+
.resolve_did_doc(&did_parsed)
200
+
.await
201
+
.map_err(|e| format!("DID resolution failed: {:?}", e))?;
202
+
203
+
let doc = did_doc_response
204
+
.parse()
205
+
.map_err(|e| format!("Failed to parse DID document: {:?}", e))?;
206
+
207
+
// Extract handle from alsoKnownAs field
208
+
// Format is typically: ["at://handle.example.com"]
209
+
let handle: String = doc
210
+
.also_known_as
211
+
.as_ref()
212
+
.and_then(|aka| {
213
+
aka.iter()
214
+
.find(|uri| uri.starts_with("at://"))
215
+
.map(|uri| uri.strip_prefix("at://").unwrap_or(uri.as_ref()).to_string())
216
+
})
217
+
.ok_or_else(|| "No ATProto handle found in DID document".to_string())?;
218
+
219
+
// Cache the result
220
+
cache.insert(did.to_string(), handle.clone());
221
+
222
+
Ok(handle)
223
+
}
224
+
225
+
// ============================================================================
226
+
// Helper Functions for Creating Middleware State
227
+
// ============================================================================
228
+
229
+
/// Creates an `AuthMiddlewareState` for requiring the handle to end with a specific suffix.
230
+
///
231
+
/// # Example
232
+
/// ```ignore
233
+
/// use axum::middleware::from_fn_with_state;
234
+
/// use crate::auth::{auth_middleware, handle_ends_with};
235
+
///
236
+
/// .route("/protected", get(handler).layer(
237
+
/// from_fn_with_state(handle_ends_with(".blacksky.team", &state), auth_middleware)
238
+
/// ))
239
+
/// ```
240
+
pub fn handle_ends_with(suffix: impl Into<String>, state: &AppState) -> AuthMiddlewareState {
241
+
AuthMiddlewareState {
242
+
app_state: state.clone(),
243
+
rules: AuthRules::HandleEndsWith(suffix.into()),
244
+
}
245
+
}
246
+
247
+
/// Creates an `AuthMiddlewareState` for requiring the handle to end with any of the specified suffixes.
248
+
pub fn handle_ends_with_any<I, T>(suffixes: I, state: &AppState) -> AuthMiddlewareState
249
+
where
250
+
I: IntoIterator<Item = T>,
251
+
T: Into<String>,
252
+
{
253
+
AuthMiddlewareState {
254
+
app_state: state.clone(),
255
+
rules: AuthRules::HandleEndsWithAny(suffixes.into_iter().map(|s| s.into()).collect()),
256
+
}
257
+
}
258
+
259
+
/// Creates an `AuthMiddlewareState` for requiring the DID to equal a specific value.
260
+
pub fn did_equals(did: impl Into<String>, state: &AppState) -> AuthMiddlewareState {
261
+
AuthMiddlewareState {
262
+
app_state: state.clone(),
263
+
rules: AuthRules::DidEquals(did.into()),
264
+
}
265
+
}
266
+
267
+
/// Creates an `AuthMiddlewareState` for requiring the DID to be one of the specified values.
268
+
pub fn did_equals_any<I, T>(dids: I, state: &AppState) -> AuthMiddlewareState
269
+
where
270
+
I: IntoIterator<Item = T>,
271
+
T: Into<String>,
272
+
{
273
+
AuthMiddlewareState {
274
+
app_state: state.clone(),
275
+
rules: AuthRules::DidEqualsAny(dids.into_iter().map(|d| d.into()).collect()),
276
+
}
277
+
}
278
+
279
+
/// Creates an `AuthMiddlewareState` with custom auth rules.
280
+
pub fn with_rules(rules: AuthRules, state: &AppState) -> AuthMiddlewareState {
281
+
AuthMiddlewareState {
282
+
app_state: state.clone(),
283
+
rules,
284
+
}
285
+
}
286
+
287
+
// ============================================================================
288
+
// Scope Helper Functions
289
+
// ============================================================================
290
+
291
+
/// Creates an `AuthMiddlewareState` requiring a specific OAuth scope.
292
+
///
293
+
/// # Example
294
+
/// ```ignore
295
+
/// .route("/xrpc/com.atproto.repo.createRecord",
296
+
/// post(handler).layer(from_fn_with_state(
297
+
/// scope_equals("repo:app.bsky.feed.post", &state),
298
+
/// auth_middleware
299
+
/// )))
300
+
/// ```
301
+
pub fn scope_equals(scope: impl Into<String>, state: &AppState) -> AuthMiddlewareState {
302
+
AuthMiddlewareState {
303
+
app_state: state.clone(),
304
+
rules: AuthRules::ScopeEquals(scope.into()),
305
+
}
306
+
}
307
+
308
+
/// Creates an `AuthMiddlewareState` requiring ANY of the specified scopes (OR logic).
309
+
///
310
+
/// # Example
311
+
/// ```ignore
312
+
/// .route("/xrpc/com.atproto.repo.putRecord",
313
+
/// post(handler).layer(from_fn_with_state(
314
+
/// scope_any(["repo:app.bsky.feed.post", "transition:generic"], &state),
315
+
/// auth_middleware
316
+
/// )))
317
+
/// ```
318
+
pub fn scope_any<I, T>(scopes: I, state: &AppState) -> AuthMiddlewareState
319
+
where
320
+
I: IntoIterator<Item = T>,
321
+
T: Into<String>,
322
+
{
323
+
AuthMiddlewareState {
324
+
app_state: state.clone(),
325
+
rules: AuthRules::ScopeEqualsAny(scopes.into_iter().map(|s| s.into()).collect()),
326
+
}
327
+
}
328
+
329
+
/// Creates an `AuthMiddlewareState` requiring ALL of the specified scopes (AND logic).
330
+
///
331
+
/// # Example
332
+
/// ```ignore
333
+
/// .route("/xrpc/com.atproto.admin.updateAccount",
334
+
/// post(handler).layer(from_fn_with_state(
335
+
/// scope_all(["account:email", "account:repo?action=manage"], &state),
336
+
/// auth_middleware
337
+
/// )))
338
+
/// ```
339
+
pub fn scope_all<I, T>(scopes: I, state: &AppState) -> AuthMiddlewareState
340
+
where
341
+
I: IntoIterator<Item = T>,
342
+
T: Into<String>,
343
+
{
344
+
AuthMiddlewareState {
345
+
app_state: state.clone(),
346
+
rules: AuthRules::ScopeEqualsAll(scopes.into_iter().map(|s| s.into()).collect()),
347
+
}
348
+
}
349
+
350
+
// ============================================================================
351
+
// Combined Rule Helpers (Identity + Scope)
352
+
// ============================================================================
353
+
354
+
/// Creates an `AuthMiddlewareState` requiring handle to end with suffix AND have a specific scope.
355
+
///
356
+
/// # Example
357
+
/// ```ignore
358
+
/// .route("/xrpc/community.blacksky.feed.generator",
359
+
/// post(handler).layer(from_fn_with_state(
360
+
/// handle_ends_with_and_scope(".blacksky.team", "transition:generic", &state),
361
+
/// auth_middleware
362
+
/// )))
363
+
/// ```
364
+
pub fn handle_ends_with_and_scope(
365
+
suffix: impl Into<String>,
366
+
scope: impl Into<String>,
367
+
state: &AppState,
368
+
) -> AuthMiddlewareState {
369
+
AuthMiddlewareState {
370
+
app_state: state.clone(),
371
+
rules: AuthRules::All(vec![
372
+
AuthRules::HandleEndsWith(suffix.into()),
373
+
AuthRules::ScopeEquals(scope.into()),
374
+
]),
375
+
}
376
+
}
377
+
378
+
/// Creates an `AuthMiddlewareState` requiring handle to end with suffix AND have ALL specified scopes.
379
+
///
380
+
/// # Example
381
+
/// ```ignore
382
+
/// .route("/xrpc/community.blacksky.admin.manage",
383
+
/// post(handler).layer(from_fn_with_state(
384
+
/// handle_ends_with_and_scopes(".blacksky.team", ["transition:generic", "identity:*"], &state),
385
+
/// auth_middleware
386
+
/// )))
387
+
/// ```
388
+
pub fn handle_ends_with_and_scopes<I, T>(
389
+
suffix: impl Into<String>,
390
+
scopes: I,
391
+
state: &AppState,
392
+
) -> AuthMiddlewareState
393
+
where
394
+
I: IntoIterator<Item = T>,
395
+
T: Into<String>,
396
+
{
397
+
AuthMiddlewareState {
398
+
app_state: state.clone(),
399
+
rules: AuthRules::All(vec![
400
+
AuthRules::HandleEndsWith(suffix.into()),
401
+
AuthRules::ScopeEqualsAll(scopes.into_iter().map(|s| s.into()).collect()),
402
+
]),
403
+
}
404
+
}
405
+
406
+
/// Creates an `AuthMiddlewareState` requiring DID to equal value AND have a specific scope.
407
+
///
408
+
/// # Example
409
+
/// ```ignore
410
+
/// .route("/xrpc/com.atproto.admin.deleteAccount",
411
+
/// post(handler).layer(from_fn_with_state(
412
+
/// did_with_scope("did:plc:rnpkyqnmsw4ipey6eotbdnnf", "transition:generic", &state),
413
+
/// auth_middleware
414
+
/// )))
415
+
/// ```
416
+
pub fn did_with_scope(
417
+
did: impl Into<String>,
418
+
scope: impl Into<String>,
419
+
state: &AppState,
420
+
) -> AuthMiddlewareState {
421
+
AuthMiddlewareState {
422
+
app_state: state.clone(),
423
+
rules: AuthRules::All(vec![
424
+
AuthRules::DidEquals(did.into()),
425
+
AuthRules::ScopeEquals(scope.into()),
426
+
]),
427
+
}
428
+
}
429
+
430
+
/// Creates an `AuthMiddlewareState` requiring DID to equal value AND have ALL specified scopes.
431
+
///
432
+
/// # Example
433
+
/// ```ignore
434
+
/// .route("/xrpc/com.atproto.admin.fullAccess",
435
+
/// post(handler).layer(from_fn_with_state(
436
+
/// did_with_scopes("did:plc:rnpkyqnmsw4ipey6eotbdnnf", ["transition:generic", "identity:*"], &state),
437
+
/// auth_middleware
438
+
/// )))
439
+
/// ```
440
+
pub fn did_with_scopes<I, T>(
441
+
did: impl Into<String>,
442
+
scopes: I,
443
+
state: &AppState,
444
+
) -> AuthMiddlewareState
445
+
where
446
+
I: IntoIterator<Item = T>,
447
+
T: Into<String>,
448
+
{
449
+
AuthMiddlewareState {
450
+
app_state: state.clone(),
451
+
rules: AuthRules::All(vec![
452
+
AuthRules::DidEquals(did.into()),
453
+
AuthRules::ScopeEqualsAll(scopes.into_iter().map(|s| s.into()).collect()),
454
+
]),
455
+
}
456
+
}
+16
src/auth/mod.rs
+16
src/auth/mod.rs
···
1
+
mod cache;
2
+
mod middleware;
3
+
mod rules;
4
+
5
+
pub use cache::HandleCache;
6
+
pub use middleware::{
7
+
// Core middleware
8
+
auth_middleware, with_rules, AuthMiddlewareState,
9
+
// Identity helpers
10
+
did_equals, did_equals_any, handle_ends_with, handle_ends_with_any,
11
+
// Scope helpers
12
+
scope_all, scope_any, scope_equals,
13
+
// Combined helpers (identity + scope)
14
+
did_with_scope, did_with_scopes, handle_ends_with_and_scope, handle_ends_with_and_scopes,
15
+
};
16
+
pub use rules::{AuthRules, SessionData};
+694
src/auth/rules.rs
+694
src/auth/rules.rs
···
1
+
/// Authentication rules that can be validated against session data
2
+
#[derive(Debug, Clone, PartialEq)]
3
+
pub enum AuthRules {
4
+
/// Handle must end with the specified suffix
5
+
HandleEndsWith(String),
6
+
/// Handle must end with any of the specified suffixes (OR logic)
7
+
HandleEndsWithAny(Vec<String>),
8
+
/// DID must exactly match the specified value
9
+
DidEquals(String),
10
+
/// DID must match any of the specified values (OR logic)
11
+
DidEqualsAny(Vec<String>),
12
+
/// Session must have the specified OAuth scope
13
+
ScopeEquals(String),
14
+
/// Session must have ANY of the specified scopes (OR logic)
15
+
ScopeEqualsAny(Vec<String>),
16
+
/// Session must have ALL of the specified scopes (AND logic)
17
+
ScopeEqualsAll(Vec<String>),
18
+
/// All nested rules must be satisfied (AND logic)
19
+
All(Vec<AuthRules>),
20
+
/// At least one nested rule must be satisfied (OR logic)
21
+
Any(Vec<AuthRules>),
22
+
}
23
+
24
+
/// Session data used for authentication validation
25
+
#[derive(Debug, Clone)]
26
+
pub struct SessionData {
27
+
/// The user's DID
28
+
pub did: String,
29
+
/// The user's handle
30
+
pub handle: String,
31
+
/// OAuth 2.0 scopes granted to this session
32
+
pub scopes: Vec<String>,
33
+
}
34
+
35
+
impl AuthRules {
36
+
/// Validates if the given session data meets the authentication requirements
37
+
pub fn validate(&self, session_data: &SessionData) -> bool {
38
+
match self {
39
+
AuthRules::HandleEndsWith(suffix) => session_data.handle.ends_with(suffix),
40
+
AuthRules::HandleEndsWithAny(suffixes) => {
41
+
suffixes.iter().any(|s| session_data.handle.ends_with(s))
42
+
}
43
+
AuthRules::DidEquals(did) => session_data.did == *did,
44
+
AuthRules::DidEqualsAny(dids) => dids.iter().any(|d| session_data.did == *d),
45
+
AuthRules::ScopeEquals(scope) => has_scope(&session_data.scopes, scope),
46
+
AuthRules::ScopeEqualsAny(scopes) => has_any_scope(&session_data.scopes, scopes),
47
+
AuthRules::ScopeEqualsAll(scopes) => has_all_scopes(&session_data.scopes, scopes),
48
+
AuthRules::All(rules) => rules.iter().all(|r| r.validate(session_data)),
49
+
AuthRules::Any(rules) => rules.iter().any(|r| r.validate(session_data)),
50
+
}
51
+
}
52
+
}
53
+
54
+
/// Checks if the session has a specific scope
55
+
pub fn has_scope(scopes: &[String], required_scope: &str) -> bool {
56
+
scopes.iter().any(|s| s == required_scope)
57
+
}
58
+
59
+
/// Checks if the session has ANY of the required scopes (OR logic)
60
+
pub fn has_any_scope(scopes: &[String], required_scopes: &[String]) -> bool {
61
+
required_scopes.iter().any(|req| has_scope(scopes, req))
62
+
}
63
+
64
+
/// Checks if the session has ALL of the required scopes (AND logic)
65
+
pub fn has_all_scopes(scopes: &[String], required_scopes: &[String]) -> bool {
66
+
required_scopes.iter().all(|req| has_scope(scopes, req))
67
+
}
68
+
69
+
#[cfg(test)]
70
+
mod tests {
71
+
use super::*;
72
+
73
+
fn test_session(did: &str, handle: &str, scopes: Vec<&str>) -> SessionData {
74
+
SessionData {
75
+
did: did.to_string(),
76
+
handle: handle.to_string(),
77
+
scopes: scopes.into_iter().map(|s| s.to_string()).collect(),
78
+
}
79
+
}
80
+
81
+
#[test]
82
+
fn test_handle_ends_with() {
83
+
let rules = AuthRules::HandleEndsWith(".blacksky.team".into());
84
+
85
+
let valid = test_session("did:plc:123", "alice.blacksky.team", vec!["atproto"]);
86
+
assert!(rules.validate(&valid));
87
+
88
+
let invalid = test_session("did:plc:123", "alice.bsky.social", vec!["atproto"]);
89
+
assert!(!rules.validate(&invalid));
90
+
}
91
+
92
+
#[test]
93
+
fn test_handle_ends_with_any() {
94
+
let rules = AuthRules::HandleEndsWithAny(vec![".blacksky.team".into(), ".bsky.team".into()]);
95
+
96
+
let valid1 = test_session("did:plc:123", "alice.blacksky.team", vec!["atproto"]);
97
+
assert!(rules.validate(&valid1));
98
+
99
+
let valid2 = test_session("did:plc:123", "bob.bsky.team", vec!["atproto"]);
100
+
assert!(rules.validate(&valid2));
101
+
102
+
let invalid = test_session("did:plc:123", "charlie.bsky.social", vec!["atproto"]);
103
+
assert!(!rules.validate(&invalid));
104
+
}
105
+
106
+
#[test]
107
+
fn test_did_equals() {
108
+
let rules = AuthRules::DidEquals("did:plc:alice".into());
109
+
110
+
let valid = test_session("did:plc:alice", "alice.bsky.social", vec!["atproto"]);
111
+
assert!(rules.validate(&valid));
112
+
113
+
let invalid = test_session("did:plc:bob", "bob.bsky.social", vec!["atproto"]);
114
+
assert!(!rules.validate(&invalid));
115
+
}
116
+
117
+
#[test]
118
+
fn test_any_combinator() {
119
+
let rules = AuthRules::Any(vec![
120
+
AuthRules::DidEquals("did:plc:admin".into()),
121
+
AuthRules::HandleEndsWith(".blacksky.team".into()),
122
+
]);
123
+
124
+
// First condition met
125
+
let valid1 = test_session("did:plc:admin", "admin.bsky.social", vec!["atproto"]);
126
+
assert!(rules.validate(&valid1));
127
+
128
+
// Second condition met
129
+
let valid2 = test_session("did:plc:user", "user.blacksky.team", vec!["atproto"]);
130
+
assert!(rules.validate(&valid2));
131
+
132
+
// Neither condition met
133
+
let invalid = test_session("did:plc:user", "user.bsky.social", vec!["atproto"]);
134
+
assert!(!rules.validate(&invalid));
135
+
}
136
+
137
+
#[test]
138
+
fn test_all_combinator() {
139
+
let rules = AuthRules::All(vec![
140
+
AuthRules::HandleEndsWith(".blacksky.team".into()),
141
+
AuthRules::DidEqualsAny(vec!["did:plc:alice".into(), "did:plc:bob".into()]),
142
+
]);
143
+
144
+
// Both conditions met
145
+
let valid = test_session("did:plc:alice", "alice.blacksky.team", vec!["atproto"]);
146
+
assert!(rules.validate(&valid));
147
+
148
+
// Handle wrong
149
+
let invalid1 = test_session("did:plc:alice", "alice.bsky.social", vec!["atproto"]);
150
+
assert!(!rules.validate(&invalid1));
151
+
152
+
// DID wrong
153
+
let invalid2 = test_session("did:plc:charlie", "charlie.blacksky.team", vec!["atproto"]);
154
+
assert!(!rules.validate(&invalid2));
155
+
}
156
+
157
+
// ========================================================================
158
+
// Scope Tests
159
+
// ========================================================================
160
+
161
+
#[test]
162
+
fn test_scope_equals() {
163
+
let rules = AuthRules::ScopeEquals("transition:generic".into());
164
+
165
+
let valid = test_session("did:plc:123", "alice.bsky.social", vec!["atproto", "transition:generic"]);
166
+
assert!(rules.validate(&valid));
167
+
168
+
let invalid = test_session("did:plc:123", "alice.bsky.social", vec!["atproto"]);
169
+
assert!(!rules.validate(&invalid));
170
+
}
171
+
172
+
#[test]
173
+
fn test_scope_any() {
174
+
let rules = AuthRules::ScopeEqualsAny(vec![
175
+
"transition:generic".into(),
176
+
"repo:app.bsky.feed.post".into(),
177
+
]);
178
+
179
+
// Has first scope
180
+
let valid1 = test_session("did:plc:123", "alice.bsky.social", vec!["atproto", "transition:generic"]);
181
+
assert!(rules.validate(&valid1));
182
+
183
+
// Has second scope
184
+
let valid2 = test_session("did:plc:123", "alice.bsky.social", vec!["atproto", "repo:app.bsky.feed.post"]);
185
+
assert!(rules.validate(&valid2));
186
+
187
+
// Has neither
188
+
let invalid = test_session("did:plc:123", "alice.bsky.social", vec!["atproto"]);
189
+
assert!(!rules.validate(&invalid));
190
+
}
191
+
192
+
#[test]
193
+
fn test_scope_all() {
194
+
let rules = AuthRules::ScopeEqualsAll(vec![
195
+
"atproto".into(),
196
+
"transition:generic".into(),
197
+
]);
198
+
199
+
// Has both scopes
200
+
let valid = test_session("did:plc:123", "alice.bsky.social", vec!["atproto", "transition:generic"]);
201
+
assert!(rules.validate(&valid));
202
+
203
+
// Missing one scope
204
+
let invalid = test_session("did:plc:123", "alice.bsky.social", vec!["atproto"]);
205
+
assert!(!rules.validate(&invalid));
206
+
}
207
+
208
+
// ========================================================================
209
+
// Combined Rules Tests (Identity + Scope)
210
+
// ========================================================================
211
+
212
+
#[test]
213
+
fn test_handle_ends_with_and_scope() {
214
+
let rules = AuthRules::All(vec![
215
+
AuthRules::HandleEndsWith(".blacksky.team".into()),
216
+
AuthRules::ScopeEquals("transition:generic".into()),
217
+
]);
218
+
219
+
// Both conditions met
220
+
let valid = test_session(
221
+
"did:plc:123",
222
+
"alice.blacksky.team",
223
+
vec!["atproto", "transition:generic"],
224
+
);
225
+
assert!(rules.validate(&valid));
226
+
227
+
// Handle correct, scope wrong
228
+
let invalid1 = test_session("did:plc:123", "alice.blacksky.team", vec!["atproto"]);
229
+
assert!(!rules.validate(&invalid1));
230
+
231
+
// Scope correct, handle wrong
232
+
let invalid2 = test_session(
233
+
"did:plc:123",
234
+
"alice.bsky.social",
235
+
vec!["atproto", "transition:generic"],
236
+
);
237
+
assert!(!rules.validate(&invalid2));
238
+
}
239
+
240
+
#[test]
241
+
fn test_did_with_scope() {
242
+
let rules = AuthRules::All(vec![
243
+
AuthRules::DidEquals("did:plc:rnpkyqnmsw4ipey6eotbdnnf".into()),
244
+
AuthRules::ScopeEquals("transition:generic".into()),
245
+
]);
246
+
247
+
// Both conditions met
248
+
let valid = test_session(
249
+
"did:plc:rnpkyqnmsw4ipey6eotbdnnf",
250
+
"admin.bsky.social",
251
+
vec!["atproto", "transition:generic"],
252
+
);
253
+
assert!(rules.validate(&valid));
254
+
255
+
// DID correct, scope wrong
256
+
let invalid1 = test_session(
257
+
"did:plc:rnpkyqnmsw4ipey6eotbdnnf",
258
+
"admin.bsky.social",
259
+
vec!["atproto"],
260
+
);
261
+
assert!(!rules.validate(&invalid1));
262
+
263
+
// Scope correct, DID wrong
264
+
let invalid2 = test_session(
265
+
"did:plc:wrongdid",
266
+
"admin.bsky.social",
267
+
vec!["atproto", "transition:generic"],
268
+
);
269
+
assert!(!rules.validate(&invalid2));
270
+
}
271
+
272
+
#[test]
273
+
fn test_complex_admin_or_moderator_rule() {
274
+
// Admin DID OR (moderator handle + scope)
275
+
let rules = AuthRules::Any(vec![
276
+
AuthRules::DidEquals("did:plc:rnpkyqnmsw4ipey6eotbdnnf".into()),
277
+
AuthRules::All(vec![
278
+
AuthRules::HandleEndsWith(".mod.team".into()),
279
+
AuthRules::ScopeEquals("account:email".into()),
280
+
]),
281
+
]);
282
+
283
+
// Admin DID (doesn't need scope)
284
+
let admin = test_session("did:plc:rnpkyqnmsw4ipey6eotbdnnf", "admin.bsky.social", vec!["atproto"]);
285
+
assert!(rules.validate(&admin));
286
+
287
+
// Moderator with correct handle and scope
288
+
let mod_valid = test_session(
289
+
"did:plc:somemod",
290
+
"alice.mod.team",
291
+
vec!["atproto", "account:email"],
292
+
);
293
+
assert!(rules.validate(&mod_valid));
294
+
295
+
// Moderator handle but missing scope
296
+
let mod_no_scope = test_session("did:plc:somemod", "alice.mod.team", vec!["atproto"]);
297
+
assert!(!rules.validate(&mod_no_scope));
298
+
299
+
// Has scope but not moderator handle
300
+
let not_mod = test_session(
301
+
"did:plc:someuser",
302
+
"alice.bsky.social",
303
+
vec!["atproto", "account:email"],
304
+
);
305
+
assert!(!rules.validate(¬_mod));
306
+
}
307
+
308
+
// ========================================================================
309
+
// Additional Coverage Tests
310
+
// ========================================================================
311
+
312
+
#[test]
313
+
fn test_did_equals_any() {
314
+
let rules = AuthRules::DidEqualsAny(vec![
315
+
"did:plc:alice123456789012345678".into(),
316
+
"did:plc:bob12345678901234567890".into(),
317
+
"did:plc:charlie12345678901234567".into(),
318
+
]);
319
+
320
+
// First DID matches
321
+
let valid1 = test_session("did:plc:alice123456789012345678", "alice.bsky.social", vec!["atproto"]);
322
+
assert!(rules.validate(&valid1));
323
+
324
+
// Second DID matches
325
+
let valid2 = test_session("did:plc:bob12345678901234567890", "bob.bsky.social", vec!["atproto"]);
326
+
assert!(rules.validate(&valid2));
327
+
328
+
// Third DID matches
329
+
let valid3 = test_session("did:plc:charlie12345678901234567", "charlie.bsky.social", vec!["atproto"]);
330
+
assert!(rules.validate(&valid3));
331
+
332
+
// DID not in list
333
+
let invalid = test_session("did:plc:unknown1234567890123456", "unknown.bsky.social", vec!["atproto"]);
334
+
assert!(!rules.validate(&invalid));
335
+
336
+
// Partial match should fail (prefix)
337
+
let partial = test_session("did:plc:alice", "alice.bsky.social", vec!["atproto"]);
338
+
assert!(!rules.validate(&partial));
339
+
}
340
+
341
+
// ========================================================================
342
+
// Empty Combinator Edge Cases
343
+
// ========================================================================
344
+
345
+
#[test]
346
+
fn test_empty_any_returns_false() {
347
+
// Any with empty rules should return false (no rule can be satisfied)
348
+
let rules = AuthRules::Any(vec![]);
349
+
let session = test_session("did:plc:test12345678901234567", "test.bsky.social", vec!["atproto"]);
350
+
assert!(!rules.validate(&session));
351
+
}
352
+
353
+
#[test]
354
+
fn test_empty_all_returns_true() {
355
+
// All with empty rules should return true (vacuous truth - all zero rules are satisfied)
356
+
let rules = AuthRules::All(vec![]);
357
+
let session = test_session("did:plc:test12345678901234567", "test.bsky.social", vec!["atproto"]);
358
+
assert!(rules.validate(&session));
359
+
}
360
+
361
+
// ========================================================================
362
+
// Handle Edge Cases
363
+
// ========================================================================
364
+
365
+
#[test]
366
+
fn test_handle_exact_suffix_match() {
367
+
// Handle that IS exactly the suffix should still match
368
+
let rules = AuthRules::HandleEndsWith(".blacksky.team".into());
369
+
370
+
// Handle is exactly the suffix
371
+
let exact = test_session("did:plc:test12345678901234567", ".blacksky.team", vec!["atproto"]);
372
+
assert!(rules.validate(&exact));
373
+
374
+
// Normal case - handle with prefix
375
+
let normal = test_session("did:plc:test12345678901234567", "alice.blacksky.team", vec!["atproto"]);
376
+
assert!(rules.validate(&normal));
377
+
378
+
// Empty handle should not match
379
+
let empty = test_session("did:plc:test12345678901234567", "", vec!["atproto"]);
380
+
assert!(!rules.validate(&empty));
381
+
}
382
+
383
+
// ========================================================================
384
+
// Deeply Nested Combinators
385
+
// ========================================================================
386
+
387
+
#[test]
388
+
fn test_deeply_nested_rules() {
389
+
// Complex nested rule: Any(All(Any(...), ...), All(...))
390
+
// Scenario: (Admin OR VIP) AND (has scope OR team member)
391
+
// OR
392
+
// Specific moderator DID
393
+
let rules = AuthRules::Any(vec![
394
+
// Branch 1: Complex nested condition
395
+
AuthRules::All(vec![
396
+
// Must be admin or VIP
397
+
AuthRules::Any(vec![
398
+
AuthRules::DidEquals("did:plc:admin123456789012345".into()),
399
+
AuthRules::HandleEndsWith(".vip.social".into()),
400
+
]),
401
+
// AND must have scope or be team member
402
+
AuthRules::Any(vec![
403
+
AuthRules::ScopeEquals("transition:generic".into()),
404
+
AuthRules::HandleEndsWith(".team.internal".into()),
405
+
]),
406
+
]),
407
+
// Branch 2: Specific moderator bypass
408
+
AuthRules::DidEquals("did:plc:moderator12345678901".into()),
409
+
]);
410
+
411
+
// Admin with required scope - should pass via Branch 1
412
+
let admin_with_scope = test_session(
413
+
"did:plc:admin123456789012345",
414
+
"admin.bsky.social",
415
+
vec!["atproto", "transition:generic"],
416
+
);
417
+
assert!(rules.validate(&admin_with_scope));
418
+
419
+
// VIP with required scope - should pass via Branch 1
420
+
let vip_with_scope = test_session(
421
+
"did:plc:somevip1234567890123",
422
+
"alice.vip.social",
423
+
vec!["atproto", "transition:generic"],
424
+
);
425
+
assert!(rules.validate(&vip_with_scope));
426
+
427
+
// Moderator bypass - should pass via Branch 2
428
+
let moderator = test_session(
429
+
"did:plc:moderator12345678901",
430
+
"mod.bsky.social",
431
+
vec!["atproto"],
432
+
);
433
+
assert!(rules.validate(&moderator));
434
+
435
+
// Admin without scope and not team member - should fail
436
+
let admin_no_scope = test_session(
437
+
"did:plc:admin123456789012345",
438
+
"admin.bsky.social",
439
+
vec!["atproto"],
440
+
);
441
+
assert!(!rules.validate(&admin_no_scope));
442
+
443
+
// Random user - should fail
444
+
let random = test_session(
445
+
"did:plc:random12345678901234",
446
+
"random.bsky.social",
447
+
vec!["atproto", "transition:generic"],
448
+
);
449
+
assert!(!rules.validate(&random));
450
+
}
451
+
452
+
// ========================================================================
453
+
// ATProto Scope Specification Tests
454
+
// ========================================================================
455
+
456
+
#[test]
457
+
fn test_scope_with_query_params() {
458
+
// ATProto scopes can have query parameters
459
+
// These are treated as literal strings (exact matching)
460
+
461
+
// blob scope with accept parameter
462
+
let blob_rules = AuthRules::ScopeEquals("blob?accept=image/*".into());
463
+
let has_blob = test_session(
464
+
"did:plc:test12345678901234567",
465
+
"test.bsky.social",
466
+
vec!["atproto", "blob?accept=image/*"],
467
+
);
468
+
assert!(blob_rules.validate(&has_blob));
469
+
470
+
// Different query param should not match
471
+
let wrong_blob = test_session(
472
+
"did:plc:test12345678901234567",
473
+
"test.bsky.social",
474
+
vec!["atproto", "blob?accept=video/*"],
475
+
);
476
+
assert!(!blob_rules.validate(&wrong_blob));
477
+
478
+
// account:repo with action parameter
479
+
let account_rules = AuthRules::ScopeEquals("account:repo?action=manage".into());
480
+
let has_account = test_session(
481
+
"did:plc:test12345678901234567",
482
+
"test.bsky.social",
483
+
vec!["atproto", "account:repo?action=manage"],
484
+
);
485
+
assert!(account_rules.validate(&has_account));
486
+
487
+
// Multiple query params
488
+
let multi_param_rules = AuthRules::ScopeEquals("blob?accept=image/*&accept=video/*".into());
489
+
let has_multi = test_session(
490
+
"did:plc:test12345678901234567",
491
+
"test.bsky.social",
492
+
vec!["atproto", "blob?accept=image/*&accept=video/*"],
493
+
);
494
+
assert!(multi_param_rules.validate(&has_multi));
495
+
}
496
+
497
+
#[test]
498
+
fn test_scope_exact_matching_no_wildcards() {
499
+
// ATProto spec: Wildcards do NOT work for collections
500
+
// repo:app.bsky.feed.post should NOT match repo:app.bsky.feed.*
501
+
// This test verifies our exact matching is correct
502
+
503
+
let rules = AuthRules::ScopeEquals("repo:app.bsky.feed.post".into());
504
+
505
+
// Exact match works
506
+
let exact = test_session(
507
+
"did:plc:test12345678901234567",
508
+
"test.bsky.social",
509
+
vec!["atproto", "repo:app.bsky.feed.post"],
510
+
);
511
+
assert!(rules.validate(&exact));
512
+
513
+
// Wildcard scope in JWT should NOT satisfy specific requirement
514
+
// (user has repo:app.bsky.feed.* but endpoint requires repo:app.bsky.feed.post)
515
+
let wildcard = test_session(
516
+
"did:plc:test12345678901234567",
517
+
"test.bsky.social",
518
+
vec!["atproto", "repo:app.bsky.feed.*"],
519
+
);
520
+
assert!(!rules.validate(&wildcard));
521
+
522
+
// Different collection should not match
523
+
let different = test_session(
524
+
"did:plc:test12345678901234567",
525
+
"test.bsky.social",
526
+
vec!["atproto", "repo:app.bsky.feed.like"],
527
+
);
528
+
assert!(!rules.validate(&different));
529
+
530
+
// Prefix should not match
531
+
let prefix = test_session(
532
+
"did:plc:test12345678901234567",
533
+
"test.bsky.social",
534
+
vec!["atproto", "repo:app.bsky.feed"],
535
+
);
536
+
assert!(!rules.validate(&prefix));
537
+
538
+
// repo:* should not match specific collection (exact matching)
539
+
let full_wildcard = test_session(
540
+
"did:plc:test12345678901234567",
541
+
"test.bsky.social",
542
+
vec!["atproto", "repo:*"],
543
+
);
544
+
assert!(!rules.validate(&full_wildcard));
545
+
}
546
+
547
+
#[test]
548
+
fn test_scope_case_sensitivity() {
549
+
// OAuth scopes are case-sensitive per RFC 6749
550
+
551
+
let rules = AuthRules::ScopeEquals("atproto".into());
552
+
553
+
// Exact case matches
554
+
let exact = test_session("did:plc:test12345678901234567", "test.bsky.social", vec!["atproto"]);
555
+
assert!(rules.validate(&exact));
556
+
557
+
// UPPERCASE should NOT match
558
+
let upper = test_session("did:plc:test12345678901234567", "test.bsky.social", vec!["ATPROTO"]);
559
+
assert!(!rules.validate(&upper));
560
+
561
+
// Mixed case should NOT match
562
+
let mixed = test_session("did:plc:test12345678901234567", "test.bsky.social", vec!["AtProto"]);
563
+
assert!(!rules.validate(&mixed));
564
+
565
+
// Test with namespaced scope
566
+
let ns_rules = AuthRules::ScopeEquals("transition:generic".into());
567
+
let ns_upper = test_session(
568
+
"did:plc:test12345678901234567",
569
+
"test.bsky.social",
570
+
vec!["TRANSITION:GENERIC"],
571
+
);
572
+
assert!(!ns_rules.validate(&ns_upper));
573
+
}
574
+
575
+
#[test]
576
+
fn test_scope_with_wildcards_exact_match() {
577
+
// Wildcard scopes like blob:*/* and identity:* are stored as literal strings
578
+
// The middleware does exact matching, so JWT must contain the exact string
579
+
580
+
// blob:*/* - full blob wildcard
581
+
let blob_rules = AuthRules::ScopeEquals("blob:*/*".into());
582
+
let has_blob_wildcard = test_session(
583
+
"did:plc:test12345678901234567",
584
+
"test.bsky.social",
585
+
vec!["atproto", "blob:*/*"],
586
+
);
587
+
assert!(blob_rules.validate(&has_blob_wildcard));
588
+
589
+
// Specific blob type should NOT match blob:*/* requirement
590
+
let has_specific_blob = test_session(
591
+
"did:plc:test12345678901234567",
592
+
"test.bsky.social",
593
+
vec!["atproto", "blob:image/png"],
594
+
);
595
+
assert!(!blob_rules.validate(&has_specific_blob));
596
+
597
+
// identity:* - full identity wildcard
598
+
let identity_rules = AuthRules::ScopeEquals("identity:*".into());
599
+
let has_identity_wildcard = test_session(
600
+
"did:plc:test12345678901234567",
601
+
"test.bsky.social",
602
+
vec!["atproto", "identity:*"],
603
+
);
604
+
assert!(identity_rules.validate(&has_identity_wildcard));
605
+
606
+
// Specific identity scope should NOT match identity:* requirement
607
+
let has_specific_identity = test_session(
608
+
"did:plc:test12345678901234567",
609
+
"test.bsky.social",
610
+
vec!["atproto", "identity:handle"],
611
+
);
612
+
assert!(!identity_rules.validate(&has_specific_identity));
613
+
}
614
+
615
+
// ========================================================================
616
+
// Scope Helper Function Tests
617
+
// ========================================================================
618
+
619
+
#[test]
620
+
fn test_has_scope_helper() {
621
+
let scopes: Vec<String> = vec![
622
+
"atproto".to_string(),
623
+
"transition:generic".to_string(),
624
+
"repo:app.bsky.feed.post".to_string(),
625
+
];
626
+
627
+
// Present scopes
628
+
assert!(has_scope(&scopes, "atproto"));
629
+
assert!(has_scope(&scopes, "transition:generic"));
630
+
assert!(has_scope(&scopes, "repo:app.bsky.feed.post"));
631
+
632
+
// Absent scopes
633
+
assert!(!has_scope(&scopes, "identity:*"));
634
+
assert!(!has_scope(&scopes, ""));
635
+
assert!(!has_scope(&scopes, "ATPROTO")); // Case sensitive
636
+
637
+
// Empty scopes list
638
+
let empty: Vec<String> = vec![];
639
+
assert!(!has_scope(&empty, "atproto"));
640
+
}
641
+
642
+
#[test]
643
+
fn test_has_any_scope_helper() {
644
+
let scopes: Vec<String> = vec![
645
+
"atproto".to_string(),
646
+
"repo:app.bsky.feed.post".to_string(),
647
+
];
648
+
649
+
// Has one of the required scopes
650
+
let required1 = vec!["transition:generic".to_string(), "atproto".to_string()];
651
+
assert!(has_any_scope(&scopes, &required1));
652
+
653
+
// Has none of the required scopes
654
+
let required2 = vec!["transition:generic".to_string(), "identity:*".to_string()];
655
+
assert!(!has_any_scope(&scopes, &required2));
656
+
657
+
// Empty required list - should return false (no scope to match)
658
+
let empty_required: Vec<String> = vec![];
659
+
assert!(!has_any_scope(&scopes, &empty_required));
660
+
661
+
// Empty scopes list
662
+
let empty_scopes: Vec<String> = vec![];
663
+
assert!(!has_any_scope(&empty_scopes, &required1));
664
+
}
665
+
666
+
#[test]
667
+
fn test_has_all_scopes_helper() {
668
+
let scopes: Vec<String> = vec![
669
+
"atproto".to_string(),
670
+
"transition:generic".to_string(),
671
+
"repo:app.bsky.feed.post".to_string(),
672
+
];
673
+
674
+
// Has all required scopes
675
+
let required1 = vec!["atproto".to_string(), "transition:generic".to_string()];
676
+
assert!(has_all_scopes(&scopes, &required1));
677
+
678
+
// Missing one required scope
679
+
let required2 = vec!["atproto".to_string(), "identity:*".to_string()];
680
+
assert!(!has_all_scopes(&scopes, &required2));
681
+
682
+
// Empty required list - should return true (vacuously all zero required are present)
683
+
let empty_required: Vec<String> = vec![];
684
+
assert!(has_all_scopes(&scopes, &empty_required));
685
+
686
+
// Empty scopes list with requirements
687
+
let empty_scopes: Vec<String> = vec![];
688
+
assert!(!has_all_scopes(&empty_scopes, &required1));
689
+
690
+
// Single scope requirement
691
+
let single = vec!["atproto".to_string()];
692
+
assert!(has_all_scopes(&scopes, &single));
693
+
}
694
+
}
+4
-1
src/main.rs
+4
-1
src/main.rs
···
37
37
use tracing::log;
38
38
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
39
39
40
+
mod auth;
40
41
mod gate;
41
42
pub mod helpers;
42
43
mod middleware;
···
153
154
mailer: AsyncSmtpTransport<Tokio1Executor>,
154
155
template_engine: Engine<Handlebars<'static>>,
155
156
resolver: Arc<PublicResolver>,
157
+
handle_cache: auth::HandleCache,
156
158
app_config: AppConfig,
157
159
}
158
160
···
278
280
mailer,
279
281
template_engine: Engine::from(hbs),
280
282
resolver: Arc::new(resolver),
283
+
handle_cache: auth::HandleCache::new(),
281
284
app_config: AppConfig::new(),
282
285
};
283
286
···
387
390
.layer(cors)
388
391
.with_state(state);
389
392
390
-
let host = env::var("GATEKEEPER_HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
393
+
let host = env::var("GATEKEEPER_HOST").unwrap_or_else(|_| "0.0.0.0".to_string());
391
394
let port: u16 = env::var("GATEKEEPER_PORT")
392
395
.ok()
393
396
.and_then(|s| s.parse().ok())