diff --git a/backend/danswer/auth/users.py b/backend/danswer/auth/users.py index 39e2477f6ddf..95db824798c4 100644 --- a/backend/danswer/auth/users.py +++ b/backend/danswer/auth/users.py @@ -8,6 +8,8 @@ from email.mime.text import MIMEText from typing import Optional from typing import Tuple +from email_validator import EmailNotValidError +from email_validator import validate_email from fastapi import APIRouter from fastapi import Depends from fastapi import HTTPException @@ -62,7 +64,6 @@ from danswer.utils.telemetry import optional_telemetry from danswer.utils.telemetry import RecordType from danswer.utils.variable_functionality import fetch_versioned_implementation - logger = setup_logger() @@ -105,8 +106,28 @@ def user_needs_to_be_verified() -> bool: def verify_email_is_invited(email: str) -> None: whitelist = get_invited_users() - if (whitelist and email not in whitelist) or not email: - raise PermissionError("User not on allowed user whitelist") + if not whitelist: + return + + if not email: + raise PermissionError("Email must be specified") + + email_info = validate_email(email) # can raise EmailNotValidError + + for email_whitelist in whitelist: + try: + # normalized emails are now being inserted into the db + # we can remove this normalization on read after some time has passed + email_info_whitelist = validate_email(email_whitelist) + except EmailNotValidError: + continue + + # oddly, normalization does not include lowercasing the user part of the + # email address ... which we want to allow + if email_info.normalized.lower() == email_info_whitelist.normalized.lower(): + return + + raise PermissionError("User not on allowed user whitelist") def verify_email_in_whitelist(email: str) -> None: diff --git a/backend/danswer/server/manage/users.py b/backend/danswer/server/manage/users.py index c50df365dd8f..dac134946bd6 100644 --- a/backend/danswer/server/manage/users.py +++ b/backend/danswer/server/manage/users.py @@ -2,6 +2,7 @@ import re from datetime import datetime from datetime import timezone +from email_validator import validate_email from fastapi import APIRouter from fastapi import Body from fastapi import Depends @@ -159,12 +160,18 @@ def bulk_invite_users( emails: list[str] = Body(..., embed=True), current_user: User | None = Depends(current_admin_user), ) -> int: + """emails are string validated. If any email fails validation, no emails are + invited and an exception is raised.""" if current_user is None: raise HTTPException( status_code=400, detail="Auth is disabled, cannot invite users" ) - all_emails = list(set(emails) | set(get_invited_users())) + normalized_emails = [] + for email in emails: + email_info = validate_email(email) # can raise EmailNotValidError + normalized_emails.append(email_info.normalized) # type: ignore + all_emails = list(set(normalized_emails) | set(get_invited_users())) return write_invited_users(all_emails)