oficina / meet Public

Clone
git clone https://amadan.net/oficina/meet

Plain git — no account needed to clone.

Download

Download this file

1package calls
2
3import (
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.
14const sqidAlphabet = "23456789abcdefghjkmnpqrstuvwxyz"
15const sqidLength = 10
16const 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).
23func validSqid(s string) bool {
24 return len(s) == sqidLength && strings.Trim(s, sqidAlphabet) == ""
25}
26
27func 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
39const 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.
43func 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
52func hashLinkToken(token string) string {
53 sum := sha256.Sum256([]byte(token))
54 return hex.EncodeToString(sum[:])
55}
56