• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DigitalTolk / wireguard-ui / 24860158850

23 Apr 2026 09:37PM UTC coverage: 89.866% (-0.2%) from 90.064%
24860158850

Pull #21

github

web-flow
Merge a78b67a93 into 2b36d33b8
Pull Request #21: Remove remember-me

535 of 600 branches covered (89.17%)

Branch coverage included in aggregate %.

4 of 5 new or added lines in 2 files covered. (80.0%)

2 existing lines in 1 file now uncovered.

3216 of 3574 relevant lines covered (89.98%)

44.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.7
/handler/session.go
1
package handler
2

3
import (
4
        "fmt"
5
        "net/http"
6
        "time"
7

8
        "github.com/DigitalTolk/wireguard-ui/util"
9
        "github.com/gorilla/sessions"
10
        "github.com/labstack/echo-contrib/session"
11
        "github.com/labstack/echo/v4"
12
        "github.com/labstack/gommon/log"
13
        "github.com/rs/xid"
14
)
15

16
func isValidSession(c echo.Context) bool {
9✔
17
        if util.DisableLogin {
10✔
18
                return true
1✔
19
        }
1✔
20
        sess, _ := session.Get("session", c)
8✔
21
        cookie, err := c.Cookie("session_token")
8✔
22
        if err != nil || sess.Values["session_token"] != cookie.Value {
10✔
23
                log.Debugf("session invalid: token cookie mismatch (err=%v)", err)
2✔
24
                return false
2✔
25
        }
2✔
26

27
        // Check time bounds
28
        createdAt := getCreatedAt(sess)
6✔
29
        updatedAt := getUpdatedAt(sess)
6✔
30
        maxAge := getMaxAge(sess)
6✔
31
        // Temporary session is considered valid within 24h if browser is not closed before
6✔
32
        // This value is not saved and is used as virtual expiration
6✔
33
        if maxAge == 0 {
6✔
UNCOV
34
                maxAge = 86400
×
UNCOV
35
        }
×
36
        expiration := updatedAt + int64(maxAge)
6✔
37
        now := time.Now().UTC().Unix()
6✔
38
        if updatedAt > now || expiration < now || createdAt+util.SessionMaxDuration < now {
7✔
39
                log.Debugf("session invalid: time bounds (updatedAt=%d, expiration=%d, maxDuration=%d, now=%d)", updatedAt, expiration, createdAt+util.SessionMaxDuration, now)
1✔
40
                return false
1✔
41
        }
1✔
42

43
        // Check if user still exists and unchanged
44
        username := fmt.Sprintf("%s", sess.Values["username"])
5✔
45
        userHash := getUserHash(sess)
5✔
46
        util.DBUsersToCRC32Mutex.RLock()
5✔
47
        uHash, ok := util.DBUsersToCRC32[username]
5✔
48
        util.DBUsersToCRC32Mutex.RUnlock()
5✔
49
        if !ok || userHash != uHash {
7✔
50
                log.Debugf("session invalid: user hash mismatch (user=%s, ok=%v, sessHash=%d, dbHash=%d)", username, ok, userHash, uHash)
2✔
51
                return false
2✔
52
        }
2✔
53

54
        return true
3✔
55
}
56

57
// Get time in seconds this session is valid without updating
58
func getMaxAge(sess *sessions.Session) int {
10✔
59
        if util.DisableLogin {
11✔
60
                return 0
1✔
61
        }
1✔
62

63
        maxAge := sess.Values["max_age"]
9✔
64

9✔
65
        switch typedMaxAge := maxAge.(type) {
9✔
66
        case int:
7✔
67
                return typedMaxAge
7✔
68
        default:
2✔
69
                return 0
2✔
70
        }
71
}
72

73
// Get a timestamp in seconds of the time the session was created
74
func getCreatedAt(sess *sessions.Session) int64 {
10✔
75
        if util.DisableLogin {
11✔
76
                return 0
1✔
77
        }
1✔
78

79
        createdAt := sess.Values["created_at"]
9✔
80

9✔
81
        switch typedCreatedAt := createdAt.(type) {
9✔
82
        case int64:
7✔
83
                return typedCreatedAt
7✔
84
        default:
2✔
85
                return 0
2✔
86
        }
87
}
88

89
// Get a timestamp in seconds of the last session update
90
func getUpdatedAt(sess *sessions.Session) int64 {
10✔
91
        if util.DisableLogin {
11✔
92
                return 0
1✔
93
        }
1✔
94

95
        lastUpdate := sess.Values["updated_at"]
9✔
96

9✔
97
        switch typedLastUpdate := lastUpdate.(type) {
9✔
98
        case int64:
7✔
99
                return typedLastUpdate
7✔
100
        default:
2✔
101
                return 0
2✔
102
        }
103
}
104

105
// Get CRC32 of a user at the moment of log in
106
// Any changes to user will result in logout of other (not updated) sessions
107
func getUserHash(sess *sessions.Session) uint32 {
8✔
108
        if util.DisableLogin {
9✔
109
                return 0
1✔
110
        }
1✔
111

112
        userHash := sess.Values["user_hash"]
7✔
113

7✔
114
        switch typedUserHash := userHash.(type) {
7✔
115
        case uint32:
6✔
116
                return typedUserHash
6✔
117
        default:
1✔
118
                return 0
1✔
119
        }
120
}
121

122
// currentUser to get username of logged in user
123
func currentUser(c echo.Context) string {
25✔
124
        if util.DisableLogin {
31✔
125
                return ""
6✔
126
        }
6✔
127

128
        sess, _ := session.Get("session", c)
19✔
129
        username := fmt.Sprintf("%s", sess.Values["username"])
19✔
130
        return username
19✔
131
}
132

133
// isAdmin to get user type: admin or manager
134
func isAdmin(c echo.Context) bool {
27✔
135
        if util.DisableLogin {
43✔
136
                return true
16✔
137
        }
16✔
138

139
        sess, _ := session.Get("session", c)
11✔
140
        admin := fmt.Sprintf("%t", sess.Values["admin"])
11✔
141
        return admin == "true"
11✔
142
}
143

144
// createSession establishes a new authenticated session for the user
145
func createSession(c echo.Context, username string, admin bool, userCRC32 uint32) {
21✔
146
        maxAge := int(util.SessionMaxDuration)
21✔
147
        if maxAge <= 0 {
39✔
148
                maxAge = 86400 // 1 day default
18✔
149
        }
18✔
150

151
        cookiePath := util.GetCookiePath()
21✔
152
        sess, _ := session.Get("session", c)
21✔
153
        sess.Options = &sessions.Options{
21✔
154
                Path:     cookiePath,
21✔
155
                MaxAge:   maxAge,
21✔
156
                HttpOnly: true,
21✔
157
                SameSite: http.SameSiteLaxMode,
21✔
158
        }
21✔
159

21✔
160
        tokenUID := xid.New().String()
21✔
161
        now := time.Now().UTC().Unix()
21✔
162
        sess.Values["username"] = username
21✔
163
        sess.Values["user_hash"] = userCRC32
21✔
164
        sess.Values["admin"] = admin
21✔
165
        sess.Values["session_token"] = tokenUID
21✔
166
        sess.Values["max_age"] = maxAge
21✔
167
        sess.Values["created_at"] = now
21✔
168
        sess.Values["updated_at"] = now
21✔
169
        sess.Save(c.Request(), c.Response())
21✔
170

21✔
171
        cookie := new(http.Cookie)
21✔
172
        cookie.Name = "session_token"
21✔
173
        cookie.Path = cookiePath
21✔
174
        cookie.Value = tokenUID
21✔
175
        cookie.MaxAge = maxAge
21✔
176
        cookie.HttpOnly = true
21✔
177
        cookie.SameSite = http.SameSiteLaxMode
21✔
178
        c.SetCookie(cookie)
21✔
179
}
180

181
func setUser(c echo.Context, username string, admin bool, userCRC32 uint32) {
1✔
182
        sess, _ := session.Get("session", c)
1✔
183
        sess.Values["username"] = username
1✔
184
        sess.Values["user_hash"] = userCRC32
1✔
185
        sess.Values["admin"] = admin
1✔
186
        sess.Save(c.Request(), c.Response())
1✔
187
}
1✔
188

189
// clearSession to remove current session
190
func clearSession(c echo.Context) {
3✔
191
        sess, _ := session.Get("session", c)
3✔
192
        sess.Values["username"] = ""
3✔
193
        sess.Values["user_hash"] = 0
3✔
194
        sess.Values["admin"] = false
3✔
195
        sess.Values["session_token"] = ""
3✔
196
        sess.Values["max_age"] = -1
3✔
197
        sess.Options.MaxAge = -1
3✔
198
        sess.Save(c.Request(), c.Response())
3✔
199

3✔
200
        cookiePath := util.GetCookiePath()
3✔
201

3✔
202
        cookie, err := c.Cookie("session_token")
3✔
203
        if err != nil {
5✔
204
                cookie = new(http.Cookie)
2✔
205
        }
2✔
206

207
        cookie.Name = "session_token"
3✔
208
        cookie.Path = cookiePath
3✔
209
        cookie.MaxAge = -1
3✔
210
        cookie.HttpOnly = true
3✔
211
        cookie.SameSite = http.SameSiteLaxMode
3✔
212
        c.SetCookie(cookie)
3✔
213
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc