5b9c6ad4 Andy McCall 1 month ago ↶
1
2
750251b2 Andy McCall 1 month ago ↶
3
4
5
6
7
5b9c6ad4 Andy McCall 1 month ago ↶
8
9
use crate :: attest:: Attest;
750251b2 Andy McCall 1 month ago ↶
10
use crate :: cbor:: { self , Value} ;
5b9c6ad4 Andy McCall 1 month ago ↶
11
use crate :: hash:: { ChangeHash, ObjectRef, ObjectType} ;
12
use crate :: identity:: Signature;
750251b2 Andy McCall 1 month ago ↶
13
use crate :: objects:: { self as o, Change, ObjectError} ;
83e0677b Andy McCall 1 month ago ↶
14
use crate :: policy:: Policy;
5b9c6ad4 Andy McCall 1 month ago ↶
15
use crate :: repo:: { Repo, RepoError, Result } ;
2b5ee371 Andy McCall 1 month ago ↶
16
use std:: path:: { Path, PathBuf} ;
9f9e72b9 Andy McCall 1 month ago ↶
17
use std:: sync:: { Arc, Mutex} ;
5b9c6ad4 Andy McCall 1 month ago ↶
18
750251b2 Andy McCall 1 month ago ↶
19
pub const CONTENT_TYPE : & str = " application/oxy-cbor" ;
20
pub const PROTOCOL_VERSION : u64 = 1 ;
21
5b9c6ad4 Andy McCall 1 month ago ↶
22
23
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
24
pub struct SignedAttest {
25
pub attest : Attest,
26
pub sigs : Vec< Signature> ,
27
}
28
83e0677b Andy McCall 1 month ago ↶
29
30
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
31
pub struct SignedPolicy {
32
pub policy : Policy,
33
pub sigs : Vec< Signature> ,
34
}
35
28fc23d7 Andy McCall 1 month ago ↶
36
impl SignedPolicy {
37
38
pub fn encode ( & self ) -> Vec< u8 > {
39
crate :: cbor:: encode( & wire:: policy_value( self ) )
40
}
41
pub fn decode ( b : & [u8 ]) -> Result< SignedPolicy> {
75167672 Andy McCall 1 month ago
42
wire:: policy_from(
43
& crate :: cbor:: decode( b) .map_err ( | e | RepoError:: Object( ObjectError:: from( e) ) ) ? ,
44
)
28fc23d7 Andy McCall 1 month ago ↶
45
}
46
}
47
132b884b Andy McCall 1 month ago ↶
48
83e0677b Andy McCall 1 month ago ↶
49
# [ derive ( Clone, Debug, Default ) ]
50
pub struct RefsResponse {
51
pub refs : Vec< RemoteRef> ,
52
pub policy : Option< SignedPolicy> ,
132b884b Andy McCall 1 month ago ↶
53
pub tags : Vec< TagRef> ,
28fc23d7 Andy McCall 1 month ago ↶
54
55
56
pub history : Vec< SignedPolicy> ,
14edbaaf Andy McCall 1 month ago ↶
57
58
pub default_bookmark : Option< String> ,
4b9d0677 Andy McCall 18 days ago ↶
59
60
61
62
pub log : Option< String> ,
028545df Andy McCall 17 days ago ↶
63
64
65
66
pub witnesses : Vec< ( String, Vec< u8 > ) > ,
b63fc7a7 Andy McCall 11 days ago ↶
67
68
69
70
71
pub withdrawn : Vec< TagRef> ,
83e0677b Andy McCall 1 month ago ↶
72
}
73
4b9d0677 Andy McCall 18 days ago ↶
74
75
76
77
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
78
pub struct Logged {
79
pub index : u64 ,
80
pub entry : Vec< u8 > ,
81
pub proof : Vec< [ u8 ; 32 ] > ,
82
}
83
028545df Andy McCall 17 days ago ↶
84
85
86
87
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
88
pub struct Integration {
89
pub note : String,
90
pub proof : Vec< [ u8 ; 32 ] > ,
91
}
92
132b884b Andy McCall 1 month ago ↶
93
94
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
95
pub struct TagRef {
96
pub name : String,
97
pub state : ObjectRef,
98
pub heads : Vec< ChangeHash> ,
99
pub attestation : Option< SignedAttest> ,
1ec6fdbc Andy McCall 16 days ago ↶
100
101
102
103
pub accepted : Option< SignedAttest> ,
104
105
106
pub logged : Option< Logged> ,
107
108
109
pub integration : Vec< Integration> ,
110
}
111
112
impl TagRef {
b63fc7a7 Andy McCall 11 days ago ↶
113
114
115
pub fn is_withdrawal ( & self ) -> bool {
116
self .attestation
117
.as_ref ( )
118
.is_some_and ( | a | matches! ( a.attest.body, crate :: attest:: AttestBody:: Untag { .. } ) )
119
}
120
1ec6fdbc Andy McCall 16 days ago ↶
121
122
pub fn new (
123
name : String,
124
state : ObjectRef,
125
heads : Vec< ChangeHash> ,
126
attestation : Option< SignedAttest> ,
127
) -> TagRef {
128
TagRef {
129
name,
130
state,
131
heads,
132
attestation,
133
accepted: None ,
134
logged: None ,
135
integration: vec! [ ] ,
136
}
137
}
132b884b Andy McCall 1 month ago ↶
138
}
139
5b9c6ad4 Andy McCall 1 month ago ↶
140
141
# [ derive ( Clone, Debug ) ]
142
pub struct RemoteRef {
143
pub name : String,
144
pub state : ObjectRef,
145
pub heads : Vec< ChangeHash> ,
4161262e Andy McCall 1 month ago ↶
146
147
5b9c6ad4 Andy McCall 1 month ago ↶
148
pub attestation : Option< SignedAttest> ,
4161262e Andy McCall 1 month ago ↶
149
150
151
pub last_serial : Option< u64 > ,
f53cbe7a Andy McCall 18 days ago ↶
152
153
154
pub accepted : Option< SignedAttest> ,
4b9d0677 Andy McCall 18 days ago ↶
155
156
157
pub logged : Option< Logged> ,
028545df Andy McCall 17 days ago ↶
158
159
160
pub integration : Vec< Integration> ,
5b9c6ad4 Andy McCall 1 month ago ↶
161
}
162
163
164
# [ derive ( Clone, Debug, Default ) ]
165
pub struct Bundle {
166
167
pub changes : Vec< ( Change, Vec< Signature> ) > ,
168
169
pub attests : Vec< SignedAttest> ,
170
171
pub objects : Vec< ( ObjectType, Vec< u8 > ) > ,
28fc23d7 Andy McCall 1 month ago ↶
172
173
174
pub policies : Vec< SignedPolicy> ,
598009a7 Andy McCall 1 month ago ↶
175
176
177
178
pub hashes : Vec< ChangeHash> ,
2c75672f Andy McCall 1 month ago ↶
179
180
181
182
pub raw_changes : Vec< ( Vec< u8 > , Vec< Signature> ) > ,
f0a517d2 Andy McCall 18 days ago ↶
183
184
185
pub certificates : Vec< crate:: cert:: SignedCertificate> ,
5b9c6ad4 Andy McCall 1 month ago ↶
186
}
187
188
impl Bundle {
189
pub fn is_empty ( & self ) -> bool {
190
self .changes.is_empty ( ) & & self .attests.is_empty ( ) & & self .objects.is_empty ( )
191
}
192
}
193
194
195
# [ derive ( Clone, Debug ) ]
196
pub struct RefUpdate {
197
pub name : String,
198
pub old_state : ObjectRef,
199
pub new_state : ObjectRef,
200
pub force : bool ,
201
pub attestation : Option< SignedAttest> ,
202
}
203
204
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
205
pub struct RefResult {
206
pub name : String,
207
pub ok : bool ,
208
pub reason : String,
209
}
210
211
pub trait Remote {
212
fn repo_id ( & self ) -> Result< [ u8 ; 16 ] > ;
83e0677b Andy McCall 1 month ago ↶
213
fn refs ( & self ) -> Result< RefsResponse> ;
5b9c6ad4 Andy McCall 1 month ago ↶
214
215
fn negotiate ( & self , have : & [ChangeHash], want : & [ChangeHash]) -> Result< Vec< ChangeHash> > ;
b3c5a59a Andy McCall 1 month ago ↶
216
217
218
fn fetch ( & self , changes : & [ChangeHash], max_blob : Option< u64 > ) -> Result< Bundle> ;
219
220
221
fn objects ( & self , refs : & [ObjectRef]) -> Result< Vec< ( ObjectType, Vec< u8 > ) > > ;
2863456a Andy McCall 1 month ago ↶
222
223
224
fn checkpoint ( & self , heads : & [ChangeHash]) -> Result< Bundle> ;
225
226
fn shallow ( & self , heads : & [ChangeHash], depth : u32 ) -> Result< Vec< ChangeHash> > ;
132b884b Andy McCall 1 month ago ↶
227
228
229
75167672 Andy McCall 1 month ago
230
fn push (
231
& self ,
232
bundle : Bundle,
233
updates : Vec< RefUpdate> ,
234
policy : Option< SignedPolicy> ,
235
tags : Vec< TagRef> ,
236
) -> Result< Vec< RefResult> > ;
5b9c6ad4 Andy McCall 1 month ago ↶
237
}
238
750251b2 Andy McCall 1 month ago ↶
239
240
5b9c6ad4 Andy McCall 1 month ago ↶
241
242
pub struct LocalRemote {
243
pub repo : Repo,
84b9e9ac Andy McCall 1 month ago ↶
244
245
246
pub claimed_id : Option< [ u8 ; 16 ] > ,
5b9c6ad4 Andy McCall 1 month ago ↶
247
}
248
249
impl LocalRemote {
250
pub fn open ( path : & Path) -> Result< LocalRemote> {
75167672 Andy McCall 1 month ago
251
Ok ( LocalRemote {
252
repo: Repo:: open( path) ? ,
84b9e9ac Andy McCall 1 month ago ↶
253
claimed_id: None ,
75167672 Andy McCall 1 month ago
254
} )
5b9c6ad4 Andy McCall 1 month ago ↶
255
}
256
}
257
258
impl Remote for LocalRemote {
259
fn repo_id ( & self ) -> Result< [ u8 ; 16 ] > {
260
self .repo.id ( )
261
}
83e0677b Andy McCall 1 month ago ↶
262
fn refs ( & self ) -> Result< RefsResponse> {
5b9c6ad4 Andy McCall 1 month ago ↶
263
self .repo.remote_refs ( )
264
}
265
fn negotiate ( & self , have : & [ChangeHash], want : & [ChangeHash]) -> Result< Vec< ChangeHash> > {
266
self .repo.negotiate ( have, want)
267
}
b3c5a59a Andy McCall 1 month ago ↶
268
fn fetch ( & self , changes : & [ChangeHash], max_blob : Option< u64 > ) -> Result< Bundle> {
2c75672f Andy McCall 1 month ago ↶
269
self .repo.bundle_raw_for ( changes, max_blob)
b3c5a59a Andy McCall 1 month ago ↶
270
}
271
fn objects ( & self , refs : & [ObjectRef]) -> Result< Vec< ( ObjectType, Vec< u8 > ) > > {
272
self .repo.objects_for ( refs)
5b9c6ad4 Andy McCall 1 month ago ↶
273
}
2863456a Andy McCall 1 month ago ↶
274
fn checkpoint ( & self , heads : & [ChangeHash]) -> Result< Bundle> {
275
self .repo.checkpoint_bundle_for ( heads)
276
}
277
fn shallow ( & self , heads : & [ChangeHash], depth : u32 ) -> Result< Vec< ChangeHash> > {
278
self .repo.shallow_changes ( heads, depth)
279
}
75167672 Andy McCall 1 month ago
280
fn push (
281
& self ,
282
bundle : Bundle,
283
updates : Vec< RefUpdate> ,
284
policy : Option< SignedPolicy> ,
285
tags : Vec< TagRef> ,
286
) -> Result< Vec< RefResult> > {
84b9e9ac Andy McCall 1 month ago ↶
287
if self .repo.is_unbound ( ) {
288
match self .claimed_id {
289
Some ( id) => self .repo.bind_id ( id) ? ,
eae59556 Andy McCall 1 month ago ↶
290
None => {
291
return Err ( RepoError:: Msg(
292
" the remote is unbound and this client did not say which repository it is"
293
.into ( ) ,
294
) )
295
}
84b9e9ac Andy McCall 1 month ago ↶
296
}
297
}
132b884b Andy McCall 1 month ago ↶
298
self .repo.receive_push ( bundle, updates, policy, tags)
5b9c6ad4 Andy McCall 1 month ago ↶
299
}
300
}
301
750251b2 Andy McCall 1 month ago ↶
302
303
2b5ee371 Andy McCall 1 month ago ↶
304
305
# [ derive ( Clone, Debug, Default ) ]
306
pub struct RemoteOptions {
307
308
pub token : Option< String> ,
309
310
311
pub ca : Option< PathBuf> ,
75167672 Andy McCall 1 month ago
312
313
314
pub repo_id : Option< [ u8 ; 16 ] > ,
9f9e72b9 Andy McCall 1 month ago ↶
315
316
317
318
319
pub cache_dir : Option< PathBuf> ,
68a92484 Andy McCall 22 days ago ↶
320
321
322
323
324
pub fallback_tokens : Vec< String> ,
2b5ee371 Andy McCall 1 month ago ↶
325
}
326
9f9e72b9 Andy McCall 1 month ago ↶
327
328
329
330
pub type StoreOpener =
331
fn ( & str , & RemoteOptions) -> Option< crate:: strata:: Result< Box< dyn crate:: strata:: Store> > > ;
332
333
static STORE_OPENERS : Mutex< Vec< StoreOpener> > = Mutex:: new( Vec :: new( ) ) ;
334
335
pub fn register_store_opener ( opener : StoreOpener) {
336
STORE_OPENERS
337
.lock ( )
338
.unwrap_or_else ( | p | p.into_inner ( ) )
339
.push ( opener) ;
340
}
341
342
343
pub fn open_store (
344
url : & str ,
345
options : & RemoteOptions,
346
) -> Option< crate:: strata:: Result< Box< dyn crate:: strata:: Store> > > {
347
if let Some ( path) = url.strip_prefix ( " dir://" ) {
348
return Some (
349
crate :: strata:: LocalStore:: open( path)
350
.map ( | s | Box :: new( s) as Box< dyn crate:: strata:: Store> ) ,
351
) ;
352
}
353
let openers = STORE_OPENERS .lock ( ) .unwrap_or_else ( | p | p.into_inner ( ) ) ;
354
openers.iter ( ) .find_map ( | open | open ( url, options) )
355
}
356
75167672 Andy McCall 1 month ago
357
358
pub const REPO_ID_HEADER : & str = " Oxy-Repo-Id" ;
359
360
361
pub const UNBOUND_ID : [ u8 ; 16 ] = [ 0 ; 16 ] ;
362
ee130dd9 Andy McCall 15 days ago ↶
363
364
365
366
367
pub const FEATURES_HEADER : & str = " Oxy-Features" ;
368
369
370
371
372
373
pub const FEATURE_CERTIFIED_TAGS : & str = " certified-tags" ;
374
375
376
pub const CLIENT_FEATURES : & [ & str ] = & [ FEATURE_CERTIFIED_TAGS ] ;
377
378
379
pub fn user_agent ( ) -> String {
380
format! ( " oxy/{} " , env! ( " CARGO_PKG_VERSION" ) )
381
}
382
383
384
385
386
pub fn declares_feature ( header : Option< & str > , feature : & str ) -> bool {
387
header.is_some_and ( | h | h.split ( ' ,' ) .any ( | f | f.trim ( ) .eq_ignore_ascii_case ( feature) ) )
388
}
389
750251b2 Andy McCall 1 month ago ↶
390
391
pub struct HttpRemote {
392
base : String,
68a92484 Andy McCall 22 days ago ↶
393
394
token : Mutex< Option< String> > ,
395
fallbacks : Mutex< Vec< String> > ,
75167672 Andy McCall 1 month ago
396
repo_id : Option< [ u8 ; 16 ] > ,
750251b2 Andy McCall 1 month ago ↶
397
agent : ureq:: Agent,
398
}
399
2b5ee371 Andy McCall 1 month ago ↶
400
401
fn tls_client_config ( ca : Option< & Path> ) -> Result< Arc< rustls:: ClientConfig> > {
402
let mut roots = rustls:: RootCertStore:: empty( ) ;
403
roots.extend ( webpki_roots:: TLS_SERVER_ROOTS .iter ( ) .cloned ( ) ) ;
404
if let Some ( path) = ca {
75167672 Andy McCall 1 month ago
405
let pem = std:: fs:: read( path)
406
.map_err ( | e | RepoError:: Msg( format! ( " reading CA file {} : {e} " , path.display ( ) ) ) ) ? ;
2b5ee371 Andy McCall 1 month ago ↶
407
let certs = rustls_pemfile:: certs( & mut pem.as_slice ( ) )
408
.collect:: < std:: result:: Result< Vec< _ > , _ > > ( )
409
.map_err ( | e | RepoError:: Msg( format! ( " parsing CA file {} : {e} " , path.display ( ) ) ) ) ? ;
410
if certs.is_empty ( ) {
75167672 Andy McCall 1 month ago
411
return Err ( RepoError:: Msg( format! (
412
" CA file {} holds no certificates" ,
413
path.display ( )
414
) ) ) ;
2b5ee371 Andy McCall 1 month ago ↶
415
}
416
for c in certs {
75167672 Andy McCall 1 month ago
417
roots
418
.add ( c)
419
.map_err ( | e | RepoError:: Msg( format! ( " CA file {} : {e} " , path.display ( ) ) ) ) ? ;
2b5ee371 Andy McCall 1 month ago ↶
420
}
421
}
75167672 Andy McCall 1 month ago
422
let cfg = rustls:: ClientConfig:: builder_with_provider( Arc:: new(
423
rustls:: crypto:: ring:: default_provider( ) ,
424
) )
425
.with_safe_default_protocol_versions ( )
426
.map_err ( | e | RepoError:: Msg( e.to_string ( ) ) ) ?
427
.with_root_certificates ( roots)
428
.with_no_client_auth ( ) ;
2b5ee371 Andy McCall 1 month ago ↶
429
Ok ( Arc:: new( cfg) )
430
}
431
750251b2 Andy McCall 1 month ago ↶
432
impl HttpRemote {
2b5ee371 Andy McCall 1 month ago ↶
433
pub fn new ( base : & str , options : & RemoteOptions) -> Result< HttpRemote> {
ff1f62fe Andy McCall 1 month ago ↶
434
refuse_plain_token ( base, options) ? ;
75167672 Andy McCall 1 month ago
435
let agent = ureq:: AgentBuilder:: new( )
436
.tls_config ( tls_client_config ( options.ca.as_deref ( ) ) ? )
ee130dd9 Andy McCall 15 days ago ↶
437
.user_agent ( & user_agent ( ) )
75167672 Andy McCall 1 month ago
438
.build ( ) ;
439
Ok ( HttpRemote {
440
base: base.trim_end_matches ( ' /' ) .to_string ( ) ,
68a92484 Andy McCall 22 days ago ↶
441
token: Mutex:: new( options.token.clone ( ) ) ,
442
fallbacks: Mutex:: new( options.fallback_tokens.iter ( ) .rev ( ) .cloned ( ) .collect ( ) ) ,
75167672 Andy McCall 1 month ago
443
repo_id: options.repo_id,
444
agent,
445
} )
750251b2 Andy McCall 1 month ago ↶
446
}
447
68a92484 Andy McCall 22 days ago ↶
448
449
750251b2 Andy McCall 1 month ago ↶
450
fn call ( & self , post : bool , endpoint : & str , body : Option< & [ u8 ] > ) -> Result< Vec< u8 > > {
68a92484 Andy McCall 22 days ago ↶
451
loop {
452
let token = self .token.lock ( ) .unwrap_or_else ( | p | p.into_inner ( ) ) .clone ( ) ;
453
match self .call_once ( post, endpoint, body, token.as_deref ( ) ) {
454
Err ( RepoError:: Msg( m) ) if token.is_some ( ) & & refused ( & m) => {
455
let next = self
456
.fallbacks
457
.lock ( )
458
.unwrap_or_else ( | p | p.into_inner ( ) )
459
.pop ( ) ;
460
let Some ( next) = next else {
461
return Err ( RepoError:: Msg( m) ) ;
462
} ;
463
crate :: credentials:: warn_once( & format! (
464
" {} : the stored token was refused; using the one an enclosing checkout has for this hub" ,
465
self .base
466
) ) ;
467
* self .token.lock ( ) .unwrap_or_else ( | p | p.into_inner ( ) ) = Some ( next) ;
468
}
469
other => return other,
470
}
471
}
472
}
473
474
fn call_once (
475
& self ,
476
post : bool ,
477
endpoint : & str ,
478
body : Option< & [ u8 ] > ,
479
token : Option< & str > ,
480
) -> Result< Vec< u8 > > {
750251b2 Andy McCall 1 month ago ↶
481
let url = format! ( " {} /oxy/v1/{endpoint} " , self .base) ;
75167672 Andy McCall 1 month ago
482
let mut req = if post {
483
self .agent.post ( & url)
484
} else {
485
self .agent.get ( & url)
486
} ;
ee130dd9 Andy McCall 15 days ago ↶
487
req = req
488
.set ( " Accept" , CONTENT_TYPE )
489
.set ( FEATURES_HEADER , & CLIENT_FEATURES .join ( " ," ) ) ;
68a92484 Andy McCall 22 days ago ↶
490
if let Some ( t) = token {
750251b2 Andy McCall 1 month ago ↶
491
req = req.set ( " Authorization" , & format! ( " Bearer {t} " ) ) ;
492
}
75167672 Andy McCall 1 month ago
493
if let Some ( id) = & self .repo_id {
494
req = req.set ( REPO_ID_HEADER , & hex:: encode( id) ) ;
495
}
750251b2 Andy McCall 1 month ago ↶
496
let resp = match body {
497
Some ( b) => req.set ( " Content-Type" , CONTENT_TYPE ) .send_bytes ( b) ,
498
None => req.call ( ) ,
499
} ;
500
match resp {
501
Ok ( r) => {
502
let mut out = Vec :: new( ) ;
75167672 Andy McCall 1 month ago
503
r.into_reader ( )
504
.read_to_end ( & mut out)
505
.map_err ( | e | RepoError:: Msg( format! ( " {url} : {e} " ) ) ) ? ;
750251b2 Andy McCall 1 month ago ↶
506
Ok ( out)
507
}
508
Err ( ureq:: Error:: Status( code, r) ) => {
509
let text = r.into_string ( ) .unwrap_or_default ( ) ;
67a4fe1a Andy McCall 16 days ago ↶
510
511
512
513
let status = format! ( " {url} : HTTP {code} " ) ;
514
let msg = format! ( " {status} : {} " , text.trim ( ) ) ;
515
Err ( RepoError:: Msg( match hint_for ( & status) {
516
Some ( h) => format! ( " {msg} \n hint: {h} " ) ,
517
None => msg,
518
} ) )
750251b2 Andy McCall 1 month ago ↶
519
}
3e5772cc Andy McCall 1 month ago ↶
520
521
Err ( e) => Err ( RepoError:: Msg( with_hint ( e.to_string ( ) ) ) ) ,
750251b2 Andy McCall 1 month ago ↶
522
}
523
}
68a92484 Andy McCall 22 days ago ↶
524
}
525
526
527
528
529
fn refused ( message : & str ) -> bool {
530
[ " : HTTP 401" , " : HTTP 403" , " : HTTP 404" ]
531
.iter ( )
532
.any ( | c | message.contains ( c) )
750251b2 Andy McCall 1 month ago ↶
533
}
534
ff1f62fe Andy McCall 1 month ago ↶
535
536
537
fn refuse_plain_token ( url : & str , options : & RemoteOptions) -> Result< ( ) > {
538
if options.token.is_some ( ) & & ! crate :: credentials:: token_allowed( url) {
539
return Err ( RepoError:: Msg( format! (
540
" {url} : refusing to send a token over plain http; use https"
541
) ) ) ;
542
}
543
Ok ( ( ) )
544
}
545
3e5772cc Andy McCall 1 month ago ↶
546
547
pub fn hint_for ( message : & str ) -> Option< & 'static str > {
548
let m = message.to_ascii_lowercase ( ) ;
549
let hint = if m.contains ( " http 401" ) {
ff1f62fe Andy McCall 1 month ago ↶
550
" the hub needs you signed in, or did not accept the token: run `oxy auth login HUB` (pushing needs repo:write)"
3e5772cc Andy McCall 1 month ago ↶
551
} else if m.contains ( " http 403" ) {
552
" the token or account lacks permission: pushing needs a token with repo:write and write access to the repository"
553
} else if m.contains ( " http 404" ) {
ff1f62fe Andy McCall 1 month ago ↶
554
" nothing at this URL that you can see: check the owner and repository name; a private repository needs you signed in (`oxy auth login HUB`)"
3e5772cc Andy McCall 1 month ago ↶
555
} else if m.contains ( " unknownissuer" )
556
| | m.contains ( " unknown issuer" )
557
| | m.contains ( " certificate" )
558
| | m.contains ( " invalidcertificate" )
559
{
560
" the server's certificate is not trusted: for a hub with a self-signed certificate, download it from /.well-known/oxyhub-ca.pem on the hub and run `oxy config remote.<remote>.ca FILE`"
561
} else if m.contains ( " connection refused" ) {
562
" nothing is listening there: check the URL and port, and that the server is running"
563
} else if m.contains ( " dns" )
564
| | m.contains ( " failed to lookup" )
565
| | m.contains ( " name or service not known" )
566
{
567
" the host name does not resolve: check the URL"
568
} else if m.contains ( " timed out" ) | | m.contains ( " timeout" ) {
569
" the server did not answer in time: check the network, or try again"
570
} else {
571
return None ;
572
} ;
573
Some ( hint)
574
}
575
576
577
pub fn with_hint ( message : String) -> String {
578
match hint_for ( & message) {
579
Some ( h) => format! ( " {message} \n hint: {h} " ) ,
580
None => message,
ff1f62fe Andy McCall 1 month ago ↶
581
}
582
}
583
584
585
586
587
pub fn http_json (
588
method : & str ,
589
url : & str ,
590
body : Option< & str > ,
591
options : & RemoteOptions,
592
) -> Result< ( u16 , String) > {
593
refuse_plain_token ( url, options) ? ;
594
let agent = ureq:: AgentBuilder:: new( )
595
.tls_config ( tls_client_config ( options.ca.as_deref ( ) ) ? )
596
.timeout ( std:: time:: Duration:: from_secs( 60 ) )
ee130dd9 Andy McCall 15 days ago ↶
597
.user_agent ( & user_agent ( ) )
ff1f62fe Andy McCall 1 month ago ↶
598
.build ( ) ;
599
let mut req = agent.request ( method, url) .set ( " Accept" , " application/json" ) ;
600
if let Some ( t) = & options.token {
601
req = req.set ( " Authorization" , & format! ( " Bearer {t} " ) ) ;
602
}
603
let resp = match body {
604
Some ( b) => req.set ( " Content-Type" , " application/json" ) .send_string ( b) ,
605
None => req.call ( ) ,
606
} ;
607
match resp {
608
Ok ( r) => {
609
let code = r.status ( ) ;
610
Ok ( ( code, r.into_string ( ) .unwrap_or_default ( ) ) )
611
}
612
Err ( ureq:: Error:: Status( code, r) ) => Ok ( ( code, r.into_string ( ) .unwrap_or_default ( ) ) ) ,
613
Err ( e) => Err ( RepoError:: Msg( with_hint ( e.to_string ( ) ) ) ) ,
3e5772cc Andy McCall 1 month ago ↶
614
}
615
}
616
d82e4409 Andy McCall 1 month ago ↶
617
618
619
pub fn http_get ( url : & str , options : & RemoteOptions) -> Result< Vec< u8 > > {
ff1f62fe Andy McCall 1 month ago ↶
620
refuse_plain_token ( url, options) ? ;
d82e4409 Andy McCall 1 month ago ↶
621
let agent = ureq:: AgentBuilder:: new( )
622
.tls_config ( tls_client_config ( options.ca.as_deref ( ) ) ? )
ee130dd9 Andy McCall 15 days ago ↶
623
.user_agent ( & user_agent ( ) )
d82e4409 Andy McCall 1 month ago ↶
624
.build ( ) ;
625
let mut req = agent.get ( url) .set ( " Accept" , " application/json" ) ;
626
if let Some ( t) = & options.token {
627
req = req.set ( " Authorization" , & format! ( " Bearer {t} " ) ) ;
628
}
629
match req.call ( ) {
630
Ok ( r) => {
631
let mut out = Vec :: new( ) ;
632
r.into_reader ( )
633
.read_to_end ( & mut out)
634
.map_err ( | e | RepoError:: Msg( format! ( " {url} : {e} " ) ) ) ? ;
635
Ok ( out)
636
}
637
Err ( ureq:: Error:: Status( code, r) ) => {
638
let text = r.into_string ( ) .unwrap_or_default ( ) ;
3e5772cc Andy McCall 1 month ago ↶
639
Err ( RepoError:: Msg( with_hint ( format! (
4213c41d Andy McCall 1 month ago ↶
640
" {url} : HTTP {code} : {} " ,
641
text.trim ( )
3e5772cc Andy McCall 1 month ago ↶
642
) ) ) )
d82e4409 Andy McCall 1 month ago ↶
643
}
3e5772cc Andy McCall 1 month ago ↶
644
645
Err ( e) => Err ( RepoError:: Msg( with_hint ( e.to_string ( ) ) ) ) ,
d82e4409 Andy McCall 1 month ago ↶
646
}
647
}
648
750251b2 Andy McCall 1 month ago ↶
649
impl Remote for HttpRemote {
650
fn repo_id ( & self ) -> Result< [ u8 ; 16 ] > {
651
wire:: decode_capabilities( & self .call ( false , " capabilities" , None ) ? )
652
}
83e0677b Andy McCall 1 month ago ↶
653
fn refs ( & self ) -> Result< RefsResponse> {
750251b2 Andy McCall 1 month ago ↶
654
Ok ( wire:: decode_refs( & self .call ( false , " refs" , None ) ? ) ? .1 )
655
}
656
fn negotiate ( & self , have : & [ChangeHash], want : & [ChangeHash]) -> Result< Vec< ChangeHash> > {
75167672 Andy McCall 1 month ago
657
wire:: decode_hashes( & self .call (
658
true ,
659
" negotiate" ,
660
Some ( & wire:: encode_negotiate( have, want) ) ,
661
) ? )
750251b2 Andy McCall 1 month ago ↶
662
}
b3c5a59a Andy McCall 1 month ago ↶
663
fn fetch ( & self , changes : & [ChangeHash], max_blob : Option< u64 > ) -> Result< Bundle> {
75167672 Andy McCall 1 month ago
664
wire:: decode_bundle( & self .call (
665
true ,
666
" fetch" ,
667
Some ( & wire:: encode_fetch( changes, max_blob) ) ,
668
) ? )
750251b2 Andy McCall 1 month ago ↶
669
}
b3c5a59a Andy McCall 1 month ago ↶
670
fn objects ( & self , refs : & [ObjectRef]) -> Result< Vec< ( ObjectType, Vec< u8 > ) > > {
75167672 Andy McCall 1 month ago
671
Ok (
672
wire:: decode_bundle( & self .call ( true , " objects" , Some ( & wire:: encode_hashes( refs) ) ) ? ) ?
673
.objects,
674
)
b3c5a59a Andy McCall 1 month ago ↶
675
}
2863456a Andy McCall 1 month ago ↶
676
fn checkpoint ( & self , heads : & [ChangeHash]) -> Result< Bundle> {
677
wire:: decode_bundle( & self .call ( true , " checkpoint" , Some ( & wire:: encode_hashes( heads) ) ) ? )
678
}
679
fn shallow ( & self , heads : & [ChangeHash], depth : u32 ) -> Result< Vec< ChangeHash> > {
75167672 Andy McCall 1 month ago
680
wire:: decode_hashes( & self .call (
681
true ,
682
" shallow" ,
683
Some ( & wire:: encode_shallow( heads, depth) ) ,
684
) ? )
2863456a Andy McCall 1 month ago ↶
685
}
75167672 Andy McCall 1 month ago
686
fn push (
687
& self ,
688
bundle : Bundle,
689
updates : Vec< RefUpdate> ,
690
policy : Option< SignedPolicy> ,
691
tags : Vec< TagRef> ,
692
) -> Result< Vec< RefResult> > {
693
wire:: decode_push_response( & self .call (
694
true ,
695
" push" ,
696
Some ( & wire:: encode_push(
697
& bundle,
698
& updates,
699
policy.as_ref ( ) ,
700
& tags,
701
) ) ,
702
) ? )
750251b2 Andy McCall 1 month ago ↶
703
}
704
}
705
827281ee Andy McCall 1 month ago ↶
706
707
708
709
pub fn stored_url ( url : & str ) -> String {
8d803563 Andy McCall 1 month ago ↶
710
711
9f9e72b9 Andy McCall 1 month ago ↶
712
let ( prefix, path) = match ( url.strip_prefix ( " file://" ) , url.strip_prefix ( " dir://" ) ) {
713
( Some ( p) , _ ) => ( " file://" , p) ,
714
( _ , Some ( p) ) => ( " dir://" , p) ,
8d803563 Andy McCall 1 month ago ↶
715
_ if url.contains ( " ://" ) => return url.to_string ( ) ,
9f9e72b9 Andy McCall 1 month ago ↶
716
_ => ( " " , url) ,
827281ee Andy McCall 1 month ago ↶
717
} ;
718
match std:: path:: absolute( path) {
719
Ok ( abs) => format! ( " {prefix} {} " , abs.display ( ) ) ,
720
Err ( _ ) => url.to_string ( ) ,
721
}
722
}
723
9f9e72b9 Andy McCall 1 month ago ↶
724
725
2b5ee371 Andy McCall 1 month ago ↶
726
pub fn open_remote ( url : & str , options : & RemoteOptions) -> Result< Box< dyn Remote> > {
750251b2 Andy McCall 1 month ago ↶
727
if url.starts_with ( " http://" ) | | url.starts_with ( " https://" ) {
2b5ee371 Andy McCall 1 month ago ↶
728
return Ok ( Box :: new( HttpRemote:: new( url, options) ? ) ) ;
9f9e72b9 Andy McCall 1 month ago ↶
729
}
730
if let Some ( store) = open_store ( url, options) {
731
return crate :: repo:: strata:: open_store_remote( store? , options) ;
750251b2 Andy McCall 1 month ago ↶
732
}
5b9c6ad4 Andy McCall 1 month ago ↶
733
let path = url.strip_prefix ( " file://" ) .unwrap_or ( url) ;
734
if path.contains ( " ://" ) {
750251b2 Andy McCall 1 month ago ↶
735
return Err ( RepoError:: Msg( format! ( " unsupported remote URL {url:?} " ) ) ) ;
5b9c6ad4 Andy McCall 1 month ago ↶
736
}
84b9e9ac Andy McCall 1 month ago ↶
737
let mut local = LocalRemote:: open( Path:: new( path) ) ? ;
738
local.claimed_id = options.repo_id;
739
Ok ( Box :: new( local) )
5b9c6ad4 Andy McCall 1 month ago ↶
740
}
750251b2 Andy McCall 1 month ago ↶
741
742
743
744
745
pub mod wire {
746
use super :: * ;
747
748
fn schema ( msg : & str ) -> RepoError {
749
RepoError:: Object( ObjectError:: Schema( msg.into ( ) ) )
750
}
751
fn sigs_value ( sigs : & [Signature]) -> Value {
752
Value:: Array( sigs.iter ( ) .map ( | s | s.to_value ( ) ) .collect ( ) )
753
}
754
fn sigs_from ( v : & Value) -> Result< Vec< Signature> > {
75167672 Andy McCall 1 month ago
755
Ok ( o:: array( v, " signatures" ) ?
756
.iter ( )
757
.map ( Signature:: from_value)
758
.collect:: < std:: result:: Result< Vec< _ > , _ > > ( ) ? )
750251b2 Andy McCall 1 month ago ↶
759
}
760
fn hashes_value ( hs : & [ObjectRef]) -> Value {
761
Value:: Array( hs.iter ( ) .map ( | h | Value:: Bytes( h.0. to_vec ( ) ) ) .collect ( ) )
762
}
763
fn hashes_from ( v : & Value) -> Result< Vec< ObjectRef> > {
75167672 Andy McCall 1 month ago
764
Ok ( o:: array( v, " hashes" ) ?
765
.iter ( )
766
.map ( | h | o:: oref( h, " hash" ) )
767
.collect:: < std:: result:: Result< Vec< _ > , _ > > ( ) ? )
750251b2 Andy McCall 1 month ago ↶
768
}
769
fn attest_value ( sa : & SignedAttest) -> Value {
770
Value:: Array( vec! [ Value:: Bytes( sa.attest.encode ( ) ) , sigs_value ( & sa.sigs) ] )
771
}
772
fn attest_from ( v : & Value) -> Result< SignedAttest> {
773
let a = o:: array( v, " signed attest" ) ? ;
774
if a.len ( ) ! = 2 {
775
return Err ( schema ( " signed attest: expected [attest, sigs]" ) ) ;
776
}
75167672 Andy McCall 1 month ago
777
Ok ( SignedAttest {
778
attest: Attest:: decode( o:: bytes( & a[ 0 ] , " attest" ) ? ) ? ,
779
sigs: sigs_from ( & a[ 1 ] ) ? ,
780
} )
750251b2 Andy McCall 1 month ago ↶
781
}
782
fn opt_attest_value ( sa : & Option< SignedAttest> ) -> Value {
783
sa.as_ref ( ) .map ( attest_value) .unwrap_or ( Value:: Null)
784
}
785
fn opt_attest_from ( v : & Value) -> Result< Option< SignedAttest> > {
75167672 Andy McCall 1 month ago
786
if v.is_null ( ) {
787
Ok ( None )
788
} else {
789
attest_from ( v) .map ( Some )
790
}
750251b2 Andy McCall 1 month ago ↶
791
}
28fc23d7 Andy McCall 1 month ago ↶
792
793
794
pub fn policy_value ( sp : & SignedPolicy) -> Value {
795
Value:: Array( vec! [ Value:: Bytes( sp.policy.encode ( ) ) , sigs_value ( & sp.sigs) ] )
83e0677b Andy McCall 1 month ago ↶
796
}
28fc23d7 Andy McCall 1 month ago ↶
797
pub fn policy_from ( v : & Value) -> Result< SignedPolicy> {
83e0677b Andy McCall 1 month ago ↶
798
let a = o:: array( v, " signed policy" ) ? ;
799
if a.len ( ) ! = 2 {
800
return Err ( schema ( " signed policy: expected [policy, sigs]" ) ) ;
801
}
75167672 Andy McCall 1 month ago
802
Ok ( SignedPolicy {
803
policy: Policy:: decode( o:: bytes( & a[ 0 ] , " policy" ) ? ) ? ,
804
sigs: sigs_from ( & a[ 1 ] ) ? ,
805
} )
28fc23d7 Andy McCall 1 month ago ↶
806
}
807
fn opt_policy_value ( sp : Option< & SignedPolicy> ) -> Value {
808
sp.map ( policy_value) .unwrap_or ( Value:: Null)
809
}
810
fn opt_policy_from ( v : & Value) -> Result< Option< SignedPolicy> > {
75167672 Andy McCall 1 month ago
811
if v.is_null ( ) {
812
Ok ( None )
813
} else {
814
policy_from ( v) .map ( Some )
815
}
83e0677b Andy McCall 1 month ago ↶
816
}
750251b2 Andy McCall 1 month ago ↶
817
fn map < 'a > ( v : & 'a Value, what : & str ) -> Result< & 'a o:: Map> {
818
Ok ( o:: map( v, what) ? )
819
}
820
fn field < 'a > ( m : & 'a o:: Map, k : u64 , what : & str ) -> Result< & 'a Value> {
821
Ok ( o:: field( m, k, what) ? )
822
}
823
6f8aeb99 Andy McCall 1 month ago ↶
824
825
826
750251b2 Andy McCall 1 month ago ↶
827
pub fn bundle_value ( b : & Bundle) -> Value {
2c75672f Andy McCall 1 month ago ↶
828
let mut changes = Vec :: with_capacity( b.raw_changes.len ( ) + b.changes.len ( ) ) ;
829
830
831
for ( bytes, s) in & b.raw_changes {
832
changes.push ( Value:: Array( vec! [
833
Value:: Bytes( bytes.clone ( ) ) ,
834
sigs_value ( s) ,
835
] ) ) ;
836
}
6f8aeb99 Andy McCall 1 month ago ↶
837
let mut texts: Vec< ( ObjectType, Vec< u8 > ) > = Vec :: new( ) ;
838
let mut listed: Option< std:: collections:: HashSet< ObjectRef> > = None ;
839
for ( c, s) in & b.changes {
840
let ( bytes, stored) = c.encode_parts ( ) ;
841
for t in stored {
842
let listed = listed.get_or_insert_with ( | | {
843
b.objects
844
.iter ( )
845
.map ( | ( ty , body ) | crate :: hash:: hash_object( * ty, body) )
846
.collect ( )
847
} ) ;
848
if ! listed.insert ( t.blob.hash ( ) ) {
849
continue ;
850
}
851
for chunk in crate :: chunk:: chunks( & t.content) {
852
if listed.insert ( crate :: hash:: hash_object( ObjectType:: Chunk, chunk) ) {
853
texts.push ( ( ObjectType:: Chunk, chunk.to_vec ( ) ) ) ;
854
}
855
}
856
texts.push ( ( ObjectType:: Blob, t.blob.encode ( ) ) ) ;
857
}
858
changes.push ( Value:: Array( vec! [ Value:: Bytes( bytes) , sigs_value ( s) ] ) ) ;
859
}
f0a517d2 Andy McCall 18 days ago ↶
860
let mut v = Value:: map( [
6f8aeb99 Andy McCall 1 month ago ↶
861
( 0 , Value:: Array( changes) ) ,
750251b2 Andy McCall 1 month ago ↶
862
(
75167672 Andy McCall 1 month ago
863
1 ,
864
Value:: Array( b.attests.iter ( ) .map ( attest_value) .collect ( ) ) ,
865
) ,
866
(
750251b2 Andy McCall 1 month ago ↶
867
2 ,
868
Value:: Array(
75167672 Andy McCall 1 month ago
869
b.objects
870
.iter ( )
6f8aeb99 Andy McCall 1 month ago ↶
871
.chain ( & texts)
75167672 Andy McCall 1 month ago
872
.map ( | ( t , body ) | {
873
Value:: Array( vec! [
874
Value:: Text( t.name ( ) .into ( ) ) ,
875
Value:: Bytes( body.clone ( ) ) ,
876
] )
877
} )
878
.collect ( ) ,
750251b2 Andy McCall 1 month ago ↶
879
) ,
880
) ,
75167672 Andy McCall 1 month ago
881
(
882
3 ,
883
Value:: Array( b.policies.iter ( ) .map ( policy_value) .collect ( ) ) ,
884
) ,
f0a517d2 Andy McCall 18 days ago ↶
885
] ) ;
886
887
if ! b.certificates.is_empty ( ) {
888
if let Value:: Map( m) = & mut v {
889
m.insert (
890
4 ,
891
Value:: Array(
892
b.certificates
893
.iter ( )
894
.map ( | c | Value:: Bytes( c.encode ( ) ) )
895
.collect ( ) ,
896
) ,
897
) ;
898
}
899
}
900
v
750251b2 Andy McCall 1 month ago ↶
901
}
902
903
pub fn bundle_from_value ( v : & Value) -> Result< Bundle> {
904
let m = map ( v, " bundle" ) ? ;
905
let mut b = Bundle:: default( ) ;
906
for ob in o:: array( field ( m, 2 , " objects" ) ? , " objects" ) ? {
907
let pair = o:: array( ob, " object" ) ? ;
908
if pair.len ( ) ! = 2 {
909
return Err ( schema ( " object: expected [type, body]" ) ) ;
910
}
75167672 Andy McCall 1 month ago
911
let ty = ObjectType:: from_name( o:: text( & pair[ 0 ] , " object type" ) ? )
912
.ok_or_else ( | | schema ( " unknown object type" ) ) ? ;
913
b.objects
914
.push ( ( ty, o:: bytes( & pair[ 1 ] , " object body" ) ? .to_vec ( ) ) ) ;
6f8aeb99 Andy McCall 1 month ago ↶
915
}
916
917
let mut by_ref: Option< std:: collections:: HashMap< ObjectRef, usize > > = None ;
918
for c in o:: array( field ( m, 0 , " changes" ) ? , " changes" ) ? {
919
let pair = o:: array( c, " change entry" ) ? ;
920
if pair.len ( ) ! = 2 {
921
return Err ( schema ( " change entry: expected [change, sigs]" ) ) ;
922
}
598009a7 Andy McCall 1 month ago ↶
923
let encoded = o:: bytes( & pair[ 0 ] , " change" ) ? ;
924
b.hashes
925
.push ( crate :: hash:: hash_object( ObjectType:: Change, encoded) ) ;
0f93f49c Andy McCall 1 month ago ↶
926
let change = Change:: decode_with( encoded, & mut | text, count, form| {
6f8aeb99 Andy McCall 1 month ago ↶
927
let by_ref = by_ref.get_or_insert_with ( | | {
928
b.objects
929
.iter ( )
930
.enumerate ( )
931
.map ( | ( i , (ty , body ) ) | ( crate :: hash:: hash_object( * ty, body) , i) )
932
.collect ( )
933
} ) ;
934
let get =
935
| r : & ObjectRef, want : ObjectType| match by_ref.get ( r) .map ( | i | & b.objects[ * i] ) {
936
Some ( ( ty, body) ) if * ty = = want => Ok ( body) ,
937
_ => Err ( ObjectError:: Schema( format! (
938
" the bundle lacks {} {} " ,
939
want.name ( ) ,
940
r.short ( 12 )
941
) ) ) ,
942
} ;
943
let blob = crate :: objects:: Blob:: decode( get ( text, ObjectType:: Blob) ? ) ? ;
944
let mut content = Vec :: with_capacity( blob.length as usize ) ;
945
for chunk in & blob.chunks {
946
content.extend_from_slice ( get ( chunk, ObjectType:: Chunk) ? ) ;
947
}
0f93f49c Andy McCall 1 month ago ↶
948
crate :: objects:: text_lines( & content, count, form)
6f8aeb99 Andy McCall 1 month ago ↶
949
} ) ? ;
950
b.changes.push ( ( change, sigs_from ( & pair[ 1 ] ) ? ) ) ;
951
}
952
for a in o:: array( field ( m, 1 , " attests" ) ? , " attests" ) ? {
953
b.attests.push ( attest_from ( a) ? ) ;
750251b2 Andy McCall 1 month ago ↶
954
}
28fc23d7 Andy McCall 1 month ago ↶
955
if let Some ( ps) = m.get ( & 3 ) {
956
for p in o:: array( ps, " policies" ) ? {
957
b.policies.push ( policy_from ( p) ? ) ;
f0a517d2 Andy McCall 18 days ago ↶
958
}
959
}
960
if let Some ( cs) = m.get ( & 4 ) {
961
for c in o:: array( cs, " certificates" ) ? {
962
b.certificates.push (
963
crate :: cert:: SignedCertificate:: decode( o:: bytes( c, " certificate" ) ? )
964
.map_err ( | e | schema ( & format! ( " certificate: {e} " ) ) ) ? ,
965
) ;
28fc23d7 Andy McCall 1 month ago ↶
966
}
967
}
750251b2 Andy McCall 1 month ago ↶
968
Ok ( b)
969
}
970
971
pub fn encode_bundle ( b : & Bundle) -> Vec< u8 > {
972
cbor:: encode( & bundle_value ( b) )
973
}
974
pub fn decode_bundle ( bytes : & [u8 ]) -> Result< Bundle> {
975
bundle_from_value ( & cbor:: decode( bytes) .map_err ( ObjectError:: from) ? )
976
}
977
978
pub fn encode_capabilities ( id : [u8 ; 16]) -> Vec< u8 > {
979
cbor:: encode( & Value:: map( [
980
( 0 , Value:: Array( vec! [ Value:: Uint( PROTOCOL_VERSION ) ] ) ) ,
981
( 1 , Value:: Bytes( id.to_vec ( ) ) ) ,
982
( 2 , Value:: Array( vec! [ Value:: Text( " seal" .into ( ) ) ] ) ) ,
983
] ) )
984
}
985
pub fn decode_capabilities ( bytes : & [u8 ]) -> Result< [ u8 ; 16 ] > {
986
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
987
let m = map ( & v, " capabilities" ) ? ;
988
let versions = o:: array( field ( m, 0 , " versions" ) ? , " versions" ) ? ;
75167672 Andy McCall 1 month ago
989
if ! versions
990
.iter ( )
991
.any ( | x | x.as_uint ( ) = = Some ( PROTOCOL_VERSION ) )
992
{
993
return Err ( RepoError:: Msg(
994
" remote does not speak protocol version 1" .into ( ) ,
995
) ) ;
750251b2 Andy McCall 1 month ago ↶
996
}
75167672 Andy McCall 1 month ago
997
o:: bytes( field ( m, 1 , " repo id" ) ? , " repo id" ) ?
998
.try_into ( )
999
.map_err ( | _| schema ( " repo id: expected 16 bytes" ) )
750251b2 Andy McCall 1 month ago ↶
1000
}
1001
132b884b Andy McCall 1 month ago ↶
1002
fn tags_value ( tags : & [TagRef]) -> Value {
1003
Value:: Array(
1004
tags.iter ( )
1005
.map ( | t | {
1ec6fdbc Andy McCall 16 days ago ↶
1006
let mut v = Value:: map( [
132b884b Andy McCall 1 month ago ↶
1007
( 0 , Value:: Text( t.name.clone ( ) ) ) ,
1008
( 1 , Value:: Bytes( t.state.0. to_vec ( ) ) ) ,
1009
( 2 , hashes_value ( & t.heads) ) ,
1010
( 3 , opt_attest_value ( & t.attestation) ) ,
1ec6fdbc Andy McCall 16 days ago ↶
1011
] ) ;
1012
1013
1014
if let Value:: Map( m) = & mut v {
1015
if t.accepted.is_some ( ) {
1016
m.insert ( 4 , opt_attest_value ( & t.accepted) ) ;
1017
}
1018
if let Some ( l) = & t.logged {
1019
m.insert ( 5 , logged_value ( l) ) ;
1020
}
1021
if ! t.integration.is_empty ( ) {
1022
m.insert ( 6 , integration_value ( & t.integration) ) ;
1023
}
1024
}
1025
v
132b884b Andy McCall 1 month ago ↶
1026
} )
1027
.collect ( ) ,
1028
)
1029
}
1030
fn tags_from ( v : & Value) -> Result< Vec< TagRef> > {
1031
let mut out = Vec :: new( ) ;
1032
for t in o:: array( v, " tags" ) ? {
1033
let tm = map ( t, " tag" ) ? ;
1034
out.push ( TagRef {
1035
name: o:: text( field ( tm, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
1036
state: o:: oref( field ( tm, 1 , " state" ) ? , " state" ) ? ,
1037
heads: hashes_from ( field ( tm, 2 , " heads" ) ? ) ? ,
1038
attestation: opt_attest_from ( field ( tm, 3 , " attestation" ) ? ) ? ,
1ec6fdbc Andy McCall 16 days ago ↶
1039
accepted: match tm.get ( & 4 ) {
1040
Some ( a) => opt_attest_from ( a) ? ,
1041
None => None ,
1042
} ,
1043
logged: tm.get ( & 5 ) .map ( logged_from) .transpose ( ) ? ,
1044
integration: match tm.get ( & 6 ) {
1045
Some ( l) => integration_from ( l) ? ,
1046
None => Vec :: new( ) ,
1047
} ,
132b884b Andy McCall 1 month ago ↶
1048
} ) ;
1ec6fdbc Andy McCall 16 days ago ↶
1049
}
1050
Ok ( out)
1051
}
1052
1053
1054
1055
1056
# [ cfg ( test ) ]
1057
pub ( super ) fn tags_as_0_5_read_them ( bytes : & [u8 ]) -> Result< Vec< TagRef> > {
1058
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
1059
let m = map ( & v, " refs" ) ? ;
1060
let mut out = Vec :: new( ) ;
1061
for t in o:: array( field ( m, 3 , " tags" ) ? , " tags" ) ? {
1062
let tm = map ( t, " tag" ) ? ;
1063
out.push ( TagRef:: new(
1064
o:: text( field ( tm, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
1065
o:: oref( field ( tm, 1 , " state" ) ? , " state" ) ? ,
1066
hashes_from ( field ( tm, 2 , " heads" ) ? ) ? ,
1067
opt_attest_from ( field ( tm, 3 , " attestation" ) ? ) ? ,
1068
) ) ;
132b884b Andy McCall 1 month ago ↶
1069
}
1070
Ok ( out)
1ec6fdbc Andy McCall 16 days ago ↶
1071
}
1072
1073
1074
fn logged_value ( l : & Logged) -> Value {
1075
Value:: Array( vec! [
1076
Value:: Uint( l.index) ,
1077
Value:: Bytes( l.entry.clone ( ) ) ,
1078
proof_value ( & l.proof) ,
1079
] )
132b884b Andy McCall 1 month ago ↶
1080
}
1ec6fdbc Andy McCall 16 days ago ↶
1081
fn logged_from ( v : & Value) -> Result< Logged> {
1082
let a = o:: array( v, " logged" ) ? ;
1083
if a.len ( ) ! = 3 {
1084
return Err ( schema ( " logged: expected [index, entry, proof]" ) ) ;
1085
}
1086
Ok ( Logged {
1087
index: o:: uint( & a[ 0 ] , " index" ) ? ,
1088
entry: o:: bytes( & a[ 1 ] , " entry" ) ? .to_vec ( ) ,
1089
proof: proof_from ( & a[ 2 ] ) ? ,
1090
} )
1091
}
132b884b Andy McCall 1 month ago ↶
1092
1ec6fdbc Andy McCall 16 days ago ↶
1093
1094
fn integration_value ( integration : & [Integration]) -> Value {
1095
Value:: Array(
1096
integration
1097
.iter ( )
1098
.map ( | i | Value:: Array( vec! [ Value:: Text( i.note.clone ( ) ) , proof_value ( & i.proof) ] ) )
1099
.collect ( ) ,
1100
)
1101
}
1102
fn integration_from ( v : & Value) -> Result< Vec< Integration> > {
1103
let mut out = Vec :: new( ) ;
1104
for i in o:: array( v, " integration" ) ? {
1105
let a = o:: array( i, " integration" ) ? ;
1106
if a.len ( ) ! = 2 {
1107
return Err ( schema ( " integration: expected [note, proof]" ) ) ;
1108
}
1109
out.push ( Integration {
1110
note: o:: text( & a[ 0 ] , " note" ) ? .to_owned ( ) ,
1111
proof: proof_from ( & a[ 1 ] ) ? ,
1112
} ) ;
1113
}
1114
Ok ( out)
1115
}
1116
83e0677b Andy McCall 1 month ago ↶
1117
pub fn encode_refs ( id : [u8 ; 16], resp : & RefsResponse) -> Vec< u8 > {
4b9d0677 Andy McCall 18 days ago ↶
1118
let mut v = Value:: map( [
750251b2 Andy McCall 1 month ago ↶
1119
(
1120
0 ,
1121
Value:: Array(
83e0677b Andy McCall 1 month ago ↶
1122
resp.refs
1123
.iter ( )
750251b2 Andy McCall 1 month ago ↶
1124
.map ( | r | {
f53cbe7a Andy McCall 18 days ago ↶
1125
let mut v = Value:: map( [
750251b2 Andy McCall 1 month ago ↶
1126
( 0 , Value:: Text( r.name.clone ( ) ) ) ,
1127
( 1 , Value:: Bytes( r.state.0. to_vec ( ) ) ) ,
1128
( 2 , hashes_value ( & r.heads) ) ,
1129
( 3 , opt_attest_value ( & r.attestation) ) ,
1130
( 4 , r.last_serial.map ( Value:: Uint) .unwrap_or ( Value:: Null) ) ,
f53cbe7a Andy McCall 18 days ago ↶
1131
] ) ;
1132
4b9d0677 Andy McCall 18 days ago ↶
1133
if let Value:: Map( m) = & mut v {
1134
if r.accepted.is_some ( ) {
f53cbe7a Andy McCall 18 days ago ↶
1135
m.insert ( 5 , opt_attest_value ( & r.accepted) ) ;
4b9d0677 Andy McCall 18 days ago ↶
1136
}
1137
if let Some ( l) = & r.logged {
1ec6fdbc Andy McCall 16 days ago ↶
1138
m.insert ( 6 , logged_value ( l) ) ;
f53cbe7a Andy McCall 18 days ago ↶
1139
}
028545df Andy McCall 17 days ago ↶
1140
if ! r.integration.is_empty ( ) {
1ec6fdbc Andy McCall 16 days ago ↶
1141
m.insert ( 7 , integration_value ( & r.integration) ) ;
028545df Andy McCall 17 days ago ↶
1142
}
f53cbe7a Andy McCall 18 days ago ↶
1143
}
1144
v
750251b2 Andy McCall 1 month ago ↶
1145
} )
1146
.collect ( ) ,
1147
) ,
1148
) ,
1149
( 1 , Value:: Bytes( id.to_vec ( ) ) ) ,
83e0677b Andy McCall 1 month ago ↶
1150
( 2 , opt_policy_value ( resp.policy.as_ref ( ) ) ) ,
132b884b Andy McCall 1 month ago ↶
1151
( 3 , tags_value ( & resp.tags) ) ,
75167672 Andy McCall 1 month ago
1152
(
1153
4 ,
1154
Value:: Array( resp.history.iter ( ) .map ( policy_value) .collect ( ) ) ,
1155
) ,
14edbaaf Andy McCall 1 month ago ↶
1156
(
1157
5 ,
1158
resp.default_bookmark
1159
.clone ( )
1160
.map ( Value:: Text)
1161
.unwrap_or ( Value:: Null) ,
1162
) ,
4b9d0677 Andy McCall 18 days ago ↶
1163
] ) ;
028545df Andy McCall 17 days ago ↶
1164
if let Value:: Map( m) = & mut v {
1165
if let Some ( log) = & resp.log {
1166
m.insert ( 6 , Value:: Text( log.clone ( ) ) ) ;
b63fc7a7 Andy McCall 11 days ago ↶
1167
}
1168
if ! resp.withdrawn.is_empty ( ) {
1169
m.insert ( 8 , tags_value ( & resp.withdrawn) ) ;
028545df Andy McCall 17 days ago ↶
1170
}
1171
if ! resp.witnesses.is_empty ( ) {
1172
m.insert (
1173
7 ,
1174
Value:: Array(
1175
resp.witnesses
1176
.iter ( )
1177
.map ( | ( name , id ) | {
1178
Value:: Array( vec! [
1179
Value:: Text( name.clone ( ) ) ,
1180
Value:: Bytes( id.clone ( ) ) ,
1181
] )
1182
} )
1183
.collect ( ) ,
1184
) ,
1185
) ;
1186
}
4b9d0677 Andy McCall 18 days ago ↶
1187
}
1188
cbor:: encode( & v)
750251b2 Andy McCall 1 month ago ↶
1189
}
83e0677b Andy McCall 1 month ago ↶
1190
pub fn decode_refs ( bytes : & [u8 ]) -> Result< ( [u8 ; 16], RefsResponse) > {
750251b2 Andy McCall 1 month ago ↶
1191
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
1192
let m = map ( & v, " refs" ) ? ;
75167672 Andy McCall 1 month ago
1193
let id: [ u8 ; 16 ] = o:: bytes( field ( m, 1 , " repo id" ) ? , " repo id" ) ?
1194
.try_into ( )
1195
.map_err ( | _| schema ( " repo id: expected 16 bytes" ) ) ? ;
750251b2 Andy McCall 1 month ago ↶
1196
let mut refs = Vec :: new( ) ;
1197
for r in o:: array( field ( m, 0 , " refs" ) ? , " refs" ) ? {
1198
let rm = map ( r, " ref" ) ? ;
1199
let ls = field ( rm, 4 , " last serial" ) ? ;
1200
refs.push ( RemoteRef {
1201
name: o:: text( field ( rm, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
1202
state: o:: oref( field ( rm, 1 , " state" ) ? , " state" ) ? ,
1203
heads: hashes_from ( field ( rm, 2 , " heads" ) ? ) ? ,
1204
attestation: opt_attest_from ( field ( rm, 3 , " attestation" ) ? ) ? ,
75167672 Andy McCall 1 month ago
1205
last_serial: if ls.is_null ( ) {
1206
None
1207
} else {
1208
Some ( o:: uint( ls, " last serial" ) ? )
f53cbe7a Andy McCall 18 days ago ↶
1209
} ,
1210
accepted: match rm.get ( & 5 ) {
1211
Some ( a) => opt_attest_from ( a) ? ,
1212
None => None ,
75167672 Andy McCall 1 month ago
1213
} ,
1ec6fdbc Andy McCall 16 days ago ↶
1214
logged: rm.get ( & 6 ) .map ( logged_from) .transpose ( ) ? ,
028545df Andy McCall 17 days ago ↶
1215
integration: match rm.get ( & 7 ) {
1ec6fdbc Andy McCall 16 days ago ↶
1216
Some ( l) => integration_from ( l) ? ,
028545df Andy McCall 17 days ago ↶
1217
None => Vec :: new( ) ,
1218
} ,
750251b2 Andy McCall 1 month ago ↶
1219
} ) ;
1220
}
83e0677b Andy McCall 1 month ago ↶
1221
let policy = match m.get ( & 2 ) {
1222
Some ( p) => opt_policy_from ( p) ? ,
1223
None => None ,
1224
} ;
132b884b Andy McCall 1 month ago ↶
1225
let tags = match m.get ( & 3 ) {
1226
Some ( t) => tags_from ( t) ? ,
1227
None => Vec :: new( ) ,
1228
} ;
28fc23d7 Andy McCall 1 month ago ↶
1229
let mut history = Vec :: new( ) ;
1230
if let Some ( h) = m.get ( & 4 ) {
1231
for p in o:: array( h, " history" ) ? {
1232
history.push ( policy_from ( p) ? ) ;
1233
}
1234
}
14edbaaf Andy McCall 1 month ago ↶
1235
let default_bookmark = match m.get ( & 5 ) {
4b9d0677 Andy McCall 18 days ago ↶
1236
Some ( Value:: Text( t) ) => Some ( t.clone ( ) ) ,
1237
_ => None ,
1238
} ;
1239
let log = match m.get ( & 6 ) {
14edbaaf Andy McCall 1 month ago ↶
1240
Some ( Value:: Text( t) ) => Some ( t.clone ( ) ) ,
1241
_ => None ,
1242
} ;
028545df Andy McCall 17 days ago ↶
1243
let mut witnesses = Vec :: new( ) ;
1244
if let Some ( w) = m.get ( & 7 ) {
1245
for x in o:: array( w, " witnesses" ) ? {
1246
let a = o:: array( x, " witness" ) ? ;
1247
if a.len ( ) ! = 2 {
1248
return Err ( schema ( " witness: expected [name, identity]" ) ) ;
1249
}
1250
witnesses.push ( (
1251
o:: text( & a[ 0 ] , " witness name" ) ? .to_owned ( ) ,
1252
o:: bytes( & a[ 1 ] , " witness identity" ) ? .to_vec ( ) ,
1253
) ) ;
1254
}
1255
}
b63fc7a7 Andy McCall 11 days ago ↶
1256
let withdrawn = match m.get ( & 8 ) {
1257
Some ( t) => tags_from ( t) ? ,
1258
None => Vec :: new( ) ,
1259
} ;
75167672 Andy McCall 1 month ago
1260
Ok ( (
1261
id,
1262
RefsResponse {
1263
refs,
1264
policy,
1265
tags,
1266
history,
14edbaaf Andy McCall 1 month ago ↶
1267
default_bookmark,
4b9d0677 Andy McCall 18 days ago ↶
1268
log,
028545df Andy McCall 17 days ago ↶
1269
witnesses,
b63fc7a7 Andy McCall 11 days ago ↶
1270
withdrawn,
75167672 Andy McCall 1 month ago
1271
} ,
1272
) )
750251b2 Andy McCall 1 month ago ↶
1273
}
1274
028545df Andy McCall 17 days ago ↶
1275
1276
fn proof_value ( proof : & [[u8 ; 32]]) -> Value {
1277
Value:: Array( proof.iter ( ) .map ( | h | Value:: Bytes( h.to_vec ( ) ) ) .collect ( ) )
1278
}
1279
1280
fn proof_from ( v : & Value) -> Result< Vec< [ u8 ; 32 ] > > {
1281
let mut proof = Vec :: new( ) ;
1282
for h in o:: array( v, " proof" ) ? {
1283
proof.push (
1284
o:: bytes( h, " proof hash" ) ?
1285
.try_into ( )
1286
.map_err ( | _| schema ( " proof hash: expected 32 bytes" ) ) ? ,
1287
) ;
1288
}
1289
Ok ( proof)
1290
}
1291
750251b2 Andy McCall 1 month ago ↶
1292
pub fn encode_negotiate ( have : & [ChangeHash], want : & [ChangeHash]) -> Vec< u8 > {
75167672 Andy McCall 1 month ago
1293
cbor:: encode( & Value:: map( [
1294
( 0 , hashes_value ( have) ) ,
1295
( 1 , hashes_value ( want) ) ,
1296
] ) )
750251b2 Andy McCall 1 month ago ↶
1297
}
1298
pub fn decode_negotiate ( bytes : & [u8 ]) -> Result< ( Vec< ChangeHash> , Vec< ChangeHash> ) > {
1299
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
1300
let m = map ( & v, " negotiate" ) ? ;
75167672 Andy McCall 1 month ago
1301
Ok ( (
1302
hashes_from ( field ( m, 0 , " have" ) ? ) ? ,
1303
hashes_from ( field ( m, 1 , " want" ) ? ) ? ,
1304
) )
750251b2 Andy McCall 1 month ago ↶
1305
}
1306
b3c5a59a Andy McCall 1 month ago ↶
1307
1308
pub fn encode_fetch ( hs : & [ChangeHash], max_blob : Option< u64 > ) -> Vec< u8 > {
75167672 Andy McCall 1 month ago
1309
cbor:: encode( & Value:: map( [
1310
( 0 , hashes_value ( hs) ) ,
1311
( 1 , max_blob.map ( Value:: Uint) .unwrap_or ( Value:: Null) ) ,
1312
] ) )
b3c5a59a Andy McCall 1 month ago ↶
1313
}
1314
pub fn decode_fetch ( bytes : & [u8 ]) -> Result< ( Vec< ChangeHash> , Option< u64 > ) > {
1315
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
1316
let m = map ( & v, " fetch" ) ? ;
1317
let max = match m.get ( & 1 ) {
1318
Some ( x) if ! x.is_null ( ) => Some ( o:: uint( x, " max blob" ) ? ) ,
1319
_ => None ,
1320
} ;
1321
Ok ( ( hashes_from ( field ( m, 0 , " changes" ) ? ) ? , max) )
1322
}
1323
2863456a Andy McCall 1 month ago ↶
1324
1325
pub fn encode_shallow ( hs : & [ChangeHash], depth : u32 ) -> Vec< u8 > {
75167672 Andy McCall 1 month ago
1326
cbor:: encode( & Value:: map( [
1327
( 0 , hashes_value ( hs) ) ,
1328
( 1 , Value:: Uint( depth as u64 ) ) ,
1329
] ) )
2863456a Andy McCall 1 month ago ↶
1330
}
1331
pub fn decode_shallow ( bytes : & [u8 ]) -> Result< ( Vec< ChangeHash> , u32 ) > {
1332
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
1333
let m = map ( & v, " shallow" ) ? ;
75167672 Andy McCall 1 month ago
1334
Ok ( (
1335
hashes_from ( field ( m, 0 , " heads" ) ? ) ? ,
1336
o:: u32_( field ( m, 1 , " depth" ) ? , " depth" ) ? ,
1337
) )
2863456a Andy McCall 1 month ago ↶
1338
}
1339
750251b2 Andy McCall 1 month ago ↶
1340
pub fn encode_hashes ( hs : & [ChangeHash]) -> Vec< u8 > {
1341
cbor:: encode( & Value:: map( [ ( 0 , hashes_value ( hs) ) ] ) )
1342
}
1343
pub fn decode_hashes ( bytes : & [u8 ]) -> Result< Vec< ChangeHash> > {
1344
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
1345
hashes_from ( field ( map ( & v, " hashes" ) ? , 0 , " hashes" ) ? )
1346
}
1347
75167672 Andy McCall 1 month ago
1348
pub fn encode_push (
1349
bundle : & Bundle,
1350
updates : & [RefUpdate],
1351
policy : Option< & SignedPolicy> ,
1352
tags : & [TagRef],
1353
) -> Vec< u8 > {
750251b2 Andy McCall 1 month ago ↶
1354
cbor:: encode( & Value:: map( [
1355
( 0 , bundle_value ( bundle) ) ,
83e0677b Andy McCall 1 month ago ↶
1356
( 2 , opt_policy_value ( policy) ) ,
132b884b Andy McCall 1 month ago ↶
1357
( 3 , tags_value ( tags) ) ,
750251b2 Andy McCall 1 month ago ↶
1358
(
1359
1 ,
1360
Value:: Array(
1361
updates
1362
.iter ( )
1363
.map ( | u | {
1364
Value:: map( [
1365
( 0 , Value:: Text( u.name.clone ( ) ) ) ,
1366
( 1 , Value:: Bytes( u.old_state.0. to_vec ( ) ) ) ,
1367
( 2 , Value:: Bytes( u.new_state.0. to_vec ( ) ) ) ,
1368
( 3 , Value:: Bool( u.force) ) ,
1369
( 4 , opt_attest_value ( & u.attestation) ) ,
1370
] )
1371
} )
1372
.collect ( ) ,
1373
) ,
1374
) ,
1375
] ) )
1376
}
132b884b Andy McCall 1 month ago ↶
1377
1378
pub type PushParts = ( Bundle, Vec< RefUpdate> , Option< SignedPolicy> , Vec< TagRef> ) ;
1379
1380
pub fn decode_push ( bytes : & [u8 ]) -> Result< PushParts> {
750251b2 Andy McCall 1 month ago ↶
1381
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
1382
let m = map ( & v, " push" ) ? ;
1383
let bundle = bundle_from_value ( field ( m, 0 , " bundle" ) ? ) ? ;
1384
let mut updates = Vec :: new( ) ;
1385
for u in o:: array( field ( m, 1 , " updates" ) ? , " updates" ) ? {
1386
let um = map ( u, " update" ) ? ;
1387
updates.push ( RefUpdate {
1388
name: o:: text( field ( um, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
1389
old_state: o:: oref( field ( um, 1 , " old_state" ) ? , " old_state" ) ? ,
1390
new_state: o:: oref( field ( um, 2 , " new_state" ) ? , " new_state" ) ? ,
75167672 Andy McCall 1 month ago
1391
force: field ( um, 3 , " force" ) ?
1392
.as_bool ( )
1393
.ok_or_else ( | | schema ( " force: expected bool" ) ) ? ,
750251b2 Andy McCall 1 month ago ↶
1394
attestation: opt_attest_from ( field ( um, 4 , " attestation" ) ? ) ? ,
1395
} ) ;
1396
}
83e0677b Andy McCall 1 month ago ↶
1397
let policy = match m.get ( & 2 ) {
1398
Some ( p) => opt_policy_from ( p) ? ,
1399
None => None ,
1400
} ;
132b884b Andy McCall 1 month ago ↶
1401
let tags = match m.get ( & 3 ) {
1402
Some ( t) => tags_from ( t) ? ,
1403
None => Vec :: new( ) ,
1404
} ;
1405
Ok ( ( bundle, updates, policy, tags) )
750251b2 Andy McCall 1 month ago ↶
1406
}
1407
1408
pub fn encode_push_response ( results : & [RefResult]) -> Vec< u8 > {
1409
cbor:: encode( & Value:: map( [ (
1410
0 ,
1411
Value:: Array(
1412
results
1413
.iter ( )
75167672 Andy McCall 1 month ago
1414
.map ( | r | {
1415
Value:: map( [
1416
( 0 , Value:: Text( r.name.clone ( ) ) ) ,
1417
( 1 , Value:: Bool( r.ok) ) ,
1418
( 2 , Value:: Text( r.reason.clone ( ) ) ) ,
1419
] )
1420
} )
750251b2 Andy McCall 1 month ago ↶
1421
.collect ( ) ,
1422
) ,
1423
) ] ) )
1424
}
1425
pub fn decode_push_response ( bytes : & [u8 ]) -> Result< Vec< RefResult> > {
1426
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
1427
let m = map ( & v, " push response" ) ? ;
1428
let mut out = Vec :: new( ) ;
1429
for r in o:: array( field ( m, 0 , " results" ) ? , " results" ) ? {
1430
let rm = map ( r, " result" ) ? ;
1431
out.push ( RefResult {
1432
name: o:: text( field ( rm, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
75167672 Andy McCall 1 month ago
1433
ok: field ( rm, 1 , " ok" ) ?
1434
.as_bool ( )
1435
.ok_or_else ( | | schema ( " ok: expected bool" ) ) ? ,
750251b2 Andy McCall 1 month ago ↶
1436
reason: o:: text( field ( rm, 2 , " reason" ) ? , " reason" ) ? .to_owned ( ) ,
1437
} ) ;
1438
}
1439
Ok ( out)
1440
}
1441
}
1442
1443
# [ cfg ( test ) ]
1444
mod tests {
1445
use super :: * ;
1446
use crate :: attest:: AttestBody;
1447
use crate :: objects:: Hlc;
ee130dd9 Andy McCall 15 days ago ↶
1448
1449
# [ test ]
1450
fn client_features_are_declared_and_read ( ) {
1451
assert_eq! ( CLIENT_FEATURES .join ( " ," ) , " certified-tags" ) ;
1452
assert! ( user_agent ( ) .starts_with ( " oxy/" ) ) ;
1453
assert! ( declares_feature (
1454
Some ( " certified-tags" ) ,
1455
FEATURE_CERTIFIED_TAGS
1456
) ) ;
1457
assert! ( declares_feature (
1458
Some ( " later-thing, Certified-Tags ,x" ) ,
1459
FEATURE_CERTIFIED_TAGS
1460
) ) ;
1461
assert! ( ! declares_feature (
1462
Some ( " certified-tags-v2" ) ,
1463
FEATURE_CERTIFIED_TAGS
1464
) ) ;
1465
assert! ( ! declares_feature ( Some ( " " ) , FEATURE_CERTIFIED_TAGS ) ) ;
1466
assert! ( ! declares_feature ( None , FEATURE_CERTIFIED_TAGS ) ) ;
1467
}
750251b2 Andy McCall 1 month ago ↶
1468
1469
# [ test ]
1470
fn wire_round_trips ( ) {
1471
let c = crate :: objects:: tests:: sample_change( ) ;
75167672 Andy McCall 1 month ago
1472
let sk = crate :: identity:: SecretKey {
1473
ed_seed: [ 1 ; 32 ] ,
1474
ml_seed: [ 2 ; 32 ] ,
1475
} ;
750251b2 Andy McCall 1 month ago ↶
1476
let id = sk.identity ( " a" , " b" , 0 ) ;
1477
let key = id.hash ( ) ;
1478
let sig = sk.sign ( crate :: identity:: Domain:: Change, & key, & c.hash ( ) ) ;
1479
let seal = Attest:: seal( [ 3 ; 16 ] , vec! [ c.hash ( ) ] ) ;
1480
let seal_sig = sk.sign ( crate :: identity:: Domain:: Attest, & key, & seal.hash ( ) ) ;
28fc23d7 Andy McCall 1 month ago ↶
1481
let policy = Policy:: single_root( [ 3 ; 16 ] , id.clone ( ) , 99 ) ;
1482
let psig = sk.sign ( crate :: identity:: Domain:: Policy, & key, & policy.hash ( ) ) ;
750251b2 Andy McCall 1 month ago ↶
1483
let bundle = Bundle {
1484
changes: vec! [ ( c.clone ( ) , vec! [ sig.clone ( ) ] ) ] ,
75167672 Andy McCall 1 month ago
1485
attests: vec! [ SignedAttest {
1486
attest: seal.clone ( ) ,
1487
sigs: vec! [ seal_sig] ,
1488
} ] ,
1489
objects: vec! [
1490
( ObjectType:: Identity, id.encode ( ) ) ,
1491
( ObjectType:: Chunk, b " xyz" .to_vec ( ) ) ,
1492
] ,
1493
policies: vec! [ SignedPolicy {
1494
policy: policy.clone ( ) ,
1495
sigs: vec! [ psig.clone ( ) ] ,
1496
} ] ,
598009a7 Andy McCall 1 month ago ↶
1497
hashes: vec! [ ] ,
2c75672f Andy McCall 1 month ago ↶
1498
raw_changes: vec! [ ] ,
f0a517d2 Andy McCall 18 days ago ↶
1499
certificates: vec! [ ] ,
750251b2 Andy McCall 1 month ago ↶
1500
} ;
1501
let d = wire:: decode_bundle( & wire:: encode_bundle( & bundle) ) .unwrap ( ) ;
598009a7 Andy McCall 1 month ago ↶
1502
assert_eq! (
1503
d.hashes,
1504
vec! [ c.hash ( ) ] ,
1505
" the receiver hashes what it was sent"
1506
) ;
750251b2 Andy McCall 1 month ago ↶
1507
assert_eq! ( d.changes, bundle.changes) ;
1508
assert_eq! ( d.attests, bundle.attests) ;
1509
assert_eq! ( d.objects, bundle.objects) ;
28fc23d7 Andy McCall 1 month ago ↶
1510
assert_eq! ( d.policies, bundle.policies) ;
f0a517d2 Andy McCall 18 days ago ↶
1511
assert! ( d.certificates.is_empty ( ) ) ;
1512
1513
1514
let plain = wire:: encode_bundle( & bundle) ;
1515
let mut with = bundle.clone ( ) ;
1516
let issuer_sk = crate :: identity:: SecretKey:: generate( ) ;
1517
let issuer = issuer_sk.identity ( " hub" , " h@x" , 1 ) ;
1518
with.certificates.push ( crate :: cert:: SignedCertificate:: sign(
1519
crate :: cert:: Certificate {
1520
key: id.clone ( ) ,
1521
issuer: issuer.hash ( ) ,
1522
subject: " agent:a@b" .into ( ) ,
1523
claims: vec! [ ] ,
1524
scope: crate :: identity:: Scope:: CHANGES ,
1525
not_before: 1 ,
1526
expires: 2 ,
a2387d54 Andy McCall 18 days ago ↶
1527
grant: None ,
f0a517d2 Andy McCall 18 days ago ↶
1528
} ,
1529
& issuer,
1530
& issuer_sk,
1531
) ) ;
1532
let encoded = wire:: encode_bundle( & with) ;
1533
assert_ne! ( encoded, plain) ;
1534
assert_eq! (
1535
wire:: decode_bundle( & encoded) .unwrap ( ) .certificates,
1536
with.certificates
1537
) ;
1538
with.certificates.clear ( ) ;
1539
assert_eq! ( wire:: encode_bundle( & with) , plain) ;
750251b2 Andy McCall 1 month ago ↶
1540
75167672 Andy McCall 1 month ago
1541
let att = Attest {
1542
repo: [ 3 ; 16 ] ,
1543
hlc: Hlc:: default( ) ,
1544
body: AttestBody:: Ref {
1545
name: " main" .into ( ) ,
1546
old_state: ObjectRef( [ 1 ; 32 ] ) ,
1547
new_state: ObjectRef( [ 2 ; 32 ] ) ,
1548
serial: 4 ,
1549
} ,
1550
} ;
750251b2 Andy McCall 1 month ago ↶
1551
let refs = vec! [
75167672 Andy McCall 1 month ago
1552
RemoteRef {
1553
name: " main" .into ( ) ,
1554
state: ObjectRef( [ 2 ; 32 ] ) ,
1555
heads: vec! [ c.hash ( ) ] ,
1556
attestation: Some ( SignedAttest {
1557
attest: att.clone ( ) ,
1558
sigs: vec! [ sig.clone ( ) ] ,
1559
} ) ,
1560
last_serial: Some ( 4 ) ,
f53cbe7a Andy McCall 18 days ago ↶
1561
accepted: None ,
4b9d0677 Andy McCall 18 days ago ↶
1562
logged: None ,
028545df Andy McCall 17 days ago ↶
1563
integration: vec! [ ] ,
75167672 Andy McCall 1 month ago
1564
} ,
1565
RemoteRef {
1566
name: " dev" .into ( ) ,
1567
state: ObjectRef( [ 5 ; 32 ] ) ,
1568
heads: vec! [ ] ,
1569
attestation: None ,
1570
last_serial: None ,
f53cbe7a Andy McCall 18 days ago ↶
1571
accepted: None ,
4b9d0677 Andy McCall 18 days ago ↶
1572
logged: None ,
028545df Andy McCall 17 days ago ↶
1573
integration: vec! [ ] ,
75167672 Andy McCall 1 month ago
1574
} ,
750251b2 Andy McCall 1 month ago ↶
1575
] ;
1ec6fdbc Andy McCall 16 days ago ↶
1576
let tag = TagRef:: new( " v1" .into ( ) , ObjectRef( [ 2 ; 32 ] ) , vec! [ c.hash ( ) ] , None ) ;
4b9d0677 Andy McCall 18 days ago ↶
1577
let mut resp = RefsResponse {
75167672 Andy McCall 1 month ago
1578
refs,
1579
policy: Some ( SignedPolicy {
1580
policy: policy.clone ( ) ,
1581
sigs: vec! [ psig.clone ( ) ] ,
1582
} ) ,
1583
tags: vec! [ tag.clone ( ) ] ,
1584
history: vec! [ SignedPolicy {
1585
policy: policy.clone ( ) ,
1586
sigs: vec! [ ] ,
1587
} ] ,
14edbaaf Andy McCall 1 month ago ↶
1588
default_bookmark: Some ( " develop" .into ( ) ) ,
4b9d0677 Andy McCall 18 days ago ↶
1589
log: Some ( " hub.example/log\n 2\n root\n \n - sig\n " .into ( ) ) ,
028545df Andy McCall 17 days ago ↶
1590
witnesses: vec! [ ] ,
b63fc7a7 Andy McCall 11 days ago ↶
1591
withdrawn: vec! [ ] ,
75167672 Andy McCall 1 month ago
1592
} ;
028545df Andy McCall 17 days ago ↶
1593
1594
1595
let old = wire:: encode_refs( [ 3 ; 16 ] , & resp) ;
1596
let back = wire:: decode_refs( & old) .unwrap ( ) .1 ;
1597
assert! ( back.witnesses.is_empty ( ) & & back.refs.iter ( ) .all ( | r | r.integration.is_empty ( ) ) ) ;
4b9d0677 Andy McCall 18 days ago ↶
1598
resp.refs[ 1 ] .logged = Some ( Logged {
1599
index: 41 ,
1600
entry: vec! [ 1 , 2 , 3 ] ,
1601
proof: vec! [ [ 9 ; 32 ] , [ 8 ; 32 ] ] ,
1602
} ) ;
028545df Andy McCall 17 days ago ↶
1603
resp.refs[ 1 ] .integration = vec! [ Integration {
1604
note: " hub.example/log\n 42\n root\n \n - sig\n " .into ( ) ,
1605
proof: vec! [ [ 7 ; 32 ] ] ,
1606
} ] ;
1607
resp.witnesses = vec! [ ( " w.example" .into ( ) , vec! [ 4 , 5 , 6 ] ) ] ;
1608
let new = wire:: encode_refs( [ 3 ; 16 ] , & resp) ;
1609
let ( id_back, back) = wire:: decode_refs( & new) .unwrap ( ) ;
4b9d0677 Andy McCall 18 days ago ↶
1610
assert_eq! ( back.log, resp.log) ;
1611
assert_eq! ( back.refs[ 1 ] .logged, resp.refs[ 1 ] .logged) ;
028545df Andy McCall 17 days ago ↶
1612
assert_eq! ( back.refs[ 1 ] .integration, resp.refs[ 1 ] .integration) ;
1613
assert_eq! ( back.witnesses, resp.witnesses) ;
4b9d0677 Andy McCall 18 days ago ↶
1614
assert_eq! ( back.refs[ 0 ] .logged, None ) ;
028545df Andy McCall 17 days ago ↶
1615
1616
let crate :: cbor:: Value:: Map( m) = crate :: cbor:: decode( & new) .unwrap ( ) else {
1617
panic! ( )
1618
} ;
1619
assert! ( m.contains_key ( & 7 ) ) ;
750251b2 Andy McCall 1 month ago ↶
1620
assert_eq! ( id_back, [ 3 ; 16 ] ) ;
83e0677b Andy McCall 1 month ago ↶
1621
assert_eq! ( back.refs.len ( ) , 2 ) ;
1622
assert_eq! ( back.refs[ 0 ] .attestation.as_ref ( ) .unwrap ( ) .attest, att) ;
1623
assert_eq! ( back.refs[ 1 ] .last_serial, None ) ;
1624
assert_eq! ( back.policy.as_ref ( ) .unwrap ( ) .policy, policy) ;
28fc23d7 Andy McCall 1 month ago ↶
1625
assert_eq! ( back.history, resp.history) ;
132b884b Andy McCall 1 month ago ↶
1626
assert_eq! ( back.tags, vec! [ tag.clone ( ) ] ) ;
1ec6fdbc Andy McCall 16 days ago ↶
1627
1628
1629
1630
let crate :: cbor:: Value:: Map( m) = crate :: cbor:: decode( & new) .unwrap ( ) else {
1631
panic! ( )
1632
} ;
1633
let crate :: cbor:: Value:: Array( tags) = & m[ & 3 ] else {
1634
panic! ( )
1635
} ;
1636
let crate :: cbor:: Value:: Map( plain) = & tags[ 0 ] else {
1637
panic! ( )
1638
} ;
1639
assert_eq! ( plain.keys ( ) .copied ( ) .collect:: < Vec< _ > > ( ) , vec! [ 0 , 1 , 2 , 3 ] ) ;
1640
let mut full = tag.clone ( ) ;
1641
full.name = " v2" .into ( ) ;
1642
full.attestation = Some ( SignedAttest {
1643
attest: att.clone ( ) ,
1644
sigs: vec! [ sig.clone ( ) ] ,
1645
} ) ;
1646
full.accepted = full.attestation.clone ( ) ;
1647
full.logged = Some ( Logged {
1648
index: 7 ,
1649
entry: vec! [ 4 ] ,
1650
proof: vec! [ [ 3 ; 32 ] ] ,
1651
} ) ;
1652
full.integration = vec! [ Integration {
1653
note: " hub.example/log\n 8\n root\n \n - sig\n " .into ( ) ,
1654
proof: vec! [ ] ,
1655
} ] ;
1656
resp.tags = vec! [ full.clone ( ) , tag.clone ( ) ] ;
1657
let bytes = wire:: encode_refs( [ 3 ; 16 ] , & resp) ;
1658
assert_eq! ( wire:: decode_refs( & bytes) .unwrap ( ) .1. tags, resp.tags) ;
1659
1660
let pushed = wire:: encode_push( & Bundle:: default( ) , & [ ] , None , & resp.tags) ;
1661
assert_eq! ( wire:: decode_push( & pushed) .unwrap ( ) .3 , resp.tags) ;
1662
1663
1664
let stripped: Vec< TagRef> = resp
1665
.tags
1666
.iter ( )
1667
.map ( | t | {
1668
TagRef:: new(
1669
t.name.clone ( ) ,
1670
t.state,
1671
t.heads.clone ( ) ,
1672
t.attestation.clone ( ) ,
1673
)
1674
} )
1675
.collect ( ) ;
1676
assert_eq! ( wire:: tags_as_0_5_read_them( & bytes) .unwrap ( ) , stripped) ;
750251b2 Andy McCall 1 month ago ↶
1677
75167672 Andy McCall 1 month ago
1678
let ( h, w) = wire:: decode_negotiate( & wire:: encode_negotiate(
1679
& [ ObjectRef( [ 1 ; 32 ] ) ] ,
1680
& [ ObjectRef( [ 2 ; 32 ] ) ] ,
1681
) )
1682
.unwrap ( ) ;
750251b2 Andy McCall 1 month ago ↶
1683
assert_eq! ( ( h, w) , ( vec! [ ObjectRef( [ 1 ; 32 ] ) ] , vec! [ ObjectRef( [ 2 ; 32 ] ) ] ) ) ;
75167672 Andy McCall 1 month ago
1684
assert_eq! (
1685
wire:: decode_hashes( & wire:: encode_hashes( & [ c.hash ( ) ] ) ) .unwrap ( ) ,
1686
vec! [ c.hash ( ) ]
1687
) ;
1688
assert_eq! (
1689
wire:: decode_fetch( & wire:: encode_fetch( & [ c.hash ( ) ] , Some ( 4096 ) ) ) .unwrap ( ) ,
1690
( vec! [ c.hash ( ) ] , Some ( 4096 ) )
1691
) ;
1692
assert_eq! (
1693
wire:: decode_fetch( & wire:: encode_fetch( & [ ] , None ) ) .unwrap ( ) ,
1694
( vec! [ ] , None )
1695
) ;
1696
assert_eq! (
1697
wire:: decode_shallow( & wire:: encode_shallow( & [ c.hash ( ) ] , 3 ) ) .unwrap ( ) ,
1698
( vec! [ c.hash ( ) ] , 3 )
1699
) ;
b3c5a59a Andy McCall 1 month ago ↶
1700
75167672 Andy McCall 1 month ago
1701
assert_eq! (
1702
wire:: decode_fetch( & wire:: encode_hashes( & [ c.hash ( ) ] ) ) .unwrap ( ) ,
1703
( vec! [ c.hash ( ) ] , None )
1704
) ;
750251b2 Andy McCall 1 month ago ↶
1705
75167672 Andy McCall 1 month ago
1706
let up = RefUpdate {
1707
name: " main" .into ( ) ,
1708
old_state: ObjectRef( [ 1 ; 32 ] ) ,
1709
new_state: ObjectRef( [ 2 ; 32 ] ) ,
1710
force: true ,
1711
attestation: Some ( SignedAttest {
1712
attest: att,
1713
sigs: vec! [ sig] ,
1714
} ) ,
1715
} ;
1716
let sp = SignedPolicy {
1717
policy,
1718
sigs: vec! [ psig] ,
1719
} ;
1720
let ( b2, ups, pol, tags) = wire:: decode_push( & wire:: encode_push(
1721
& bundle,
1722
std:: slice:: from_ref( & up) ,
1723
Some ( & sp) ,
1724
std:: slice:: from_ref( & tag) ,
1725
) )
1726
.unwrap ( ) ;
83e0677b Andy McCall 1 month ago ↶
1727
assert_eq! ( pol, Some ( sp) ) ;
132b884b Andy McCall 1 month ago ↶
1728
assert_eq! ( tags, vec! [ tag] ) ;
750251b2 Andy McCall 1 month ago ↶
1729
assert_eq! ( b2.changes.len ( ) , 1 ) ;
1730
assert_eq! ( ups[ 0 ] .name, " main" ) ;
1731
assert! ( ups[ 0 ] .force) ;
1732
assert_eq! ( ups[ 0 ] .attestation, up.attestation) ;
75167672 Andy McCall 1 month ago
1733
let res = vec! [ RefResult {
1734
name: " main" .into ( ) ,
1735
ok: false ,
1736
reason: " stale" .into ( ) ,
1737
} ] ;
1738
assert_eq! (
1739
wire:: decode_push_response( & wire:: encode_push_response( & res) ) .unwrap ( ) ,
1740
res
1741
) ;
1742
assert_eq! (
1743
wire:: decode_capabilities( & wire:: encode_capabilities( [ 7 ; 16 ] ) ) .unwrap ( ) ,
1744
[ 7 ; 16 ]
1745
) ;
750251b2 Andy McCall 1 month ago ↶
1746
}
1747
}