Commit 1d75fcb4 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Fix code reuse in storage

parent ea159ad6
......@@ -3,7 +3,6 @@ package irmago
import (
"crypto/rand"
"math/big"
"os"
"sort"
"time"
......@@ -77,7 +76,7 @@ func NewCredentialManager(
}
// Ensure storage path exists, and populate it with necessary files
if err = cm.storage.ensureStorageExists(); err != nil {
if err = cm.storage.EnsureStorageExists(); err != nil {
return nil, err
}
......@@ -87,16 +86,16 @@ func NewCredentialManager(
}
// Load our stuff
if cm.secretkey, err = cm.storage.loadSecretKey(); err != nil {
if cm.secretkey, err = cm.storage.LoadSecretKey(); err != nil {
return nil, err
}
if cm.attributes, err = cm.storage.loadAttributes(); err != nil {
if cm.attributes, err = cm.storage.LoadAttributes(); err != nil {
return nil, err
}
if cm.paillierKeyCache, err = cm.storage.loadPaillierKeys(); err != nil {
if cm.paillierKeyCache, err = cm.storage.LoadPaillierKeys(); err != nil {
return nil, err
}
if cm.keyshareServers, err = cm.storage.loadKeyshareServers(); err != nil {
if cm.keyshareServers, err = cm.storage.LoadKeyshareServers(); err != nil {
return nil, err
}
......@@ -142,7 +141,7 @@ func (cm *CredentialManager) remove(id CredentialTypeIdentifier, index int, stor
attrs := list[index]
cm.attributes[id] = append(list[:index], list[index+1:]...)
if storenow {
cm.storage.storeAttributes(cm.attributes)
cm.storage.StoreAttributes(cm.attributes)
}
// Remove credential
......@@ -154,7 +153,7 @@ func (cm *CredentialManager) remove(id CredentialTypeIdentifier, index int, stor
}
// Remove signature from storage
if err := os.Remove(cm.storage.signatureFilename(attrs)); err != nil {
if err := cm.storage.DeleteSignature(attrs); err != nil {
return err
}
......@@ -184,10 +183,10 @@ func (cm *CredentialManager) RemoveAllCredentials() error {
return err
}
}
if err := cm.storage.storeAttributes(cm.attributes); err != nil {
if err := cm.storage.StoreAttributes(cm.attributes); err != nil {
return err
}
return cm.storage.storeLogs(cm.logs)
return cm.storage.StoreLogs(cm.logs)
}
// attrs returns cm.attributes[id], initializing it to an empty slice if neccesary
......@@ -245,7 +244,7 @@ func (cm *CredentialManager) credential(id CredentialTypeIdentifier, counter int
if attrs == nil { // We do not have the requested cred
return
}
sig, err := cm.storage.loadSignature(attrs)
sig, err := cm.storage.LoadSignature(attrs)
if err != nil {
return nil, err
}
......@@ -286,11 +285,11 @@ func (cm *CredentialManager) addCredential(cred *credential, storeAttributes boo
counter := len(cm.attributes[id]) - 1
cm.credentials[id][counter] = cred
if err = cm.storage.storeSignature(cred); err != nil {
if err = cm.storage.StoreSignature(cred); err != nil {
return
}
if storeAttributes {
err = cm.storage.storeAttributes(cm.attributes)
err = cm.storage.StoreAttributes(cm.attributes)
}
return
}
......@@ -550,7 +549,7 @@ func (cm *CredentialManager) KeyshareEnroll(managerID SchemeManagerIdentifier, e
}
cm.keyshareServers[managerID] = kss
return cm.storage.storeKeyshareServers(cm.keyshareServers)
return cm.storage.StoreKeyshareServers(cm.keyshareServers)
}
// KeyshareRemove unregisters the keyshare server of the specified scheme manager.
......@@ -559,13 +558,13 @@ func (cm *CredentialManager) KeyshareRemove(manager SchemeManagerIdentifier) err
return errors.New("Can't uninstall unknown keyshare server")
}
delete(cm.keyshareServers, manager)
return cm.storage.storeKeyshareServers(cm.keyshareServers)
return cm.storage.StoreKeyshareServers(cm.keyshareServers)
}
func (cm *CredentialManager) addLogEntry(entry *LogEntry, storenow bool) error {
cm.logs = append(cm.logs, entry)
if storenow {
return cm.storage.storeLogs(cm.logs)
return cm.storage.StoreLogs(cm.logs)
}
return nil
}
......@@ -573,10 +572,18 @@ func (cm *CredentialManager) addLogEntry(entry *LogEntry, storenow bool) error {
func (cm *CredentialManager) Logs() ([]*LogEntry, error) {
if cm.logs == nil || len(cm.logs) == 0 {
var err error
cm.logs, err = cm.storage.loadLogs()
cm.logs, err = cm.storage.LoadLogs()
if err != nil {
return nil, err
}
}
return cm.logs, nil
}
func generateSecretKey() (*secretKey, error) {
key, err := gabi.RandomBigInt(gabi.DefaultSystemParameters[1024].Lm)
if err != nil {
return nil, err
}
return &secretKey{Key: key}, nil
}
......@@ -12,6 +12,9 @@ import (
"github.com/mhe/gabi"
)
// This file contains the storage struct and its methods,
// and some general filesystem functions.
// Storage provider for a CredentialManager
type storage struct {
storagePath string
......@@ -89,63 +92,64 @@ func saveFile(filepath string, content []byte) (err error) {
return os.Rename(dir+"/"+tempfilename, filepath)
}
func generateSecretKey() (*secretKey, error) {
key, err := gabi.RandomBigInt(gabi.DefaultSystemParameters[1024].Lm)
if err != nil {
return nil, err
}
return &secretKey{Key: key}, nil
}
func (s *storage) path(p string) string {
return s.storagePath + "/" + p
}
func (s *storage) signatureFilename(attrs *AttributeList) string {
// We take the SHA256 hash over all attributes as the filename for the signature.
// This means that the signatures of two credentials that have identical attributes
// will be written to the same file, one overwriting the other - but that doesn't
// matter, because either one of the signatures is valid over both attribute lists,
// so keeping one of them suffices.
return s.path(signaturesDir) + "/" + attrs.hash()
}
// ensureStorageExists initializes the credential storage folder,
// EnsureStorageExists initializes the credential storage folder,
// ensuring that it is in a usable state.
// NOTE: we do not create the folder if it does not exist!
// Setting it up in a properly protected location (e.g., with automatic
// backups to iCloud/Google disabled) is the responsibility of the user.
func (s *storage) ensureStorageExists() error {
func (s *storage) EnsureStorageExists() error {
if err := AssertPathExists(s.storagePath); err != nil {
return err
}
return ensureDirectoryExists(s.path(signaturesDir))
}
func (s *storage) storeSecretKey(sk *secretKey) error {
bytes, err := json.Marshal(sk)
func (s *storage) load(dest interface{}, path string) (err error) {
exists, err := PathExists(s.path(path))
if err != nil || !exists {
return
}
bytes, err := ioutil.ReadFile(s.path(path))
if err != nil {
return err
return
}
return saveFile(s.path(skFile), bytes)
return json.Unmarshal(bytes, dest)
}
func (s *storage) storeSignature(cred *credential) (err error) {
if cred.CredentialType() == nil {
return errors.New("cannot add unknown credential type")
}
credbytes, err := json.Marshal(cred.Signature)
func (s *storage) store(contents interface{}, file string) error {
bts, err := json.Marshal(contents)
if err != nil {
return err
}
return saveFile(s.path(file), bts)
}
func (s *storage) signatureFilename(attrs *AttributeList) string {
// We take the SHA256 hash over all attributes as the filename for the signature.
// This means that the signatures of two credentials that have identical attributes
// will be written to the same file, one overwriting the other - but that doesn't
// matter, because either one of the signatures is valid over both attribute lists,
// so keeping one of them suffices.
return signaturesDir + "/" + attrs.hash()
}
func (s *storage) DeleteSignature(attrs *AttributeList) error {
return os.Remove(s.path(s.signatureFilename(attrs)))
}
filename := s.signatureFilename(cred.AttributeList())
err = saveFile(filename, credbytes)
return
func (s *storage) StoreSignature(cred *credential) error {
return s.store(cred.Signature, s.signatureFilename(cred.AttributeList()))
}
func (s *storage) storeAttributes(attributes map[CredentialTypeIdentifier][]*AttributeList) error {
func (s *storage) StoreSecretKey(sk *secretKey) error {
return s.store(sk, skFile)
}
func (s *storage) StoreAttributes(attributes map[CredentialTypeIdentifier][]*AttributeList) error {
temp := []*AttributeList{}
for _, attrlistlist := range attributes {
for _, attrlist := range attrlistlist {
......@@ -153,110 +157,66 @@ func (s *storage) storeAttributes(attributes map[CredentialTypeIdentifier][]*Att
}
}
if attrbytes, err := json.Marshal(temp); err == nil {
return saveFile(s.path(attributesFile), attrbytes)
} else {
return err
}
return s.store(temp, attributesFile)
}
func (s *storage) storeKeyshareServers(keyshareServers map[SchemeManagerIdentifier]*keyshareServer) (err error) {
bts, err := json.Marshal(keyshareServers)
if err != nil {
return
}
err = saveFile(s.path(kssFile), bts)
return
func (s *storage) StoreKeyshareServers(keyshareServers map[SchemeManagerIdentifier]*keyshareServer) (err error) {
return s.store(keyshareServers, kssFile)
}
func (s *storage) storePaillierKeys(key *paillierPrivateKey) (err error) {
bts, err := json.Marshal(key)
if err != nil {
return
}
err = saveFile(s.path(paillierFile), bts)
return
func (s *storage) StorePaillierKeys(key *paillierPrivateKey) (err error) {
return s.store(key, paillierFile)
}
func (s *storage) storeLogs(logs []*LogEntry) (err error) {
bts, err := json.Marshal(logs)
if err != nil {
return
}
err = saveFile(s.path(logsFile), bts)
return
func (s *storage) StoreLogs(logs []*LogEntry) (err error) {
return s.store(logs, logsFile)
}
func (s *storage) storeUpdates(updates []update) (err error) {
bts, err := json.Marshal(updates)
if err != nil {
return
}
err = saveFile(s.path(updatesFile), bts)
return
func (s *storage) StoreUpdates(updates []update) (err error) {
return s.store(updates, updatesFile)
}
func (s *storage) loadSignature(attrs *AttributeList) (signature *gabi.CLSignature, err error) {
func (s *storage) LoadSignature(attrs *AttributeList) (signature *gabi.CLSignature, err error) {
sigpath := s.signatureFilename(attrs)
if err := AssertPathExists(sigpath); err != nil {
if err := AssertPathExists(s.path(sigpath)); err != nil {
return nil, err
}
bytes, err := ioutil.ReadFile(sigpath)
if err != nil {
return
}
signature = new(gabi.CLSignature)
err = json.Unmarshal(bytes, signature)
return
if err := s.load(signature, sigpath); err != nil {
return nil, err
}
return signature, nil
}
// loadSecretKey retrieves and returns the secret key from storage, or if no secret key
// LoadSecretKey retrieves and returns the secret key from storage, or if no secret key
// was found in storage, it generates, saves, and returns a new secret key.
func (s *storage) loadSecretKey() (*secretKey, error) {
sk := &secretKey{}
func (s *storage) LoadSecretKey() (*secretKey, error) {
var err error
exists, err := PathExists(s.path(skFile))
if err != nil {
sk := &secretKey{}
if err = s.load(sk, skFile); err != nil {
return nil, err
}
if exists {
var bytes []byte
if bytes, err = ioutil.ReadFile(s.path(skFile)); err != nil {
return nil, err
}
if err = json.Unmarshal(bytes, sk); err != nil {
return nil, err
}
return sk, err
if sk.Key != nil {
return sk, nil
}
sk, err = generateSecretKey()
if err != nil {
if sk, err = generateSecretKey(); err != nil {
return nil, err
}
err = s.storeSecretKey(sk)
if err != nil {
if err = s.StoreSecretKey(sk); err != nil {
return nil, err
}
return sk, nil
}
func (s *storage) loadAttributes() (list map[CredentialTypeIdentifier][]*AttributeList, err error) {
exists, err := PathExists(s.path(attributesFile))
if err != nil || !exists {
func (s *storage) LoadAttributes() (list map[CredentialTypeIdentifier][]*AttributeList, err error) {
// The attributes are stored as a list of instances of AttributeList
temp := []*AttributeList{}
if err = s.load(&temp, attributesFile); err != nil {
return
}
bytes, err := ioutil.ReadFile(s.path(attributesFile))
if err != nil {
return nil, err
}
// The attributes are stored as a list of instances of AttributeList
temp := []*AttributeList{}
list = make(map[CredentialTypeIdentifier][]*AttributeList)
if err = json.Unmarshal(bytes, &temp); err != nil {
return nil, err
}
for _, attrlist := range temp {
attrlist.MetadataAttribute = MetadataFromInt(attrlist.Ints[0], s.ConfigurationStore)
id := attrlist.CredentialType()
......@@ -273,70 +233,34 @@ func (s *storage) loadAttributes() (list map[CredentialTypeIdentifier][]*Attribu
return list, nil
}
func (s *storage) loadKeyshareServers() (ksses map[SchemeManagerIdentifier]*keyshareServer, err error) {
func (s *storage) LoadKeyshareServers() (ksses map[SchemeManagerIdentifier]*keyshareServer, err error) {
ksses = make(map[SchemeManagerIdentifier]*keyshareServer)
exists, err := PathExists(s.path(kssFile))
if err != nil || !exists {
return
}
bytes, err := ioutil.ReadFile(s.path(kssFile))
if err != nil {
if err := s.load(&ksses, kssFile); err != nil {
return nil, err
}
err = json.Unmarshal(bytes, &ksses)
if err != nil {
return nil, err
}
return
return ksses, nil
}
func (s *storage) loadPaillierKeys() (key *paillierPrivateKey, err error) {
exists, err := PathExists(s.path(paillierFile))
if err != nil || !exists {
return
}
bytes, err := ioutil.ReadFile(s.path(paillierFile))
if err != nil {
return nil, err
}
func (s *storage) LoadPaillierKeys() (key *paillierPrivateKey, err error) {
key = new(paillierPrivateKey)
err = json.Unmarshal(bytes, key)
if err != nil {
if err := s.load(key, paillierFile); err != nil {
return nil, err
}
return
return key, nil
}
func (s *storage) loadLogs() (logs []*LogEntry, err error) {
func (s *storage) LoadLogs() (logs []*LogEntry, err error) {
logs = []*LogEntry{}
exists, err := PathExists(s.path(logsFile))
if err != nil || !exists {
return
}
bytes, err := ioutil.ReadFile(s.path(logsFile))
if err != nil {
return nil, err
}
err = json.Unmarshal(bytes, &logs)
if err != nil {
if err := s.load(&logs, logsFile); err != nil {
return nil, err
}
return
return logs, nil
}
func (s *storage) loadUpdates() (updates []update, err error) {
func (s *storage) LoadUpdates() (updates []update, err error) {
updates = []update{}
exists, err := PathExists(s.path(updatesFile))
if err != nil || !exists {
return
}
bytes, err := ioutil.ReadFile(s.path(updatesFile))
if err != nil {
return nil, err
}
err = json.Unmarshal(bytes, &updates)
if err != nil {
if err := s.load(&updates, updatesFile); err != nil {
return nil, err
}
return
return updates, nil
}
......@@ -12,6 +12,9 @@ import (
"github.com/mhe/gabi"
)
// This file contains the update mechanism for CredentialManager
// as well as updates themselves.
type update struct {
When Timestamp
Number int
......@@ -32,7 +35,7 @@ var credentialManagerUpdates = []func(manager *CredentialManager) error{
func (cm *CredentialManager) update() error {
// Load and parse file containing info about already performed updates
var err error
if cm.updates, err = cm.storage.loadUpdates(); err != nil {
if cm.updates, err = cm.storage.LoadUpdates(); err != nil {
return err
}
......@@ -51,7 +54,7 @@ func (cm *CredentialManager) update() error {
cm.updates = append(cm.updates, update)
}
cm.storage.storeUpdates(cm.updates)
cm.storage.StoreUpdates(cm.updates)
return nil
}
......@@ -140,21 +143,21 @@ func (cm *CredentialManager) ParseAndroidStorage() (present bool, err error) {
}
if len(cm.credentials) > 0 {
if err = cm.storage.storeAttributes(cm.attributes); err != nil {
if err = cm.storage.StoreAttributes(cm.attributes); err != nil {
return
}
if err = cm.storage.storeSecretKey(cm.secretkey); err != nil {
if err = cm.storage.StoreSecretKey(cm.secretkey); err != nil {
return
}
}
if len(cm.keyshareServers) > 0 {
if err = cm.storage.storeKeyshareServers(cm.keyshareServers); err != nil {
if err = cm.storage.StoreKeyshareServers(cm.keyshareServers); err != nil {
return
}
}
if err = cm.storage.storePaillierKeys(cm.paillierKeyCache); err != nil {
if err = cm.storage.StorePaillierKeys(cm.paillierKeyCache); err != nil {
return
}
if cm.paillierKeyCache == nil {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment