mirror of
https://github.com/PretendoNetwork/website.git
synced 2026-08-23 09:07:40 -05:00
feat: implement birthday checks and handle all errors
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
import { ClientError } from 'nice-grpc';
|
||||
import { LoginSchema } from '#shared/api-types';
|
||||
import type { ApiErrorCodes } from '~~/shared/errors';
|
||||
import type { ApiAuthLogin } from '#shared/api-types';
|
||||
|
||||
const errors: Record<string, ApiErrorCodes> = {
|
||||
'INVALID_ARGUMENT: User not found': 'INVALID_USERNAME',
|
||||
'INVALID_ARGUMENT: Password is incorrect': 'INVALID_PASSWORD',
|
||||
'UNAUTHENTICATED: Account has been deleted': 'ACCOUNT_DELETED'
|
||||
};
|
||||
|
||||
export default defineEventHandler(async (event): Promise<ApiAuthLogin> => {
|
||||
const body = await readZodBody(event, LoginSchema);
|
||||
const grpc = useApiGrpc(event);
|
||||
@@ -19,11 +26,9 @@ export default defineEventHandler(async (event): Promise<ApiAuthLogin> => {
|
||||
};
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof ClientError) {
|
||||
if (error.details === 'INVALID_ARGUMENT: User not found') {
|
||||
throw createApiError('INVALID_USERNAME');
|
||||
}
|
||||
if (error.details === 'INVALID_ARGUMENT: Password is incorrect') {
|
||||
throw createApiError('INVALID_PASSWORD');
|
||||
const errorCode = errors[error.details];
|
||||
if (errorCode) {
|
||||
throw createApiError(errorCode);
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
|
||||
@@ -1,23 +1,57 @@
|
||||
import { ClientError } from 'nice-grpc';
|
||||
import { RegisterSchema } from '#shared/api-types';
|
||||
import type { ApiErrorCodes } from '~~/shared/errors';
|
||||
import type { ApiAuthLogin } from '#shared/api-types';
|
||||
|
||||
const errors: Record<string, ApiErrorCodes> = {
|
||||
'INVALID_ARGUMENT: Captcha verification failed': 'INVALID_CAPTCHA',
|
||||
'INVALID_ARGUMENT: Invalid email address': 'INVALID_EMAIL',
|
||||
'INVALID_ARGUMENT: Username is too short': 'USERNAME_TOO_SHORT',
|
||||
'INVALID_ARGUMENT: Username is too long': 'USERNAME_TOO_LONG',
|
||||
'INVALID_ARGUMENT: Username contains invalid characters': 'USERNAME_INVALID_CHARS',
|
||||
'INVALID_ARGUMENT: Username cannot begin with punctuation characters': 'USERNAME_INVALID_CHARS',
|
||||
'INVALID_ARGUMENT: Username cannot end with punctuation characters': 'USERNAME_INVALID_CHARS',
|
||||
'INVALID_ARGUMENT: Two or more punctuation characters cannot be used in a row': 'USERNAME_INVALID_CHARS',
|
||||
'INVALID_ARGUMENT: PNID already in use': 'USERNAME_IN_USE',
|
||||
'INVALID_ARGUMENT: Mii name too long': 'MIINAME_TOO_LONG',
|
||||
'INVALID_ARGUMENT: Password must be between 6 and 16 characters long': 'INVALID_PASSWORD_INPUT',
|
||||
'INVALID_ARGUMENT: Password cannot be the same as username': 'INVALID_PASSWORD_INPUT',
|
||||
'INVALID_ARGUMENT: Password must have combination of letters, numbers, and/or punctuation characters': 'INVALID_PASSWORD_INPUT',
|
||||
'INVALID_ARGUMENT: Password may not have 3 repeating characters': 'INVALID_PASSWORD_INPUT',
|
||||
'INVALID_ARGUMENT: Passwords do not match': 'INVALID_PASSWORD_NO_MATCH'
|
||||
};
|
||||
|
||||
function getCutoffDateForAge(today: Date, age: number) {
|
||||
return new Date(today.getFullYear() - age, today.getMonth(), today.getDate());
|
||||
}
|
||||
|
||||
function assertAge(birthDate: string | undefined) {
|
||||
if (!birthDate) {
|
||||
throw createApiError('INVALID_INPUT');
|
||||
}
|
||||
const date = new Date(birthDate);
|
||||
const today = new Date();
|
||||
|
||||
// Prevent users below 13
|
||||
if (date > getCutoffDateForAge(today, 13)) {
|
||||
throw createApiError('UNDER_THIRTEEN');
|
||||
}
|
||||
}
|
||||
|
||||
export default defineEventHandler(async (event): Promise<ApiAuthLogin> => {
|
||||
const body = await readZodBody(event, RegisterSchema);
|
||||
const grpc = useApiGrpc(event);
|
||||
assertAge(body.birthday);
|
||||
|
||||
console.log(body.birthday);
|
||||
|
||||
// eslint-disable-next-line no-useless-catch -- Temp before error handling is implemented
|
||||
try {
|
||||
// TODO Add ip
|
||||
// TODO Add birthday
|
||||
const res = await grpc.register({
|
||||
email: body.email,
|
||||
miiName: body.miiName,
|
||||
captchaResponse: body.captchaResponse,
|
||||
username: body.username,
|
||||
password: body.password,
|
||||
passwordConfirm: body.password,
|
||||
passwordConfirm: body.password
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -25,7 +59,12 @@ export default defineEventHandler(async (event): Promise<ApiAuthLogin> => {
|
||||
refreshToken: res.refreshToken
|
||||
};
|
||||
} catch (error: unknown) {
|
||||
// TODO handle errors
|
||||
if (error instanceof ClientError) {
|
||||
const errorCode = errors[error.details];
|
||||
if (errorCode) {
|
||||
throw createApiError(errorCode);
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -100,7 +100,7 @@ export const RegisterSchema = z.object({
|
||||
username: z.string(),
|
||||
miiName: z.string(),
|
||||
password: z.string(),
|
||||
birthday: z.string(),
|
||||
birthday: z.iso.date(),
|
||||
captchaResponse: z.string().optional()
|
||||
});
|
||||
export type ApiAuthRegisterRequest = z.infer<typeof RegisterSchema>;
|
||||
|
||||
@@ -7,7 +7,17 @@ const apiErrorCodes = {
|
||||
INVALID_CAPTCHA: 'Invalid captcha, try again',
|
||||
INVALID_USERNAME: 'Could not find user',
|
||||
INVALID_PASSWORD: 'Incorrect password',
|
||||
UNAUTHENTICATED: 'This request needs authentication'
|
||||
UNAUTHENTICATED: 'This request needs authentication',
|
||||
UNDER_THIRTEEN: 'Must be 13 or older to use these services',
|
||||
INVALID_EMAIL: 'Invalid email address',
|
||||
USERNAME_TOO_SHORT: 'Username is too short',
|
||||
USERNAME_TOO_LONG: 'Username is too long',
|
||||
USERNAME_INVALID_CHARS: 'Username contains invalid characters',
|
||||
USERNAME_IN_USE: 'PNID already in use',
|
||||
MIINAME_TOO_LONG: 'Mii name too long',
|
||||
INVALID_PASSWORD_INPUT: 'Password must be between 6 and 16 characters long',
|
||||
INVALID_PASSWORD_NO_MATCH: 'Passwords do not match',
|
||||
ACCOUNT_DELETED: 'Account has been deleted'
|
||||
} as const;
|
||||
|
||||
export type ApiErrorCodes = keyof typeof apiErrorCodes;
|
||||
@@ -21,7 +31,17 @@ export const apiErrorCodeStatus: Record<ApiErrorCodes, number> = {
|
||||
INVALID_CAPTCHA: 400,
|
||||
INVALID_USERNAME: 400,
|
||||
INVALID_PASSWORD: 400,
|
||||
UNAUTHENTICATED: 401
|
||||
UNAUTHENTICATED: 401,
|
||||
UNDER_THIRTEEN: 400,
|
||||
ACCOUNT_DELETED: 400,
|
||||
INVALID_EMAIL: 400,
|
||||
INVALID_PASSWORD_INPUT: 400,
|
||||
INVALID_PASSWORD_NO_MATCH: 400,
|
||||
MIINAME_TOO_LONG: 400,
|
||||
USERNAME_IN_USE: 400,
|
||||
USERNAME_INVALID_CHARS: 400,
|
||||
USERNAME_TOO_LONG: 400,
|
||||
USERNAME_TOO_SHORT: 400
|
||||
};
|
||||
|
||||
export function getTextForApiErrorCode(code: ApiErrorCodes): string {
|
||||
|
||||
Reference in New Issue
Block a user