Private
Public Access
Require password confirmation on account creation (#40)
Both account-creation surfaces now require the password twice: - Web signup (invite-based self-service): SignupComplete gains a password_confirm field with a model_validator backstop server-side, plus a client-side match check in SignupPage.tsx for immediate feedback -- the client check is the primary UX, the server check is defense in depth so the guarantee doesn't rely on the client alone. - CLI (python -m app.cli create-user): password is now an optional positional argument. If omitted, prompts interactively via getpass (hidden input) twice, retrying on mismatch -- matching what "entered twice and verified" actually means for a human typing blind. Passing the password directly as before still works unchanged, for scripted/ automated provisioning. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+18
-2
@@ -7,6 +7,7 @@ created by an operator running this script directly on the app server.
|
||||
import argparse
|
||||
import asyncio
|
||||
import base64
|
||||
import getpass
|
||||
|
||||
from pydantic import ValidationError
|
||||
|
||||
@@ -15,6 +16,15 @@ from app.schemas.user import UserCreate
|
||||
from app.services.auth_service import DuplicateUserError, register_user
|
||||
|
||||
|
||||
def _prompt_password() -> str:
|
||||
while True:
|
||||
password = getpass.getpass("Password: ")
|
||||
confirm = getpass.getpass("Confirm password: ")
|
||||
if password == confirm:
|
||||
return password
|
||||
print("Passwords didn't match -- try again.")
|
||||
|
||||
|
||||
async def _create_user(username: str, email: str, password: str, is_admin: bool) -> None:
|
||||
try:
|
||||
data = UserCreate(username=username, email=email, password=password)
|
||||
@@ -69,7 +79,12 @@ def main() -> None:
|
||||
create_user = subparsers.add_parser("create-user", help="Create a new user account")
|
||||
create_user.add_argument("username")
|
||||
create_user.add_argument("email")
|
||||
create_user.add_argument("password")
|
||||
create_user.add_argument(
|
||||
"password",
|
||||
nargs="?",
|
||||
default=None,
|
||||
help="If omitted, you'll be prompted interactively (hidden input, entered twice to confirm).",
|
||||
)
|
||||
create_user.add_argument("--admin", action="store_true", help="Grant is_site_admin")
|
||||
|
||||
subparsers.add_parser("generate-vapid-keys", help="Generate a VAPID key pair for push notifications")
|
||||
@@ -77,7 +92,8 @@ def main() -> None:
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == "create-user":
|
||||
asyncio.run(_create_user(args.username, args.email, args.password, args.admin))
|
||||
password = args.password if args.password is not None else _prompt_password()
|
||||
asyncio.run(_create_user(args.username, args.email, password, args.admin))
|
||||
elif args.command == "generate-vapid-keys":
|
||||
_generate_vapid_keys()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user