@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 137 lines 3.76 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package standardstek
16
17 import (
18 "log"
19 "runtime/debug"
20 "sync"
21 "time"
22
23 "github.com/caddyserver/caddy/v2"
24 "github.com/caddyserver/caddy/v2/modules/caddytls"
25 )
26
27 func init() {
28 caddy.RegisterModule(standardSTEKProvider{})
29 }
30
31 type standardSTEKProvider struct {
32 stekConfig *caddytls.SessionTicketService
33 timer *time.Timer
34 }
35
36 // CaddyModule returns the Caddy module information.
37 func (standardSTEKProvider) CaddyModule() caddy.ModuleInfo {
38 return caddy.ModuleInfo{
39 ID: "tls.stek.standard",
40 New: func() caddy.Module { return new(standardSTEKProvider) },
41 }
42 }
43
44 // Initialize sets the configuration for s and returns the starting keys.
45 func (s *standardSTEKProvider) Initialize(config *caddytls.SessionTicketService) ([][32]byte, error) {
46 // keep a reference to the config; we'll need it when rotating keys
47 s.stekConfig = config
48
49 itvl := time.Duration(s.stekConfig.RotationInterval)
50
51 mutex.Lock()
52 defer mutex.Unlock()
53
54 // if this is our first rotation or we are overdue
55 // for one, perform a rotation immediately; otherwise,
56 // we assume that the keys are non-empty and fresh
57 since := time.Since(lastRotation)
58 if lastRotation.IsZero() || since > itvl {
59 var err error
60 keys, err = s.stekConfig.RotateSTEKs(keys)
61 if err != nil {
62 return nil, err
63 }
64 since = 0 // since this is overdue or is the first rotation, use full interval
65 lastRotation = time.Now()
66 }
67
68 // create timer for the remaining time on the interval;
69 // this timer is cleaned up only when Next() returns
70 s.timer = time.NewTimer(itvl - since)
71
72 return keys, nil
73 }
74
75 // Next returns a channel which transmits the latest session ticket keys.
76 func (s *standardSTEKProvider) Next(doneChan <-chan struct{}) <-chan [][32]byte {
77 keysChan := make(chan [][32]byte)
78 go s.rotate(doneChan, keysChan)
79 return keysChan
80 }
81
82 // rotate rotates keys on a regular basis, sending each updated set of
83 // keys down keysChan, until doneChan is closed.
84 func (s *standardSTEKProvider) rotate(doneChan <-chan struct{}, keysChan chan<- [][32]byte) {
85 defer func() {
86 if err := recover(); err != nil {
87 log.Printf("[PANIC] standard STEK rotation: %v\n%s", err, debug.Stack())
88 }
89 }()
90 for {
91 select {
92 case now := <-s.timer.C:
93 // copy the slice header to avoid races
94 mutex.RLock()
95 keysCopy := keys
96 mutex.RUnlock()
97
98 // generate a new key, rotating old ones
99 var err error
100 keysCopy, err = s.stekConfig.RotateSTEKs(keysCopy)
101 if err != nil {
102 // TODO: improve this handling
103 log.Printf("[ERROR] Generating STEK: %v", err)
104 continue
105 }
106
107 // replace keys slice with updated value and
108 // record the timestamp of rotation
109 mutex.Lock()
110 keys = keysCopy
111 lastRotation = now
112 mutex.Unlock()
113
114 // send the updated keys to the service
115 keysChan <- keysCopy
116
117 // timer channel is already drained, so reset directly (see godoc)
118 s.timer.Reset(time.Duration(s.stekConfig.RotationInterval))
119
120 case <-doneChan:
121 // again, see godocs for why timer is stopped this way
122 if !s.timer.Stop() {
123 <-s.timer.C
124 }
125 return
126 }
127 }
128 }
129
130 var (
131 lastRotation time.Time
132 keys [][32]byte
133 mutex sync.RWMutex // protects keys and lastRotation
134 )
135
136 // Interface guard
137 var _ caddytls.STEKProvider = (*standardSTEKProvider)(nil)