@@ -102,7 +102,7 @@ def encryptrefname(ref, key):
102102
103103 sref = splitref (ref )
104104 rawname = sref [0 ].encode ('utf-8' )
105- return 'refs/heads/' + base64 .b64encode (encryptdata (
105+ return base64 .b64encode (encryptdata (
106106 hashlib .sha1 (rawname ).digest () + rawname , key ),
107107 b'+#' ).decode ('utf-8' ) + sref [1 ]
108108
@@ -132,33 +132,20 @@ class CryptRepo:
132132 'followtags' : False
133133 }
134134 hashstr = hashlib .sha1 (url .encode ('utf-8' )).hexdigest ()
135- self .refprefix = f'refs/incrypt/{ hashstr } /'
135+ self .prefix = f'refs/incrypt/{ hashstr } /'
136+ self .url = url
136137 if init :
137138 self .repo = pygit2 .init_repository (clearname , bare = True )
138- self .repo .remotes .create ('incrypt' , url )
139139 template = self ._mktemplate (init .name , init .email ,
140140 init .date , init .m )
141- self .meta = MetaData (self .repo ).init (init . keys , template ,
142- 'refs/heads/master' )
141+ self .meta = MetaData (self .repo , self . url , self . prefix + '1/' ).init (
142+ init . keys , template , 'refs/heads/master' )
143143 self .trust (force = True , sign = True )
144- self .clearrepo = pygit2 .Repository (clearname )
145144 else :
146- self .clearrepo = pygit2 .Repository (clearname )
147- name = os .path .join (self .clearrepo .path , 'incrypt' , hashstr )
148- if not os .path .isdir (name ):
149- subprocess .run (
150- ['git' , 'clone' ,
151- CryptRepo .verbosityflags [self .settings ['verbosity' ]],
152- '--progress' if self .settings ['progress' ]
153- else '--no-progress' ,
154- '-o' , 'incrypt' , '-c' , 'fetch.prune=true' ,
155- '--mirror' , url , name ],
156- check = True , stdout = sys .stderr )
157- subprocess .run (
158- ['git' , 'config' , 'unset' , 'remote.incrypt.mirror' ],
159- cwd = name , check = True , stdout = sys .stderr )
160- self .repo = pygit2 .Repository (name )
161- self .meta = MetaData (self .repo ).read ()
145+ self .repo = pygit2 .Repository (clearname )
146+ self ._fetch ('_' )
147+ self .meta = MetaData (self .repo , self .url ,
148+ self .prefix + '1/' ).read ()
162149 if forcetrust :
163150 self .trust (force = forcetrust )
164151
@@ -228,16 +215,25 @@ class CryptRepo:
228215 ([f'^{ x } \n ' for x in excl ] if excl else [])))
229216 return text .strip ().split ('\n ' ) if text else []
230217
218+ def _fetch (self , pattern ):
219+ subprocess .run (
220+ ['git' , 'fetch' ,
221+ CryptRepo .verbosityflags [self .settings ['verbosity' ]],
222+ '--progress' if self .settings ['progress' ] else '--no-progress' ,
223+ '--no-write-fetch-head' , '-p' , self .url ,
224+ f'+refs/heads/{ pattern } :{ self .prefix } 1/{ pattern } ' ],
225+ cwd = self .repo .path , check = True , stdout = sys .stderr )
226+
231227 def trust (self , force = False , sign = False ):
232228 'trust this repository'
233229 if force :
234230 trusted = True
235231 else :
236232 try :
237- with open ( os . path . join ( self .repo .path , 'incrypt-keyhash' ), 'r' ,
238- encoding = 'utf-8' ) as file :
239- expectedhash = file . read ().strip ( )
240- except FileNotFoundError :
233+ expectedhash = self .repo .revparse_single (
234+ self . prefix +
235+ 'keyhash' ). tree [ '_' ]. read_raw ().decode ( 'utf-8' )
236+ except KeyError :
241237 expectedhash = None
242238 if expectedhash :
243239 assert expectedhash == self .meta .keyhash , \
@@ -248,53 +244,56 @@ class CryptRepo:
248244 assert trusted , 'Key is not trusted'
249245 if sign :
250246 self .meta .sign ()
251- with open (os .path .join (self .repo .path , 'incrypt-keyhash' ), 'w' ,
252- encoding = 'utf-8' ) as file :
253- file .write (self .meta .keyhash )
247+ collector = self .repo .TreeBuilder ()
248+ collector .insert ('_' , self .repo .create_blob (self .meta .keyhash ),
249+ pygit2 .enums .FileMode .BLOB )
250+ colid = collector .write ()
251+ commit = self .meta .secretcommit (
252+ colid , [])
253+ self .repo .create_reference (self .prefix + 'keyhash' , commit , force = True )
254254
255255 def getrefs (self ):
256256 'list all cleartext references'
257257 def decryptobject (oid ):
258258 'decrypt an object'
259259 raw = decryptdata (self .repo .get (oid ).read_raw (), self .meta .key )
260- return self .clearrepo .odb .write (raw [20 ], raw [21 :])
261- subprocess .run (
262- ['git' , 'fetch' ,
263- CryptRepo .verbosityflags [self .settings ['verbosity' ]],
264- '--progress' if self .settings ['progress' ] else '--no-progress' ],
265- cwd = self .repo .path , check = True , stdout = sys .stderr )
260+ return self .repo .odb .write (raw [20 ], raw [21 :])
261+ self ._fetch ('*' )
266262 self .meta .read ()
267263 self .trust ()
268264 # [ dec(crypt) , prefdec(crypt), crypt ]
269- refs = [[r [0 ], self .refprefix + r [0 ], self .repo .revparse_single (r [1 ])]
265+ refs = [[r [0 ], self .prefix + '0/' + r [0 ],
266+ self .repo .revparse_single (r [1 ])]
270267 for r in [[decryptrefname (r , self .meta .key ), r ] for r in
271- filter (lambda r : len (r ) > 14 , self .repo .references )]]
272- cryptmap = self .meta .readmap (reverse = self .clearrepo )
268+ filter (lambda r : len (r ) > len (self .prefix )+ 3 and
269+ r .startswith (self .prefix + '1/' ),
270+ self .repo .references )]]
271+ cryptmap = self .meta .readmap (reverse = True )
273272 self ._progress_for (
274273 'Decrypting objects' ,
275274 CryptRepo ._revlist (CryptRepo .RevMode .BLOB , [r [2 ].id for r in refs ],
276275 cryptmap , cwd = self .repo .path ),
277276 decryptobject )
278277 for r in refs :
279- self .clearrepo .create_reference (
278+ self .repo .create_reference (
280279 r [1 ], decryptdata (r [2 ].tree ['0' ].read_raw (),
281280 self .meta .key )[0 :20 ].hex (), force = True )
282281 expected = [r [1 ] for r in refs ]
283282 result = [['HEAD' , f'@{ self .meta .defaultbranch } ' ]]
284- for r in self .clearrepo .references :
285- if r .startswith (self .refprefix ):
283+ for r in self .repo .references :
284+ if r .startswith (self .prefix + '0/' ):
286285 if r in expected :
287- result .append ([r [len (self .refprefix ) :],
288- self .clearrepo .lookup_reference (r ).target ])
286+ result .append ([r [len (self .prefix ) + 2 :],
287+ self .repo .lookup_reference (r ).target ])
289288 else :
290- self .clearrepo .references .delete (r )
289+ self .repo .references .delete (r )
291290 return result
292291
293292 def push (self , refs ):
294293 'push refs'
295294 def encryptobject (oid ):
296295 'encrypt an object'
297- clear = self .clearrepo .get (oid )
296+ clear = self .repo .get (oid )
298297 cryptobjs [clear .id ] = self .repo .create_blob (encryptdata (
299298 clear .id .raw + clear .type .to_bytes (1 , byteorder = 'big' ) +
300299 clear .read_raw (), self .meta .key ))
@@ -314,7 +313,7 @@ class CryptRepo:
314313 collectorinsert (collector , cryptobjs [obj .id ])
315314 collectorinsert (collector , cryptobjs [tree .id ])
316315
317- obj = self .clearrepo .get (oid )
316+ obj = self .repo .get (oid )
318317 collector = self .repo .TreeBuilder ()
319318 if obj .type == pygit2 .enums .ObjectType .COMMIT :
320319 encrypttree (obj .tree )
@@ -329,11 +328,13 @@ class CryptRepo:
329328 if obj .type == pygit2 .enums .ObjectType .COMMIT
330329 else [cryptmap [str (obj .target )]])
331330
332- xrefs = [[r [0 ], r [1 ], r [3 ],
333- f"{ '+' if r [2 ] else '' } { r [3 ] if r [0 ] else '' } :{ r [3 ]} " ,
334- self .clearrepo .revparse_single (r [0 ]) if r [0 ] else None ]
335- for r in [[r [0 ], r [1 ], r [2 ], encryptrefname (r [1 ],
336- self .meta .key )] for r in refs ]]
331+ xrefs = [[r [0 ], r [1 ], r [3 ], ('+' if r [2 ] else '' ) +
332+ (self .prefix + '1/' + r [3 ] if r [0 ] else '' ) +
333+ ':refs/heads/' + r [3 ],
334+ self .repo .revparse_single (r [0 ]) if r [0 ] else None ]
335+ for r in [[r [0 ], r [1 ], r [2 ],
336+ encryptrefname (r [1 ], self .meta .key )]
337+ for r in refs ]]
337338 cryptmap = self .meta .readmap ()
338339 colobjs = CryptRepo ._revlist (
339340 CryptRepo .RevMode .PARENT , [r [4 ].id for r in xrefs if r [4 ]],
@@ -346,11 +347,12 @@ class CryptRepo:
346347 self .meta .write (cryptmap )
347348 for r in xrefs :
348349 if r [4 ]:
349- self .repo .create_reference (r [2 ], cryptmap [str (r [4 ].id )],
350- force = True )
350+ self .repo .create_reference (
351+ self .prefix + '1/' + r [2 ], cryptmap [str (r [4 ].id )],
352+ force = True )
351353 else :
352354 try :
353- self .repo .references .delete (r [2 ])
355+ self .repo .references .delete (self . prefix + '1/' + r [2 ])
354356 except KeyError :
355357 pass
356358 resdict = {}
@@ -361,7 +363,7 @@ class CryptRepo:
361363 ['--progress' if self .settings ['progress' ]
362364 else '--no-progress' , '--porcelain' ] +
363365 (['--atomic' ] if self .settings ['atomic' ] else []) +
364- ['incrypt' , f'+ { MetaData . REFNAME } : { MetaData .REFNAME } ' ] +
366+ [self . url , '+' + self . prefix + '1/_:' + MetaData .REFNAME ] +
365367 [r [3 ] for r in xrefs ],
366368 cwd = self .repo .path , check = False , text = True ,
367369 stdout = subprocess .PIPE ,
@@ -372,7 +374,7 @@ class CryptRepo:
372374 if len (e ) == 3 :
373375 resdict [e [1 ].split (':' , 1 )[1 ]] = \
374376 e [2 ].split ('(' , 1 )[1 ][0 :- 1 ] if e [0 ] == '!' else None
375- return {r [1 ]: resdict [r [2 ]] for r in xrefs }
377+ return {r [1 ]: resdict ['refs/heads/' + r [2 ]] for r in xrefs }
376378
377379
378380def remotehelperloop ():
@@ -433,13 +435,16 @@ def remotehelperloop():
433435
434436
435437class MetaData :
438+ # pylint: disable=too-many-instance-attributes
436439 'container for meta data'
437440 VER = b'git-incrypt\n 1.0.0\n '
438441 KEYVER = b'AES-256-CBC+IV'
439442 REFNAME = 'refs/heads/_'
440443
441- def __init__ (self , repo ):
444+ def __init__ (self , repo , url , prefix ):
442445 self .repo = repo
446+ self .url = url
447+ self .prefix = prefix
443448 self .files = None
444449 self .key = None
445450 self .keyhash = None
@@ -450,7 +455,7 @@ class MetaData:
450455 def _gpg (self , args , inp ):
451456 'run gpg'
452457 return subprocess .check_output (
453- [f'gpg@incrypt::{ self .repo . remotes [ "incrypt" ]. url } ' ] + args ,
458+ [f'gpg@incrypt::{ self .url } ' ] + args ,
454459 executable = 'gpg' , input = inp )
455460
456461 def init (self , gpgkeys , template , defaultbranch ):
@@ -485,7 +490,7 @@ class MetaData:
485490 def read (self ):
486491 'read the metadata'
487492 self .files = {}
488- tree = self .repo .revparse_single (MetaData . REFNAME ).tree
493+ tree = self .repo .revparse_single (self . prefix + '_' ).tree
489494 obj = tree ['ver' ]
490495 self .files ['ver' ] = obj .id
491496 data = obj .read_raw ()
@@ -582,18 +587,18 @@ class MetaData:
582587 collector .insert ('README.md' , readmefile , pygit2 .enums .FileMode .BLOB )
583588 colid = collector .write ()
584589 commit = self .secretcommit (colid , [])
585- self .repo .create_reference (MetaData . REFNAME , commit , force = True )
590+ self .repo .create_reference (self . prefix + '_' , commit , force = True )
586591 return self
587592
588- def readmap (self , reverse = None ):
593+ def readmap (self , reverse = False ):
589594 'read the mapping table'
590- tree = self .repo .revparse_single (MetaData . REFNAME ).tree
595+ tree = self .repo .revparse_single (self . prefix + '_' ).tree
591596 o = 20 if reverse else 0
592597 processed = {}
593598 rawdata = decryptdata (tree ['map' ].read_raw (), self .key )
594599 for i in range (20 , len (rawdata ), 40 ):
595600 target = rawdata [i + 20 - o :i + 40 - o ].hex ()
596- if target in ( reverse if reverse else self .repo ) :
601+ if target in self .repo :
597602 processed [rawdata [i + o :i + 20 + o ].hex ()] = target
598603 return processed
599604
0 commit comments