Skip to content

Commit 1d49e4f

Browse files
committed
Lightly refactor nonce service to clean up abstraction
1 parent c1af7fc commit 1d49e4f

File tree

5 files changed

+63
-78
lines changed

5 files changed

+63
-78
lines changed

cmd/nonce-service/main.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,8 @@ func main() {
9393
tlsConfig, err := c.NonceService.TLS.Load(scope)
9494
cmd.FailOnError(err, "tlsConfig config")
9595

96-
nonceServer := nonce.NewServer(ns)
9796
start, err := bgrpc.NewServer(c.NonceService.GRPC, logger).Add(
98-
&noncepb.NonceService_ServiceDesc, nonceServer).Build(tlsConfig, scope, clock.New())
97+
&noncepb.NonceService_ServiceDesc, ns).Build(tlsConfig, scope, clock.New())
9998
cmd.FailOnError(err, "Unable to setup nonce service gRPC server")
10099

101100
logger.Info(fmt.Sprintf("Nonce server listening on %s with prefix %q", c.NonceService.GRPC.Address, noncePrefix))

nonce/nonce.go

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ func DerivePrefix(grpcAddr string, key []byte) string {
6363

6464
// NonceService generates, cancels, and tracks Nonces.
6565
type NonceService struct {
66+
noncepb.UnsafeNonceServiceServer
6667
mu sync.Mutex
6768
latest int64
6869
earliest int64
@@ -232,8 +233,8 @@ func (ns *NonceService) decrypt(nonce string) (int64, error) {
232233
return ctr.Int64(), nil
233234
}
234235

235-
// Nonce provides a new Nonce.
236-
func (ns *NonceService) Nonce() (string, error) {
236+
// nonce provides a new Nonce.
237+
func (ns *NonceService) nonce() (string, error) {
237238
ns.mu.Lock()
238239
ns.latest++
239240
latest := ns.latest
@@ -242,30 +243,30 @@ func (ns *NonceService) Nonce() (string, error) {
242243
return ns.encrypt(latest)
243244
}
244245

245-
// Valid determines whether the provided Nonce string is valid, returning
246+
// valid determines whether the provided Nonce string is valid, returning
246247
// true if so.
247-
func (ns *NonceService) Valid(nonce string) bool {
248+
func (ns *NonceService) valid(nonce string) error {
248249
c, err := ns.decrypt(nonce)
249250
if err != nil {
250251
ns.nonceRedeems.WithLabelValues("invalid", "decrypt").Inc()
251-
return false
252+
return fmt.Errorf("unable to decrypt nonce: %s", err)
252253
}
253254

254255
ns.mu.Lock()
255256
defer ns.mu.Unlock()
256257
if c > ns.latest {
257258
ns.nonceRedeems.WithLabelValues("invalid", "too high").Inc()
258-
return false
259+
return fmt.Errorf("nonce greater than highest dispensed nonce: %d > %d", c, ns.latest)
259260
}
260261

261262
if c <= ns.earliest {
262263
ns.nonceRedeems.WithLabelValues("invalid", "too low").Inc()
263-
return false
264+
return fmt.Errorf("nonce less than lowest eligible nonce: %d < %d", c, ns.earliest)
264265
}
265266

266267
if ns.used[c] {
267268
ns.nonceRedeems.WithLabelValues("invalid", "already used").Inc()
268-
return false
269+
return fmt.Errorf("nonce already marked as used: %d ∈ used{%d}", c, len(ns.used))
269270
}
270271

271272
ns.used[c] = true
@@ -279,7 +280,7 @@ func (ns *NonceService) Valid(nonce string) bool {
279280
}
280281

281282
ns.nonceRedeems.WithLabelValues("valid", "").Inc()
282-
return true
283+
return nil
283284
}
284285

285286
// splitNonce splits a nonce into a prefix and a body.
@@ -290,27 +291,18 @@ func (ns *NonceService) splitNonce(nonce string) (string, string, error) {
290291
return nonce[:PrefixLen], nonce[PrefixLen:], nil
291292
}
292293

293-
// NewServer returns a new Server, wrapping a NonceService.
294-
func NewServer(inner *NonceService) *Server {
295-
return &Server{inner: inner}
296-
}
297-
298-
// Server implements the gRPC nonce service.
299-
type Server struct {
300-
noncepb.UnsafeNonceServiceServer
301-
inner *NonceService
302-
}
303-
304-
var _ noncepb.NonceServiceServer = (*Server)(nil)
305-
306294
// Redeem accepts a nonce from a gRPC client and redeems it using the inner nonce service.
307-
func (ns *Server) Redeem(ctx context.Context, msg *noncepb.NonceMessage) (*noncepb.ValidMessage, error) {
308-
return &noncepb.ValidMessage{Valid: ns.inner.Valid(msg.Nonce)}, nil
295+
func (ns *NonceService) Redeem(ctx context.Context, msg *noncepb.NonceMessage) (*noncepb.ValidMessage, error) {
296+
err := ns.valid(msg.Nonce)
297+
if err != nil {
298+
return nil, err
299+
}
300+
return &noncepb.ValidMessage{Valid: true}, nil
309301
}
310302

311303
// Nonce generates a nonce and sends it to a gRPC client.
312-
func (ns *Server) Nonce(_ context.Context, _ *emptypb.Empty) (*noncepb.NonceMessage, error) {
313-
nonce, err := ns.inner.Nonce()
304+
func (ns *NonceService) Nonce(_ context.Context, _ *emptypb.Empty) (*noncepb.NonceMessage, error) {
305+
nonce, err := ns.nonce()
314306
if err != nil {
315307
return nil, err
316308
}

nonce/nonce_test.go

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,32 @@ import (
1111
func TestValidNonce(t *testing.T) {
1212
ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
1313
test.AssertNotError(t, err, "Could not create nonce service")
14-
n, err := ns.Nonce()
14+
n, err := ns.nonce()
1515
test.AssertNotError(t, err, "Could not create nonce")
16-
test.Assert(t, ns.Valid(n), fmt.Sprintf("Did not recognize fresh nonce %s", n))
16+
test.AssertNotError(t, ns.valid(n), fmt.Sprintf("Did not recognize fresh nonce %s", n))
1717
}
1818

1919
func TestAlreadyUsed(t *testing.T) {
2020
ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
2121
test.AssertNotError(t, err, "Could not create nonce service")
22-
n, err := ns.Nonce()
22+
n, err := ns.nonce()
2323
test.AssertNotError(t, err, "Could not create nonce")
24-
test.Assert(t, ns.Valid(n), "Did not recognize fresh nonce")
25-
test.Assert(t, !ns.Valid(n), "Recognized the same nonce twice")
24+
test.AssertNotError(t, ns.valid(n), "Did not recognize fresh nonce")
25+
test.AssertError(t, ns.valid(n), "Recognized the same nonce twice")
2626
}
2727

2828
func TestRejectMalformed(t *testing.T) {
2929
ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
3030
test.AssertNotError(t, err, "Could not create nonce service")
31-
n, err := ns.Nonce()
31+
n, err := ns.nonce()
3232
test.AssertNotError(t, err, "Could not create nonce")
33-
test.Assert(t, !ns.Valid("asdf"+n), "Accepted an invalid nonce")
33+
test.AssertError(t, ns.valid("asdf"+n), "Accepted an invalid nonce")
3434
}
3535

3636
func TestRejectShort(t *testing.T) {
3737
ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
3838
test.AssertNotError(t, err, "Could not create nonce service")
39-
test.Assert(t, !ns.Valid("aGkK"), "Accepted an invalid nonce")
39+
test.AssertError(t, ns.valid("aGkK"), "Accepted an invalid nonce")
4040
}
4141

4242
func TestRejectUnknown(t *testing.T) {
@@ -45,48 +45,48 @@ func TestRejectUnknown(t *testing.T) {
4545
ns2, err := NewNonceService(metrics.NoopRegisterer, 0, "")
4646
test.AssertNotError(t, err, "Could not create nonce service")
4747

48-
n, err := ns1.Nonce()
48+
n, err := ns1.nonce()
4949
test.AssertNotError(t, err, "Could not create nonce")
50-
test.Assert(t, !ns2.Valid(n), "Accepted a foreign nonce")
50+
test.AssertError(t, ns2.valid(n), "Accepted a foreign nonce")
5151
}
5252

5353
func TestRejectTooLate(t *testing.T) {
5454
ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
5555
test.AssertNotError(t, err, "Could not create nonce service")
5656

5757
ns.latest = 2
58-
n, err := ns.Nonce()
58+
n, err := ns.nonce()
5959
test.AssertNotError(t, err, "Could not create nonce")
6060
ns.latest = 1
61-
test.Assert(t, !ns.Valid(n), "Accepted a nonce with a too-high counter")
61+
test.AssertError(t, ns.valid(n), "Accepted a nonce with a too-high counter")
6262
}
6363

6464
func TestRejectTooEarly(t *testing.T) {
6565
ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
6666
test.AssertNotError(t, err, "Could not create nonce service")
6767

68-
n0, err := ns.Nonce()
68+
n0, err := ns.nonce()
6969
test.AssertNotError(t, err, "Could not create nonce")
7070

7171
for range ns.maxUsed {
72-
n, err := ns.Nonce()
72+
n, err := ns.nonce()
7373
test.AssertNotError(t, err, "Could not create nonce")
74-
if !ns.Valid(n) {
74+
if ns.valid(n) != nil {
7575
t.Errorf("generated invalid nonce")
7676
}
7777
}
7878

79-
n1, err := ns.Nonce()
79+
n1, err := ns.nonce()
8080
test.AssertNotError(t, err, "Could not create nonce")
81-
n2, err := ns.Nonce()
81+
n2, err := ns.nonce()
8282
test.AssertNotError(t, err, "Could not create nonce")
83-
n3, err := ns.Nonce()
83+
n3, err := ns.nonce()
8484
test.AssertNotError(t, err, "Could not create nonce")
8585

86-
test.Assert(t, ns.Valid(n3), "Rejected a valid nonce")
87-
test.Assert(t, ns.Valid(n2), "Rejected a valid nonce")
88-
test.Assert(t, ns.Valid(n1), "Rejected a valid nonce")
89-
test.Assert(t, !ns.Valid(n0), "Accepted a nonce that we should have forgotten")
86+
test.AssertNotError(t, ns.valid(n3), "Rejected a valid nonce")
87+
test.AssertNotError(t, ns.valid(n2), "Rejected a valid nonce")
88+
test.AssertNotError(t, ns.valid(n1), "Rejected a valid nonce")
89+
test.AssertError(t, ns.valid(n0), "Accepted a nonce that we should have forgotten")
9090
}
9191

9292
func BenchmarkNonces(b *testing.B) {
@@ -96,23 +96,23 @@ func BenchmarkNonces(b *testing.B) {
9696
}
9797

9898
for range ns.maxUsed {
99-
n, err := ns.Nonce()
99+
n, err := ns.nonce()
100100
if err != nil {
101101
b.Fatal("noncing", err)
102102
}
103-
if !ns.Valid(n) {
103+
if ns.valid(n) != nil {
104104
b.Fatal("generated invalid nonce")
105105
}
106106
}
107107

108108
b.ResetTimer()
109109
b.RunParallel(func(pb *testing.PB) {
110110
for pb.Next() {
111-
n, err := ns.Nonce()
111+
n, err := ns.nonce()
112112
if err != nil {
113113
b.Fatal("noncing", err)
114114
}
115-
if !ns.Valid(n) {
115+
if ns.valid(n) != nil {
116116
b.Fatal("generated invalid nonce")
117117
}
118118
}
@@ -123,18 +123,18 @@ func TestNoncePrefixing(t *testing.T) {
123123
ns, err := NewNonceService(metrics.NoopRegisterer, 0, "aluminum")
124124
test.AssertNotError(t, err, "Could not create nonce service")
125125

126-
n, err := ns.Nonce()
126+
n, err := ns.nonce()
127127
test.AssertNotError(t, err, "Could not create nonce")
128-
test.Assert(t, ns.Valid(n), "Valid nonce rejected")
128+
test.AssertNotError(t, ns.valid(n), "Valid nonce rejected")
129129

130-
n, err = ns.Nonce()
130+
n, err = ns.nonce()
131131
test.AssertNotError(t, err, "Could not create nonce")
132132
n = n[1:]
133-
test.Assert(t, !ns.Valid(n), "Valid nonce with incorrect prefix accepted")
133+
test.AssertError(t, ns.valid(n), "Valid nonce with incorrect prefix accepted")
134134

135-
n, err = ns.Nonce()
135+
n, err = ns.nonce()
136136
test.AssertNotError(t, err, "Could not create nonce")
137-
test.Assert(t, !ns.Valid(n[6:]), "Valid nonce without prefix accepted")
137+
test.AssertError(t, ns.valid(n[6:]), "Valid nonce without prefix accepted")
138138
}
139139

140140
func TestNoncePrefixValidation(t *testing.T) {

test/inmem/nonce/nonce.go

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,27 @@ import (
1111
noncepb "github.com/letsencrypt/boulder/nonce/proto"
1212
)
1313

14-
// Service implements noncepb.NonceServiceClient for tests.
15-
type Service struct {
16-
*nonce.NonceService
14+
// NonceService implements noncepb.NonceServiceClient for tests.
15+
type NonceService struct {
16+
noncepb.NonceServiceClient
17+
Impl *nonce.NonceService
1718
}
1819

19-
var _ noncepb.NonceServiceClient = &Service{}
20+
var _ noncepb.NonceServiceClient = &NonceService{}
2021

21-
// Nonce implements proto.NonceServiceClient
22-
func (imns *Service) Nonce(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*noncepb.NonceMessage, error) {
23-
n, err := imns.NonceService.Nonce()
24-
if err != nil {
25-
return nil, err
26-
}
27-
return &noncepb.NonceMessage{Nonce: n}, nil
22+
func (ns *NonceService) Nonce(ctx context.Context, req *emptypb.Empty, opts ...grpc.CallOption) (*noncepb.NonceMessage, error) {
23+
return ns.Impl.Nonce(ctx, req)
2824
}
2925

30-
// Redeem implements proto.NonceServiceClient
31-
func (imns *Service) Redeem(ctx context.Context, in *noncepb.NonceMessage, opts ...grpc.CallOption) (*noncepb.ValidMessage, error) {
32-
valid := imns.NonceService.Valid(in.Nonce)
33-
return &noncepb.ValidMessage{Valid: valid}, nil
26+
func (ns *NonceService) Redeem(ctx context.Context, req *noncepb.NonceMessage, opts ...grpc.CallOption) (*noncepb.ValidMessage, error) {
27+
return ns.Impl.Redeem(ctx, req)
3428
}
3529

3630
// AsSource returns a wrapper type that implements jose.NonceSource using this
3731
// inmemory service. This is useful so that tests can get nonces for signing
3832
// their JWS that will be accepted by the test WFE configured using this service.
39-
func (imns *Service) AsSource() jose.NonceSource {
40-
return nonceServiceAdapter{imns}
33+
func (ns *NonceService) AsSource() jose.NonceSource {
34+
return nonceServiceAdapter{ns}
4135
}
4236

4337
// nonceServiceAdapter changes the gRPC nonce service interface to the one

wfe2/wfe_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ func setupWFE(t *testing.T) (WebFrontEndImpl, clock.FakeClock, requestSigner) {
404404
nonceService, err := nonce.NewNonceService(metrics.NoopRegisterer, 100, noncePrefix)
405405
test.AssertNotError(t, err, "making nonceService")
406406

407-
inmemNonceService := &inmemnonce.Service{NonceService: nonceService}
407+
inmemNonceService := &inmemnonce.NonceService{Impl: nonceService}
408408
gnc := inmemNonceService
409409
rnc := inmemNonceService
410410

0 commit comments

Comments
 (0)