carlos / movement Public

Clone
git clone https://amadan.net/carlos/movement

Plain git — no account needed to clone.

Download

Download this file

1package movement
2
3import (
4 "crypto/rand"
5 "crypto/sha256"
6 "encoding/hex"
7 "time"
8)
9
10// TokenLifetime is how long a confirmation link stays good. Long enough for
11// somebody to come back to their inbox tomorrow; short enough that a link
12// sitting in an archive forever is not a live credential.
13const TokenLifetime = 24 * time.Hour
14
15// mintToken returns the token to mail and the hash to store.
16//
17// The token is random, not derived from the instance key. Deriving it would
18// mean a key rotation silently killed every link already in somebody's inbox,
19// and would make the key a second thing that has to survive for the app to
20// keep its promises. Only the hash is stored, so a database read does not
21// hand somebody the ability to confirm other people's addresses.
22func mintToken() (token string, hash []byte) {
23 var raw [32]byte
24 if _, err := rand.Read(raw[:]); err != nil {
25 // Every property of the confirmation flow rests on this being
26 // unguessable. There is no degraded mode worth having.
27 panic("movement: crypto/rand unavailable")
28 }
29 token = hex.EncodeToString(raw[:])
30 return token, hashToken(token)
31}
32
33// hashToken is how a presented token is looked up. Plain SHA-256 is right
34// here and would be wrong for a password: the input is 256 bits of entropy we
35// generated, so there is nothing to brute-force and nothing a slow hash would
36// buy.
37func hashToken(token string) []byte {
38 sum := sha256.Sum256([]byte(token))
39 return sum[:]
40}
41