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

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

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

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

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

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

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

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

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

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

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

43
	// 6: Remove earlier log items of wrong format
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
	nil, // No longer necessary

	// 7: Concert log entries to bolthold database
	func(client *Client) error {
		var logs []*LogEntry
		var err error

		start := time.Now()
		fmt.Println(start.UnixNano(), "started")
		if err = client.storage.load(&logs, logsFile); err != nil {
			return err
		}

		loaded := time.Now()
		fmt.Println(loaded.Sub(start), "loaded")

		// Open one bolt transaction to process all our log entries in
		err = client.storage.db.Bolt().Update(func(tx *bbolt.Tx) error {
			for _, log := range logs {
				// As log.Request is a json.RawMessage it woult 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.db.TxUpsert(tx, client.storage.logEntryKey(log), log); err != nil {
					return err
				}
			}
			return nil
		})

		done := time.Now()
		fmt.Println(done.Sub(loaded), "done converting", len(logs), "logs")

		return err
Tomas's avatar
Tomas committed
85
	},
86
}
87

88
// update performs any function from clientUpdates that has not
89
90
// already been executed in the past, keeping track of previously executed updates
// in the file at updatesFile.
91
func (client *Client) update() error {
92
93
	// Load and parse file containing info about already performed updates
	var err error
94
	if client.updates, err = client.storage.LoadUpdates(); err != nil {
95
96
97
98
		return err
	}

	// Perform all new updates
99
	for i := len(client.updates); i < len(clientUpdates); i++ {
100
101
102
		err = nil
		if clientUpdates[i] != nil {
			err = clientUpdates[i](client)
103
		}
Sietse Ringers's avatar
Sietse Ringers committed
104
		u := update{
105
			When:    irma.Timestamp(time.Now()),
106
107
108
109
110
			Number:  i,
			Success: err == nil,
		}
		if err != nil {
			str := err.Error()
Sietse Ringers's avatar
Sietse Ringers committed
111
			u.Error = &str
112
		}
113
		client.updates = append(client.updates, u)
114
115
116
		if err != nil {
			break
		}
117
118
	}

119
120
121
122
123
	storeErr := client.storage.StoreUpdates(client.updates)
	if storeErr != nil {
		return storeErr
	}
	return err
124
}