Refactor authentication handler

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-03-11 12:28:51 +01:00
parent 1f4675f692
commit 019f76ecfd
15 changed files with 718 additions and 534 deletions

View File

@@ -16,12 +16,15 @@ package coredata
import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
"go.gearno.de/kit/pg"
)
@@ -34,8 +37,24 @@ type (
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
ErrUserNotFound struct {
Identifier string
}
ErrUserAlreadyExists struct {
message string
}
)
func (e ErrUserNotFound) Error() string {
return fmt.Sprintf("user not found: %q", e.Identifier)
}
func (e ErrUserAlreadyExists) Error() string {
return e.message
}
func (u User) CursorKey() page.CursorKey {
return page.NewCursorKey(u.ID, u.CreatedAt)
}
@@ -69,6 +88,10 @@ LIMIT 1;
user, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[User])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return &ErrUserNotFound{Identifier: email}
}
return fmt.Errorf("cannot collect user: %w", err)
}
@@ -106,6 +129,10 @@ LIMIT 1;
user, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[User])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return &ErrUserNotFound{Identifier: userID.String()}
}
return fmt.Errorf("cannot collect user: %w", err)
}
@@ -141,5 +168,19 @@ VALUES (
}
_, err := conn.Exec(ctx, q, args)
return err
if err != nil {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) {
if pgErr.Code == "23505" && strings.Contains(pgErr.ConstraintName, "email_address") {
return &ErrUserAlreadyExists{
message: fmt.Sprintf("user with email %s already exists", u.EmailAddress),
}
}
}
return err
}
return nil
}

View File

@@ -27,32 +27,34 @@ import (
type (
Profile struct {
minIterations uint
saltLength uint
keyLength uint
pepper []byte
iterations uint32
saltLength uint
keyLength uint
pepper []byte
}
)
const (
versionByte = 0x01 // Version identifier
algorithmByte = 0x01 // Algorithm identifier (0x01 for PBKDF2-SHA256)
minIterations = 600000
)
func NewProfile(pepper []byte) (*Profile, error) {
func NewProfile(pepper []byte, iterations uint32) (*Profile, error) {
if len(pepper) < 32 {
return nil, fmt.Errorf("pepper must be at least 32 bytes")
}
// NIST SP 800-63B recommendations:
// - At least 32 bits of salt (we use 256 bits/32 bytes for extra security)
// - At least 1000 iterations (we use higher based on processing capabilities)
// - Resulting key length should be at least 160 bits (we use 256 bits)
if iterations < minIterations {
return nil, fmt.Errorf("iterations below minimum security threshold")
}
return &Profile{
minIterations: 600000, // Minimum iterations (adjusted based on hardware speed)
saltLength: 32, // Salt length in bytes (256 bits)
keyLength: 32, // Output key length in bytes (256 bits)
pepper: pepper, // Pepper length in bytes (256 bits)
iterations: iterations,
saltLength: 32,
keyLength: 32,
pepper: pepper,
}, nil
}
@@ -62,14 +64,14 @@ func (hp Profile) applyPepper(input []byte) []byte {
return mac.Sum(nil)
}
func (hp Profile) HashPassword(password []byte, iterations uint32) ([]byte, error) {
func (hp Profile) HashPassword(password []byte) ([]byte, error) {
salt := make([]byte, hp.saltLength)
if _, err := rand.Read(salt); err != nil {
return nil, fmt.Errorf("error generating salt: %v", err)
}
pepperedPassword := hp.applyPepper([]byte(password))
hash := pbkdf2.Key(pepperedPassword, salt, int(iterations), int(hp.keyLength), sha256.New)
hash := pbkdf2.Key(pepperedPassword, salt, int(hp.iterations), int(hp.keyLength), sha256.New)
// Binary format:
// [1B version][1B algorithm][4B iterations][1B salt length][salt bytes][hash bytes]
@@ -81,7 +83,7 @@ func (hp Profile) HashPassword(password []byte, iterations uint32) ([]byte, erro
// Iterations (4 bytes, big endian)
iterBytes := make([]byte, 4)
binary.BigEndian.PutUint32(iterBytes, iterations)
binary.BigEndian.PutUint32(iterBytes, hp.iterations)
binaryHash = append(binaryHash, iterBytes...)
// Salt length and salt
@@ -110,13 +112,13 @@ func (hp Profile) ComparePasswordAndHash(password, passwordHash []byte) (bool, e
// Extract iterations
iterations := binary.BigEndian.Uint32(passwordHash[2:6])
if iterations < uint32(hp.minIterations) {
if iterations < minIterations {
return false, fmt.Errorf("iterations below minimum security threshold")
}
// Extract salt length and validate
saltLen := int(passwordHash[6])
if saltLen < 32 { // NIST minimum requirement
if saltLen < 32 {
return false, fmt.Errorf("salt length below security minimum")
}

View File

@@ -21,53 +21,57 @@ import (
type (
authConfig struct {
// Pepper is a secret key used for password hashing
// It should be at least 32 bytes long
Pepper string `json:"pepper"`
SessionDuration int `json:"session-duration"`
CookieName string `json:"cookie-name"`
CookieSecure bool `json:"cookie-secure"`
CookieHTTPOnly bool `json:"cookie-http-only"`
CookieDomain string `json:"cookie-domain"`
CookiePath string `json:"cookie-path"`
CookieSecret string `json:"cookie-secret"`
Cookie cookieConfig `json:"cookie"`
Password passwordConfig `json:"password"`
}
cookieConfig struct {
Domain string `json:"domain"`
Secret string `json:"secret"`
Duration int `json:"duration"`
Name string `json:"name"`
}
passwordConfig struct {
Iterations uint32 `json:"iterations"`
Pepper string `json:"pepper"`
}
)
func (c authConfig) GetPepperBytes() ([]byte, error) {
if c.Pepper == "" {
if c.Password.Pepper == "" {
return nil, fmt.Errorf("pepper cannot be empty")
}
if decoded, err := base64.StdEncoding.DecodeString(c.Pepper); err == nil {
if decoded, err := base64.StdEncoding.DecodeString(c.Password.Pepper); err == nil {
if len(decoded) < 32 {
return nil, fmt.Errorf("decoded pepper must be at least 32 bytes long")
}
return decoded, nil
}
if len(c.Pepper) < 32 {
if len(c.Password.Pepper) < 32 {
return nil, fmt.Errorf("pepper must be at least 32 bytes long")
}
return []byte(c.Pepper), nil
return []byte(c.Password.Pepper), nil
}
func (c authConfig) GetCookieSecretBytes() ([]byte, error) {
if c.CookieSecret == "" {
if c.Cookie.Secret == "" {
return nil, fmt.Errorf("cookie secret cannot be empty")
}
if decoded, err := base64.StdEncoding.DecodeString(c.CookieSecret); err == nil {
if decoded, err := base64.StdEncoding.DecodeString(c.Cookie.Secret); err == nil {
if len(decoded) < 32 {
return nil, fmt.Errorf("decoded cookie secret must be at least 32 bytes long")
}
return decoded, nil
}
if len(c.CookieSecret) < 32 {
if len(c.Cookie.Secret) < 32 {
return nil, fmt.Errorf("cookie secret must be at least 32 bytes long")
}
return []byte(c.CookieSecret), nil
return []byte(c.Cookie.Secret), nil
}

View File

@@ -26,6 +26,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/getprobo/probo/pkg/awsconfig"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/crypto/passwdhash"
"github.com/getprobo/probo/pkg/probo"
"github.com/getprobo/probo/pkg/server"
console_v1 "github.com/getprobo/probo/pkg/server/api/console/v1"
@@ -75,14 +76,16 @@ func New() *Implm {
PoolSize: 100,
},
Auth: authConfig{
Pepper: "this-is-a-secure-pepper-for-password-hashing-at-least-32-bytes",
SessionDuration: 24,
CookieName: "SSID",
CookieSecure: false,
CookieHTTPOnly: true,
CookieDomain: "localhost",
CookiePath: "/",
CookieSecret: "this-is-a-secure-secret-for-cookie-signing-at-least-32-bytes",
Password: passwordConfig{
Pepper: "this-is-a-secure-pepper-for-password-hashing-at-least-32-bytes",
Iterations: 1000000,
},
Cookie: cookieConfig{
Name: "SSID",
Secret: "this-is-a-secure-secret-for-cookie-signing-at-least-32-bytes",
Duration: 24,
Domain: "localhost",
},
},
AWS: awsConfig{
Region: "us-east-1",
@@ -153,7 +156,12 @@ func (impl *Implm) Run(
return fmt.Errorf("cannot migrate database schema: %w", err)
}
usrmgrService, err := usrmgr.NewService(ctx, pgClient, pepper)
hp, err := passwdhash.NewProfile(pepper, uint32(impl.cfg.Auth.Password.Iterations))
if err != nil {
return fmt.Errorf("cannot create hashing profile: %w", err)
}
usrmgrService, err := usrmgr.NewService(ctx, pgClient, hp)
if err != nil {
return fmt.Errorf("cannot create usrmgr service: %w", err)
}
@@ -169,13 +177,10 @@ func (impl *Implm) Run(
Probo: proboService,
Usrmgr: usrmgrService,
Auth: console_v1.AuthConfig{
CookieName: impl.cfg.Auth.CookieName,
CookieSecure: impl.cfg.Auth.CookieSecure,
CookieHTTPOnly: impl.cfg.Auth.CookieHTTPOnly,
CookieDomain: impl.cfg.Auth.CookieDomain,
CookiePath: impl.cfg.Auth.CookiePath,
SessionDuration: time.Duration(impl.cfg.Auth.SessionDuration) * time.Hour,
CookieSecret: impl.cfg.Auth.CookieSecret,
CookieName: impl.cfg.Auth.Cookie.Name,
CookieDomain: impl.cfg.Auth.Cookie.Domain,
SessionDuration: time.Duration(impl.cfg.Auth.Cookie.Duration) * time.Hour,
CookieSecret: impl.cfg.Auth.Cookie.Secret,
},
},
)

View File

@@ -0,0 +1,164 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package securecookie
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"net/http"
"strings"
"time"
)
var (
ErrInvalidCookie = errors.New("invalid cookie")
ErrCookieNotFound = errors.New("cookie not found")
ErrInvalidSignature = errors.New("invalid signature")
)
// Config holds the configuration for secure cookies
type Config struct {
// Name is the name of the cookie
Name string
// Secret is the secret key used for signing cookies
Secret string
// Domain is the cookie domain
Domain string
// Path is the cookie path
Path string
// MaxAge is the maximum age of the cookie in seconds
MaxAge int
// Secure indicates if the cookie should only be sent over HTTPS
Secure bool
// HTTPOnly indicates if the cookie should be inaccessible to JavaScript
HTTPOnly bool
// SameSite defines the SameSite attribute of the cookie
SameSite http.SameSite
}
// DefaultConfig returns a default secure cookie configuration
func DefaultConfig(name, secret string) Config {
return Config{
Name: name,
Secret: secret,
Path: "/",
MaxAge: 86400 * 30, // 30 days
Secure: true,
HTTPOnly: true,
SameSite: http.SameSiteStrictMode,
}
}
// Set creates and sets a secure cookie with the given value
func Set(w http.ResponseWriter, config Config, value string) error {
signedValue, err := Sign(value, config.Secret)
if err != nil {
return fmt.Errorf("failed to sign cookie value: %w", err)
}
cookie := &http.Cookie{
Name: config.Name,
Value: signedValue,
Path: config.Path,
Domain: config.Domain,
MaxAge: config.MaxAge,
Secure: config.Secure,
HttpOnly: config.HTTPOnly,
SameSite: config.SameSite,
}
http.SetCookie(w, cookie)
return nil
}
// Get retrieves and verifies a secure cookie
func Get(r *http.Request, config Config) (string, error) {
cookie, err := r.Cookie(config.Name)
if err != nil {
return "", ErrCookieNotFound
}
value, err := Verify(cookie.Value, config.Secret)
if err != nil {
return "", ErrInvalidCookie
}
return value, nil
}
// Clear removes a cookie by setting its expiration in the past
func Clear(w http.ResponseWriter, config Config) {
cookie := &http.Cookie{
Name: config.Name,
Value: "",
Path: config.Path,
Domain: config.Domain,
MaxAge: -1,
Expires: time.Now().Add(-1 * time.Hour),
Secure: config.Secure,
HttpOnly: config.HTTPOnly,
SameSite: config.SameSite,
}
http.SetCookie(w, cookie)
}
// Sign creates a signed value using HMAC-SHA256
func Sign(value, secret string) (string, error) {
if secret == "" {
return "", fmt.Errorf("secret cannot be empty")
}
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(value))
signature := base64.RawURLEncoding.EncodeToString(h.Sum(nil))
return value + "." + signature, nil
}
// Verify checks if a signed value is valid
func Verify(signedValue, secret string) (string, error) {
if secret == "" {
return "", fmt.Errorf("secret cannot be empty")
}
parts := strings.Split(signedValue, ".")
if len(parts) != 2 {
return "", fmt.Errorf("invalid signed value format")
}
value := parts[0]
expectedSignedValue, err := Sign(value, secret)
if err != nil {
return "", fmt.Errorf("failed to sign value: %w", err)
}
if signedValue != expectedSignedValue {
return "", ErrInvalidSignature
}
return value, nil
}

View File

@@ -1,215 +1,21 @@
package console_v1
import (
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/usrmgr"
"github.com/go-chi/chi/v5"
)
type (
// RegisterRequest represents the request body for user registration
RegisterRequest struct {
Email string `json:"email"`
Password string `json:"password"`
FullName string `json:"fullName"`
}
// LoginRequest represents the request body for user login
LoginRequest struct {
Email string `json:"email"`
Password string `json:"password"`
}
// AuthResponse represents the response for successful authentication
AuthResponse struct {
User UserResponse `json:"user"`
Session SessionResponse `json:"session"`
}
// UserResponse represents user data in the authentication response
UserResponse struct {
ID gid.GID `json:"id"`
Email string `json:"email"`
FullName string `json:"fullName"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
// SessionResponse represents session data in the authentication response
SessionResponse struct {
ID gid.GID `json:"id"`
ExpiresAt time.Time `json:"expiresAt"`
}
)
// RegisterHandler handles user registration
func RegisterHandler(usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Parse request body
var req RegisterRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
// Validate request
if req.Email == "" || req.Password == "" {
http.Error(w, "Email and password are required", http.StatusBadRequest)
return
}
// Register the user
user, err := usrmgrSvc.RegisterUser(
r.Context(),
usrmgr.RegisterUserParams{
Email: req.Email,
Password: req.Password,
FullName: req.FullName,
},
)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to register user: %v", err), http.StatusInternalServerError)
return
}
// Log the user in
session, err := usrmgrSvc.Login(r.Context(), req.Email, req.Password)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to login after registration: %v", err), http.StatusInternalServerError)
return
}
// Set the session cookie
setSessionCookie(w, session.ID.String(), authCfg)
// Return response
resp := AuthResponse{
User: UserResponse{
ID: user.ID,
Email: user.EmailAddress,
FullName: user.FullName,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
},
Session: SessionResponse{
ID: session.ID,
ExpiresAt: session.ExpiredAt,
},
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(resp); err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
return
}
}
}
// LoginHandler handles user login
func LoginHandler(usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Parse request body
var req LoginRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
// Validate request
if req.Email == "" || req.Password == "" {
http.Error(w, "Email and password are required", http.StatusBadRequest)
return
}
// Login the user
session, err := usrmgrSvc.Login(r.Context(), req.Email, req.Password)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to login: %v", err), http.StatusUnauthorized)
return
}
// Get the user
user, err := usrmgrSvc.GetUserBySession(r.Context(), session.ID)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to get user: %v", err), http.StatusInternalServerError)
return
}
// Set the session cookie
setSessionCookie(w, session.ID.String(), authCfg)
// Return response
resp := AuthResponse{
User: UserResponse{
ID: user.ID,
Email: user.EmailAddress,
FullName: user.FullName,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
},
Session: SessionResponse{
ID: session.ID,
ExpiresAt: session.ExpiredAt,
},
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(resp); err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
return
}
}
}
// LogoutHandler handles user logout
func LogoutHandler(usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Get session from cookie
cookie, err := r.Cookie(authCfg.CookieName)
if err != nil || cookie.Value == "" {
http.Error(w, "No active session", http.StatusBadRequest)
return
}
// Verify the cookie signature
originalValue, err := verifyCookieValue(cookie.Value, authCfg.CookieSecret)
if err != nil {
http.Error(w, "Invalid session cookie", http.StatusBadRequest)
return
}
// Parse the session ID
sessionID, err := gid.ParseGID(originalValue)
if err != nil {
http.Error(w, "Invalid session ID", http.StatusBadRequest)
return
}
// Logout the user
err = usrmgrSvc.Logout(r.Context(), sessionID)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to logout: %v", err), http.StatusInternalServerError)
return
}
// Clear the session cookie
clearSessionCookie(w, authCfg)
// Return success response
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]bool{"success": true})
}
}
// RegisterAuthRoutes registers the authentication routes
func RegisterAuthRoutes(r chi.Router, usrmgrSvc *usrmgr.Service, authCfg AuthConfig) {
r.Post("/auth/register", RegisterHandler(usrmgrSvc, authCfg))
r.Post("/auth/login", LoginHandler(usrmgrSvc, authCfg))
r.Post("/auth/logout", LogoutHandler(usrmgrSvc, authCfg))
r.Post("/auth/register", SignUpHandler(usrmgrSvc, authCfg))
r.Post("/auth/login", SignInHandler(usrmgrSvc, authCfg))
r.Post("/auth/logout", SignOutHandler(usrmgrSvc, authCfg))
}

View File

@@ -1,38 +0,0 @@
package console_v1
import (
"net/http"
)
// setSessionCookie sets a session cookie in the response
func setSessionCookie(w http.ResponseWriter, sessionID string, cfg AuthConfig) {
// Sign the session ID
signedValue := signCookieValue(sessionID, cfg.CookieSecret)
cookie := &http.Cookie{
Name: cfg.CookieName,
Value: signedValue,
Path: cfg.CookiePath,
Domain: cfg.CookieDomain,
Secure: cfg.CookieSecure,
HttpOnly: cfg.CookieHTTPOnly,
MaxAge: int(cfg.SessionDuration.Seconds()),
SameSite: http.SameSiteLaxMode,
}
http.SetCookie(w, cookie)
}
// clearSessionCookie clears the session cookie
func clearSessionCookie(w http.ResponseWriter, cfg AuthConfig) {
cookie := &http.Cookie{
Name: cfg.CookieName,
Value: "",
Path: cfg.CookiePath,
Domain: cfg.CookieDomain,
Secure: cfg.CookieSecure,
HttpOnly: cfg.CookieHTTPOnly,
MaxAge: -1,
SameSite: http.SameSiteLaxMode,
}
http.SetCookie(w, cookie)
}

View File

@@ -1,50 +0,0 @@
package console_v1
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"strings"
)
func signCookieValue(value string, secret string) string {
if secret == "" {
panic(fmt.Errorf("cookie secret is not set"))
}
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(value))
signature := base64.URLEncoding.EncodeToString(h.Sum(nil))
return fmt.Sprintf("%s.%s", value, signature)
}
func verifyCookieValue(signedValue string, secret string) (string, error) {
if secret == "" {
panic(fmt.Errorf("cookie secret is not set"))
}
parts := strings.Split(signedValue, ".")
if len(parts) != 2 {
return "", fmt.Errorf("invalid signed cookie format")
}
value, signature := parts[0], parts[1]
expectedSignedValue := signCookieValue(value, secret)
expectedParts := strings.Split(expectedSignedValue, ".")
if len(expectedParts) != 2 {
return "", fmt.Errorf("error computing signature")
}
expectedSignature := expectedParts[1]
if signature != expectedSignature {
return "", fmt.Errorf("cookie signature verification failed")
}
return value, nil
}

View File

@@ -18,6 +18,7 @@ package console_v1
import (
"context"
"errors"
"fmt"
"net/http"
"time"
@@ -30,6 +31,7 @@ import (
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/probo"
"github.com/getprobo/probo/pkg/securecookie"
"github.com/getprobo/probo/pkg/server/api/console/v1/schema"
"github.com/getprobo/probo/pkg/usrmgr"
"github.com/go-chi/chi/v5"
@@ -39,10 +41,7 @@ import (
type (
AuthConfig struct {
CookieName string
CookieSecure bool
CookieHTTPOnly bool
CookieDomain string
CookiePath string
SessionDuration time.Duration
CookieSecret string
}
@@ -141,28 +140,29 @@ func graphqlHandler(proboSvc *probo.Service, usrmgrSvc *usrmgr.Service, authCfg
}
ctx := context.WithValue(r.Context(), httpContextKey, httpCtx)
// Extract session from cookie
cookie, err := r.Cookie(authCfg.CookieName)
if err == nil && cookie.Value != "" {
// Verify the cookie signature
originalValue, err := verifyCookieValue(cookie.Value, authCfg.CookieSecret)
if err == nil {
// Parse the session ID
sessionID, err := gid.ParseGID(originalValue)
if err == nil {
// Get the session
session, err := usrmgrSvc.GetSession(r.Context(), sessionID)
if err == nil {
// Add session to context
ctx = context.WithValue(ctx, sessionContextKey, session)
cookieValue, err := securecookie.Get(r, securecookie.DefaultConfig(
authCfg.CookieName,
authCfg.CookieSecret,
))
if err != nil {
if !errors.Is(err, securecookie.ErrCookieNotFound) {
panic(fmt.Errorf("failed to get session: %w", err))
}
}
// Get the user
user, err := usrmgrSvc.GetUserBySession(r.Context(), sessionID)
if err == nil {
// Add user to context
ctx = context.WithValue(ctx, userContextKey, user)
}
}
sessionID, err := gid.ParseGID(cookieValue)
if err == nil {
// Get the session
session, err := usrmgrSvc.GetSession(r.Context(), sessionID)
if err == nil {
// Add session to context
ctx = context.WithValue(ctx, sessionContextKey, session)
// Get the user
user, err := usrmgrSvc.GetUserBySession(r.Context(), sessionID)
if err == nil {
// Add user to context
ctx = context.WithValue(ctx, userContextKey, user)
}
}
}

View File

@@ -14,9 +14,9 @@ import (
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/introspection"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/server/api/console/v1/types"
gqlparser "github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast"
@@ -1845,20 +1845,14 @@ enum ControlState
enum TaskState
@goModel(model: "github.com/getprobo/probo/pkg/coredata.TaskState") {
TODO
@goEnum(value: "github.com/getprobo/probo/pkg/coredata.TaskStateTodo")
DONE
@goEnum(value: "github.com/getprobo/probo/pkg/coredata.TaskStateDone")
TODO @goEnum(value: "github.com/getprobo/probo/pkg/coredata.TaskStateTodo")
DONE @goEnum(value: "github.com/getprobo/probo/pkg/coredata.TaskStateDone")
}
enum EvidenceState
@goModel(
model: "github.com/getprobo/probo/pkg/coredata.EvidenceState"
) {
@goModel(model: "github.com/getprobo/probo/pkg/coredata.EvidenceState") {
VALID
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.EvidenceStateValid"
)
@goEnum(value: "github.com/getprobo/probo/pkg/coredata.EvidenceStateValid")
INVALID
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.EvidenceStateInvalid"
@@ -1872,9 +1866,7 @@ enum EvidenceState
enum PeopleKind
@goModel(model: "github.com/getprobo/probo/pkg/coredata.PeopleKind") {
EMPLOYEE
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.PeopleKindEmployee"
)
@goEnum(value: "github.com/getprobo/probo/pkg/coredata.PeopleKindEmployee")
CONTRACTOR
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.PeopleKindContractor"
@@ -2181,9 +2173,7 @@ input UpdatePeopleInput {
}
enum ServiceCriticality
@goModel(
model: "github.com/getprobo/probo/pkg/coredata.ServiceCriticality"
) {
@goModel(model: "github.com/getprobo/probo/pkg/coredata.ServiceCriticality") {
LOW
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.ServiceCriticalityLow"
@@ -2201,17 +2191,11 @@ enum ServiceCriticality
enum RiskTier
@goModel(model: "github.com/getprobo/probo/pkg/coredata.RiskTier") {
CRITICAL
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.RiskTierCritical"
)
@goEnum(value: "github.com/getprobo/probo/pkg/coredata.RiskTierCritical")
SIGNIFICANT
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.RiskTierSignificant"
)
@goEnum(value: "github.com/getprobo/probo/pkg/coredata.RiskTierSignificant")
GENERAL
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.RiskTierGeneral"
)
@goEnum(value: "github.com/getprobo/probo/pkg/coredata.RiskTierGeneral")
}
input UpdateVendorInput {
@@ -2352,13 +2336,9 @@ type DeleteEvidencePayload {
enum PolicyStatus
@goModel(model: "github.com/getprobo/probo/pkg/coredata.PolicyStatus") {
DRAFT
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.PolicyStatusDraft"
)
@goEnum(value: "github.com/getprobo/probo/pkg/coredata.PolicyStatusDraft")
ACTIVE
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.PolicyStatusActive"
)
@goEnum(value: "github.com/getprobo/probo/pkg/coredata.PolicyStatusActive")
}
input CreatePolicyInput {
@@ -3871,7 +3851,7 @@ func (ec *executionContext) _Control_state(ctx context.Context, field graphql.Co
}
res := resTmp.(coredata.ControlState)
fc.Result = res
return ec.marshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState(ctx, field.Selections, res)
return ec.marshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Control_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -4910,7 +4890,7 @@ func (ec *executionContext) _Evidence_state(ctx context.Context, field graphql.C
}
res := resTmp.(coredata.EvidenceState)
fc.Result = res
return ec.marshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐEvidenceState(ctx, field.Selections, res)
return ec.marshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐEvidenceState(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Evidence_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -7521,7 +7501,7 @@ func (ec *executionContext) _People_kind(ctx context.Context, field graphql.Coll
}
res := resTmp.(coredata.PeopleKind)
fc.Result = res
return ec.marshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind(ctx, field.Selections, res)
return ec.marshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_People_kind(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -7973,7 +7953,7 @@ func (ec *executionContext) _Policy_status(ctx context.Context, field graphql.Co
}
res := resTmp.(coredata.PolicyStatus)
fc.Result = res
return ec.marshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus(ctx, field.Selections, res)
return ec.marshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Policy_status(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -8840,7 +8820,7 @@ func (ec *executionContext) _Task_state(ctx context.Context, field graphql.Colle
}
res := resTmp.(coredata.TaskState)
fc.Result = res
return ec.marshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState(ctx, field.Selections, res)
return ec.marshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Task_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -10007,7 +9987,7 @@ func (ec *executionContext) _Vendor_serviceCriticality(ctx context.Context, fiel
}
res := resTmp.(coredata.ServiceCriticality)
fc.Result = res
return ec.marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx, field.Selections, res)
return ec.marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Vendor_serviceCriticality(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -10045,7 +10025,7 @@ func (ec *executionContext) _Vendor_riskTier(ctx context.Context, field graphql.
}
res := resTmp.(coredata.RiskTier)
fc.Result = res
return ec.marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx, field.Selections, res)
return ec.marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Vendor_riskTier(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -12335,7 +12315,7 @@ func (ec *executionContext) unmarshalInputCreatePeopleInput(ctx context.Context,
it.AdditionalEmailAddresses = data
case "kind":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("kind"))
data, err := ec.unmarshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind(ctx, v)
data, err := ec.unmarshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind(ctx, v)
if err != nil {
return it, err
}
@@ -12383,7 +12363,7 @@ func (ec *executionContext) unmarshalInputCreatePolicyInput(ctx context.Context,
it.Content = data
case "status":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("status"))
data, err := ec.unmarshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus(ctx, v)
data, err := ec.unmarshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus(ctx, v)
if err != nil {
return it, err
}
@@ -12500,14 +12480,14 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context,
it.ServiceTerminationAt = data
case "serviceCriticality":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceCriticality"))
data, err := ec.unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx, v)
data, err := ec.unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx, v)
if err != nil {
return it, err
}
it.ServiceCriticality = data
case "riskTier":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("riskTier"))
data, err := ec.unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx, v)
data, err := ec.unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx, v)
if err != nil {
return it, err
}
@@ -12752,7 +12732,7 @@ func (ec *executionContext) unmarshalInputUpdateControlInput(ctx context.Context
it.Category = data
case "state":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
data, err := ec.unmarshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState(ctx, v)
data, err := ec.unmarshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState(ctx, v)
if err != nil {
return it, err
}
@@ -12862,7 +12842,7 @@ func (ec *executionContext) unmarshalInputUpdatePeopleInput(ctx context.Context,
it.AdditionalEmailAddresses = data
case "kind":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("kind"))
data, err := ec.unmarshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind(ctx, v)
data, err := ec.unmarshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind(ctx, v)
if err != nil {
return it, err
}
@@ -12917,7 +12897,7 @@ func (ec *executionContext) unmarshalInputUpdatePolicyInput(ctx context.Context,
it.Content = data
case "status":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("status"))
data, err := ec.unmarshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus(ctx, v)
data, err := ec.unmarshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus(ctx, v)
if err != nil {
return it, err
}
@@ -12986,7 +12966,7 @@ func (ec *executionContext) unmarshalInputUpdateTaskInput(ctx context.Context, o
it.Description = data
case "state":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("state"))
data, err := ec.unmarshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState(ctx, v)
data, err := ec.unmarshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState(ctx, v)
if err != nil {
return it, err
}
@@ -13055,14 +13035,14 @@ func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context,
it.ServiceTerminationAt = data
case "serviceCriticality":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceCriticality"))
data, err := ec.unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx, v)
data, err := ec.unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx, v)
if err != nil {
return it, err
}
it.ServiceCriticality = data
case "riskTier":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("riskTier"))
data, err := ec.unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx, v)
data, err := ec.unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx, v)
if err != nil {
return it, err
}
@@ -16415,14 +16395,14 @@ func (ec *executionContext) marshalNControlEdge2ᚖgithubᚗcomᚋgetproboᚋpro
return ec._ControlEdge(ctx, sel, v)
}
func (ec *executionContext) unmarshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState(ctx context.Context, v any) (coredata.ControlState, error) {
func (ec *executionContext) unmarshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState(ctx context.Context, v any) (coredata.ControlState, error) {
tmp, err := graphql.UnmarshalString(v)
res := unmarshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState[tmp]
res := unmarshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState[tmp]
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState(ctx context.Context, sel ast.SelectionSet, v coredata.ControlState) graphql.Marshaler {
res := graphql.MarshalString(marshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState[v])
func (ec *executionContext) marshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState(ctx context.Context, sel ast.SelectionSet, v coredata.ControlState) graphql.Marshaler {
res := graphql.MarshalString(marshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState[v])
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
@@ -16432,13 +16412,13 @@ func (ec *executionContext) marshalNControlState2githubᚗcomᚋgetproboᚋprobo
}
var (
unmarshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState = map[string]coredata.ControlState{
unmarshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState = map[string]coredata.ControlState{
"NOT_STARTED": coredata.ControlStateNotStarted,
"IN_PROGRESS": coredata.ControlStateInProgress,
"NOT_APPLICABLE": coredata.ControlStateNotApplicable,
"IMPLEMENTED": coredata.ControlStateImplemented,
}
marshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState = map[coredata.ControlState]string{
marshalNControlState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState = map[coredata.ControlState]string{
coredata.ControlStateNotStarted: "NOT_STARTED",
coredata.ControlStateInProgress: "IN_PROGRESS",
coredata.ControlStateNotApplicable: "NOT_APPLICABLE",
@@ -16795,14 +16775,14 @@ func (ec *executionContext) marshalNEvidenceEdge2ᚖgithubᚗcomᚋgetproboᚋpr
return ec._EvidenceEdge(ctx, sel, v)
}
func (ec *executionContext) unmarshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐEvidenceState(ctx context.Context, v any) (coredata.EvidenceState, error) {
func (ec *executionContext) unmarshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐEvidenceState(ctx context.Context, v any) (coredata.EvidenceState, error) {
tmp, err := graphql.UnmarshalString(v)
res := unmarshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐEvidenceState[tmp]
res := unmarshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐEvidenceState[tmp]
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐEvidenceState(ctx context.Context, sel ast.SelectionSet, v coredata.EvidenceState) graphql.Marshaler {
res := graphql.MarshalString(marshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐEvidenceState[v])
func (ec *executionContext) marshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐEvidenceState(ctx context.Context, sel ast.SelectionSet, v coredata.EvidenceState) graphql.Marshaler {
res := graphql.MarshalString(marshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐEvidenceState[v])
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
@@ -16812,12 +16792,12 @@ func (ec *executionContext) marshalNEvidenceState2githubᚗcomᚋgetproboᚋprob
}
var (
unmarshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐEvidenceState = map[string]coredata.EvidenceState{
unmarshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐEvidenceState = map[string]coredata.EvidenceState{
"VALID": coredata.EvidenceStateValid,
"INVALID": coredata.EvidenceStateInvalid,
"EXPIRED": coredata.EvidenceStateExpired,
}
marshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐEvidenceState = map[coredata.EvidenceState]string{
marshalNEvidenceState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐEvidenceState = map[coredata.EvidenceState]string{
coredata.EvidenceStateValid: "VALID",
coredata.EvidenceStateInvalid: "INVALID",
coredata.EvidenceStateExpired: "EXPIRED",
@@ -17094,14 +17074,14 @@ func (ec *executionContext) marshalNPeopleEdge2ᚖgithubᚗcomᚋgetproboᚋprob
return ec._PeopleEdge(ctx, sel, v)
}
func (ec *executionContext) unmarshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind(ctx context.Context, v any) (coredata.PeopleKind, error) {
func (ec *executionContext) unmarshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind(ctx context.Context, v any) (coredata.PeopleKind, error) {
tmp, err := graphql.UnmarshalString(v)
res := unmarshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind[tmp]
res := unmarshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind[tmp]
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind(ctx context.Context, sel ast.SelectionSet, v coredata.PeopleKind) graphql.Marshaler {
res := graphql.MarshalString(marshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind[v])
func (ec *executionContext) marshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind(ctx context.Context, sel ast.SelectionSet, v coredata.PeopleKind) graphql.Marshaler {
res := graphql.MarshalString(marshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind[v])
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
@@ -17111,11 +17091,11 @@ func (ec *executionContext) marshalNPeopleKind2githubᚗcomᚋgetproboᚋprobo
}
var (
unmarshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind = map[string]coredata.PeopleKind{
unmarshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind = map[string]coredata.PeopleKind{
"EMPLOYEE": coredata.PeopleKindEmployee,
"CONTRACTOR": coredata.PeopleKindContractor,
}
marshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind = map[coredata.PeopleKind]string{
marshalNPeopleKind2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind = map[coredata.PeopleKind]string{
coredata.PeopleKindEmployee: "EMPLOYEE",
coredata.PeopleKindContractor: "CONTRACTOR",
}
@@ -17193,14 +17173,14 @@ func (ec *executionContext) marshalNPolicyEdge2ᚖgithubᚗcomᚋgetproboᚋprob
return ec._PolicyEdge(ctx, sel, v)
}
func (ec *executionContext) unmarshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus(ctx context.Context, v any) (coredata.PolicyStatus, error) {
func (ec *executionContext) unmarshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus(ctx context.Context, v any) (coredata.PolicyStatus, error) {
tmp, err := graphql.UnmarshalString(v)
res := unmarshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus[tmp]
res := unmarshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus[tmp]
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus(ctx context.Context, sel ast.SelectionSet, v coredata.PolicyStatus) graphql.Marshaler {
res := graphql.MarshalString(marshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus[v])
func (ec *executionContext) marshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus(ctx context.Context, sel ast.SelectionSet, v coredata.PolicyStatus) graphql.Marshaler {
res := graphql.MarshalString(marshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus[v])
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
@@ -17210,24 +17190,24 @@ func (ec *executionContext) marshalNPolicyStatus2githubᚗcomᚋgetproboᚋprobo
}
var (
unmarshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus = map[string]coredata.PolicyStatus{
unmarshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus = map[string]coredata.PolicyStatus{
"DRAFT": coredata.PolicyStatusDraft,
"ACTIVE": coredata.PolicyStatusActive,
}
marshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus = map[coredata.PolicyStatus]string{
marshalNPolicyStatus2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus = map[coredata.PolicyStatus]string{
coredata.PolicyStatusDraft: "DRAFT",
coredata.PolicyStatusActive: "ACTIVE",
}
)
func (ec *executionContext) unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx context.Context, v any) (coredata.RiskTier, error) {
func (ec *executionContext) unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx context.Context, v any) (coredata.RiskTier, error) {
tmp, err := graphql.UnmarshalString(v)
res := unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier[tmp]
res := unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier[tmp]
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx context.Context, sel ast.SelectionSet, v coredata.RiskTier) graphql.Marshaler {
res := graphql.MarshalString(marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier[v])
func (ec *executionContext) marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx context.Context, sel ast.SelectionSet, v coredata.RiskTier) graphql.Marshaler {
res := graphql.MarshalString(marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier[v])
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
@@ -17237,26 +17217,26 @@ func (ec *executionContext) marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋp
}
var (
unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier = map[string]coredata.RiskTier{
unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier = map[string]coredata.RiskTier{
"CRITICAL": coredata.RiskTierCritical,
"SIGNIFICANT": coredata.RiskTierSignificant,
"GENERAL": coredata.RiskTierGeneral,
}
marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier = map[coredata.RiskTier]string{
marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier = map[coredata.RiskTier]string{
coredata.RiskTierCritical: "CRITICAL",
coredata.RiskTierSignificant: "SIGNIFICANT",
coredata.RiskTierGeneral: "GENERAL",
}
)
func (ec *executionContext) unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx context.Context, v any) (coredata.ServiceCriticality, error) {
func (ec *executionContext) unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx context.Context, v any) (coredata.ServiceCriticality, error) {
tmp, err := graphql.UnmarshalString(v)
res := unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality[tmp]
res := unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality[tmp]
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx context.Context, sel ast.SelectionSet, v coredata.ServiceCriticality) graphql.Marshaler {
res := graphql.MarshalString(marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality[v])
func (ec *executionContext) marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx context.Context, sel ast.SelectionSet, v coredata.ServiceCriticality) graphql.Marshaler {
res := graphql.MarshalString(marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality[v])
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
@@ -17266,12 +17246,12 @@ func (ec *executionContext) marshalNServiceCriticality2githubᚗcomᚋgetprobo
}
var (
unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality = map[string]coredata.ServiceCriticality{
unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality = map[string]coredata.ServiceCriticality{
"LOW": coredata.ServiceCriticalityLow,
"MEDIUM": coredata.ServiceCriticalityMedium,
"HIGH": coredata.ServiceCriticalityHigh,
}
marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality = map[coredata.ServiceCriticality]string{
marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality = map[coredata.ServiceCriticality]string{
coredata.ServiceCriticalityLow: "LOW",
coredata.ServiceCriticalityMedium: "MEDIUM",
coredata.ServiceCriticalityHigh: "HIGH",
@@ -17397,14 +17377,14 @@ func (ec *executionContext) marshalNTaskEdge2ᚖgithubᚗcomᚋgetproboᚋprobo
return ec._TaskEdge(ctx, sel, v)
}
func (ec *executionContext) unmarshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState(ctx context.Context, v any) (coredata.TaskState, error) {
func (ec *executionContext) unmarshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState(ctx context.Context, v any) (coredata.TaskState, error) {
tmp, err := graphql.UnmarshalString(v)
res := unmarshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState[tmp]
res := unmarshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState[tmp]
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState(ctx context.Context, sel ast.SelectionSet, v coredata.TaskState) graphql.Marshaler {
res := graphql.MarshalString(marshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState[v])
func (ec *executionContext) marshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState(ctx context.Context, sel ast.SelectionSet, v coredata.TaskState) graphql.Marshaler {
res := graphql.MarshalString(marshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState[v])
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
@@ -17414,11 +17394,11 @@ func (ec *executionContext) marshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋ
}
var (
unmarshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState = map[string]coredata.TaskState{
unmarshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState = map[string]coredata.TaskState{
"TODO": coredata.TaskStateTodo,
"DONE": coredata.TaskStateDone,
}
marshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState = map[coredata.TaskState]string{
marshalNTaskState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState = map[coredata.TaskState]string{
coredata.TaskStateTodo: "TODO",
coredata.TaskStateDone: "DONE",
}
@@ -17913,31 +17893,31 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast
return res
}
func (ec *executionContext) unmarshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState(ctx context.Context, v any) (*coredata.ControlState, error) {
func (ec *executionContext) unmarshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState(ctx context.Context, v any) (*coredata.ControlState, error) {
if v == nil {
return nil, nil
}
tmp, err := graphql.UnmarshalString(v)
res := unmarshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState[tmp]
res := unmarshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState[tmp]
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState(ctx context.Context, sel ast.SelectionSet, v *coredata.ControlState) graphql.Marshaler {
func (ec *executionContext) marshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState(ctx context.Context, sel ast.SelectionSet, v *coredata.ControlState) graphql.Marshaler {
if v == nil {
return graphql.Null
}
res := graphql.MarshalString(marshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState[*v])
res := graphql.MarshalString(marshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState[*v])
return res
}
var (
unmarshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState = map[string]coredata.ControlState{
unmarshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState = map[string]coredata.ControlState{
"NOT_STARTED": coredata.ControlStateNotStarted,
"IN_PROGRESS": coredata.ControlStateInProgress,
"NOT_APPLICABLE": coredata.ControlStateNotApplicable,
"IMPLEMENTED": coredata.ControlStateImplemented,
}
marshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐControlState = map[coredata.ControlState]string{
marshalOControlState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐControlState = map[coredata.ControlState]string{
coredata.ControlStateNotStarted: "NOT_STARTED",
coredata.ControlStateInProgress: "IN_PROGRESS",
coredata.ControlStateNotApplicable: "NOT_APPLICABLE",
@@ -18009,116 +17989,116 @@ func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.Sele
return res
}
func (ec *executionContext) unmarshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind(ctx context.Context, v any) (*coredata.PeopleKind, error) {
func (ec *executionContext) unmarshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind(ctx context.Context, v any) (*coredata.PeopleKind, error) {
if v == nil {
return nil, nil
}
tmp, err := graphql.UnmarshalString(v)
res := unmarshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind[tmp]
res := unmarshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind[tmp]
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind(ctx context.Context, sel ast.SelectionSet, v *coredata.PeopleKind) graphql.Marshaler {
func (ec *executionContext) marshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind(ctx context.Context, sel ast.SelectionSet, v *coredata.PeopleKind) graphql.Marshaler {
if v == nil {
return graphql.Null
}
res := graphql.MarshalString(marshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind[*v])
res := graphql.MarshalString(marshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind[*v])
return res
}
var (
unmarshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind = map[string]coredata.PeopleKind{
unmarshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind = map[string]coredata.PeopleKind{
"EMPLOYEE": coredata.PeopleKindEmployee,
"CONTRACTOR": coredata.PeopleKindContractor,
}
marshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPeopleKind = map[coredata.PeopleKind]string{
marshalOPeopleKind2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPeopleKind = map[coredata.PeopleKind]string{
coredata.PeopleKindEmployee: "EMPLOYEE",
coredata.PeopleKindContractor: "CONTRACTOR",
}
)
func (ec *executionContext) unmarshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus(ctx context.Context, v any) (*coredata.PolicyStatus, error) {
func (ec *executionContext) unmarshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus(ctx context.Context, v any) (*coredata.PolicyStatus, error) {
if v == nil {
return nil, nil
}
tmp, err := graphql.UnmarshalString(v)
res := unmarshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus[tmp]
res := unmarshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus[tmp]
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus(ctx context.Context, sel ast.SelectionSet, v *coredata.PolicyStatus) graphql.Marshaler {
func (ec *executionContext) marshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus(ctx context.Context, sel ast.SelectionSet, v *coredata.PolicyStatus) graphql.Marshaler {
if v == nil {
return graphql.Null
}
res := graphql.MarshalString(marshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus[*v])
res := graphql.MarshalString(marshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus[*v])
return res
}
var (
unmarshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus = map[string]coredata.PolicyStatus{
unmarshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus = map[string]coredata.PolicyStatus{
"DRAFT": coredata.PolicyStatusDraft,
"ACTIVE": coredata.PolicyStatusActive,
}
marshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐPolicyStatus = map[coredata.PolicyStatus]string{
marshalOPolicyStatus2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐPolicyStatus = map[coredata.PolicyStatus]string{
coredata.PolicyStatusDraft: "DRAFT",
coredata.PolicyStatusActive: "ACTIVE",
}
)
func (ec *executionContext) unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx context.Context, v any) (*coredata.RiskTier, error) {
func (ec *executionContext) unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx context.Context, v any) (*coredata.RiskTier, error) {
if v == nil {
return nil, nil
}
tmp, err := graphql.UnmarshalString(v)
res := unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier[tmp]
res := unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier[tmp]
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx context.Context, sel ast.SelectionSet, v *coredata.RiskTier) graphql.Marshaler {
func (ec *executionContext) marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx context.Context, sel ast.SelectionSet, v *coredata.RiskTier) graphql.Marshaler {
if v == nil {
return graphql.Null
}
res := graphql.MarshalString(marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier[*v])
res := graphql.MarshalString(marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier[*v])
return res
}
var (
unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier = map[string]coredata.RiskTier{
unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier = map[string]coredata.RiskTier{
"CRITICAL": coredata.RiskTierCritical,
"SIGNIFICANT": coredata.RiskTierSignificant,
"GENERAL": coredata.RiskTierGeneral,
}
marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier = map[coredata.RiskTier]string{
marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier = map[coredata.RiskTier]string{
coredata.RiskTierCritical: "CRITICAL",
coredata.RiskTierSignificant: "SIGNIFICANT",
coredata.RiskTierGeneral: "GENERAL",
}
)
func (ec *executionContext) unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx context.Context, v any) (*coredata.ServiceCriticality, error) {
func (ec *executionContext) unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx context.Context, v any) (*coredata.ServiceCriticality, error) {
if v == nil {
return nil, nil
}
tmp, err := graphql.UnmarshalString(v)
res := unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality[tmp]
res := unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality[tmp]
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx context.Context, sel ast.SelectionSet, v *coredata.ServiceCriticality) graphql.Marshaler {
func (ec *executionContext) marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx context.Context, sel ast.SelectionSet, v *coredata.ServiceCriticality) graphql.Marshaler {
if v == nil {
return graphql.Null
}
res := graphql.MarshalString(marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality[*v])
res := graphql.MarshalString(marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality[*v])
return res
}
var (
unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality = map[string]coredata.ServiceCriticality{
unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality = map[string]coredata.ServiceCriticality{
"LOW": coredata.ServiceCriticalityLow,
"MEDIUM": coredata.ServiceCriticalityMedium,
"HIGH": coredata.ServiceCriticalityHigh,
}
marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality = map[coredata.ServiceCriticality]string{
marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality = map[coredata.ServiceCriticality]string{
coredata.ServiceCriticalityLow: "LOW",
coredata.ServiceCriticalityMedium: "MEDIUM",
coredata.ServiceCriticalityHigh: "HIGH",
@@ -18179,29 +18159,29 @@ func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel as
return res
}
func (ec *executionContext) unmarshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState(ctx context.Context, v any) (*coredata.TaskState, error) {
func (ec *executionContext) unmarshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState(ctx context.Context, v any) (*coredata.TaskState, error) {
if v == nil {
return nil, nil
}
tmp, err := graphql.UnmarshalString(v)
res := unmarshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState[tmp]
res := unmarshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState[tmp]
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState(ctx context.Context, sel ast.SelectionSet, v *coredata.TaskState) graphql.Marshaler {
func (ec *executionContext) marshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState(ctx context.Context, sel ast.SelectionSet, v *coredata.TaskState) graphql.Marshaler {
if v == nil {
return graphql.Null
}
res := graphql.MarshalString(marshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState[*v])
res := graphql.MarshalString(marshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState[*v])
return res
}
var (
unmarshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState = map[string]coredata.TaskState{
unmarshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState = map[string]coredata.TaskState{
"TODO": coredata.TaskStateTodo,
"DONE": coredata.TaskStateDone,
}
marshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐTaskState = map[coredata.TaskState]string{
marshalOTaskState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐTaskState = map[coredata.TaskState]string{
coredata.TaskStateTodo: "TODO",
coredata.TaskStateDone: "DONE",
}

View File

@@ -0,0 +1,92 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package console_v1
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/securecookie"
"github.com/getprobo/probo/pkg/usrmgr"
"go.gearno.de/kit/httpserver"
)
type (
SignInRequest struct {
Email string `json:"email"`
Password string `json:"password"`
}
SignInResponse struct {
User UserResponse `json:"user"`
}
UserResponse struct {
ID gid.GID `json:"id"`
Email string `json:"email"`
FullName string `json:"fullName"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
)
func SignInHandler(usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req SignInRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
httpserver.RenderError(w, http.StatusBadRequest, fmt.Errorf("cannot decode body: %w", err))
return
}
user, session, err := usrmgrSvc.SignIn(r.Context(), req.Email, req.Password)
if err != nil {
var ErrInvalidCredentials *usrmgr.ErrInvalidCredentials
if errors.As(err, &ErrInvalidCredentials) {
httpserver.RenderError(w, http.StatusUnauthorized, err)
return
}
panic(fmt.Errorf("cannot sign in: %w", err))
}
securecookie.Set(
w,
securecookie.DefaultConfig(
authCfg.CookieName,
authCfg.CookieSecret,
),
session.ID.String(),
)
httpserver.RenderJSON(
w,
http.StatusOK,
SignInResponse{
User: UserResponse{
ID: user.ID,
Email: user.EmailAddress,
FullName: user.FullName,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
},
},
)
}
}

View File

@@ -0,0 +1,57 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package console_v1
import (
"fmt"
"net/http"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/securecookie"
"github.com/getprobo/probo/pkg/usrmgr"
"go.gearno.de/kit/httpserver"
)
func SignOutHandler(usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
sessionID, err := securecookie.Get(r, securecookie.DefaultConfig(
authCfg.CookieName,
authCfg.CookieSecret,
))
if err != nil {
httpserver.RenderError(w, http.StatusBadRequest, err)
return
}
gid, err := gid.ParseGID(sessionID)
if err != nil {
httpserver.RenderError(w, http.StatusBadRequest, err)
return
}
err = usrmgrSvc.SignOut(r.Context(), gid)
if err != nil {
panic(fmt.Errorf("cannot sign out: %w", err))
}
securecookie.Clear(w, securecookie.DefaultConfig(
authCfg.CookieName,
authCfg.CookieSecret,
))
httpserver.RenderJSON(w, http.StatusOK, map[string]bool{"success": true})
}
}

View File

@@ -0,0 +1,88 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package console_v1
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/securecookie"
"github.com/getprobo/probo/pkg/usrmgr"
"go.gearno.de/kit/httpserver"
)
type (
SignUpRequest struct {
Email string `json:"email"`
Password string `json:"password"`
FullName string `json:"fullName"`
}
SignUpResponse struct {
User UserResponse `json:"user"`
}
)
func SignUpHandler(usrmgrSvc *usrmgr.Service, authCfg AuthConfig) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req SignUpRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
httpserver.RenderError(w, http.StatusBadRequest, fmt.Errorf("cannot decode body: %w", err))
return
}
user, session, err := usrmgrSvc.SignUp(
r.Context(),
req.Email,
req.Password,
req.FullName,
)
if err != nil {
var errUserAlreadyExists *coredata.ErrUserAlreadyExists
if errors.As(err, &errUserAlreadyExists) {
httpserver.RenderError(w, http.StatusBadRequest, fmt.Errorf("cannot register user: %w", err))
return
}
panic(fmt.Errorf("cannot register user: %w", err))
}
securecookie.Set(
w,
securecookie.DefaultConfig(
authCfg.CookieName,
authCfg.CookieSecret,
),
session.ID.String(),
)
httpserver.RenderJSON(
w,
http.StatusOK,
SignUpResponse{
User: UserResponse{
ID: user.ID,
Email: user.EmailAddress,
FullName: user.FullName,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
},
},
)
}
}

View File

@@ -6,9 +6,9 @@ import (
"time"
"github.com/99designs/gqlgen/graphql"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"github.com/getprobo/probo/pkg/coredata"
)
type Node interface {

View File

@@ -16,7 +16,9 @@ package usrmgr
import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/getprobo/probo/pkg/coredata"
@@ -32,16 +34,22 @@ type (
hp *passwdhash.Profile
}
RegisterUserParams struct {
Email string
Password string
FullName string
}
ErrInvalidCredentials struct {
message string
}
ErrInvalidEmail struct {
email string
}
ErrInvalidPassword struct {
length int
}
ErrInvalidFullName struct {
fullName string
}
ErrUserAlreadyExists struct {
message string
}
@@ -71,78 +79,93 @@ func (e ErrSessionExpired) Error() string {
return e.message
}
func (e ErrInvalidEmail) Error() string {
return fmt.Sprintf("invalid email: %s", e.email)
}
func (e ErrInvalidPassword) Error() string {
return fmt.Sprintf("invalid password: the length must be at least %d characters", e.length)
}
func (e ErrInvalidFullName) Error() string {
return fmt.Sprintf("invalid full name: %s", e.fullName)
}
func NewService(
ctx context.Context,
pgClient *pg.Client,
pepper []byte,
hp *passwdhash.Profile,
) (*Service, error) {
hp, err := passwdhash.NewProfile(pepper)
if err != nil {
return nil, fmt.Errorf("cannot create hashing profile: %w", err)
}
return &Service{
pg: pgClient,
hp: hp,
}, nil
}
func (s Service) RegisterUser(
func (s Service) SignUp(
ctx context.Context,
params RegisterUserParams,
) (*coredata.User, error) {
if params.Email == "" || params.Password == "" || params.FullName == "" {
return nil, fmt.Errorf("email, password, and full name are required")
email, password, fullName string,
) (*coredata.User, *coredata.Session, error) {
if !strings.Contains(email, "@") {
return nil, nil, &ErrInvalidEmail{email}
}
// Use a high iteration count for password hashing
const iterations = 600000
hashedPassword, err := s.hp.HashPassword([]byte(params.Password), iterations)
if len(password) < 8 {
return nil, nil, &ErrInvalidPassword{len(password)}
}
if fullName == "" {
return nil, nil, &ErrInvalidFullName{fullName}
}
hashedPassword, err := s.hp.HashPassword([]byte(password))
if err != nil {
return nil, fmt.Errorf("cannot hash password: %w", err)
return nil, nil, fmt.Errorf("cannot hash password: %w", err)
}
now := time.Now()
user := &coredata.User{
ID: gid.New(gid.NilTenant, coredata.UserEntityType),
EmailAddress: params.Email,
EmailAddress: email,
HashedPassword: hashedPassword,
FullName: params.FullName,
FullName: fullName,
CreatedAt: now,
UpdatedAt: now,
}
session := &coredata.Session{
ID: gid.New(gid.NilTenant, coredata.SessionEntityType),
UserID: user.ID,
CreatedAt: now,
UpdatedAt: now,
}
err = s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
// Check if user already exists
existingUser := &coredata.User{}
err := existingUser.LoadByEmail(ctx, tx, params.Email)
if err == nil {
return &ErrUserAlreadyExists{message: "user with this email already exists"}
}
// Insert the new user
if err := user.Insert(ctx, tx); err != nil {
return fmt.Errorf("cannot insert user: %w", err)
}
if err := session.Insert(ctx, tx); err != nil {
return fmt.Errorf("cannot insert session: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
return nil, nil, err
}
return user, nil
return user, session, nil
}
func (s Service) Login(
func (s Service) SignIn(
ctx context.Context,
email string,
password string,
) (*coredata.Session, error) {
email, password string,
) (*coredata.User, *coredata.Session, error) {
now := time.Now()
user := &coredata.User{}
session := &coredata.Session{
@@ -157,7 +180,13 @@ func (s Service) Login(
ctx,
func(tx pg.Conn) error {
if err := user.LoadByEmail(ctx, tx, email); err != nil {
return &ErrInvalidCredentials{message: "invalid email or password"}
var errUserNotFound *coredata.ErrUserNotFound
if errors.As(err, &errUserNotFound) {
return &ErrInvalidCredentials{message: "invalid email or password"}
}
return fmt.Errorf("cannot load user by email: %w", err)
}
ok, err := s.hp.ComparePasswordAndHash([]byte(password), user.HashedPassword)
@@ -169,7 +198,6 @@ func (s Service) Login(
return &ErrInvalidCredentials{message: "invalid email or password"}
}
// Set the user ID in the session
session.UserID = user.ID
if err := session.Insert(ctx, tx); err != nil {
@@ -181,20 +209,25 @@ func (s Service) Login(
)
if err != nil {
return nil, err
return nil, nil, err
}
return session, nil
return user, session, nil
}
func (s Service) Logout(
func (s Service) SignOut(
ctx context.Context,
sessionID gid.GID,
) error {
return s.pg.WithTx(
return s.pg.WithConn(
ctx,
func(tx pg.Conn) error {
return coredata.DeleteSession(ctx, tx, sessionID)
err := coredata.DeleteSession(ctx, tx, sessionID)
if err != nil {
return fmt.Errorf("cannot delete session: %w", err)
}
return nil
},
)
}