Added option to disable captcha

This commit is contained in:
WardPearce
2026-02-17 20:28:42 +13:00
parent b10b5c2a24
commit 3f112ada56
6 changed files with 34 additions and 21 deletions
+6
View File
@@ -12,6 +12,9 @@ invidious_companion:
public_url: "http://companion.example.com/companion" public_url: "http://companion.example.com/companion"
``` ```
### Proof-of-work Captcha
Will only work while using HTTPS. If in HTTP set `PUBLIC_CAPTCHA_DISABLED` to `true`
### Docker Compose ### Docker Compose
```yaml ```yaml
@@ -42,6 +45,9 @@ services:
# Allow anyone to register # Allow anyone to register
PUBLIC_REGISTRATION_ALLOWED: "false" PUBLIC_REGISTRATION_ALLOWED: "false"
# Disable POW Captcha
PUBLIC_CAPTCHA_DISABLED: "false"
# Allow any domain in proxy # Allow any domain in proxy
# This shouldn't be used unless you KNOW what your doing # This shouldn't be used unless you KNOW what your doing
# requires VITE_REGISTRATION_ALLOWED to be false # requires VITE_REGISTRATION_ALLOWED to be false
+3
View File
@@ -1,8 +1,11 @@
import { error } from '@sveltejs/kit'; import { error } from '@sveltejs/kit';
import { verifySolution } from 'altcha-lib'; import { verifySolution } from 'altcha-lib';
import { getSequelize } from './database'; import { getSequelize } from './database';
import { isOwnBackend } from '$lib/shared';
export async function verifyCaptcha(payload: string, key: string, maxUses: number = -1) { export async function verifyCaptcha(payload: string, key: string, maxUses: number = -1) {
if (isOwnBackend()?.captchaDisabled) return;
const passedCaptcha = await verifySolution(payload, key, true); const passedCaptcha = await verifySolution(payload, key, true);
if (!passedCaptcha) { if (!passedCaptcha) {
throw error(400, 'Unsupported payload'); throw error(400, 'Unsupported payload');
+3 -1
View File
@@ -6,6 +6,7 @@ export type IsOwnBackend = {
requireAuth: boolean; requireAuth: boolean;
registrationAllowed: boolean; registrationAllowed: boolean;
allowAnyProxy: boolean; allowAnyProxy: boolean;
captchaDisabled: boolean;
}; };
export function isOwnBackend(): IsOwnBackend | null { export function isOwnBackend(): IsOwnBackend | null {
@@ -16,6 +17,7 @@ export function isOwnBackend(): IsOwnBackend | null {
internalAuth: env.PUBLIC_INTERNAL_AUTH !== 'false', internalAuth: env.PUBLIC_INTERNAL_AUTH !== 'false',
requireAuth: env.PUBLIC_REQUIRE_AUTH !== 'false', requireAuth: env.PUBLIC_REQUIRE_AUTH !== 'false',
registrationAllowed: env.PUBLIC_REGISTRATION_ALLOWED === 'true', registrationAllowed: env.PUBLIC_REGISTRATION_ALLOWED === 'true',
allowAnyProxy: env.PUBLIC_DANGEROUS_ALLOW_ANY_PROXY === 'true' allowAnyProxy: env.PUBLIC_DANGEROUS_ALLOW_ANY_PROXY === 'true',
captchaDisabled: env.PUBLIC_CAPTCHA_DISABLED === 'true'
}; };
} }
@@ -81,22 +81,24 @@
{/if} {/if}
</div> </div>
<article {#if !isOwnBackend()?.captchaDisabled}
class="surface-container-highest no-padding" <article
style="width: 100%;height: fit-content;" class="surface-container-highest no-padding"
> style="width: 100%;height: fit-content;"
<altcha-widget >
challengeurl="/api/captcha" <altcha-widget
hidelogo challengeurl="/api/captcha"
hidefooter hidelogo
onstatechange={(ev) => { hidefooter
const { payload, state } = ev.detail; onstatechange={(ev) => {
if (state === 'verified' && payload) { const { payload, state } = ev.detail;
captchaPayload = payload; if (state === 'verified' && payload) {
} captchaPayload = payload;
}} }
></altcha-widget> }}
</article> ></altcha-widget>
</article>
{/if}
<nav class="right-align"> <nav class="right-align">
<button <button
@@ -16,7 +16,7 @@ const zUserCreate = z.object({
cipher: z.string().max(255), cipher: z.string().max(255),
nonce: z.string().max(255) nonce: z.string().max(255)
}), }),
captchaPayload: z.string() captchaPayload: z.string().optional()
}); });
export async function POST({ request, cookies, locals }) { export async function POST({ request, cookies, locals }) {
@@ -28,7 +28,7 @@ export async function POST({ request, cookies, locals }) {
if (!userToCreate.success) throw error(400); if (!userToCreate.success) throw error(400);
await verifyCaptcha(userToCreate.data.captchaPayload, locals.captchaKey, 1); await verifyCaptcha(userToCreate.data.captchaPayload ?? '', locals.captchaKey, 1);
const createdUser = await createUser({ const createdUser = await createUser({
username: userToCreate.data.username, username: userToCreate.data.username,
@@ -8,7 +8,7 @@ import { verifyCaptcha } from '$lib/server/captcha';
const zUserLogin = z.object({ const zUserLogin = z.object({
username: z.string(), username: z.string(),
passwordHash: z.string(), passwordHash: z.string(),
captchaPayload: z.string() captchaPayload: z.string().optional()
}); });
export async function POST({ request, cookies, locals }) { export async function POST({ request, cookies, locals }) {
@@ -20,7 +20,7 @@ export async function POST({ request, cookies, locals }) {
if (!userLogin.success) throw error(401); if (!userLogin.success) throw error(401);
await verifyCaptcha(userLogin.data.captchaPayload, locals.captchaKey, 1); await verifyCaptcha(userLogin.data.captchaPayload ?? '', locals.captchaKey, 1);
const userModel = await authenticateUser(userLogin.data.username, userLogin.data.passwordHash); const userModel = await authenticateUser(userLogin.data.username, userLogin.data.passwordHash);