65 lines
2.4 KiB
Go
65 lines
2.4 KiB
Go
package domain
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"crypto/subtle"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.cin.su/m/Assistant/contracts/identity"
|
|
)
|
|
|
|
var ErrInvalidCreatorSession = errors.New("invalid creator session")
|
|
|
|
func IssueCreatorSession(secret []byte, now time.Time, ttl time.Duration) (string, identity.CreatorSession, error) {
|
|
if len(secret) < 32 || ttl <= 0 {
|
|
return "", identity.CreatorSession{}, ErrInvalidCreatorSession
|
|
}
|
|
session := identity.CreatorSession{ActorID: "domovoy-creator-actor", PrincipalID: "domovoy-creator-principal", ExpiresAtUnix: now.Add(ttl).Unix()}
|
|
payload, err := json.Marshal(session)
|
|
if err != nil {
|
|
return "", identity.CreatorSession{}, err
|
|
}
|
|
encoded := base64.RawURLEncoding.EncodeToString(payload)
|
|
return encoded + "." + signature(secret, encoded), session, nil
|
|
}
|
|
|
|
func ValidateCreatorSession(secret []byte, token string, now time.Time) (identity.CreatorSession, error) {
|
|
parts := strings.Split(token, ".")
|
|
if len(parts) != 2 || len(secret) < 32 || subtle.ConstantTimeCompare([]byte(signature(secret, parts[0])), []byte(parts[1])) != 1 {
|
|
return identity.CreatorSession{}, ErrInvalidCreatorSession
|
|
}
|
|
payload, err := base64.RawURLEncoding.DecodeString(parts[0])
|
|
if err != nil {
|
|
return identity.CreatorSession{}, ErrInvalidCreatorSession
|
|
}
|
|
var session identity.CreatorSession
|
|
if json.Unmarshal(payload, &session) != nil || session.ActorID != "domovoy-creator-actor" || session.PrincipalID != "domovoy-creator-principal" || now.Unix() >= session.ExpiresAtUnix {
|
|
return identity.CreatorSession{}, ErrInvalidCreatorSession
|
|
}
|
|
return session, nil
|
|
}
|
|
|
|
func BootstrapMatches(expected, supplied string) bool {
|
|
return expected != "" && supplied != "" && subtle.ConstantTimeCompare([]byte(expected), []byte(supplied)) == 1
|
|
}
|
|
|
|
func CreatorCredentialsMatch(expectedUsername, expectedPassword string, supplied identity.CreatorCredentials) bool {
|
|
if expectedUsername == "" || expectedPassword == "" || supplied.Username == "" || supplied.Password == "" {
|
|
return false
|
|
}
|
|
usernameMatches := subtle.ConstantTimeCompare([]byte(expectedUsername), []byte(supplied.Username))
|
|
passwordMatches := subtle.ConstantTimeCompare([]byte(expectedPassword), []byte(supplied.Password))
|
|
return usernameMatches&passwordMatches == 1
|
|
}
|
|
|
|
func signature(secret []byte, payload string) string {
|
|
mac := hmac.New(sha256.New, secret)
|
|
mac.Write([]byte(payload))
|
|
return base64.RawURLEncoding.EncodeToString(mac.Sum(nil))
|
|
}
|