feat(users): passwordless user creation via emailed set-password link, display full name instead of username
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled
Admins now create users with a name + email (no password) and role; a Send Email action (per-user, also reusable for resets) issues a one-time token and POSTs it to an admin-configurable webhook URL — intended for a Power Automate flow that delivers the actual email. The old admin-sets-the-password flow is kept server-side (LegacyUserCreateWithPassword) but no longer wired into the UI. Every user-facing surface (top bar, sidebar, user management, audit log, assignee pickers, dispute notifications) now shows full_name instead of username, falling back to username when unset. Also fixes long attack_procedure/expected_detection/suggested_text text overflowing its container in the template review panels and Red/Blue team fields (missing break-words on whitespace-pre-wrap blocks).
This commit is contained in:
@@ -48,6 +48,7 @@ from app.models.test_template import TestTemplate
|
||||
from app.models.procedure_suggestion import ProcedureSuggestion
|
||||
from app.models.template_suggestion import TemplateSuggestion
|
||||
from app.models.user import User
|
||||
from app.models.password_setup_token import PasswordSetupToken
|
||||
|
||||
# Assign __all__ = [
|
||||
__all__ = [
|
||||
@@ -92,4 +93,5 @@ __all__ = [
|
||||
"TestRoundHistory",
|
||||
"ProcedureSuggestion",
|
||||
"TemplateSuggestion",
|
||||
"PasswordSetupToken",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
"""SQLAlchemy model for one-time password setup/reset tokens.
|
||||
|
||||
Issued when an admin sends a "set your password" email — a passwordless
|
||||
user (freshly created, or one whose password an admin wants to reset)
|
||||
uses the token to pick their own password without ever having a temporary
|
||||
one shared with them.
|
||||
"""
|
||||
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import Column, DateTime, ForeignKey, String, func
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class PasswordSetupToken(Base):
|
||||
"""A one-time token letting its owning user set their own password."""
|
||||
|
||||
__tablename__ = "password_setup_tokens"
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||
token = Column(String(128), unique=True, nullable=False, index=True)
|
||||
expires_at = Column(DateTime, nullable=False)
|
||||
used_at = Column(DateTime, nullable=True)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
user = relationship("User", foreign_keys=[user_id])
|
||||
@@ -30,6 +30,9 @@ class User(Base):
|
||||
username = Column(String, unique=True, nullable=False)
|
||||
# Assign email = Column(String, nullable=True)
|
||||
email = Column(String, nullable=True)
|
||||
# Display name shown everywhere in the UI instead of username (which is
|
||||
# now just an internal login identifier, auto-set to the user's email).
|
||||
full_name = Column(String, nullable=True)
|
||||
# Assign hashed_password = Column(String, nullable=False)
|
||||
hashed_password = Column(String, nullable=False)
|
||||
# Assign role = Column(String, nullable=False, default="viewer")
|
||||
|
||||
Reference in New Issue
Block a user