-
Notifications
You must be signed in to change notification settings - Fork 1
/
store.go
162 lines (145 loc) · 3.55 KB
/
store.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
package main
import (
"bufio"
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"encoding/json"
"errors"
"fmt"
"log"
"math/big"
"net"
"os"
"strings"
"github.com/tstranex/u2f"
)
type miniReg struct {
Raw []byte
KeyHandle []byte
PubKey struct {
X big.Int
Y big.Int
}
}
// SaveRegistration saves registration to file
func SaveRegistration(remoteAddr string, r u2f.Registration) error {
if err := write("registration", remoteAddr, &r); err != nil {
return err
}
return nil
}
// LoadRegistration loads a registration based on an ip
// It is not possible to just unmarshal the elliptic.Curve
// object, so we jump through some hoops for that.
func LoadRegistration(remoteAddr string) (*u2f.Registration, error) {
mreg := miniReg{}
if err := load("registration", remoteAddr, &mreg); err != nil {
return nil, err
}
var pubk = ecdsa.PublicKey{
Curve: elliptic.P256(),
X: &mreg.PubKey.X,
Y: &mreg.PubKey.Y,
}
var reg = u2f.Registration{
Raw: mreg.Raw,
KeyHandle: mreg.KeyHandle,
PubKey: pubk,
}
return ®, nil
}
// SaveChallenge saves a challenge to file
func SaveChallenge(remoteAddr string, c *u2f.Challenge) error {
log.Printf("saving challenge to %v", remoteAddr)
if err := write("challenge", remoteAddr, c); err != nil {
return err
}
return nil
}
// LoadChallenge loads a registration based on an ip
func LoadChallenge(remoteAddr string) (*u2f.Challenge, error) {
var chl = u2f.Challenge{}
if err := load("challenge", remoteAddr, &chl); err != nil {
log.Printf("Failed to load challenge for ip %v", remoteAddr)
return nil, err
}
log.Printf("challenge; %v", chl)
return &chl, nil
}
func write(t string, remoteAddr string, val interface{}) error {
if err := ensureDir(t); err != nil {
return err
}
sIp, err := safeIp(remoteAddr)
if err != nil {
return errors.New("Invalid ip")
}
var buf bytes.Buffer
encoder := json.NewEncoder(&buf)
encoder.Encode(&val)
filePath := fmt.Sprintf("%v/%v", t, sIp)
log.Printf("will write %v to %v", buf, filePath)
fd, err := os.Create(filePath)
if err != nil {
log.Printf("Failed to create file %v", filePath)
return err
}
defer fd.Close()
w := bufio.NewWriter(fd)
writtenBytes, err := buf.WriteTo(w)
w.Flush()
if err != nil {
log.Printf("failed to write file %v", filePath)
return err
}
log.Printf("Success writing to file %v", writtenBytes)
return nil
}
func load(t string, remoteAddr string, val interface{}) error {
if err := ensureDir(t); err != nil {
return err
}
sIp, err := safeIp(remoteAddr)
if err != nil {
return err
}
filePath := fmt.Sprintf("%v/%v", t, sIp)
fd, err := os.Open(filePath)
if err != nil {
log.Printf("Failed to open file: %v", filePath)
return err
}
defer fd.Close()
ioR := bufio.NewReader(fd)
decoder := json.NewDecoder(ioR)
err = decoder.Decode(&val)
if err != nil {
log.Printf("Failed to decode json from %v, %v", filePath, err)
return err
}
return nil
}
func safeIp(remoteAddr string) (string, error) {
splitted, _, err := net.SplitHostPort(remoteAddr)
if err != nil {
return "", errors.New(fmt.Sprintf("failed to split port from ip %v", remoteAddr))
}
ipObj := net.ParseIP(splitted)
if ipObj == nil {
log.Printf("Failed to parse ip: %v", remoteAddr)
return "", errors.New("Failed to parse ip")
}
return strings.Replace(ipObj.String(), ":", "x", -1), nil
}
func ensureDir(t string) error {
path := t
if _, err := os.Stat(path); os.IsNotExist(err) {
osErr := os.Mkdir(path, 0755)
if osErr != nil {
log.Printf("failed to create dir %v due to %v", path, osErr)
return osErr
}
}
return nil
}