/
siamux.go
139 lines (123 loc) · 4.12 KB
/
siamux.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
package modules
import (
"errors"
"os"
"path/filepath"
"gitlab.com/NebulousLabs/siamux"
"gitlab.com/NebulousLabs/siamux/mux"
"go.sia.tech/siad/build"
"go.sia.tech/siad/crypto"
"go.sia.tech/siad/persist"
"go.sia.tech/siad/types"
)
const (
// logfile is the filename of the siamux log file
logfile = "siamux.log"
// SiaMuxDir is the name of the siamux dir
SiaMuxDir = "siamux"
)
// NewSiaMux returns a new SiaMux object
func NewSiaMux(siaMuxDir, siaDir, tcpaddress, wsaddress string) (*siamux.SiaMux, error) {
// can't use relative path
if !filepath.IsAbs(siaMuxDir) || !filepath.IsAbs(siaDir) {
err := errors.New("paths need to be absolute")
build.Critical(err)
return nil, err
}
// ensure the persist directory exists
err := os.MkdirAll(siaMuxDir, 0700)
if err != nil {
return nil, err
}
// CompatV143 migrate existing mux in siaDir root to siaMuxDir.
if err := compatV143MigrateSiaMux(siaMuxDir, siaDir); err != nil {
return nil, err
}
// create a logger
file, err := os.OpenFile(filepath.Join(siaMuxDir, logfile), os.O_RDWR|os.O_CREATE, 0600)
if err != nil {
return nil, err
}
logger, err := persist.NewLogger(file)
if err != nil {
return nil, err
}
// create a siamux, if the host's persistence file is at v120 we want to
// recycle the host's key pair to use in the siamux
pubKey, privKey, compat := compatLoadKeysFromHost(siaDir)
if compat {
return siamux.CompatV1421NewWithKeyPair(tcpaddress, wsaddress, logger.Logger, siaMuxDir, privKey, pubKey)
}
return siamux.New(tcpaddress, wsaddress, logger.Logger, siaMuxDir)
}
// SiaPKToMuxPK turns a SiaPublicKey into a mux.ED25519PublicKey
func SiaPKToMuxPK(spk types.SiaPublicKey) (mk mux.ED25519PublicKey) {
// Sanity check key length
if len(spk.Key) != len(mk) {
panic("Expected the given SiaPublicKey to have a length equal to the mux.ED25519PublicKey length")
}
copy(mk[:], spk.Key)
return
}
// compatLoadKeysFromHost will try and load the host's keypair from its
// persistence file. It tries all host metadata versions before v143. From that
// point on, the siamux was introduced and will already have a correct set of
// keys persisted in its persistence file. Only for hosts upgrading to v143 we
// want to recycle the host keys in the siamux.
func compatLoadKeysFromHost(persistDir string) (pubKey mux.ED25519PublicKey, privKey mux.ED25519SecretKey, compat bool) {
persistPath := filepath.Join(persistDir, HostDir, HostSettingsFile)
historicMetadata := []persist.Metadata{
Hostv120PersistMetadata,
Hostv112PersistMetadata,
}
// Try to load the host's key pair from its persistence file, we try all
// metadata version up until v143
hk := struct {
PublicKey types.SiaPublicKey `json:"publickey"`
SecretKey crypto.SecretKey `json:"secretkey"`
}{}
for _, metadata := range historicMetadata {
err := persist.LoadJSON(metadata, &hk, persistPath)
if err == nil {
copy(pubKey[:], hk.PublicKey.Key[:])
copy(privKey[:], hk.SecretKey[:])
compat = true
return
}
}
compat = false
return
}
// compatV143MigrateSiaMux migrates the SiaMux from the root dir of the sia data
// dir to the siamux subdir.
func compatV143MigrateSiaMux(siaMuxDir, siaDir string) error {
oldPath := filepath.Join(siaDir, "siamux.json")
newPath := filepath.Join(siaMuxDir, "siamux.json")
oldPathTmp := filepath.Join(siaDir, "siamux.json_temp")
newPathTmp := filepath.Join(siaMuxDir, "siamux.json_temp")
oldPathLog := filepath.Join(siaDir, logfile)
newPathLog := filepath.Join(siaMuxDir, logfile)
_, errOld := os.Stat(oldPath)
_, errNew := os.Stat(newPath)
// Migrate if old file exists but no file at new location exists yet.
migrated := false
if errOld == nil && os.IsNotExist(errNew) {
if err := os.Rename(oldPath, newPath); err != nil {
return err
}
migrated = true
}
// If no migration is necessary we are done.
if !migrated {
return nil
}
// If we migrated the main files, also migrate the tmp files if available.
if err := os.Rename(oldPathTmp, newPathTmp); err != nil && !os.IsNotExist(err) {
return err
}
// Also migrate the log file.
if err := os.Rename(oldPathLog, newPathLog); err != nil && !os.IsNotExist(err) {
return err
}
return nil
}