2023-02-08 15:26:23 +00:00
when ( NimMajor , NimMinor ) < ( 1 , 4 ) :
{. push raises : [ Defect ] . }
else :
{. push raises : [ ] . }
2023-04-04 13:34:53 +00:00
import
2023-02-08 15:26:23 +00:00
json ,
std / [ options , os , sequtils ] ,
. / keyfile ,
. / protocol_types
# Checks if a JsonNode has all keys contained in "keys"
proc hasKeys * ( data : JsonNode , keys : openArray [ string ] ) : bool =
return all ( keys , proc ( key : string ) : bool = return data . hasKey ( key ) )
# Defines how to sort membership groups
proc sortMembershipGroup * ( a , b : MembershipGroup ) : int =
return cmp ( a . membershipContract . address , b . membershipContract . address )
2023-04-04 13:34:53 +00:00
# Safely saves a Keystore's JsonNode to disk.
# If exists, the destination file is renamed with extension .bkp; the file is written at its destination and the .bkp file is removed if write is successful, otherwise is restored
2023-02-08 15:26:23 +00:00
proc save * ( json : JsonNode , path : string , separator : string ) : KeystoreResult [ void ] =
# We first backup the current keystore
if fileExists ( path ) :
try :
moveFile ( path , path & " .bkp " )
2023-04-04 13:34:53 +00:00
except : # TODO: Fix "BareExcept" warning
2023-02-08 15:26:23 +00:00
return err ( KeystoreOsError )
2023-04-04 13:34:53 +00:00
2023-02-08 15:26:23 +00:00
# We save the updated json
var f : File
if not f . open ( path , fmAppend ) :
return err ( KeystoreOsError )
try :
# To avoid other users/attackers to be able to read keyfiles, we make the file readable/writable only by the running user
setFilePermissions ( path , { fpUserWrite , fpUserRead } )
f . write ( $ json )
# We store a keyfile per line
f . write ( separator )
except CatchableError :
# We got some KeystoreOsError writing to disk. We attempt to restore the previous keystore backup
if fileExists ( path & " .bkp " ) :
try :
f . close ( )
removeFile ( path )
moveFile ( path & " .bkp " , path )
2023-04-04 13:34:53 +00:00
except : # TODO: Fix "BareExcept" warning
2023-02-08 15:26:23 +00:00
# Unlucky, we just fail
return err ( KeystoreOsError )
return err ( KeystoreOsError )
finally :
f . close ( )
# The write went fine, so we can remove the backup keystore
if fileExists ( path & " .bkp " ) :
try :
removeFile ( path & " .bkp " )
2023-04-04 13:34:53 +00:00
except CatchableError :
2023-02-08 15:26:23 +00:00
return err ( KeystoreOsError )
return ok ( )
# Filters a membership credential based on either input identity credential's value, membership contracts or both
proc filterCredential * ( credential : MembershipCredentials ,
filterIdentityCredentials : seq [ IdentityCredential ] ,
filterMembershipContracts : seq [ MembershipContract ] ) : Option [ MembershipCredentials ] =
2023-04-04 13:34:53 +00:00
2023-02-08 15:26:23 +00:00
# We filter by identity credentials
if filterIdentityCredentials . len ( ) ! = 0 :
if ( credential . identityCredential in filterIdentityCredentials ) = = false :
return none ( MembershipCredentials )
# We filter by membership groups credentials
if filterMembershipContracts . len ( ) ! = 0 :
# Here we keep only groups that match a contract in the filter
2023-04-04 13:34:53 +00:00
var membershipGroupsIntersection : seq [ MembershipGroup ] = @ [ ]
2023-02-08 15:26:23 +00:00
# We check if we have a group in the input credential matching any contract in the filter
for membershipGroup in credential . membershipGroups :
if membershipGroup . membershipContract in filterMembershipContracts :
membershipGroupsIntersection . add ( membershipGroup )
if membershipGroupsIntersection . len ( ) ! = 0 :
# If we have a match on some groups, we return the credential with filtered groups
return some ( MembershipCredentials ( identityCredential : credential . identityCredential ,
membershipGroups : membershipGroupsIntersection ) )
else :
return none ( MembershipCredentials )
2023-04-04 13:34:53 +00:00
# We hit this return only if
2023-02-08 15:26:23 +00:00
# - filterIdentityCredentials.len() == 0 and filterMembershipContracts.len() == 0 (no filter)
# - filterIdentityCredentials.len() != 0 and filterMembershipContracts.len() == 0 (filter only on identity credential)
# Indeed, filterMembershipContracts.len() != 0 will have its exclusive return based on all values of membershipGroupsIntersection.len()
2023-04-04 13:34:53 +00:00
return some ( credential )