mirror of
https://github.com/PretendoNetwork/website.git
synced 2026-09-15 12:27:40 -05:00
feat: handle errors, add lenient ratelimin
This commit is contained in:
@@ -1,16 +1,48 @@
|
||||
import { ClientError } from 'nice-grpc';
|
||||
import { AccountUpdateSchema } from '~~/shared/api-types';
|
||||
import type { ApiErrorCodes } from '~~/shared/errors';
|
||||
|
||||
const bucket = createRatelimitBucket({
|
||||
id: 'account-update',
|
||||
points: 100,
|
||||
durationSec: 5 * 60, // 5 minutes
|
||||
blockDurationSec: 1 * 60 * 60 // 1 hour
|
||||
});
|
||||
|
||||
const errors: Record<string, ApiErrorCodes> = {
|
||||
'INVALID_ARGUMENT: Must be one of: prod, test, dev': 'INVALID_ACCESS_LEVEL',
|
||||
'PERMISSION_DENIED: Banned': 'BANNED',
|
||||
'INVALID_ARGUMENT: Do not have permission to enter this environment': 'INSUFFICIENT_ACCESS_LEVEL',
|
||||
'INVALID_ARGUMENT: Must be a valid date formatted as: YYYY-MM-DD': 'INVALID_DATE',
|
||||
'INVALID_ARGUMENT: Must be one of: F, M': 'INVALID_GENDER',
|
||||
'INVALID_ARGUMENT: Invalid region': 'INVALID_REGION',
|
||||
'INVALID_ARGUMENT: Invalid timezone': 'INVALID_TIMEZONE',
|
||||
'INVALID_ARGUMENT: Invalid mii data': 'INVALID_MII_DATA'
|
||||
};
|
||||
|
||||
export default defineEventHandler(async (event): Promise<void> => {
|
||||
await enforceRatelimit(event, bucket);
|
||||
|
||||
const body = await readZodBody(event, AccountUpdateSchema);
|
||||
const auth = enforceLoggedIn(event);
|
||||
const grpc = useApiGrpcWithToken(event, auth.token);
|
||||
|
||||
await grpc.updateUserData({
|
||||
gender: body.gender,
|
||||
birthday: body.birthday,
|
||||
region: body.region,
|
||||
timezone: body.timezone,
|
||||
mii: body.mii,
|
||||
serverAccessLevel: body.serverAccessLevel
|
||||
});
|
||||
try {
|
||||
await grpc.updateUserData({
|
||||
gender: body.gender,
|
||||
birthday: body.birthday,
|
||||
region: body.region,
|
||||
timezone: body.timezone,
|
||||
mii: body.mii,
|
||||
serverAccessLevel: body.serverAccessLevel
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof ClientError) {
|
||||
const errorCode = errors[error.details];
|
||||
if (errorCode) {
|
||||
throw createApiError(errorCode);
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -18,7 +18,15 @@ const apiErrorCodes = {
|
||||
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'
|
||||
ACCOUNT_DELETED: 'Account has been deleted',
|
||||
INVALID_ACCESS_LEVEL: 'Invalid access level',
|
||||
BANNED: 'Account is banned',
|
||||
INSUFFICIENT_ACCESS_LEVEL: 'Do not have permission to enter this environment',
|
||||
INVALID_DATE: 'Invalid date',
|
||||
INVALID_GENDER: 'Invalid gender',
|
||||
INVALID_REGION: 'Invalid region',
|
||||
INVALID_TIMEZONE: 'Invalid timezone',
|
||||
INVALID_MII_DATA: 'Invalid mii data'
|
||||
} as const;
|
||||
|
||||
export type ApiErrorCodes = keyof typeof apiErrorCodes;
|
||||
@@ -43,7 +51,15 @@ export const apiErrorCodeStatus: Record<ApiErrorCodes, number> = {
|
||||
USERNAME_IN_USE: 400,
|
||||
USERNAME_INVALID_CHARS: 400,
|
||||
USERNAME_TOO_LONG: 400,
|
||||
USERNAME_TOO_SHORT: 400
|
||||
USERNAME_TOO_SHORT: 400,
|
||||
INVALID_ACCESS_LEVEL: 400,
|
||||
BANNED: 403,
|
||||
INSUFFICIENT_ACCESS_LEVEL: 403,
|
||||
INVALID_DATE: 400,
|
||||
INVALID_GENDER: 400,
|
||||
INVALID_REGION: 400,
|
||||
INVALID_TIMEZONE: 400,
|
||||
INVALID_MII_DATA: 400
|
||||
};
|
||||
|
||||
export function getTextForApiErrorCode(code: ApiErrorCodes): string {
|
||||
|
||||
@@ -114,7 +114,7 @@ watchOnce(newRegion, () => {
|
||||
|
||||
watch(newRegion, (o, n) => {
|
||||
if ((((o || 0) >>> 24) & 0xff) === (((n || 0) >>> 24) & 0xff)) {
|
||||
// same country so we leave the timezone as is, or we might override the user's choice.
|
||||
// same country so we leave the timezone as is, else we might override the user's choice.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -634,7 +634,10 @@ useHead({
|
||||
})
|
||||
"
|
||||
>
|
||||
{{ $t("modals.confirm") }}
|
||||
<Loader v-if="isLoadingUpdateUserData" />
|
||||
<span v-else>{{
|
||||
$t("modals.confirm")
|
||||
}}</span>
|
||||
</Dialog.Close>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
|
||||
Reference in New Issue
Block a user