updates.go 3.23 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
	nil, // No longer necessary

Ivar Derksen's avatar
Ivar Derksen committed
46
	// 7: Concert log entries to bbolt database
47
48
49
50
51
52
53
54
55
56
57
58
59
60
	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
Ivar Derksen's avatar
Ivar Derksen committed
61
		err = client.storage.db.Update(func(tx *bbolt.Tx) error {
62
			for _, log := range logs {
63
				// As log.Request is a json.RawMessage it would not get updated to the new session request
64
65
66
67
68
69
70
71
72
73
				// 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
74
				if err = client.storage.TxAddLogEntry(tx, log); err != nil {
75
76
77
78
79
80
81
82
83
84
					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
}