~gitpocket/gitpocket

4
b2d422c9d104bb7bfce4fb06ef809146a8299551
mainfeed-discovery
gitpocket/totp.go -rw-r--r--1.8 KiB ViewLogBlameView rawPermalink e8ffab4e14 feat(basin): mail, totp, issues, stars, blame and feeds 1 months ago
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package main

import (
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/base32"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"strings"
	"time"
)

func newSecret() string {
	b := make([]byte, 20)
	rand.Read(b)
	return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(b)
}

func totpCode(secret string, t time.Time) string {
	key, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(strings.ToUpper(secret))
	if err != nil {
		return ""
	}
	counter := make([]byte, 8)
	binary.BigEndian.PutUint64(counter, uint64(t.Unix()/30))
	mac := hmac.New(sha1.New, key)
	mac.Write(counter)
	sum := mac.Sum(nil)
	offset := sum[len(sum)-1] & 0x0f
	code := binary.BigEndian.Uint32(sum[offset:offset+4]) & 0x7fffffff
	return fmt.Sprintf("%06d", code%1000000)
}

func totpValid(secret, code string) bool {
	code = strings.ReplaceAll(strings.TrimSpace(code), " ", "")
	now := time.Now()
	for _, d := range []time.Duration{0, -30 * time.Second, 30 * time.Second} {
		if hmac.Equal([]byte(totpCode(secret, now.Add(d))), []byte(code)) {
			return true
		}
	}
	return false
}

func newRecoveryCodes() ([]string, string) {
	var codes, hashes []string
	for i := 0; i < 8; i++ {
		b := make([]byte, 5)
		rand.Read(b)
		code := hex.EncodeToString(b)
		codes = append(codes, code[:5]+"-"+code[5:])
		sum := sha256.Sum256([]byte(code))
		hashes = append(hashes, hex.EncodeToString(sum[:]))
	}
	return codes, strings.Join(hashes, ",")
}

func useRecovery(stored, code string) (string, bool) {
	code = strings.ToLower(strings.ReplaceAll(strings.TrimSpace(code), "-", ""))
	sum := sha256.Sum256([]byte(code))
	h := hex.EncodeToString(sum[:])
	var kept []string
	found := false
	for _, x := range strings.Split(stored, ",") {
		if x == h && !found {
			found = true
			continue
		}
		if x != "" {
			kept = append(kept, x)
		}
	}
	return strings.Join(kept, ","), found
}