Commit 04bb9d55 authored by Ivar Derksen's avatar Ivar Derksen Committed by Sietse Ringers

Moved file based storage functions to legacy.go

parent 951b1a5f
......@@ -48,6 +48,8 @@ type Client struct {
// Where we store/load it to/from
storage storage
// Legacy storage needed when client has not updated to the new storage yet
fileStorage fileStorage
// Other state
Preferences Preferences
......@@ -153,6 +155,8 @@ func New(
if err = cm.storage.EnsureStorageExists(); err != nil {
return nil, err
}
// Legacy storage does not need ensuring existence
cm.fileStorage = fileStorage{storagePath: storagePath, Configuration: cm.Configuration}
if cm.Preferences, err = cm.storage.LoadPreferences(); err != nil {
return nil, err
......
package irmaclient
import (
"encoding/json"
"github.com/privacybydesign/gabi"
"github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/internal/fs"
"io/ioutil"
"path/filepath"
)
// This file contains the legacy storage based on files. These functions are needed
// in the upgrade path to convert the file based storage to the bbolt based storage.
// The new storage functions for bbolt can be found in storage.go.
type fileStorage struct {
storagePath string
Configuration *irma.Configuration
}
// Legacy filenames in which we stored stuff
const (
skFile = "sk"
attributesFile = "attrs"
kssFile = "kss"
updatesFile = "updates"
logsFile = "logs"
preferencesFile = "preferences"
signaturesDir = "sigs"
)
func (f *fileStorage) path(p string) string {
return filepath.Join(f.storagePath, p)
}
func (f *fileStorage) load(dest interface{}, path string) (err error) {
exists, err := fs.PathExists(f.path(path))
if err != nil || !exists {
return
}
bytes, err := ioutil.ReadFile(f.path(path))
if err != nil {
return
}
return json.Unmarshal(bytes, dest)
}
func (f *fileStorage) signatureFilename(attrs *irma.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 filepath.Join(signaturesDir, attrs.Hash())
}
func (f *fileStorage) LoadSignature(attrs *irma.AttributeList) (signature *gabi.CLSignature, err error) {
sigpath := f.signatureFilename(attrs)
if err := fs.AssertPathExists(f.path(sigpath)); err != nil {
return nil, err
}
signature = new(gabi.CLSignature)
if err := f.load(signature, sigpath); err != nil {
return nil, err
}
return signature, nil
}
// LoadSecretKey retrieves and returns the secret key from file storage. When no secret key
// file is found, nil is returned.
func (f *fileStorage) LoadSecretKey() (*secretKey, error) {
var err error
sk := &secretKey{}
if err = f.load(sk, skFile); err != nil {
return nil, err
}
if sk.Key != nil {
return sk, nil
}
return nil, nil
}
func (f *fileStorage) LoadAttributes() (list map[irma.CredentialTypeIdentifier][]*irma.AttributeList, err error) {
// The attributes are stored as a list of instances of AttributeList
temp := []*irma.AttributeList{}
if err = f.load(&temp, attributesFile); err != nil {
return
}
list = make(map[irma.CredentialTypeIdentifier][]*irma.AttributeList)
for _, attrlist := range temp {
attrlist.MetadataAttribute = irma.MetadataFromInt(attrlist.Ints[0], f.Configuration)
id := attrlist.CredentialType()
var ct irma.CredentialTypeIdentifier
if id != nil {
ct = id.Identifier()
}
if _, contains := list[ct]; !contains {
list[ct] = []*irma.AttributeList{}
}
list[ct] = append(list[ct], attrlist)
}
return list, nil
}
func (f *fileStorage) LoadKeyshareServers() (ksses map[irma.SchemeManagerIdentifier]*keyshareServer, err error) {
ksses = make(map[irma.SchemeManagerIdentifier]*keyshareServer)
if err := f.load(&ksses, kssFile); err != nil {
return nil, err
}
return ksses, nil
}
func (f *fileStorage) LoadUpdates() (updates []update, err error) {
updates = []update{}
if err := f.load(&updates, updatesFile); err != nil {
return nil, err
}
return updates, nil
}
func (f *fileStorage) LoadPreferences() (Preferences, error) {
config := defaultPreferences
return config, f.load(&config, preferencesFile)
}
func (f *fileStorage) LoadLogs() (logs []*LogEntry, err error) {
return logs, f.load(&logs, logsFile)
}
......@@ -4,7 +4,6 @@ import (
"encoding/binary"
"encoding/json"
"github.com/go-errors/errors"
"io/ioutil"
"path/filepath"
"time"
......@@ -24,29 +23,20 @@ type storage struct {
Configuration *irma.Configuration
}
// Filenames in which we store stuff
const (
skFile = "sk"
attributesFile = "attrs"
kssFile = "kss"
updatesFile = "updates"
logsFile = "logs"
preferencesFile = "preferences"
signaturesDir = "sigs"
databaseFile = "db"
)
// Filenames
const databaseFile = "db"
// Bucketnames bbolt
const (
userdataBucket = "userdata" // Key/value: specified below
skKey = "sk" // Value: *secretKey
preferencesKey = "preferences" // Value: Preferences
updatesKey = "updates" // Value: []update
kssKey = "kss" // Value: map[irma.SchemeManagerIdentifier]*keyshareServer
attributesBucket = "attrs" // Key: irma.CredentialIdentifier, value: []*irma.AttributeList
logsBucket = "logs" // Key: (auto-increment index), value: *LogEntry
signaturesBucket = "sigs" // Key: credential.attrs.Hash, value: *gabi.CLSignature
userdataBucket = "userdata" // Key/value: specified below
skKey = "sk" // Value: *secretKey
preferencesKey = "preferences" // Value: Preferences
updatesKey = "updates" // Value: []update
kssKey = "kss" // Value: map[irma.SchemeManagerIdentifier]*keyshareServer
attributesBucket = "attrs" // Key: irma.CredentialIdentifier, value: []*irma.AttributeList
logsBucket = "logs" // Key: (auto-increment index), value: *LogEntry
signaturesBucket = "sigs" // Key: credential.attrs.Hash, value: *gabi.CLSignature
)
func (s *storage) path(p string) string {
......@@ -55,7 +45,6 @@ func (s *storage) path(p string) string {
// 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 {
......@@ -63,33 +52,10 @@ func (s *storage) EnsureStorageExists() error {
if err = fs.AssertPathExists(s.storagePath); err != nil {
return err
}
if err = fs.EnsureDirectoryExists(s.path(signaturesDir)); err != nil {
return err
}
s.db, err = bbolt.Open(s.path(databaseFile), 0600, &bbolt.Options{Timeout: 1 * time.Second})
return err
}
func (s *storage) loadFromFile(dest interface{}, path string) (err error) {
exists, err := fs.PathExists(s.path(path))
if err != nil || !exists {
return
}
bytes, err := ioutil.ReadFile(s.path(path))
if err != nil {
return
}
return json.Unmarshal(bytes, dest)
}
func (s *storage) store(contents interface{}, file string) error {
bts, err := json.Marshal(contents)
if err != nil {
return err
}
return fs.SaveFile(s.path(file), bts)
}
func (s *storage) txStore(tx *bbolt.Tx, key interface{}, value interface{}, bucketName string) error {
b, err := tx.CreateBucketIfNotExists([]byte(bucketName))
if err != nil {
......@@ -131,15 +97,6 @@ func (s *storage) load(key interface{}, dest interface{}, bucketName string) (fo
return
}
func (s *storage) signatureFilename(attrs *irma.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 filepath.Join(signaturesDir, attrs.Hash())
}
func (s *storage) DeleteSignature(attrs *irma.AttributeList) error {
return s.db.Update(func(tx *bbolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte(signaturesBucket))
......@@ -265,18 +222,6 @@ func (s *storage) TxStoreUpdates(tx *bbolt.Tx, updates []update) error {
return s.txStore(tx, updatesKey, updates, userdataBucket)
}
func (s *storage) LoadSignatureFile(attrs *irma.AttributeList) (signature *gabi.CLSignature, err error) {
sigpath := s.signatureFilename(attrs)
if err := fs.AssertPathExists(s.path(sigpath)); err != nil {
return nil, err
}
signature = new(gabi.CLSignature)
if err := s.loadFromFile(signature, sigpath); err != nil {
return nil, err
}
return signature, nil
}
func (s *storage) LoadSignature(attrs *irma.AttributeList) (signature *gabi.CLSignature, err error) {
signature = new(gabi.CLSignature)
found, err := s.load(attrs.Hash(), signature, signaturesBucket)
......@@ -288,20 +233,6 @@ func (s *storage) LoadSignature(attrs *irma.AttributeList) (signature *gabi.CLSi
return
}
// LoadSecretKeyFile retrieves and returns the secret key from file storage. When no secret key
// file is found, nil is returned.
func (s *storage) LoadSecretKeyFile() (*secretKey, error) {
var err error
sk := &secretKey{}
if err = s.loadFromFile(sk, skFile); err != nil {
return nil, err
}
if sk.Key != nil {
return sk, nil
}
return nil, nil
}
// LoadSecretKey retrieves and returns the secret key from bbolt 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) {
......@@ -323,30 +254,6 @@ func (s *storage) LoadSecretKey() (*secretKey, error) {
return sk, nil
}
func (s *storage) LoadAttributesFile() (list map[irma.CredentialTypeIdentifier][]*irma.AttributeList, err error) {
// The attributes are stored as a list of instances of AttributeList
temp := []*irma.AttributeList{}
if err = s.loadFromFile(&temp, attributesFile); err != nil {
return
}
list = make(map[irma.CredentialTypeIdentifier][]*irma.AttributeList)
for _, attrlist := range temp {
attrlist.MetadataAttribute = irma.MetadataFromInt(attrlist.Ints[0], s.Configuration)
id := attrlist.CredentialType()
var ct irma.CredentialTypeIdentifier
if id != nil {
ct = id.Identifier()
}
if _, contains := list[ct]; !contains {
list[ct] = []*irma.AttributeList{}
}
list[ct] = append(list[ct], attrlist)
}
return list, nil
}
func (s *storage) LoadAttributes() (list map[irma.CredentialTypeIdentifier][]*irma.AttributeList, err error) {
list = make(map[irma.CredentialTypeIdentifier][]*irma.AttributeList)
return list, s.db.View(func(tx *bbolt.Tx) error {
......@@ -379,14 +286,6 @@ func (s *storage) LoadAttributes() (list map[irma.CredentialTypeIdentifier][]*ir
})
}
func (s *storage) LoadKeyshareServersFile() (ksses map[irma.SchemeManagerIdentifier]*keyshareServer, err error) {
ksses = make(map[irma.SchemeManagerIdentifier]*keyshareServer)
if err := s.loadFromFile(&ksses, kssFile); err != nil {
return nil, err
}
return ksses, nil
}
func (s *storage) LoadKeyshareServers() (ksses map[irma.SchemeManagerIdentifier]*keyshareServer, err error) {
ksses = make(map[irma.SchemeManagerIdentifier]*keyshareServer)
_, err = s.load(kssKey, &ksses, userdataBucket)
......@@ -433,25 +332,12 @@ func (s *storage) loadLogs(max int, startAt func(*bbolt.Cursor) (key, value []by
})
}
func (s *storage) LoadUpdatesFile() (updates []update, err error) {
updates = []update{}
if err := s.loadFromFile(&updates, updatesFile); err != nil {
return nil, err
}
return updates, nil
}
func (s *storage) LoadUpdates() (updates []update, err error) {
updates = []update{}
_, err = s.load(updatesKey, &updates, userdataBucket)
return
}
func (s *storage) LoadPreferencesFile() (Preferences, error) {
config := defaultPreferences
return config, s.loadFromFile(&config, preferencesFile)
}
func (s *storage) LoadPreferences() (Preferences, error) {
config := defaultPreferences
_, err := s.load(preferencesKey, &config, userdataBucket)
......
......@@ -45,11 +45,11 @@ var clientUpdates = []func(client *Client) error{
// 7: Convert log entries to bbolt database
func(client *Client) error {
var logs []*LogEntry
var err error
if err = client.storage.loadFromFile(&logs, logsFile); err != nil {
logs, err := client.fileStorage.LoadLogs()
if err != nil {
return nil
}
// Open one bolt transaction to process all our log entries in
err = client.storage.db.Update(func(tx *bbolt.Tx) error {
for _, log := range logs {
......@@ -75,7 +75,7 @@ var clientUpdates = []func(client *Client) error{
// 8: Move other user storage to bbolt database
func(client *Client) error {
sk, err := client.storage.LoadSecretKeyFile()
sk, err := client.fileStorage.LoadSecretKey()
if err != nil {
return err
}
......@@ -85,7 +85,7 @@ var clientUpdates = []func(client *Client) error{
return nil
}
attrs, err := client.storage.LoadAttributesFile()
attrs, err := client.fileStorage.LoadAttributes()
if err != nil {
return err
}
......@@ -93,7 +93,7 @@ var clientUpdates = []func(client *Client) error{
sigs := make(map[string]*gabi.CLSignature)
for _, attrlistlist := range attrs {
for _, attrlist := range attrlistlist {
sig, err := client.storage.LoadSignatureFile(attrlist)
sig, err := client.fileStorage.LoadSignature(attrlist)
if err != nil {
return err
}
......@@ -101,12 +101,12 @@ var clientUpdates = []func(client *Client) error{
}
}
ksses, err := client.storage.LoadKeyshareServersFile()
ksses, err := client.fileStorage.LoadKeyshareServers()
if err != nil {
return err
}
prefs, err := client.storage.LoadPreferencesFile()
prefs, err := client.fileStorage.LoadPreferences()
if err != nil {
return err
}
......@@ -115,7 +115,7 @@ var clientUpdates = []func(client *Client) error{
client.Preferences = prefs
client.applyPreferences()
updates, err := client.storage.LoadUpdatesFile()
updates, err := client.fileStorage.LoadUpdates()
if err != nil {
return err
}
......@@ -160,7 +160,7 @@ func (client *Client) update() error {
// When no updates are found, it can either be a fresh storage or the storage has not been updated
// to bbolt yet. Therefore also check the updates file.
if len(client.updates) == 0 {
if client.updates, err = client.storage.LoadUpdatesFile(); err != nil {
if client.updates, err = client.fileStorage.LoadUpdates(); err != nil {
return err
}
}
......
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