createuser: require exactly one of -phone or -email

An account with neither can never be logged in to, since login resolves
the account by phone or signup email.
This commit is contained in:
Astra 2026-09-25 16:52:33 +01:00
parent 2bc87ea594
commit 01f3dcc189

View file

@ -14,7 +14,9 @@
// createuser -id 1000 [-first-name Test] [-last-name User] [-username testuser] -phone "15550001234"
// createuser -id 1000 [-first-name Test] [-last-name User] [-username testuser] -email "test@example.com"
//
// -phone and -email are mutually exclusive: an email-signup account never
// Exactly one of -phone or -email is required: login resolves the account by
// one of them, so an account with neither can never be signed in to. They are
// mutually exclusive because an email-signup account never
// stores the address in users.phone directly (see internal/domain/emailphone.go)
// -- it gets a synthetic "888"-prefixed display phone instead (the same one
// assignEmailSignupDisplayPhone hands a real email-signup account), with the
@ -58,8 +60,8 @@ func main() {
firstName := flag.String("first-name", "Test", "first name")
lastName := flag.String("last-name", "", "last name")
username := flag.String("username", "", "username, without @ (optional)")
phone := flag.String("phone", "", "phone number (optional; mutually exclusive with -email)")
email := flag.String("email", "", "email address for an email-signup account (optional; mutually exclusive with -phone)")
phone := flag.String("phone", "", "phone number (exactly one of -phone or -email is required)")
email := flag.String("email", "", "email address for an email-signup account (exactly one of -phone or -email is required)")
force := flag.Bool("force", false, "skip the reserved-id / sequence-collision safety checks")
flag.Parse()
@ -67,6 +69,10 @@ func main() {
fmt.Fprintln(os.Stderr, "createuser: -id is required and must be positive")
os.Exit(2)
}
if *phone == "" && *email == "" {
fmt.Fprintln(os.Stderr, "createuser: one of -phone or -email is required - an account with neither cannot be logged in to")
os.Exit(2)
}
if *phone != "" && *email != "" {
fmt.Fprintln(os.Stderr, "createuser: -phone and -email are mutually exclusive")
os.Exit(2)
@ -116,8 +122,8 @@ func main() {
}
// phone/username/signup_email all sit under partial unique indexes that
// exclude '', so leaving any of them blank never collides with another
// blank-valued account.
// exclude '', so a blank username or (for a phone account) signup_email
// never collides with another blank-valued account.
row := pool.QueryRow(ctx, `
INSERT INTO users (id, access_hash, phone, signup_email, first_name, last_name, username, country_code)
VALUES ($1, $2, $3, $4, $5, $6, $7, '')