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