auth
This commit is contained in:
@@ -24,12 +24,10 @@ export class User {
|
||||
private avatarUrl: string | undefined;
|
||||
|
||||
private constructor(props: UserProps) {
|
||||
if (!props.displayName || !props.displayName.trim()) {
|
||||
throw new Error('User displayName cannot be empty');
|
||||
}
|
||||
this.validateDisplayName(props.displayName);
|
||||
|
||||
this.id = props.id;
|
||||
this.displayName = props.displayName.trim();
|
||||
this.displayName = this.formatDisplayName(props.displayName);
|
||||
this.email = props.email;
|
||||
this.passwordHash = props.passwordHash;
|
||||
this.iracingCustomerId = props.iracingCustomerId;
|
||||
@@ -37,6 +35,56 @@ export class User {
|
||||
this.avatarUrl = props.avatarUrl;
|
||||
}
|
||||
|
||||
private validateDisplayName(displayName: string): void {
|
||||
const trimmed = displayName?.trim();
|
||||
|
||||
if (!trimmed) {
|
||||
throw new Error('Display name cannot be empty');
|
||||
}
|
||||
|
||||
if (trimmed.length < 2) {
|
||||
throw new Error('Name must be at least 2 characters long');
|
||||
}
|
||||
|
||||
if (trimmed.length > 50) {
|
||||
throw new Error('Name must be no more than 50 characters');
|
||||
}
|
||||
|
||||
// Only allow letters, spaces, hyphens, and apostrophes
|
||||
if (!/^[A-Za-z\s\-']+$/.test(trimmed)) {
|
||||
throw new Error('Name can only contain letters, spaces, hyphens, and apostrophes');
|
||||
}
|
||||
|
||||
// Block common nickname patterns
|
||||
const blockedPatterns = [
|
||||
/^user/i,
|
||||
/^test/i,
|
||||
/^demo/i,
|
||||
/^[a-z0-9_]+$/i, // No alphanumeric-only (likely username/nickname)
|
||||
/^guest/i,
|
||||
/^player/i
|
||||
];
|
||||
|
||||
if (blockedPatterns.some(pattern => pattern.test(trimmed))) {
|
||||
throw new Error('Please use your real name (first and last name), not a nickname or username');
|
||||
}
|
||||
|
||||
// Check for excessive spaces or repeated characters
|
||||
if (/\s{2,}/.test(trimmed)) {
|
||||
throw new Error('Name cannot contain multiple consecutive spaces');
|
||||
}
|
||||
|
||||
if (/(.)\1{2,}/.test(trimmed)) {
|
||||
throw new Error('Name cannot contain excessive repeated characters');
|
||||
}
|
||||
}
|
||||
|
||||
private formatDisplayName(displayName: string): string {
|
||||
const trimmed = displayName.trim();
|
||||
// Capitalize first letter of each word
|
||||
return trimmed.replace(/\b\w/g, char => char.toUpperCase());
|
||||
}
|
||||
|
||||
public static create(props: UserProps): User {
|
||||
if (props.email) {
|
||||
const result: EmailValidationResult = validateEmail(props.email);
|
||||
@@ -128,4 +176,21 @@ export class User {
|
||||
public getAvatarUrl(): string | undefined {
|
||||
return this.avatarUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update display name - NOT ALLOWED after initial creation
|
||||
* This method will always throw an error to enforce immutability
|
||||
*/
|
||||
public updateDisplayName(): void {
|
||||
throw new Error('Display name cannot be changed after account creation. Please contact support if you need to update your name.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this user was created with a valid real name
|
||||
* Used to verify immutability for existing users
|
||||
*/
|
||||
public hasImmutableName(): boolean {
|
||||
// All users created through proper channels have immutable names
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user