Files
phylum/server/internal/core/user/auth.go
2025-06-05 20:55:43 +05:30

66 lines
1.9 KiB
Go

package user
import (
"net/http"
"time"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
"github.com/shroff/phylum/server/internal/core/errors"
"github.com/shroff/phylum/server/internal/core/util/rand"
"github.com/shroff/phylum/server/internal/crypt"
)
const accessTokenLength = 16
var accessTokenValidity = pgtype.Interval{
Days: 30,
Valid: true,
}
var ErrCredentialsInvalid = errors.NewError(http.StatusUnauthorized, "credentials_invalid", "invalid Credentials")
func (m manager) VerifyUserPassword(email, password string) (User, error) {
if user, passwordHash, err := m.userPasswordHashByEmail(email); err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return User{}, ErrCredentialsInvalid
}
return User{}, err
} else if passwordHash == "" {
return User{}, ErrCredentialsInvalid
} else {
if b, err := crypt.Verify(password, passwordHash); err != nil {
return User{}, err
} else if !b {
return User{}, ErrCredentialsInvalid
}
return user, nil
}
}
func (m manager) CreateAccessToken(user User) (string, error) {
const q = `INSERT INTO access_tokens(id, expires, user_id) VALUES ($1::TEXT, NOW() + $2::INTERVAL, $3::INT)`
id := rand.GenerateRandomString(accessTokenLength)
if _, err := m.db.Exec(q, id, accessTokenValidity, user.ID); err != nil {
return "", err
} else {
return id, nil
}
}
func (m manager) ReadAccessToken(accessToken string) (user User, err error) {
const q = `SELECT t.expires, u.id, u.email, u.name, u.permissions, u.home FROM access_tokens t JOIN users u ON t.user_id = u.id WHERE t.id = $1; `
row := m.db.QueryRow(q, accessToken)
var expires pgtype.Timestamp
err = row.Scan(&expires, &user.ID, &user.Email, &user.Name, &user.Permissions, &user.Home)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
err = ErrCredentialsInvalid
}
} else if time.Now().After(expires.Time) {
return User{}, ErrCredentialsInvalid
}
return
}