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