feat: complete remaining Go backend modules
This commit is contained in:
1 parent
cea2751dc5
commit
aef5a97165
145 files changed
+18376
-199
No files matched your search
@@ -0,0 +1,102 @@
|
||||
package identity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type PasswordChanger interface {
|
||||
ChangeOwnPassword(context.Context, string, string, string, time.Time) (AuthorizationSnapshot, error)
|
||||
}
|
||||
|
||||
type PasswordChangeCommand struct {
|
||||
AccountID, CurrentPassword, NewPassword string
|
||||
}
|
||||
|
||||
type PasswordChangeFailure string
|
||||
|
||||
const (
|
||||
PasswordChangeInvalidInput PasswordChangeFailure = "invalid_input"
|
||||
PasswordChangeInvalidNewPassword PasswordChangeFailure = "invalid_new_password"
|
||||
PasswordChangeNotFound PasswordChangeFailure = "not_found"
|
||||
PasswordChangeCurrentIncorrect PasswordChangeFailure = "current_password_incorrect"
|
||||
)
|
||||
|
||||
var ErrPasswordChange = errors.New("password change failed")
|
||||
|
||||
type PasswordChangeError struct{ Reason PasswordChangeFailure }
|
||||
|
||||
func (e *PasswordChangeError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", ErrPasswordChange, e.Reason)
|
||||
}
|
||||
func (e *PasswordChangeError) Unwrap() error { return ErrPasswordChange }
|
||||
func IsPasswordChangeFailure(err error, reason PasswordChangeFailure) bool {
|
||||
var target *PasswordChangeError
|
||||
return errors.As(err, &target) && target.Reason == reason
|
||||
}
|
||||
|
||||
type PasswordChange struct {
|
||||
store PasswordChanger
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
func NewPasswordChange(store PasswordChanger, now func() time.Time) *PasswordChange {
|
||||
if now == nil {
|
||||
now = time.Now
|
||||
}
|
||||
return &PasswordChange{store: store, now: now}
|
||||
}
|
||||
|
||||
func (change *PasswordChange) Change(ctx context.Context, command PasswordChangeCommand) (Session, error) {
|
||||
command.AccountID = strings.TrimSpace(command.AccountID)
|
||||
command.CurrentPassword = strings.TrimSpace(command.CurrentPassword)
|
||||
command.NewPassword = strings.TrimSpace(command.NewPassword)
|
||||
if command.AccountID == "" || command.CurrentPassword == "" {
|
||||
return Session{}, &PasswordChangeError{Reason: PasswordChangeInvalidInput}
|
||||
}
|
||||
if len(command.NewPassword) < 8 {
|
||||
return Session{}, &PasswordChangeError{Reason: PasswordChangeInvalidNewPassword}
|
||||
}
|
||||
if change == nil || change.store == nil {
|
||||
return Session{}, fmt.Errorf("password change is not configured")
|
||||
}
|
||||
now := change.now()
|
||||
snapshot, err := change.store.ChangeOwnPassword(ctx, command.AccountID, command.CurrentPassword, command.NewPassword, now)
|
||||
if err != nil {
|
||||
return Session{}, err
|
||||
}
|
||||
return sessionFromSnapshot(snapshot, now)
|
||||
}
|
||||
|
||||
func sessionFromSnapshot(snapshot AuthorizationSnapshot, now time.Time) (Session, error) {
|
||||
account := snapshot.Account
|
||||
if account.Status != "active" {
|
||||
return Session{}, &PasswordChangeError{Reason: PasswordChangeNotFound}
|
||||
}
|
||||
authMode, authorities, valid := roleClaims(account.Role)
|
||||
if !valid {
|
||||
return Session{}, NewPasswordLoginError(LoginFailureInvalidRole)
|
||||
}
|
||||
organizationName := ""
|
||||
if account.Role != "super_admin" {
|
||||
if account.OrganizationID == "" {
|
||||
return Session{}, NewPasswordLoginError(LoginFailureOrganizationRequired)
|
||||
}
|
||||
if snapshot.Organization == nil || snapshot.Organization.ID != account.OrganizationID || snapshot.Organization.Status != "active" {
|
||||
return Session{}, NewPasswordLoginError(LoginFailureOrganizationNotActive)
|
||||
}
|
||||
organizationName = snapshot.Organization.Name
|
||||
} else if snapshot.Organization != nil && snapshot.Organization.ID == account.OrganizationID {
|
||||
organizationName = snapshot.Organization.Name
|
||||
}
|
||||
version := account.SessionVersion
|
||||
return Session{Version: 1, AuthMode: authMode, IssuedAt: now.Unix(), ExpiresAt: now.Add(passwordSessionTTL).Unix(), SessionVersion: &version, User: User{
|
||||
ID: account.ID, Subject: account.ID, Username: account.Phone, Phone: account.Phone,
|
||||
DisplayName: account.DisplayName, ClientID: "platform", OrganizationID: account.OrganizationID,
|
||||
OrganizationName: organizationName, Role: account.Role, Status: account.Status,
|
||||
Authorities: authorities, Scope: []string{},
|
||||
}}, nil
|
||||
}
|
||||
Reference in new issue
Block a user