| 1 | package calls |
| 2 | |
| 3 | import ( |
| 4 | "crypto/rand" |
| 5 | "crypto/sha256" |
| 6 | "encoding/base64" |
| 7 | "encoding/hex" |
| 8 | "fmt" |
| 9 | "strings" |
| 10 | ) |
| 11 | |
| 12 | // sqidAlphabet is Docs' and Slides' alphabet, character for character: |
| 13 | // no 0/O, no 1/l/I, so a link read aloud survives. |
| 14 | const sqidAlphabet = "23456789abcdefghjkmnpqrstuvwxyz" |
| 15 | const sqidLength = 10 |
| 16 | const maxSqidAttempts = 5 |
| 17 | |
| 18 | // validSqid reports whether s is exactly the shape newSqid ever |
| 19 | // produces: ten characters, every one of them in sqidAlphabet. A |
| 20 | // caller that trusts a room id straight from a URL — a rate limiter's |
| 21 | // key, a log line — must check this first: chi hands back whatever the |
| 22 | // request line contained, unbounded (review Task 5 item 1). |
| 23 | func validSqid(s string) bool { |
| 24 | return len(s) == sqidLength && strings.Trim(s, sqidAlphabet) == "" |
| 25 | } |
| 26 | |
| 27 | func newSqid() (string, error) { |
| 28 | raw := make([]byte, sqidLength) |
| 29 | if _, err := rand.Read(raw); err != nil { |
| 30 | return "", fmt.Errorf("calls: generate sqid: %w", err) |
| 31 | } |
| 32 | out := make([]byte, sqidLength) |
| 33 | for i, b := range raw { |
| 34 | out[i] = sqidAlphabet[int(b)%len(sqidAlphabet)] |
| 35 | } |
| 36 | return string(out), nil |
| 37 | } |
| 38 | |
| 39 | const linkTokenBytes = 32 |
| 40 | |
| 41 | // newLinkToken mints a token and its lookup hash. The store seals invitations |
| 42 | // that need to be shared again; callers never persist the plaintext token. |
| 43 | func newLinkToken() (token, hash string, err error) { |
| 44 | buf := make([]byte, linkTokenBytes) |
| 45 | if _, err := rand.Read(buf); err != nil { |
| 46 | return "", "", err |
| 47 | } |
| 48 | token = base64.RawURLEncoding.EncodeToString(buf) |
| 49 | return token, hashLinkToken(token), nil |
| 50 | } |
| 51 | |
| 52 | func hashLinkToken(token string) string { |
| 53 | sum := sha256.Sum256([]byte(token)) |
| 54 | return hex.EncodeToString(sum[:]) |
| 55 | } |
| 56 | |