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} ;
17
use std:: sync:: Arc;
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> ,
83e0677b Andy McCall 1 month ago ↶
57
}
58
132b884b Andy McCall 1 month ago ↶
59
60
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
61
pub struct TagRef {
62
pub name : String,
63
pub state : ObjectRef,
64
pub heads : Vec< ChangeHash> ,
65
pub attestation : Option< SignedAttest> ,
66
}
67
5b9c6ad4 Andy McCall 1 month ago ↶
68
69
# [ derive ( Clone, Debug ) ]
70
pub struct RemoteRef {
71
pub name : String,
72
pub state : ObjectRef,
73
pub heads : Vec< ChangeHash> ,
74
pub attestation : Option< SignedAttest> ,
75
}
76
77
78
# [ derive ( Clone, Debug, Default ) ]
79
pub struct Bundle {
80
81
pub changes : Vec< ( Change, Vec< Signature> ) > ,
82
83
pub attests : Vec< SignedAttest> ,
84
85
pub objects : Vec< ( ObjectType, Vec< u8 > ) > ,
28fc23d7 Andy McCall 1 month ago ↶
86
87
88
pub policies : Vec< SignedPolicy> ,
598009a7 Andy McCall 1 month ago ↶
89
90
91
92
pub hashes : Vec< ChangeHash> ,
5b9c6ad4 Andy McCall 1 month ago ↶
93
}
94
95
impl Bundle {
96
pub fn is_empty ( & self ) -> bool {
97
self .changes.is_empty ( ) & & self .attests.is_empty ( ) & & self .objects.is_empty ( )
98
}
99
}
100
101
102
# [ derive ( Clone, Debug ) ]
103
pub struct RefUpdate {
104
pub name : String,
105
pub old_state : ObjectRef,
106
pub new_state : ObjectRef,
107
pub force : bool ,
108
pub attestation : Option< SignedAttest> ,
109
}
110
111
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
112
pub struct RefResult {
113
pub name : String,
114
pub ok : bool ,
115
pub reason : String,
116
}
117
118
pub trait Remote {
119
fn repo_id ( & self ) -> Result< [ u8 ; 16 ] > ;
83e0677b Andy McCall 1 month ago ↶
120
fn refs ( & self ) -> Result< RefsResponse> ;
5b9c6ad4 Andy McCall 1 month ago ↶
121
122
fn negotiate ( & self , have : & [ChangeHash], want : & [ChangeHash]) -> Result< Vec< ChangeHash> > ;
b3c5a59a Andy McCall 1 month ago ↶
123
124
125
fn fetch ( & self , changes : & [ChangeHash], max_blob : Option< u64 > ) -> Result< Bundle> ;
126
127
128
fn objects ( & self , refs : & [ObjectRef]) -> Result< Vec< ( ObjectType, Vec< u8 > ) > > ;
2863456a Andy McCall 1 month ago ↶
129
130
131
fn checkpoint ( & self , heads : & [ChangeHash]) -> Result< Bundle> ;
132
133
fn shallow ( & self , heads : & [ChangeHash], depth : u32 ) -> Result< Vec< ChangeHash> > ;
132b884b Andy McCall 1 month ago ↶
134
135
136
75167672 Andy McCall 1 month ago
137
fn push (
138
& self ,
139
bundle : Bundle,
140
updates : Vec< RefUpdate> ,
141
policy : Option< SignedPolicy> ,
142
tags : Vec< TagRef> ,
143
) -> Result< Vec< RefResult> > ;
5b9c6ad4 Andy McCall 1 month ago ↶
144
}
145
750251b2 Andy McCall 1 month ago ↶
146
147
5b9c6ad4 Andy McCall 1 month ago ↶
148
149
pub struct LocalRemote {
150
pub repo : Repo,
84b9e9ac Andy McCall 1 month ago ↶
151
152
153
pub claimed_id : Option< [ u8 ; 16 ] > ,
5b9c6ad4 Andy McCall 1 month ago ↶
154
}
155
156
impl LocalRemote {
157
pub fn open ( path : & Path) -> Result< LocalRemote> {
75167672 Andy McCall 1 month ago
158
Ok ( LocalRemote {
159
repo: Repo:: open( path) ? ,
84b9e9ac Andy McCall 1 month ago ↶
160
claimed_id: None ,
75167672 Andy McCall 1 month ago
161
} )
5b9c6ad4 Andy McCall 1 month ago ↶
162
}
163
}
164
165
impl Remote for LocalRemote {
166
fn repo_id ( & self ) -> Result< [ u8 ; 16 ] > {
167
self .repo.id ( )
168
}
83e0677b Andy McCall 1 month ago ↶
169
fn refs ( & self ) -> Result< RefsResponse> {
5b9c6ad4 Andy McCall 1 month ago ↶
170
self .repo.remote_refs ( )
171
}
172
fn negotiate ( & self , have : & [ChangeHash], want : & [ChangeHash]) -> Result< Vec< ChangeHash> > {
173
self .repo.negotiate ( have, want)
174
}
b3c5a59a Andy McCall 1 month ago ↶
175
fn fetch ( & self , changes : & [ChangeHash], max_blob : Option< u64 > ) -> Result< Bundle> {
176
self .repo.bundle_for_filtered ( changes, max_blob)
177
}
178
fn objects ( & self , refs : & [ObjectRef]) -> Result< Vec< ( ObjectType, Vec< u8 > ) > > {
179
self .repo.objects_for ( refs)
5b9c6ad4 Andy McCall 1 month ago ↶
180
}
2863456a Andy McCall 1 month ago ↶
181
fn checkpoint ( & self , heads : & [ChangeHash]) -> Result< Bundle> {
182
self .repo.checkpoint_bundle_for ( heads)
183
}
184
fn shallow ( & self , heads : & [ChangeHash], depth : u32 ) -> Result< Vec< ChangeHash> > {
185
self .repo.shallow_changes ( heads, depth)
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> > {
84b9e9ac Andy McCall 1 month ago ↶
194
if self .repo.is_unbound ( ) {
195
match self .claimed_id {
196
Some ( id) => self .repo.bind_id ( id) ? ,
eae59556 Andy McCall 1 month ago ↶
197
None => {
198
return Err ( RepoError:: Msg(
199
" the remote is unbound and this client did not say which repository it is"
200
.into ( ) ,
201
) )
202
}
84b9e9ac Andy McCall 1 month ago ↶
203
}
204
}
132b884b Andy McCall 1 month ago ↶
205
self .repo.receive_push ( bundle, updates, policy, tags)
5b9c6ad4 Andy McCall 1 month ago ↶
206
}
207
}
208
750251b2 Andy McCall 1 month ago ↶
209
210
2b5ee371 Andy McCall 1 month ago ↶
211
212
# [ derive ( Clone, Debug, Default ) ]
213
pub struct RemoteOptions {
214
215
pub token : Option< String> ,
216
217
218
pub ca : Option< PathBuf> ,
75167672 Andy McCall 1 month ago
219
220
221
pub repo_id : Option< [ u8 ; 16 ] > ,
2b5ee371 Andy McCall 1 month ago ↶
222
}
223
75167672 Andy McCall 1 month ago
224
225
pub const REPO_ID_HEADER : & str = " Oxy-Repo-Id" ;
226
227
228
pub const UNBOUND_ID : [ u8 ; 16 ] = [ 0 ; 16 ] ;
229
750251b2 Andy McCall 1 month ago ↶
230
231
pub struct HttpRemote {
232
base : String,
233
token : Option< String> ,
75167672 Andy McCall 1 month ago
234
repo_id : Option< [ u8 ; 16 ] > ,
750251b2 Andy McCall 1 month ago ↶
235
agent : ureq:: Agent,
236
}
237
2b5ee371 Andy McCall 1 month ago ↶
238
239
fn tls_client_config ( ca : Option< & Path> ) -> Result< Arc< rustls:: ClientConfig> > {
240
let mut roots = rustls:: RootCertStore:: empty( ) ;
241
roots.extend ( webpki_roots:: TLS_SERVER_ROOTS .iter ( ) .cloned ( ) ) ;
242
if let Some ( path) = ca {
75167672 Andy McCall 1 month ago
243
let pem = std:: fs:: read( path)
244
.map_err ( | e | RepoError:: Msg( format! ( " reading CA file {} : {e} " , path.display ( ) ) ) ) ? ;
2b5ee371 Andy McCall 1 month ago ↶
245
let certs = rustls_pemfile:: certs( & mut pem.as_slice ( ) )
246
.collect:: < std:: result:: Result< Vec< _ > , _ > > ( )
247
.map_err ( | e | RepoError:: Msg( format! ( " parsing CA file {} : {e} " , path.display ( ) ) ) ) ? ;
248
if certs.is_empty ( ) {
75167672 Andy McCall 1 month ago
249
return Err ( RepoError:: Msg( format! (
250
" CA file {} holds no certificates" ,
251
path.display ( )
252
) ) ) ;
2b5ee371 Andy McCall 1 month ago ↶
253
}
254
for c in certs {
75167672 Andy McCall 1 month ago
255
roots
256
.add ( c)
257
.map_err ( | e | RepoError:: Msg( format! ( " CA file {} : {e} " , path.display ( ) ) ) ) ? ;
2b5ee371 Andy McCall 1 month ago ↶
258
}
259
}
75167672 Andy McCall 1 month ago
260
let cfg = rustls:: ClientConfig:: builder_with_provider( Arc:: new(
261
rustls:: crypto:: ring:: default_provider( ) ,
262
) )
263
.with_safe_default_protocol_versions ( )
264
.map_err ( | e | RepoError:: Msg( e.to_string ( ) ) ) ?
265
.with_root_certificates ( roots)
266
.with_no_client_auth ( ) ;
2b5ee371 Andy McCall 1 month ago ↶
267
Ok ( Arc:: new( cfg) )
268
}
269
750251b2 Andy McCall 1 month ago ↶
270
impl HttpRemote {
2b5ee371 Andy McCall 1 month ago ↶
271
pub fn new ( base : & str , options : & RemoteOptions) -> Result< HttpRemote> {
75167672 Andy McCall 1 month ago
272
let agent = ureq:: AgentBuilder:: new( )
273
.tls_config ( tls_client_config ( options.ca.as_deref ( ) ) ? )
274
.build ( ) ;
275
Ok ( HttpRemote {
276
base: base.trim_end_matches ( ' /' ) .to_string ( ) ,
277
token: options.token.clone ( ) ,
278
repo_id: options.repo_id,
279
agent,
280
} )
750251b2 Andy McCall 1 month ago ↶
281
}
282
283
fn call ( & self , post : bool , endpoint : & str , body : Option< & [ u8 ] > ) -> Result< Vec< u8 > > {
284
let url = format! ( " {} /oxy/v1/{endpoint} " , self .base) ;
75167672 Andy McCall 1 month ago
285
let mut req = if post {
286
self .agent.post ( & url)
287
} else {
288
self .agent.get ( & url)
289
} ;
750251b2 Andy McCall 1 month ago ↶
290
req = req.set ( " Accept" , CONTENT_TYPE ) ;
291
if let Some ( t) = & self .token {
292
req = req.set ( " Authorization" , & format! ( " Bearer {t} " ) ) ;
293
}
75167672 Andy McCall 1 month ago
294
if let Some ( id) = & self .repo_id {
295
req = req.set ( REPO_ID_HEADER , & hex:: encode( id) ) ;
296
}
750251b2 Andy McCall 1 month ago ↶
297
let resp = match body {
298
Some ( b) => req.set ( " Content-Type" , CONTENT_TYPE ) .send_bytes ( b) ,
299
None => req.call ( ) ,
300
} ;
301
match resp {
302
Ok ( r) => {
303
let mut out = Vec :: new( ) ;
75167672 Andy McCall 1 month ago
304
r.into_reader ( )
305
.read_to_end ( & mut out)
306
.map_err ( | e | RepoError:: Msg( format! ( " {url} : {e} " ) ) ) ? ;
750251b2 Andy McCall 1 month ago ↶
307
Ok ( out)
308
}
309
Err ( ureq:: Error:: Status( code, r) ) => {
310
let text = r.into_string ( ) .unwrap_or_default ( ) ;
3e5772cc Andy McCall 1 month ago ↶
311
let msg = format! ( " {url} : HTTP {code} : {} " , text.trim ( ) ) ;
312
Err ( RepoError:: Msg( with_hint ( msg) ) )
750251b2 Andy McCall 1 month ago ↶
313
}
3e5772cc Andy McCall 1 month ago ↶
314
315
Err ( e) => Err ( RepoError:: Msg( with_hint ( e.to_string ( ) ) ) ) ,
750251b2 Andy McCall 1 month ago ↶
316
}
317
}
318
}
319
3e5772cc Andy McCall 1 month ago ↶
320
321
pub fn hint_for ( message : & str ) -> Option< & 'static str > {
322
let m = message.to_ascii_lowercase ( ) ;
323
let hint = if m.contains ( " http 401" ) {
324
" the server did not accept the token: set one with `oxy config remote.<remote>.token TOKEN` (a personal access token; pushing needs repo:write)"
325
} else if m.contains ( " http 403" ) {
326
" the token or account lacks permission: pushing needs a token with repo:write and write access to the repository"
327
} else if m.contains ( " http 404" ) {
328
" nothing at this URL: check the owner and repository name, or create the repository on the hub first"
329
} else if m.contains ( " unknownissuer" )
330
| | m.contains ( " unknown issuer" )
331
| | m.contains ( " certificate" )
332
| | m.contains ( " invalidcertificate" )
333
{
334
" 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`"
335
} else if m.contains ( " connection refused" ) {
336
" nothing is listening there: check the URL and port, and that the server is running"
337
} else if m.contains ( " dns" )
338
| | m.contains ( " failed to lookup" )
339
| | m.contains ( " name or service not known" )
340
{
341
" the host name does not resolve: check the URL"
342
} else if m.contains ( " timed out" ) | | m.contains ( " timeout" ) {
343
" the server did not answer in time: check the network, or try again"
344
} else {
345
return None ;
346
} ;
347
Some ( hint)
348
}
349
350
351
pub fn with_hint ( message : String) -> String {
352
match hint_for ( & message) {
353
Some ( h) => format! ( " {message} \n hint: {h} " ) ,
354
None => message,
355
}
356
}
357
d82e4409 Andy McCall 1 month ago ↶
358
359
360
pub fn http_get ( url : & str , options : & RemoteOptions) -> Result< Vec< u8 > > {
361
let agent = ureq:: AgentBuilder:: new( )
362
.tls_config ( tls_client_config ( options.ca.as_deref ( ) ) ? )
363
.build ( ) ;
364
let mut req = agent.get ( url) .set ( " Accept" , " application/json" ) ;
365
if let Some ( t) = & options.token {
366
req = req.set ( " Authorization" , & format! ( " Bearer {t} " ) ) ;
367
}
368
match req.call ( ) {
369
Ok ( r) => {
370
let mut out = Vec :: new( ) ;
371
r.into_reader ( )
372
.read_to_end ( & mut out)
373
.map_err ( | e | RepoError:: Msg( format! ( " {url} : {e} " ) ) ) ? ;
374
Ok ( out)
375
}
376
Err ( ureq:: Error:: Status( code, r) ) => {
377
let text = r.into_string ( ) .unwrap_or_default ( ) ;
3e5772cc Andy McCall 1 month ago ↶
378
Err ( RepoError:: Msg( with_hint ( format! (
4213c41d Andy McCall 1 month ago ↶
379
" {url} : HTTP {code} : {} " ,
380
text.trim ( )
3e5772cc Andy McCall 1 month ago ↶
381
) ) ) )
d82e4409 Andy McCall 1 month ago ↶
382
}
3e5772cc Andy McCall 1 month ago ↶
383
384
Err ( e) => Err ( RepoError:: Msg( with_hint ( e.to_string ( ) ) ) ) ,
d82e4409 Andy McCall 1 month ago ↶
385
}
386
}
387
750251b2 Andy McCall 1 month ago ↶
388
impl Remote for HttpRemote {
389
fn repo_id ( & self ) -> Result< [ u8 ; 16 ] > {
390
wire:: decode_capabilities( & self .call ( false , " capabilities" , None ) ? )
391
}
83e0677b Andy McCall 1 month ago ↶
392
fn refs ( & self ) -> Result< RefsResponse> {
750251b2 Andy McCall 1 month ago ↶
393
Ok ( wire:: decode_refs( & self .call ( false , " refs" , None ) ? ) ? .1 )
394
}
395
fn negotiate ( & self , have : & [ChangeHash], want : & [ChangeHash]) -> Result< Vec< ChangeHash> > {
75167672 Andy McCall 1 month ago
396
wire:: decode_hashes( & self .call (
397
true ,
398
" negotiate" ,
399
Some ( & wire:: encode_negotiate( have, want) ) ,
400
) ? )
750251b2 Andy McCall 1 month ago ↶
401
}
b3c5a59a Andy McCall 1 month ago ↶
402
fn fetch ( & self , changes : & [ChangeHash], max_blob : Option< u64 > ) -> Result< Bundle> {
75167672 Andy McCall 1 month ago
403
wire:: decode_bundle( & self .call (
404
true ,
405
" fetch" ,
406
Some ( & wire:: encode_fetch( changes, max_blob) ) ,
407
) ? )
750251b2 Andy McCall 1 month ago ↶
408
}
b3c5a59a Andy McCall 1 month ago ↶
409
fn objects ( & self , refs : & [ObjectRef]) -> Result< Vec< ( ObjectType, Vec< u8 > ) > > {
75167672 Andy McCall 1 month ago
410
Ok (
411
wire:: decode_bundle( & self .call ( true , " objects" , Some ( & wire:: encode_hashes( refs) ) ) ? ) ?
412
.objects,
413
)
b3c5a59a Andy McCall 1 month ago ↶
414
}
2863456a Andy McCall 1 month ago ↶
415
fn checkpoint ( & self , heads : & [ChangeHash]) -> Result< Bundle> {
416
wire:: decode_bundle( & self .call ( true , " checkpoint" , Some ( & wire:: encode_hashes( heads) ) ) ? )
417
}
418
fn shallow ( & self , heads : & [ChangeHash], depth : u32 ) -> Result< Vec< ChangeHash> > {
75167672 Andy McCall 1 month ago
419
wire:: decode_hashes( & self .call (
420
true ,
421
" shallow" ,
422
Some ( & wire:: encode_shallow( heads, depth) ) ,
423
) ? )
2863456a Andy McCall 1 month ago ↶
424
}
75167672 Andy McCall 1 month ago
425
fn push (
426
& self ,
427
bundle : Bundle,
428
updates : Vec< RefUpdate> ,
429
policy : Option< SignedPolicy> ,
430
tags : Vec< TagRef> ,
431
) -> Result< Vec< RefResult> > {
432
wire:: decode_push_response( & self .call (
433
true ,
434
" push" ,
435
Some ( & wire:: encode_push(
436
& bundle,
437
& updates,
438
policy.as_ref ( ) ,
439
& tags,
440
) ) ,
441
) ? )
750251b2 Andy McCall 1 month ago ↶
442
}
443
}
444
445
2b5ee371 Andy McCall 1 month ago ↶
446
pub fn open_remote ( url : & str , options : & RemoteOptions) -> Result< Box< dyn Remote> > {
750251b2 Andy McCall 1 month ago ↶
447
if url.starts_with ( " http://" ) | | url.starts_with ( " https://" ) {
2b5ee371 Andy McCall 1 month ago ↶
448
return Ok ( Box :: new( HttpRemote:: new( url, options) ? ) ) ;
750251b2 Andy McCall 1 month ago ↶
449
}
5b9c6ad4 Andy McCall 1 month ago ↶
450
let path = url.strip_prefix ( " file://" ) .unwrap_or ( url) ;
451
if path.contains ( " ://" ) {
750251b2 Andy McCall 1 month ago ↶
452
return Err ( RepoError:: Msg( format! ( " unsupported remote URL {url:?} " ) ) ) ;
5b9c6ad4 Andy McCall 1 month ago ↶
453
}
84b9e9ac Andy McCall 1 month ago ↶
454
let mut local = LocalRemote:: open( Path:: new( path) ) ? ;
455
local.claimed_id = options.repo_id;
456
Ok ( Box :: new( local) )
5b9c6ad4 Andy McCall 1 month ago ↶
457
}
750251b2 Andy McCall 1 month ago ↶
458
459
460
461
462
pub mod wire {
463
use super :: * ;
464
465
fn schema ( msg : & str ) -> RepoError {
466
RepoError:: Object( ObjectError:: Schema( msg.into ( ) ) )
467
}
468
fn sigs_value ( sigs : & [Signature]) -> Value {
469
Value:: Array( sigs.iter ( ) .map ( | s | s.to_value ( ) ) .collect ( ) )
470
}
471
fn sigs_from ( v : & Value) -> Result< Vec< Signature> > {
75167672 Andy McCall 1 month ago
472
Ok ( o:: array( v, " signatures" ) ?
473
.iter ( )
474
.map ( Signature:: from_value)
475
.collect:: < std:: result:: Result< Vec< _ > , _ > > ( ) ? )
750251b2 Andy McCall 1 month ago ↶
476
}
477
fn hashes_value ( hs : & [ObjectRef]) -> Value {
478
Value:: Array( hs.iter ( ) .map ( | h | Value:: Bytes( h.0. to_vec ( ) ) ) .collect ( ) )
479
}
480
fn hashes_from ( v : & Value) -> Result< Vec< ObjectRef> > {
75167672 Andy McCall 1 month ago
481
Ok ( o:: array( v, " hashes" ) ?
482
.iter ( )
483
.map ( | h | o:: oref( h, " hash" ) )
484
.collect:: < std:: result:: Result< Vec< _ > , _ > > ( ) ? )
750251b2 Andy McCall 1 month ago ↶
485
}
486
fn attest_value ( sa : & SignedAttest) -> Value {
487
Value:: Array( vec! [ Value:: Bytes( sa.attest.encode ( ) ) , sigs_value ( & sa.sigs) ] )
488
}
489
fn attest_from ( v : & Value) -> Result< SignedAttest> {
490
let a = o:: array( v, " signed attest" ) ? ;
491
if a.len ( ) ! = 2 {
492
return Err ( schema ( " signed attest: expected [attest, sigs]" ) ) ;
493
}
75167672 Andy McCall 1 month ago
494
Ok ( SignedAttest {
495
attest: Attest:: decode( o:: bytes( & a[ 0 ] , " attest" ) ? ) ? ,
496
sigs: sigs_from ( & a[ 1 ] ) ? ,
497
} )
750251b2 Andy McCall 1 month ago ↶
498
}
499
fn opt_attest_value ( sa : & Option< SignedAttest> ) -> Value {
500
sa.as_ref ( ) .map ( attest_value) .unwrap_or ( Value:: Null)
501
}
502
fn opt_attest_from ( v : & Value) -> Result< Option< SignedAttest> > {
75167672 Andy McCall 1 month ago
503
if v.is_null ( ) {
504
Ok ( None )
505
} else {
506
attest_from ( v) .map ( Some )
507
}
750251b2 Andy McCall 1 month ago ↶
508
}
28fc23d7 Andy McCall 1 month ago ↶
509
510
511
pub fn policy_value ( sp : & SignedPolicy) -> Value {
512
Value:: Array( vec! [ Value:: Bytes( sp.policy.encode ( ) ) , sigs_value ( & sp.sigs) ] )
83e0677b Andy McCall 1 month ago ↶
513
}
28fc23d7 Andy McCall 1 month ago ↶
514
pub fn policy_from ( v : & Value) -> Result< SignedPolicy> {
83e0677b Andy McCall 1 month ago ↶
515
let a = o:: array( v, " signed policy" ) ? ;
516
if a.len ( ) ! = 2 {
517
return Err ( schema ( " signed policy: expected [policy, sigs]" ) ) ;
518
}
75167672 Andy McCall 1 month ago
519
Ok ( SignedPolicy {
520
policy: Policy:: decode( o:: bytes( & a[ 0 ] , " policy" ) ? ) ? ,
521
sigs: sigs_from ( & a[ 1 ] ) ? ,
522
} )
28fc23d7 Andy McCall 1 month ago ↶
523
}
524
fn opt_policy_value ( sp : Option< & SignedPolicy> ) -> Value {
525
sp.map ( policy_value) .unwrap_or ( Value:: Null)
526
}
527
fn opt_policy_from ( v : & Value) -> Result< Option< SignedPolicy> > {
75167672 Andy McCall 1 month ago
528
if v.is_null ( ) {
529
Ok ( None )
530
} else {
531
policy_from ( v) .map ( Some )
532
}
83e0677b Andy McCall 1 month ago ↶
533
}
750251b2 Andy McCall 1 month ago ↶
534
fn map < 'a > ( v : & 'a Value, what : & str ) -> Result< & 'a o:: Map> {
535
Ok ( o:: map( v, what) ? )
536
}
537
fn field < 'a > ( m : & 'a o:: Map, k : u64 , what : & str ) -> Result< & 'a Value> {
538
Ok ( o:: field( m, k, what) ? )
539
}
540
6f8aeb99 Andy McCall 1 month ago ↶
541
542
543
750251b2 Andy McCall 1 month ago ↶
544
pub fn bundle_value ( b : & Bundle) -> Value {
6f8aeb99 Andy McCall 1 month ago ↶
545
let mut changes = Vec :: with_capacity( b.changes.len ( ) ) ;
546
let mut texts: Vec< ( ObjectType, Vec< u8 > ) > = Vec :: new( ) ;
547
let mut listed: Option< std:: collections:: HashSet< ObjectRef> > = None ;
548
for ( c, s) in & b.changes {
549
let ( bytes, stored) = c.encode_parts ( ) ;
550
for t in stored {
551
let listed = listed.get_or_insert_with ( | | {
552
b.objects
553
.iter ( )
554
.map ( | ( ty , body ) | crate :: hash:: hash_object( * ty, body) )
555
.collect ( )
556
} ) ;
557
if ! listed.insert ( t.blob.hash ( ) ) {
558
continue ;
559
}
560
for chunk in crate :: chunk:: chunks( & t.content) {
561
if listed.insert ( crate :: hash:: hash_object( ObjectType:: Chunk, chunk) ) {
562
texts.push ( ( ObjectType:: Chunk, chunk.to_vec ( ) ) ) ;
563
}
564
}
565
texts.push ( ( ObjectType:: Blob, t.blob.encode ( ) ) ) ;
566
}
567
changes.push ( Value:: Array( vec! [ Value:: Bytes( bytes) , sigs_value ( s) ] ) ) ;
568
}
750251b2 Andy McCall 1 month ago ↶
569
Value:: map( [
6f8aeb99 Andy McCall 1 month ago ↶
570
( 0 , Value:: Array( changes) ) ,
750251b2 Andy McCall 1 month ago ↶
571
(
75167672 Andy McCall 1 month ago
572
1 ,
573
Value:: Array( b.attests.iter ( ) .map ( attest_value) .collect ( ) ) ,
574
) ,
575
(
750251b2 Andy McCall 1 month ago ↶
576
2 ,
577
Value:: Array(
75167672 Andy McCall 1 month ago
578
b.objects
579
.iter ( )
6f8aeb99 Andy McCall 1 month ago ↶
580
.chain ( & texts)
75167672 Andy McCall 1 month ago
581
.map ( | ( t , body ) | {
582
Value:: Array( vec! [
583
Value:: Text( t.name ( ) .into ( ) ) ,
584
Value:: Bytes( body.clone ( ) ) ,
585
] )
586
} )
587
.collect ( ) ,
750251b2 Andy McCall 1 month ago ↶
588
) ,
589
) ,
75167672 Andy McCall 1 month ago
590
(
591
3 ,
592
Value:: Array( b.policies.iter ( ) .map ( policy_value) .collect ( ) ) ,
593
) ,
750251b2 Andy McCall 1 month ago ↶
594
] )
595
}
596
597
pub fn bundle_from_value ( v : & Value) -> Result< Bundle> {
598
let m = map ( v, " bundle" ) ? ;
599
let mut b = Bundle:: default( ) ;
600
for ob in o:: array( field ( m, 2 , " objects" ) ? , " objects" ) ? {
601
let pair = o:: array( ob, " object" ) ? ;
602
if pair.len ( ) ! = 2 {
603
return Err ( schema ( " object: expected [type, body]" ) ) ;
604
}
75167672 Andy McCall 1 month ago
605
let ty = ObjectType:: from_name( o:: text( & pair[ 0 ] , " object type" ) ? )
606
.ok_or_else ( | | schema ( " unknown object type" ) ) ? ;
607
b.objects
608
.push ( ( ty, o:: bytes( & pair[ 1 ] , " object body" ) ? .to_vec ( ) ) ) ;
6f8aeb99 Andy McCall 1 month ago ↶
609
}
610
611
let mut by_ref: Option< std:: collections:: HashMap< ObjectRef, usize > > = None ;
612
for c in o:: array( field ( m, 0 , " changes" ) ? , " changes" ) ? {
613
let pair = o:: array( c, " change entry" ) ? ;
614
if pair.len ( ) ! = 2 {
615
return Err ( schema ( " change entry: expected [change, sigs]" ) ) ;
616
}
598009a7 Andy McCall 1 month ago ↶
617
let encoded = o:: bytes( & pair[ 0 ] , " change" ) ? ;
618
b.hashes
619
.push ( crate :: hash:: hash_object( ObjectType:: Change, encoded) ) ;
620
let change = Change:: decode_with( encoded, & mut | text, count| {
6f8aeb99 Andy McCall 1 month ago ↶
621
let by_ref = by_ref.get_or_insert_with ( | | {
622
b.objects
623
.iter ( )
624
.enumerate ( )
625
.map ( | ( i , (ty , body ) ) | ( crate :: hash:: hash_object( * ty, body) , i) )
626
.collect ( )
627
} ) ;
628
let get =
629
| r : & ObjectRef, want : ObjectType| match by_ref.get ( r) .map ( | i | & b.objects[ * i] ) {
630
Some ( ( ty, body) ) if * ty = = want => Ok ( body) ,
631
_ => Err ( ObjectError:: Schema( format! (
632
" the bundle lacks {} {} " ,
633
want.name ( ) ,
634
r.short ( 12 )
635
) ) ) ,
636
} ;
637
let blob = crate :: objects:: Blob:: decode( get ( text, ObjectType:: Blob) ? ) ? ;
638
let mut content = Vec :: with_capacity( blob.length as usize ) ;
639
for chunk in & blob.chunks {
640
content.extend_from_slice ( get ( chunk, ObjectType:: Chunk) ? ) ;
641
}
642
crate :: objects:: text_lines( & content, count)
643
} ) ? ;
644
b.changes.push ( ( change, sigs_from ( & pair[ 1 ] ) ? ) ) ;
645
}
646
for a in o:: array( field ( m, 1 , " attests" ) ? , " attests" ) ? {
647
b.attests.push ( attest_from ( a) ? ) ;
750251b2 Andy McCall 1 month ago ↶
648
}
28fc23d7 Andy McCall 1 month ago ↶
649
if let Some ( ps) = m.get ( & 3 ) {
650
for p in o:: array( ps, " policies" ) ? {
651
b.policies.push ( policy_from ( p) ? ) ;
652
}
653
}
750251b2 Andy McCall 1 month ago ↶
654
Ok ( b)
655
}
656
657
pub fn encode_bundle ( b : & Bundle) -> Vec< u8 > {
658
cbor:: encode( & bundle_value ( b) )
659
}
660
pub fn decode_bundle ( bytes : & [u8 ]) -> Result< Bundle> {
661
bundle_from_value ( & cbor:: decode( bytes) .map_err ( ObjectError:: from) ? )
662
}
663
664
pub fn encode_capabilities ( id : [u8 ; 16]) -> Vec< u8 > {
665
cbor:: encode( & Value:: map( [
666
( 0 , Value:: Array( vec! [ Value:: Uint( PROTOCOL_VERSION ) ] ) ) ,
667
( 1 , Value:: Bytes( id.to_vec ( ) ) ) ,
668
( 2 , Value:: Array( vec! [ Value:: Text( " seal" .into ( ) ) ] ) ) ,
669
] ) )
670
}
671
pub fn decode_capabilities ( bytes : & [u8 ]) -> Result< [ u8 ; 16 ] > {
672
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
673
let m = map ( & v, " capabilities" ) ? ;
674
let versions = o:: array( field ( m, 0 , " versions" ) ? , " versions" ) ? ;
75167672 Andy McCall 1 month ago
675
if ! versions
676
.iter ( )
677
.any ( | x | x.as_uint ( ) = = Some ( PROTOCOL_VERSION ) )
678
{
679
return Err ( RepoError:: Msg(
680
" remote does not speak protocol version 1" .into ( ) ,
681
) ) ;
750251b2 Andy McCall 1 month ago ↶
682
}
75167672 Andy McCall 1 month ago
683
o:: bytes( field ( m, 1 , " repo id" ) ? , " repo id" ) ?
684
.try_into ( )
685
.map_err ( | _| schema ( " repo id: expected 16 bytes" ) )
750251b2 Andy McCall 1 month ago ↶
686
}
687
132b884b Andy McCall 1 month ago ↶
688
fn tags_value ( tags : & [TagRef]) -> Value {
689
Value:: Array(
690
tags.iter ( )
691
.map ( | t | {
692
Value:: map( [
693
( 0 , Value:: Text( t.name.clone ( ) ) ) ,
694
( 1 , Value:: Bytes( t.state.0. to_vec ( ) ) ) ,
695
( 2 , hashes_value ( & t.heads) ) ,
696
( 3 , opt_attest_value ( & t.attestation) ) ,
697
] )
698
} )
699
.collect ( ) ,
700
)
701
}
702
fn tags_from ( v : & Value) -> Result< Vec< TagRef> > {
703
let mut out = Vec :: new( ) ;
704
for t in o:: array( v, " tags" ) ? {
705
let tm = map ( t, " tag" ) ? ;
706
out.push ( TagRef {
707
name: o:: text( field ( tm, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
708
state: o:: oref( field ( tm, 1 , " state" ) ? , " state" ) ? ,
709
heads: hashes_from ( field ( tm, 2 , " heads" ) ? ) ? ,
710
attestation: opt_attest_from ( field ( tm, 3 , " attestation" ) ? ) ? ,
711
} ) ;
712
}
713
Ok ( out)
714
}
715
83e0677b Andy McCall 1 month ago ↶
716
pub fn encode_refs ( id : [u8 ; 16], resp : & RefsResponse) -> Vec< u8 > {
750251b2 Andy McCall 1 month ago ↶
717
cbor:: encode( & Value:: map( [
718
(
719
0 ,
720
Value:: Array(
83e0677b Andy McCall 1 month ago ↶
721
resp.refs
722
.iter ( )
750251b2 Andy McCall 1 month ago ↶
723
.map ( | r | {
724
Value:: map( [
725
( 0 , Value:: Text( r.name.clone ( ) ) ) ,
726
( 1 , Value:: Bytes( r.state.0. to_vec ( ) ) ) ,
727
( 2 , hashes_value ( & r.heads) ) ,
728
( 3 , opt_attest_value ( & r.attestation) ) ,
729
( 4 , r.last_serial.map ( Value:: Uint) .unwrap_or ( Value:: Null) ) ,
730
] )
731
} )
732
.collect ( ) ,
733
) ,
734
) ,
735
( 1 , Value:: Bytes( id.to_vec ( ) ) ) ,
83e0677b Andy McCall 1 month ago ↶
736
( 2 , opt_policy_value ( resp.policy.as_ref ( ) ) ) ,
132b884b Andy McCall 1 month ago ↶
737
( 3 , tags_value ( & resp.tags) ) ,
75167672 Andy McCall 1 month ago
738
(
739
4 ,
740
Value:: Array( resp.history.iter ( ) .map ( policy_value) .collect ( ) ) ,
741
) ,
750251b2 Andy McCall 1 month ago ↶
742
] ) )
743
}
83e0677b Andy McCall 1 month ago ↶
744
pub fn decode_refs ( bytes : & [u8 ]) -> Result< ( [u8 ; 16], RefsResponse) > {
750251b2 Andy McCall 1 month ago ↶
745
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
746
let m = map ( & v, " refs" ) ? ;
75167672 Andy McCall 1 month ago
747
let id: [ u8 ; 16 ] = o:: bytes( field ( m, 1 , " repo id" ) ? , " repo id" ) ?
748
.try_into ( )
749
.map_err ( | _| schema ( " repo id: expected 16 bytes" ) ) ? ;
750251b2 Andy McCall 1 month ago ↶
750
let mut refs = Vec :: new( ) ;
751
for r in o:: array( field ( m, 0 , " refs" ) ? , " refs" ) ? {
752
let rm = map ( r, " ref" ) ? ;
753
let ls = field ( rm, 4 , " last serial" ) ? ;
754
refs.push ( RemoteRef {
755
name: o:: text( field ( rm, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
756
state: o:: oref( field ( rm, 1 , " state" ) ? , " state" ) ? ,
757
heads: hashes_from ( field ( rm, 2 , " heads" ) ? ) ? ,
758
attestation: opt_attest_from ( field ( rm, 3 , " attestation" ) ? ) ? ,
75167672 Andy McCall 1 month ago
759
last_serial: if ls.is_null ( ) {
760
None
761
} else {
762
Some ( o:: uint( ls, " last serial" ) ? )
763
} ,
750251b2 Andy McCall 1 month ago ↶
764
} ) ;
765
}
83e0677b Andy McCall 1 month ago ↶
766
let policy = match m.get ( & 2 ) {
767
Some ( p) => opt_policy_from ( p) ? ,
768
None => None ,
769
} ;
132b884b Andy McCall 1 month ago ↶
770
let tags = match m.get ( & 3 ) {
771
Some ( t) => tags_from ( t) ? ,
772
None => Vec :: new( ) ,
773
} ;
28fc23d7 Andy McCall 1 month ago ↶
774
let mut history = Vec :: new( ) ;
775
if let Some ( h) = m.get ( & 4 ) {
776
for p in o:: array( h, " history" ) ? {
777
history.push ( policy_from ( p) ? ) ;
778
}
779
}
75167672 Andy McCall 1 month ago
780
Ok ( (
781
id,
782
RefsResponse {
783
refs,
784
policy,
785
tags,
786
history,
787
} ,
788
) )
750251b2 Andy McCall 1 month ago ↶
789
}
790
791
pub fn encode_negotiate ( have : & [ChangeHash], want : & [ChangeHash]) -> Vec< u8 > {
75167672 Andy McCall 1 month ago
792
cbor:: encode( & Value:: map( [
793
( 0 , hashes_value ( have) ) ,
794
( 1 , hashes_value ( want) ) ,
795
] ) )
750251b2 Andy McCall 1 month ago ↶
796
}
797
pub fn decode_negotiate ( bytes : & [u8 ]) -> Result< ( Vec< ChangeHash> , Vec< ChangeHash> ) > {
798
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
799
let m = map ( & v, " negotiate" ) ? ;
75167672 Andy McCall 1 month ago
800
Ok ( (
801
hashes_from ( field ( m, 0 , " have" ) ? ) ? ,
802
hashes_from ( field ( m, 1 , " want" ) ? ) ? ,
803
) )
750251b2 Andy McCall 1 month ago ↶
804
}
805
b3c5a59a Andy McCall 1 month ago ↶
806
807
pub fn encode_fetch ( hs : & [ChangeHash], max_blob : Option< u64 > ) -> Vec< u8 > {
75167672 Andy McCall 1 month ago
808
cbor:: encode( & Value:: map( [
809
( 0 , hashes_value ( hs) ) ,
810
( 1 , max_blob.map ( Value:: Uint) .unwrap_or ( Value:: Null) ) ,
811
] ) )
b3c5a59a Andy McCall 1 month ago ↶
812
}
813
pub fn decode_fetch ( bytes : & [u8 ]) -> Result< ( Vec< ChangeHash> , Option< u64 > ) > {
814
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
815
let m = map ( & v, " fetch" ) ? ;
816
let max = match m.get ( & 1 ) {
817
Some ( x) if ! x.is_null ( ) => Some ( o:: uint( x, " max blob" ) ? ) ,
818
_ => None ,
819
} ;
820
Ok ( ( hashes_from ( field ( m, 0 , " changes" ) ? ) ? , max) )
821
}
822
2863456a Andy McCall 1 month ago ↶
823
824
pub fn encode_shallow ( hs : & [ChangeHash], depth : u32 ) -> Vec< u8 > {
75167672 Andy McCall 1 month ago
825
cbor:: encode( & Value:: map( [
826
( 0 , hashes_value ( hs) ) ,
827
( 1 , Value:: Uint( depth as u64 ) ) ,
828
] ) )
2863456a Andy McCall 1 month ago ↶
829
}
830
pub fn decode_shallow ( bytes : & [u8 ]) -> Result< ( Vec< ChangeHash> , u32 ) > {
831
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
832
let m = map ( & v, " shallow" ) ? ;
75167672 Andy McCall 1 month ago
833
Ok ( (
834
hashes_from ( field ( m, 0 , " heads" ) ? ) ? ,
835
o:: u32_( field ( m, 1 , " depth" ) ? , " depth" ) ? ,
836
) )
2863456a Andy McCall 1 month ago ↶
837
}
838
750251b2 Andy McCall 1 month ago ↶
839
pub fn encode_hashes ( hs : & [ChangeHash]) -> Vec< u8 > {
840
cbor:: encode( & Value:: map( [ ( 0 , hashes_value ( hs) ) ] ) )
841
}
842
pub fn decode_hashes ( bytes : & [u8 ]) -> Result< Vec< ChangeHash> > {
843
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
844
hashes_from ( field ( map ( & v, " hashes" ) ? , 0 , " hashes" ) ? )
845
}
846
75167672 Andy McCall 1 month ago
847
pub fn encode_push (
848
bundle : & Bundle,
849
updates : & [RefUpdate],
850
policy : Option< & SignedPolicy> ,
851
tags : & [TagRef],
852
) -> Vec< u8 > {
750251b2 Andy McCall 1 month ago ↶
853
cbor:: encode( & Value:: map( [
854
( 0 , bundle_value ( bundle) ) ,
83e0677b Andy McCall 1 month ago ↶
855
( 2 , opt_policy_value ( policy) ) ,
132b884b Andy McCall 1 month ago ↶
856
( 3 , tags_value ( tags) ) ,
750251b2 Andy McCall 1 month ago ↶
857
(
858
1 ,
859
Value:: Array(
860
updates
861
.iter ( )
862
.map ( | u | {
863
Value:: map( [
864
( 0 , Value:: Text( u.name.clone ( ) ) ) ,
865
( 1 , Value:: Bytes( u.old_state.0. to_vec ( ) ) ) ,
866
( 2 , Value:: Bytes( u.new_state.0. to_vec ( ) ) ) ,
867
( 3 , Value:: Bool( u.force) ) ,
868
( 4 , opt_attest_value ( & u.attestation) ) ,
869
] )
870
} )
871
.collect ( ) ,
872
) ,
873
) ,
874
] ) )
875
}
132b884b Andy McCall 1 month ago ↶
876
877
pub type PushParts = ( Bundle, Vec< RefUpdate> , Option< SignedPolicy> , Vec< TagRef> ) ;
878
879
pub fn decode_push ( bytes : & [u8 ]) -> Result< PushParts> {
750251b2 Andy McCall 1 month ago ↶
880
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
881
let m = map ( & v, " push" ) ? ;
882
let bundle = bundle_from_value ( field ( m, 0 , " bundle" ) ? ) ? ;
883
let mut updates = Vec :: new( ) ;
884
for u in o:: array( field ( m, 1 , " updates" ) ? , " updates" ) ? {
885
let um = map ( u, " update" ) ? ;
886
updates.push ( RefUpdate {
887
name: o:: text( field ( um, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
888
old_state: o:: oref( field ( um, 1 , " old_state" ) ? , " old_state" ) ? ,
889
new_state: o:: oref( field ( um, 2 , " new_state" ) ? , " new_state" ) ? ,
75167672 Andy McCall 1 month ago
890
force: field ( um, 3 , " force" ) ?
891
.as_bool ( )
892
.ok_or_else ( | | schema ( " force: expected bool" ) ) ? ,
750251b2 Andy McCall 1 month ago ↶
893
attestation: opt_attest_from ( field ( um, 4 , " attestation" ) ? ) ? ,
894
} ) ;
895
}
83e0677b Andy McCall 1 month ago ↶
896
let policy = match m.get ( & 2 ) {
897
Some ( p) => opt_policy_from ( p) ? ,
898
None => None ,
899
} ;
132b884b Andy McCall 1 month ago ↶
900
let tags = match m.get ( & 3 ) {
901
Some ( t) => tags_from ( t) ? ,
902
None => Vec :: new( ) ,
903
} ;
904
Ok ( ( bundle, updates, policy, tags) )
750251b2 Andy McCall 1 month ago ↶
905
}
906
907
pub fn encode_push_response ( results : & [RefResult]) -> Vec< u8 > {
908
cbor:: encode( & Value:: map( [ (
909
0 ,
910
Value:: Array(
911
results
912
.iter ( )
75167672 Andy McCall 1 month ago
913
.map ( | r | {
914
Value:: map( [
915
( 0 , Value:: Text( r.name.clone ( ) ) ) ,
916
( 1 , Value:: Bool( r.ok) ) ,
917
( 2 , Value:: Text( r.reason.clone ( ) ) ) ,
918
] )
919
} )
750251b2 Andy McCall 1 month ago ↶
920
.collect ( ) ,
921
) ,
922
) ] ) )
923
}
924
pub fn decode_push_response ( bytes : & [u8 ]) -> Result< Vec< RefResult> > {
925
let v = cbor:: decode( bytes) .map_err ( ObjectError:: from) ? ;
926
let m = map ( & v, " push response" ) ? ;
927
let mut out = Vec :: new( ) ;
928
for r in o:: array( field ( m, 0 , " results" ) ? , " results" ) ? {
929
let rm = map ( r, " result" ) ? ;
930
out.push ( RefResult {
931
name: o:: text( field ( rm, 0 , " name" ) ? , " name" ) ? .to_owned ( ) ,
75167672 Andy McCall 1 month ago
932
ok: field ( rm, 1 , " ok" ) ?
933
.as_bool ( )
934
.ok_or_else ( | | schema ( " ok: expected bool" ) ) ? ,
750251b2 Andy McCall 1 month ago ↶
935
reason: o:: text( field ( rm, 2 , " reason" ) ? , " reason" ) ? .to_owned ( ) ,
936
} ) ;
937
}
938
Ok ( out)
939
}
940
}
941
942
# [ cfg ( test ) ]
943
mod tests {
944
use super :: * ;
945
use crate :: attest:: AttestBody;
946
use crate :: objects:: Hlc;
947
948
# [ test ]
949
fn wire_round_trips ( ) {
950
let c = crate :: objects:: tests:: sample_change( ) ;
75167672 Andy McCall 1 month ago
951
let sk = crate :: identity:: SecretKey {
952
ed_seed: [ 1 ; 32 ] ,
953
ml_seed: [ 2 ; 32 ] ,
954
} ;
750251b2 Andy McCall 1 month ago ↶
955
let id = sk.identity ( " a" , " b" , 0 ) ;
956
let key = id.hash ( ) ;
957
let sig = sk.sign ( crate :: identity:: Domain:: Change, & key, & c.hash ( ) ) ;
958
let seal = Attest:: seal( [ 3 ; 16 ] , vec! [ c.hash ( ) ] ) ;
959
let seal_sig = sk.sign ( crate :: identity:: Domain:: Attest, & key, & seal.hash ( ) ) ;
28fc23d7 Andy McCall 1 month ago ↶
960
let policy = Policy:: single_root( [ 3 ; 16 ] , id.clone ( ) , 99 ) ;
961
let psig = sk.sign ( crate :: identity:: Domain:: Policy, & key, & policy.hash ( ) ) ;
750251b2 Andy McCall 1 month ago ↶
962
let bundle = Bundle {
963
changes: vec! [ ( c.clone ( ) , vec! [ sig.clone ( ) ] ) ] ,
75167672 Andy McCall 1 month ago
964
attests: vec! [ SignedAttest {
965
attest: seal.clone ( ) ,
966
sigs: vec! [ seal_sig] ,
967
} ] ,
968
objects: vec! [
969
( ObjectType:: Identity, id.encode ( ) ) ,
970
( ObjectType:: Chunk, b " xyz" .to_vec ( ) ) ,
971
] ,
972
policies: vec! [ SignedPolicy {
973
policy: policy.clone ( ) ,
974
sigs: vec! [ psig.clone ( ) ] ,
975
} ] ,
598009a7 Andy McCall 1 month ago ↶
976
hashes: vec! [ ] ,
750251b2 Andy McCall 1 month ago ↶
977
} ;
978
let d = wire:: decode_bundle( & wire:: encode_bundle( & bundle) ) .unwrap ( ) ;
598009a7 Andy McCall 1 month ago ↶
979
assert_eq! (
980
d.hashes,
981
vec! [ c.hash ( ) ] ,
982
" the receiver hashes what it was sent"
983
) ;
750251b2 Andy McCall 1 month ago ↶
984
assert_eq! ( d.changes, bundle.changes) ;
985
assert_eq! ( d.attests, bundle.attests) ;
986
assert_eq! ( d.objects, bundle.objects) ;
28fc23d7 Andy McCall 1 month ago ↶
987
assert_eq! ( d.policies, bundle.policies) ;
750251b2 Andy McCall 1 month ago ↶
988
75167672 Andy McCall 1 month ago
989
let att = Attest {
990
repo: [ 3 ; 16 ] ,
991
hlc: Hlc:: default( ) ,
992
body: AttestBody:: Ref {
993
name: " main" .into ( ) ,
994
old_state: ObjectRef( [ 1 ; 32 ] ) ,
995
new_state: ObjectRef( [ 2 ; 32 ] ) ,
996
serial: 4 ,
997
} ,
998
} ;
750251b2 Andy McCall 1 month ago ↶
999
let refs = vec! [
75167672 Andy McCall 1 month ago
1000
RemoteRef {
1001
name: " main" .into ( ) ,
1002
state: ObjectRef( [ 2 ; 32 ] ) ,
1003
heads: vec! [ c.hash ( ) ] ,
1004
attestation: Some ( SignedAttest {
1005
attest: att.clone ( ) ,
1006
sigs: vec! [ sig.clone ( ) ] ,
1007
} ) ,
1008
last_serial: Some ( 4 ) ,
1009
} ,
1010
RemoteRef {
1011
name: " dev" .into ( ) ,
1012
state: ObjectRef( [ 5 ; 32 ] ) ,
1013
heads: vec! [ ] ,
1014
attestation: None ,
1015
last_serial: None ,
1016
} ,
750251b2 Andy McCall 1 month ago ↶
1017
] ;
75167672 Andy McCall 1 month ago
1018
let tag = TagRef {
1019
name: " v1" .into ( ) ,
1020
state: ObjectRef( [ 2 ; 32 ] ) ,
1021
heads: vec! [ c.hash ( ) ] ,
1022
attestation: None ,
1023
} ;
1024
let resp = RefsResponse {
1025
refs,
1026
policy: Some ( SignedPolicy {
1027
policy: policy.clone ( ) ,
1028
sigs: vec! [ psig.clone ( ) ] ,
1029
} ) ,
1030
tags: vec! [ tag.clone ( ) ] ,
1031
history: vec! [ SignedPolicy {
1032
policy: policy.clone ( ) ,
1033
sigs: vec! [ ] ,
1034
} ] ,
1035
} ;
83e0677b Andy McCall 1 month ago ↶
1036
let ( id_back, back) = wire:: decode_refs( & wire:: encode_refs( [ 3 ; 16 ] , & resp) ) .unwrap ( ) ;
750251b2 Andy McCall 1 month ago ↶
1037
assert_eq! ( id_back, [ 3 ; 16 ] ) ;
83e0677b Andy McCall 1 month ago ↶
1038
assert_eq! ( back.refs.len ( ) , 2 ) ;
1039
assert_eq! ( back.refs[ 0 ] .attestation.as_ref ( ) .unwrap ( ) .attest, att) ;
1040
assert_eq! ( back.refs[ 1 ] .last_serial, None ) ;
1041
assert_eq! ( back.policy.as_ref ( ) .unwrap ( ) .policy, policy) ;
28fc23d7 Andy McCall 1 month ago ↶
1042
assert_eq! ( back.history, resp.history) ;
132b884b Andy McCall 1 month ago ↶
1043
assert_eq! ( back.tags, vec! [ tag.clone ( ) ] ) ;
750251b2 Andy McCall 1 month ago ↶
1044
75167672 Andy McCall 1 month ago
1045
let ( h, w) = wire:: decode_negotiate( & wire:: encode_negotiate(
1046
& [ ObjectRef( [ 1 ; 32 ] ) ] ,
1047
& [ ObjectRef( [ 2 ; 32 ] ) ] ,
1048
) )
1049
.unwrap ( ) ;
750251b2 Andy McCall 1 month ago ↶
1050
assert_eq! ( ( h, w) , ( vec! [ ObjectRef( [ 1 ; 32 ] ) ] , vec! [ ObjectRef( [ 2 ; 32 ] ) ] ) ) ;
75167672 Andy McCall 1 month ago
1051
assert_eq! (
1052
wire:: decode_hashes( & wire:: encode_hashes( & [ c.hash ( ) ] ) ) .unwrap ( ) ,
1053
vec! [ c.hash ( ) ]
1054
) ;
1055
assert_eq! (
1056
wire:: decode_fetch( & wire:: encode_fetch( & [ c.hash ( ) ] , Some ( 4096 ) ) ) .unwrap ( ) ,
1057
( vec! [ c.hash ( ) ] , Some ( 4096 ) )
1058
) ;
1059
assert_eq! (
1060
wire:: decode_fetch( & wire:: encode_fetch( & [ ] , None ) ) .unwrap ( ) ,
1061
( vec! [ ] , None )
1062
) ;
1063
assert_eq! (
1064
wire:: decode_shallow( & wire:: encode_shallow( & [ c.hash ( ) ] , 3 ) ) .unwrap ( ) ,
1065
( vec! [ c.hash ( ) ] , 3 )
1066
) ;
b3c5a59a Andy McCall 1 month ago ↶
1067
75167672 Andy McCall 1 month ago
1068
assert_eq! (
1069
wire:: decode_fetch( & wire:: encode_hashes( & [ c.hash ( ) ] ) ) .unwrap ( ) ,
1070
( vec! [ c.hash ( ) ] , None )
1071
) ;
750251b2 Andy McCall 1 month ago ↶
1072
75167672 Andy McCall 1 month ago
1073
let up = RefUpdate {
1074
name: " main" .into ( ) ,
1075
old_state: ObjectRef( [ 1 ; 32 ] ) ,
1076
new_state: ObjectRef( [ 2 ; 32 ] ) ,
1077
force: true ,
1078
attestation: Some ( SignedAttest {
1079
attest: att,
1080
sigs: vec! [ sig] ,
1081
} ) ,
1082
} ;
1083
let sp = SignedPolicy {
1084
policy,
1085
sigs: vec! [ psig] ,
1086
} ;
1087
let ( b2, ups, pol, tags) = wire:: decode_push( & wire:: encode_push(
1088
& bundle,
1089
std:: slice:: from_ref( & up) ,
1090
Some ( & sp) ,
1091
std:: slice:: from_ref( & tag) ,
1092
) )
1093
.unwrap ( ) ;
83e0677b Andy McCall 1 month ago ↶
1094
assert_eq! ( pol, Some ( sp) ) ;
132b884b Andy McCall 1 month ago ↶
1095
assert_eq! ( tags, vec! [ tag] ) ;
750251b2 Andy McCall 1 month ago ↶
1096
assert_eq! ( b2.changes.len ( ) , 1 ) ;
1097
assert_eq! ( ups[ 0 ] .name, " main" ) ;
1098
assert! ( ups[ 0 ] .force) ;
1099
assert_eq! ( ups[ 0 ] .attestation, up.attestation) ;
75167672 Andy McCall 1 month ago
1100
let res = vec! [ RefResult {
1101
name: " main" .into ( ) ,
1102
ok: false ,
1103
reason: " stale" .into ( ) ,
1104
} ] ;
1105
assert_eq! (
1106
wire:: decode_push_response( & wire:: encode_push_response( & res) ) .unwrap ( ) ,
1107
res
1108
) ;
1109
assert_eq! (
1110
wire:: decode_capabilities( & wire:: encode_capabilities( [ 7 ; 16 ] ) ) .unwrap ( ) ,
1111
[ 7 ; 16 ]
1112
) ;
750251b2 Andy McCall 1 month ago ↶
1113
}
1114
}