58 lines
1.3 KiB
Go
58 lines
1.3 KiB
Go
|
package dht
|
||
|
|
||
|
import (
|
||
|
"crypto/sha1"
|
||
|
"encoding/binary"
|
||
|
"time"
|
||
|
|
||
|
"github.com/bradfitz/iter"
|
||
|
)
|
||
|
|
||
|
// Manages creation and validation of tokens issued to querying nodes.
|
||
|
type tokenServer struct {
|
||
|
// Something only we know that peers can't guess, so they can't deduce valid tokens.
|
||
|
secret []byte
|
||
|
// How long between token changes.
|
||
|
interval time.Duration
|
||
|
// How many intervals may pass between the current interval, and one used to generate a token before it is invalid.
|
||
|
maxIntervalDelta int
|
||
|
timeNow func() time.Time
|
||
|
}
|
||
|
|
||
|
func (me tokenServer) CreateToken(addr Addr) string {
|
||
|
return me.createToken(addr, me.getTimeNow())
|
||
|
}
|
||
|
|
||
|
func (me tokenServer) createToken(addr Addr, t time.Time) string {
|
||
|
h := sha1.New()
|
||
|
ip := addr.UDPAddr().IP.To16()
|
||
|
if len(ip) != 16 {
|
||
|
panic(ip)
|
||
|
}
|
||
|
h.Write(ip)
|
||
|
ti := t.UnixNano() / int64(me.interval)
|
||
|
var b [8]byte
|
||
|
binary.BigEndian.PutUint64(b[:], uint64(ti))
|
||
|
h.Write(b[:])
|
||
|
h.Write(me.secret)
|
||
|
return string(h.Sum(nil))
|
||
|
}
|
||
|
|
||
|
func (me *tokenServer) ValidToken(token string, addr Addr) bool {
|
||
|
t := me.getTimeNow()
|
||
|
for range iter.N(me.maxIntervalDelta + 1) {
|
||
|
if me.createToken(addr, t) == token {
|
||
|
return true
|
||
|
}
|
||
|
t = t.Add(-me.interval)
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (me *tokenServer) getTimeNow() time.Time {
|
||
|
if me.timeNow == nil {
|
||
|
return time.Now()
|
||
|
}
|
||
|
return me.timeNow()
|
||
|
}
|