-
Notifications
You must be signed in to change notification settings - Fork 41
/
updates.go
200 lines (173 loc) · 5.23 KB
/
updates.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package irmaclient
import (
"encoding/json"
"time"
irma "github.com/privacybydesign/irmago"
)
// This file contains the update mechanism for Client
// as well as updates themselves.
type update struct {
When irma.Timestamp
Number int
Success bool
Error *string
}
var clientUpdates = []func(client *Client) error{
// 0: Convert old cardemu.xml Android storage to our own storage format
nil, // No longer necessary as the Android app was deprecated long ago
// 1: Adding scheme manager index, signature and public key
// Check the signatures of all scheme managers, if any is not ok,
// copy the entire irma_configuration folder from assets
nil, // made irrelevant by irma_configuration-autocopying
// 2: Rename config -> preferences
nil, // No longer necessary
// 3: Copy new irma_configuration out of assets
nil, // made irrelevant by irma_configuration-autocopying
// 4: For each keyshare server, include in its struct the identifier of its scheme manager
nil, // No longer necessary
// 5: Remove the test scheme manager which was erroneously included in a production build
nil, // No longer necessary, also broke many unit tests
// 6: Remove earlier log items of wrong format
nil, // No longer necessary
// 7: Convert log entries to bbolt database
func(client *Client) error {
logs, err := client.fileStorage.LoadLogs()
if err != nil {
return nil
}
// Open one bolt transaction to process all our log entries in
err = client.storage.Transaction(func(tx *transaction) error {
for _, log := range logs {
// As log.Request is a json.RawMessage it would not get updated to the new session request
// format by re-marshaling the containing struct, as normal struct members would,
// so update it manually now by marshaling the session request into it.
req, err := log.SessionRequest()
if err != nil {
return err
}
log.Request, err = json.Marshal(req)
if err != nil {
return err
}
if err = client.storage.TxAddLogEntry(tx, log); err != nil {
return err
}
}
return nil
})
return err
},
// 8: Move other user storage to bbolt database
func(client *Client) error {
sk, err := client.fileStorage.LoadSecretKey()
if err != nil {
return err
}
// When no secret key is found, it means the storage is fresh. No update is needed.
if sk == nil {
return nil
}
attrs, err := client.fileStorage.LoadAttributes()
if err != nil {
return err
}
sigs := make(map[string]*clSignatureWitness)
for _, attrlistlist := range attrs {
for _, attrlist := range attrlistlist {
sig, witness, err := client.fileStorage.LoadSignature(attrlist)
if err != nil {
return err
}
sigs[attrlist.Hash()] = &clSignatureWitness{
CLSignature: sig,
Witness: witness,
}
}
}
ksses, err := client.fileStorage.LoadKeyshareServers()
if err != nil {
return err
}
prefs, err := client.fileStorage.LoadPreferences()
if err != nil {
return err
}
// Preferences are already loaded in client, refresh
client.Preferences = prefs
client.applyPreferences()
updates, err := client.fileStorage.LoadUpdates()
if err != nil {
return err
}
return client.storage.Transaction(func(tx *transaction) error {
if err = client.storage.TxStoreSecretKey(tx, sk); err != nil {
return err
}
for credTypeID, attrslistlist := range attrs {
if err = client.storage.TxStoreAttributes(tx, credTypeID, attrslistlist); err != nil {
return err
}
}
for hash, sig := range sigs {
err = client.storage.TxStoreCLSignature(tx, hash, sig)
if err != nil {
return err
}
}
if err = client.storage.TxStoreKeyshareServers(tx, ksses); err != nil {
return err
}
if err = client.storage.TxStorePreferences(tx, prefs); err != nil {
return err
}
return client.storage.TxStoreUpdates(tx, updates)
})
},
// TODO: Maybe delete preferences file to start afresh
}
// update performs any function from clientUpdates that has not
// already been executed in the past, keeping track of previously executed updates
// in the file at updatesFile.
func (client *Client) update() error {
// Load and parse file containing info about already performed updates
var err error
if client.updates, err = client.storage.LoadUpdates(); err != nil {
return err
}
// 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.fileStorage.LoadUpdates(); err != nil {
return err
}
}
// Early exit if all updates are already performed to prevent superfluously storing the updates array
if len(client.updates) == len(clientUpdates) {
return nil
}
// Perform all new updates
for i := len(client.updates); i < len(clientUpdates); i++ {
err = nil
if clientUpdates[i] != nil {
err = clientUpdates[i](client)
}
u := update{
When: irma.Timestamp(time.Now()),
Number: i,
Success: err == nil,
}
if err != nil {
str := err.Error()
u.Error = &str
}
client.updates = append(client.updates, u)
if err != nil {
break
}
}
storeErr := client.storage.StoreUpdates(client.updates)
if storeErr != nil {
return storeErr
}
return err
}