dndex/server/auth/verify.go

79 lines
1.8 KiB
Go

package auth
import (
"context"
"errors"
"local/dndex/config"
"local/dndex/storage"
"net/http"
"time"
"github.com/google/uuid"
)
func Verify(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error {
token, ok := getToken(r)
if !ok {
return errors.New("auth not found")
}
if !config.New().Auth {
return nil
}
if isPublic(token, g, r) {
return nil
}
return verifyToken(token, g, r)
}
func getToken(r *http.Request) (Token, bool) {
if !config.New().Auth {
namespaces, ok := r.URL.Query()["ns"]
if ok && len(namespaces) > 0 {
return Token{Namespace: namespaces[0], ID: uuid.New().String()}, true
}
}
cookie, err := r.Cookie(AuthKey)
if err != nil {
return Token{}, false
}
obfuscated := cookie.Value
var token Token
err = token.Deobfuscate(obfuscated)
return token, err == nil
}
func isPublic(token Token, g storage.RateLimitedGraph, r *http.Request) bool {
return isPublicNamespace(r.Context(), g, token.Namespace)
}
func isPublicNamespace(ctx context.Context, g storage.RateLimitedGraph, namespace string) bool {
maybePublicContainer, err := g.Get(ctx, namespace, UserKey)
if err != nil {
return false
}
return maybePublicContainer.Title == ""
}
func verifyToken(token Token, g storage.RateLimitedGraph, r *http.Request) error {
serverTokenContainer, err := g.Get(r.Context(), token.Namespace+"."+AuthKey, token.ID)
if err != nil {
return err
}
var serverToken Token
if err := serverToken.Deobfuscate(serverTokenContainer.Title); err != nil {
return err
}
if token.Namespace != serverToken.Namespace {
return errors.New("token namespace does not match request's namespace")
}
modified := time.Unix(0, serverTokenContainer.Modified)
if time.Since(modified) > config.New().AuthLifetime {
return errors.New("token is expired")
}
return nil
}