/
status.go
127 lines (109 loc) · 2.86 KB
/
status.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
// Copyright 2017 David Lazar. All rights reserved.
// Use of this source code is governed by the GNU AGPL
// license that can be found in the LICENSE file.
package pkg
import (
"bytes"
"crypto/ed25519"
"encoding/json"
"net/http"
"github.com/dgraph-io/badger"
"vuvuzela.io/alpenhorn/bloom"
"vuvuzela.io/alpenhorn/log"
)
type statusArgs struct {
Username string
Message [32]byte
ServerSigningKey ed25519.PublicKey `json:"-"`
Signature []byte
}
func (a *statusArgs) msg() []byte {
buf := new(bytes.Buffer)
buf.WriteString("StatusArgs")
buf.Write(a.ServerSigningKey)
id := ValidUsernameToIdentity(a.Username)
buf.Write(id[:])
buf.Write(a.Message[:])
return buf.Bytes()
}
type statusReply struct {
}
func (srv *Server) statusHandler(w http.ResponseWriter, req *http.Request) {
body := http.MaxBytesReader(w, req.Body, 512)
args := new(statusArgs)
err := json.NewDecoder(body).Decode(args)
if err != nil {
httpError(w, errorf(ErrBadRequestJSON, "%s", err))
return
}
args.ServerSigningKey = srv.publicKey
reply, err := srv.checkStatus(args)
if err != nil {
if isInternalError(err) {
srv.log.WithFields(log.Fields{
"username": args.Username,
"code": errorCode(err).String(),
}).Errorf("Status failed: %s", err)
}
httpError(w, err)
return
}
bs, err := json.Marshal(reply)
if err != nil {
panic(err)
}
w.Write(bs)
}
func (srv *Server) checkStatus(args *statusArgs) (*statusReply, error) {
user, _, err := srv.getUser(nil, args.Username)
if err != nil {
return nil, err
}
if !ed25519.Verify(user.LoginKey, args.msg(), args.Signature) {
return nil, errorf(ErrInvalidSignature, "")
}
return &statusReply{}, nil
}
func (srv *Server) RegisteredUsernames() ([]*[64]byte, error) {
users := make([]*[64]byte, 0, 32)
err := srv.db.View(func(tx *badger.Txn) error {
opt := badger.DefaultIteratorOptions
it := tx.NewIterator(opt)
defer it.Close()
for it.Seek(dbUserPrefix); it.ValidForPrefix(dbUserPrefix); it.Next() {
key := it.Item().Key()
if !bytes.HasSuffix(key, registrationSuffix) {
continue
}
userID := bytes.TrimSuffix(bytes.TrimPrefix(key, dbUserPrefix), registrationSuffix)
clone := new([64]byte)
copy(clone[:], userID)
users = append(users, clone)
}
return nil
})
if err != nil {
return nil, err
}
return users, nil
}
func (srv *Server) userFilterHandler(w http.ResponseWriter, req *http.Request) {
if !srv.authorized(srv.registrarKey, w, req) {
return
}
usernames, err := srv.RegisteredUsernames()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Leave some room in the bloom filter so the registrar can add its own usernames.
f := bloom.New(bloom.Optimal(len(usernames)+1000, 0.0001))
for _, username := range usernames {
f.Set(username[:])
}
data, err := json.Marshal(f)
if err != nil {
panic(err)
}
w.Write(data)
}