-
Notifications
You must be signed in to change notification settings - Fork 0
/
sessions.go
128 lines (113 loc) · 2.66 KB
/
sessions.go
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package main
import (
"crypto/rand"
"fmt"
"net/http"
"github.com/ahui2016/txt/util"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
)
const (
sessionName = "txt-session"
cookieSignIn = "txt-cookie-signin"
passwordMaxTry = 5
allIP_MaxTry = 100
day = 24 * 60 * 60
defaultMaxAge = 30 * day
)
var ipTryCount = make(map[string]int)
func checkIPTryCount(ip string) error {
if *demo {
return nil // 演示版允许无限重试密码
}
if ipTryCount[ip] >= passwordMaxTry || ipTryCount["all"] >= allIP_MaxTry {
return fmt.Errorf("no more try, input wrong password too many times")
}
return nil
}
// checkPwdAndIP 检查 IP 与主密码,返回 true 表示有错误。
func checkPwdAndIP(c *gin.Context, pwd string) (exit bool) {
ip := c.ClientIP()
if err := checkIPTryCount(ip); err != nil {
c.JSON(http.StatusForbidden, Text{err.Error()})
return true
}
if pwd != db.Config.Password {
ipTryCount[ip]++
ipTryCount["all"]++
c.JSON(http.StatusUnauthorized, Text{"wrong password"})
return true
}
ipTryCount[ip] = 0
return false
}
// checkKeyAndIP 检查 IP 与日常操作密钥,返回 true 表示有错误。
func checkKeyAndIP(c *gin.Context, secretKey string) (exit bool) {
ip := c.ClientIP()
if err := checkIPTryCount(ip); err != nil {
c.JSON(http.StatusForbidden, Text{err.Error()})
return true
}
if err := db.CheckKey(secretKey); err != nil {
ipTryCount[ip]++
ipTryCount["all"]++
c.JSON(http.StatusUnauthorized, Text{err.Error()})
return true
}
ipTryCount[ip] = 0
return false
}
func CliCheckKey() gin.HandlerFunc {
return func(c *gin.Context) {
var form SignInForm
if BindCheck(c, &form) {
c.Abort()
return
}
if checkKeyAndIP(c, form.Password) {
c.Abort()
return
}
c.Next()
}
}
func isSignedIn(c *gin.Context) bool {
session := sessions.Default(c)
yes, _ := session.Get(cookieSignIn).(bool)
return yes
}
func CheckSignIn() gin.HandlerFunc {
return func(c *gin.Context) {
if !isSignedIn(c) {
c.AbortWithStatusJSON(http.StatusUnauthorized, Text{"require sign-in"})
return
}
c.Next()
}
}
func generateRandomKey() []byte {
b := make([]byte, 32)
_, err := rand.Read(b)
util.Panic(err)
return b
}
func newNormalOptions() sessions.Options {
return newOptions(defaultMaxAge)
}
func newExpireOptions() sessions.Options {
return newOptions(-1)
}
func newOptions(maxAge int) sessions.Options {
return sessions.Options{
Path: "/",
MaxAge: maxAge,
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
}
}
func sessionSet(s sessions.Session, val bool, options sessions.Options) error {
s.Set(cookieSignIn, val)
s.Options(options)
return s.Save()
}