updates.go 3 KB
Newer Older
1
package irmaclient
Sietse Ringers's avatar
Sietse Ringers committed
2
3

import (
4
	"encoding/json"
5
	"time"
Sietse Ringers's avatar
Sietse Ringers committed
6

7
	"github.com/privacybydesign/irmago"
8
	"go.etcd.io/bbolt"
Sietse Ringers's avatar
Sietse Ringers committed
9
10
)

11
// This file contains the update mechanism for Client
Sietse Ringers's avatar
Sietse Ringers committed
12
13
// as well as updates themselves.

14
type update struct {
15
	When    irma.Timestamp
16
17
18
	Number  int
	Success bool
	Error   *string
19
20
}

21
var clientUpdates = []func(client *Client) error{
22
	// 0: Convert old cardemu.xml Android storage to our own storage format
23
	nil, // No longer necessary as the Android app was deprecated long ago
24

25
	// 1: Adding scheme manager index, signature and public key
26
27
	// Check the signatures of all scheme managers, if any is not ok,
	// copy the entire irma_configuration folder from assets
28
	nil, // made irrelevant by irma_configuration-autocopying
29

30
	// 2: Rename config -> preferences
31
	nil, // No longer necessary
32

33
	// 3: Copy new irma_configuration out of assets
34
	nil, // made irrelevant by irma_configuration-autocopying
35

36
	// 4: For each keyshare server, include in its struct the identifier of its scheme manager
37
	nil, // No longer necessary
38

39
	// 5: Remove the test scheme manager which was erroneously included in a production build
40
	nil, // No longer necessary, also broke many unit tests
Tomas's avatar
Tomas committed
41

42
	// 6: Remove earlier log items of wrong format
43
44
	nil, // No longer necessary

Ivar Derksen's avatar
Ivar Derksen committed
45
	// 7: Concert log entries to bbolt database
46
47
48
49
50
51
52
	func(client *Client) error {
		var logs []*LogEntry
		var err error
		if err = client.storage.load(&logs, logsFile); err != nil {
			return err
		}
		// Open one bolt transaction to process all our log entries in
Ivar Derksen's avatar
Ivar Derksen committed
53
		err = client.storage.db.Update(func(tx *bbolt.Tx) error {
54
			for _, log := range logs {
55
				// As log.Request is a json.RawMessage it would not get updated to the new session request
56
57
58
59
60
61
62
63
64
65
				// 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
				}
Ivar Derksen's avatar
Ivar Derksen committed
66
				if err = client.storage.TxAddLogEntry(tx, log); err != nil {
67
68
69
70
71
72
					return err
				}
			}
			return nil
		})
		return err
Tomas's avatar
Tomas committed
73
	},
74
}
75

76
// update performs any function from clientUpdates that has not
77
78
// already been executed in the past, keeping track of previously executed updates
// in the file at updatesFile.
79
func (client *Client) update() error {
80
81
	// Load and parse file containing info about already performed updates
	var err error
82
	if client.updates, err = client.storage.LoadUpdates(); err != nil {
83
84
85
86
		return err
	}

	// Perform all new updates
87
	for i := len(client.updates); i < len(clientUpdates); i++ {
88
89
90
		err = nil
		if clientUpdates[i] != nil {
			err = clientUpdates[i](client)
91
		}
Sietse Ringers's avatar
Sietse Ringers committed
92
		u := update{
93
			When:    irma.Timestamp(time.Now()),
94
95
96
97
98
			Number:  i,
			Success: err == nil,
		}
		if err != nil {
			str := err.Error()
Sietse Ringers's avatar
Sietse Ringers committed
99
			u.Error = &str
100
		}
101
		client.updates = append(client.updates, u)
102
103
104
		if err != nil {
			break
		}
105
106
	}

107
108
109
110
111
	storeErr := client.storage.StoreUpdates(client.updates)
	if storeErr != nil {
		return storeErr
	}
	return err
112
}