Commit d1f72f93 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Support schema updating (i.e. ParseAndroidStorage is now automatic)

parent 90c9aea5
......@@ -39,6 +39,7 @@ func parseStorage(t *testing.T) *CredentialManager {
manager, err := NewCredentialManager(
"testdata/storage/test",
"testdata/irma_configuration",
"testdata/oldstorage",
&IgnoringKeyshareHandler{},
)
require.NoError(t, err)
......@@ -56,13 +57,6 @@ func s2big(s string) (r *big.Int) {
return
}
func parseAndroidStorage(t *testing.T, manager *CredentialManager) {
oldStoragePath = "testdata/oldstorage"
present, err := manager.ParseAndroidStorage()
require.NoError(t, err, "ParseAndroidStorage() failed")
require.True(t, present, "Android storage not found")
}
func verifyManagerIsUnmarshaled(t *testing.T, manager *CredentialManager) {
cred, err := manager.credential(NewCredentialTypeIdentifier("irma-demo.RU.studentCard"), 0)
require.NoError(t, err, "could not fetch credential")
......@@ -169,8 +163,6 @@ func verifyStoreIsLoaded(t *testing.T, store *ConfigurationStore, android bool)
func TestAndroidParse(t *testing.T) {
manager := parseStorage(t)
verifyStoreIsLoaded(t, manager.Store, false)
parseAndroidStorage(t, manager)
verifyStoreIsLoaded(t, manager.Store, true)
verifyManagerIsUnmarshaled(t, manager)
verifyCredentials(t, manager)
......@@ -180,12 +172,9 @@ func TestAndroidParse(t *testing.T) {
}
func TestUnmarshaling(t *testing.T) {
manager := parseStorage(t)
parseAndroidStorage(t, manager)
newmanager, err := NewCredentialManager("testdata/storage/test", "testdata/irma_configuration", nil)
parseStorage(t)
newmanager, err := NewCredentialManager("testdata/storage/test", "testdata/irma_configuration", "testdata/oldstorage", nil)
require.NoError(t, err)
verifyManagerIsUnmarshaled(t, newmanager)
verifyCredentials(t, newmanager)
verifyKeyshareIsUnmarshaled(t, newmanager)
......@@ -276,7 +265,6 @@ func TestAttributeDisjunctionMarshaling(t *testing.T) {
func TestCandidates(t *testing.T) {
manager := parseStorage(t)
parseAndroidStorage(t, manager)
attrtype := NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
disjunction := &AttributeDisjunction{
......@@ -366,7 +354,6 @@ func TestTransport(t *testing.T) {
func TestPaillier(t *testing.T) {
manager := parseStorage(t)
parseAndroidStorage(t, manager)
challenge, _ := gabi.RandomBigInt(256)
comm, _ := gabi.RandomBigInt(1000)
......
......@@ -22,7 +22,9 @@ type CredentialManager struct {
paillierKeyCache *paillierPrivateKey
irmaConfigurationPath string
androidStoragePath string
Store *ConfigurationStore
updates []update
}
// CredentialInfoList returns a list of information of all contained credentials.
......
......@@ -156,7 +156,6 @@ func sessionHelper(t *testing.T, jwtcontents interface{}, url string, manager *C
init := manager == nil
if init {
manager = parseStorage(t)
parseAndroidStorage(t, manager)
}
url = "http://localhost:8081/irma_api_server/api/v2/" + url
......@@ -198,7 +197,6 @@ func registerKeyshareServer(t *testing.T, manager *CredentialManager) {
// and issuance session, also using irma-demo credentials deserialized from Android storage
func TestKeyshareRegistrationAndSessions(t *testing.T) {
manager := parseStorage(t)
parseAndroidStorage(t, manager)
manager.credentials[NewCredentialTypeIdentifier("test.test.mijnirma")] = map[int]*credential{}
test := NewSchemeManagerIdentifier("test")
......@@ -248,7 +246,6 @@ func TestKeyshareRegistrationAndSessions(t *testing.T) {
// Use keyshareuser.sql to register the user at the keyshare server.
func TestKeyshareSessions(t *testing.T) {
manager := parseStorage(t)
parseAndroidStorage(t, manager)
id := NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
expiry := Timestamp(NewMetadataAttribute().Expiry())
......
......@@ -13,6 +13,8 @@ import (
"math/big"
"path"
"time"
"github.com/mhe/gabi"
)
......@@ -22,6 +24,7 @@ const (
attributesFile = "attrs"
kssFile = "kss"
paillierFile = "paillier"
updatesFile = "updates"
signaturesDir = "sigs"
)
......@@ -61,29 +64,49 @@ func writeFile(reader io.Reader, dest string) error {
return destfile.Close()
}
// NewCredentialManager deserializes the credentials from storage.
// NewCredentialManager creates a new CredentialManager that uses the directory
// specified by storagePath for (de)serializing itself. irmaConfigurationPath
// is the path to a (possibly readonly) folder containing irma_configuration;
// androidStoragePath is an optional path to the files of the old android app
// (specify "" if you do not want to parse the old android app files),
// and keyshareHandler is used for when a registration to a keyshare server needs
// to happen.
// The credential manager returned by this function has been fully deserialized
// and is ready for use.
//
// NOTE: It is the responsibility of the caller that there exists a directory
// at storagePath!
func NewCredentialManager(
storagePath string,
irmaConfigurationPath string,
androidStoragePath string,
keyshareHandler KeyshareHandler,
) (*CredentialManager, error) {
var err error
cm := &CredentialManager{
credentials: make(map[CredentialTypeIdentifier]map[int]*credential),
keyshareServers: make(map[SchemeManagerIdentifier]*keyshareServer),
attributes: make(map[CredentialTypeIdentifier][]*AttributeList),
irmaConfigurationPath: irmaConfigurationPath,
Store: NewConfigurationStore(storagePath + "/irma_configuration"),
androidStoragePath: androidStoragePath,
Store: NewConfigurationStore(storagePath + "/irma_configuration"),
}
// Ensure storage path exists, and populate it with necessary files
cm.storagePath = storagePath
if err = cm.ensureStorageExists(); err != nil {
return nil, err
}
if err = cm.Store.ParseFolder(); err != nil {
return nil, err
}
// Perform new update functions from credentialManagerUpdates, if any
if err = cm.update(); err != nil {
return nil, err
}
// Load our stuff
if cm.secretkey, err = cm.loadSecretKey(); err != nil {
return nil, err
}
......@@ -114,6 +137,50 @@ func NewCredentialManager(
return cm, nil
}
// update performs any function from credentialManagerUpdates that has not
// already been executed in the past, keeping track of previously executed updates
// in the file at updatesFile.
func (cm *CredentialManager) update() error {
// Load and parse file containing info about already performed updates
exists, err := PathExists(cm.path(updatesFile))
if err != nil {
return err
}
if !exists {
cm.updates = []update{}
} else {
bytes, err := ioutil.ReadFile(cm.path(updatesFile))
if err != nil {
return err
}
if err = json.Unmarshal(bytes, &cm.updates); err != nil {
return err
}
}
// Perform all new updates
for i := len(cm.updates); i < len(credentialManagerUpdates); i++ {
if err := credentialManagerUpdates[i](cm); err != nil {
return err
}
cm.updates = append(cm.updates,
update{
When: Timestamp(time.Now()),
Number: i,
},
)
}
// Save updates file
bytes, err := json.Marshal(cm.updates)
if err != nil {
return err
}
cm.saveFile(cm.path(updatesFile), bytes)
return nil
}
func (cm *CredentialManager) path(file string) string {
return cm.storagePath + "/" + file
}
......
......@@ -11,14 +11,28 @@ import (
"github.com/mhe/gabi"
)
var oldStoragePath = "/data/data/org.irmacard.cardemu"
type update struct {
When Timestamp
Number int
}
var credentialManagerUpdates = []func(manager *CredentialManager) error{
func(manager *CredentialManager) error {
_, err := manager.ParseAndroidStorage()
return err
},
}
// ParseAndroidStorage parses an Android cardemu.xml shared preferences file
// from the old Android IRMA app, parsing its credentials into the current instance,
// and saving them to storage.
// CAREFUL: this method overwrites any existing secret keys and attributes on storage.
func (cm *CredentialManager) ParseAndroidStorage() (present bool, err error) {
cardemuXML := oldStoragePath + "/shared_prefs/cardemu.xml"
if cm.androidStoragePath == "" {
return false, nil
}
cardemuXML := cm.androidStoragePath + "/shared_prefs/cardemu.xml"
present, err = PathExists(cardemuXML)
if err != nil || !present {
return
......@@ -114,7 +128,7 @@ func (cm *CredentialManager) ParseAndroidStorage() (present bool, err error) {
cm.paillierKey(false) // trigger calculating a new one
}
if err = cm.Store.Copy(oldStoragePath+"/app_store/irma_configuration", false); err != nil {
if err = cm.Store.Copy(cm.androidStoragePath+"/app_store/irma_configuration", false); err != nil {
return
}
// Copy from assets again to ensure we have the latest versions
......
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