add captcha support
This commit is contained in:
parent
bb571fc349
commit
cdb939bca9
|
@ -26,7 +26,7 @@ Backend for movie-web
|
|||
- [ ] provider metrics
|
||||
- [ ] ratelimits (stored in redis)
|
||||
- [X] switch to pnpm
|
||||
- [ ] catpcha support
|
||||
- [X] catpcha support
|
||||
- [ ] global namespacing (accounts are stored on a namespace)
|
||||
- [ ] cleanup jobs
|
||||
- [ ] cleanup expired sessions
|
||||
|
|
|
@ -48,4 +48,13 @@ export const configSchema = z.object({
|
|||
name: z.string().min(1),
|
||||
description: z.string().min(1).optional(),
|
||||
}),
|
||||
captcha: z
|
||||
.object({
|
||||
// enabled captchas on register
|
||||
enabled: z.coerce.boolean().default(false),
|
||||
|
||||
// captcha secret
|
||||
secret: z.string().min(1).optional(),
|
||||
})
|
||||
.default({}),
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { formatSession } from '@/db/models/Session';
|
||||
import { User, formatUser } from '@/db/models/User';
|
||||
import { assertCaptcha } from '@/services/captcha';
|
||||
import { handle } from '@/services/handler';
|
||||
import { makeRouter } from '@/services/router';
|
||||
import { makeSession, makeSessionToken } from '@/services/session';
|
||||
|
@ -13,6 +14,7 @@ const registerSchema = z.object({
|
|||
colorB: z.string(),
|
||||
icon: z.string(),
|
||||
}),
|
||||
captchaToken: z.string().optional(),
|
||||
});
|
||||
|
||||
export const manageAuthRouter = makeRouter((app) => {
|
||||
|
@ -20,6 +22,8 @@ export const manageAuthRouter = makeRouter((app) => {
|
|||
'/auth/register',
|
||||
{ schema: { body: registerSchema } },
|
||||
handle(async ({ em, body, req }) => {
|
||||
await assertCaptcha(body.captchaToken);
|
||||
|
||||
const user = new User();
|
||||
user.name = body.name;
|
||||
user.profile = body.profile;
|
||||
|
|
|
@ -22,6 +22,7 @@ export const metaRouter = makeRouter((app) => {
|
|||
return {
|
||||
name: conf.meta.name,
|
||||
description: conf.meta.description,
|
||||
hasCaptcha: conf.captcha.enabled,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { conf } from '@/config';
|
||||
import { StatusError } from '@/services/error';
|
||||
|
||||
export async function isValidCaptcha(token: string): Promise<boolean> {
|
||||
if (!conf.captcha.secret)
|
||||
throw new Error('isValidCaptcha() is called but no secret set');
|
||||
const res = await fetch('https://www.google.com/recaptcha/api/siteverify', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
secret: conf.captcha.secret,
|
||||
response: token,
|
||||
}),
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
});
|
||||
const json = await res.json();
|
||||
return !!json.success;
|
||||
}
|
||||
|
||||
export async function assertCaptcha(token?: string) {
|
||||
// early return if captchas arent enabled
|
||||
if (!conf.captcha.enabled) return;
|
||||
if (!token) throw new StatusError('captcha token is required', 400);
|
||||
|
||||
const isValid = await isValidCaptcha(token);
|
||||
if (!isValid) throw new StatusError('captcha token is invalid', 400);
|
||||
}
|
Loading…
Reference in New Issue