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