125 lines
2.5 KiB
Go
125 lines
2.5 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"crypto/hmac"
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const cookieName = "cpone_session"
|
|
const projectCookieName = "cpone_project_mcu_id"
|
|
|
|
type ctxKey string
|
|
|
|
const userCtxKey ctxKey = "username"
|
|
|
|
// Username returns the logged-in username from the request context.
|
|
func Username(r *http.Request) string {
|
|
v, _ := r.Context().Value(userCtxKey).(string)
|
|
return v
|
|
}
|
|
|
|
func setContext(r *http.Request, username string) *http.Request {
|
|
return r.WithContext(context.WithValue(r.Context(), userCtxKey, username))
|
|
}
|
|
|
|
func SetSession(w http.ResponseWriter, username, secret string) {
|
|
val := encode(username) + "." + sign(username, secret)
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: cookieName,
|
|
Value: val,
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
SameSite: http.SameSiteLaxMode,
|
|
Expires: time.Now().Add(24 * time.Hour),
|
|
})
|
|
}
|
|
|
|
func ClearSession(w http.ResponseWriter) {
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: cookieName,
|
|
Value: "",
|
|
Path: "/",
|
|
MaxAge: -1,
|
|
})
|
|
}
|
|
|
|
func SetSelectedProject(w http.ResponseWriter, mcuID int) {
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: projectCookieName,
|
|
Value: strconv.Itoa(mcuID),
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
SameSite: http.SameSiteLaxMode,
|
|
Expires: time.Now().Add(7 * 24 * time.Hour),
|
|
})
|
|
}
|
|
|
|
func ClearSelectedProject(w http.ResponseWriter) {
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: projectCookieName,
|
|
Value: "",
|
|
Path: "/",
|
|
MaxAge: -1,
|
|
})
|
|
}
|
|
|
|
func SelectedProjectID(r *http.Request) int {
|
|
c, err := r.Cookie(projectCookieName)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
id, err := strconv.Atoi(strings.TrimSpace(c.Value))
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return id
|
|
}
|
|
|
|
func getSession(r *http.Request, secret string) string {
|
|
c, err := r.Cookie(cookieName)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
parts := strings.SplitN(c.Value, ".", 2)
|
|
if len(parts) != 2 {
|
|
return ""
|
|
}
|
|
username, err := decode(parts[0])
|
|
if err != nil || username == "" {
|
|
return ""
|
|
}
|
|
if !hmac.Equal([]byte(sign(username, secret)), []byte(parts[1])) {
|
|
return ""
|
|
}
|
|
return username
|
|
}
|
|
|
|
func newUUID() string {
|
|
b := make([]byte, 16)
|
|
rand.Read(b)
|
|
return hex.EncodeToString(b)
|
|
}
|
|
|
|
func sign(username, secret string) string {
|
|
mac := hmac.New(sha256.New, []byte(secret))
|
|
mac.Write([]byte(username))
|
|
return base64.RawURLEncoding.EncodeToString(mac.Sum(nil))
|
|
}
|
|
|
|
func encode(s string) string {
|
|
return base64.RawURLEncoding.EncodeToString([]byte(s))
|
|
}
|
|
|
|
func decode(s string) (string, error) {
|
|
b, err := base64.RawURLEncoding.DecodeString(s)
|
|
return string(b), err
|
|
}
|