Filter out invalid WebSocket URLs from pool, prevent admins from setting them

Fixes https://gitlab.com/soapbox-pub/ditto/-/issues/276
This commit is contained in:
Alex Gleason 2024-12-10 17:43:01 -06:00
parent dbfd1a9d35
commit f8e77d90eb
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
3 changed files with 17 additions and 3 deletions

View file

@ -12,7 +12,7 @@ import { DittoEvent } from '@/interfaces/DittoEvent.ts';
import { DittoZapSplits, getZapSplits } from '@/utils/zap-split.ts'; import { DittoZapSplits, getZapSplits } from '@/utils/zap-split.ts';
import { AdminSigner } from '@/signers/AdminSigner.ts'; import { AdminSigner } from '@/signers/AdminSigner.ts';
import { screenshotsSchema } from '@/schemas/nostr.ts'; import { screenshotsSchema } from '@/schemas/nostr.ts';
import { booleanParamSchema, percentageSchema } from '@/schema.ts'; import { booleanParamSchema, percentageSchema, wsUrlSchema } from '@/schema.ts';
import { hydrateEvents } from '@/storages/hydrate.ts'; import { hydrateEvents } from '@/storages/hydrate.ts';
import { renderNameRequest } from '@/views/ditto.ts'; import { renderNameRequest } from '@/views/ditto.ts';
import { accountFromPubkey } from '@/views/mastodon/accounts.ts'; import { accountFromPubkey } from '@/views/mastodon/accounts.ts';
@ -23,7 +23,7 @@ import { updateListAdminEvent } from '@/utils/api.ts';
const markerSchema = z.enum(['read', 'write']); const markerSchema = z.enum(['read', 'write']);
const relaySchema = z.object({ const relaySchema = z.object({
url: z.string().url(), url: wsUrlSchema,
marker: markerSchema.optional(), marker: markerSchema.optional(),
}); });

View file

@ -33,6 +33,16 @@ const hashtagSchema = z.string().regex(/^\w{1,30}$/);
*/ */
const safeUrlSchema = z.string().max(2048).url(); const safeUrlSchema = z.string().max(2048).url();
/** WebSocket URL. */
const wsUrlSchema = z.string().refine((val) => {
try {
const { protocol } = new URL(val);
return protocol === 'wss:' || protocol === 'ws:';
} catch {
return false;
}
}, 'Invalid WebSocket URL');
/** https://github.com/colinhacks/zod/issues/1630#issuecomment-1365983831 */ /** https://github.com/colinhacks/zod/issues/1630#issuecomment-1365983831 */
const booleanParamSchema = z.enum(['true', 'false']).transform((value) => value === 'true'); const booleanParamSchema = z.enum(['true', 'false']).transform((value) => value === 'true');
@ -81,4 +91,5 @@ export {
percentageSchema, percentageSchema,
safeUrlSchema, safeUrlSchema,
sizesSchema, sizesSchema,
wsUrlSchema,
}; };

View file

@ -3,6 +3,7 @@ import { Conf } from '@/config.ts';
import { DittoDatabase } from '@/db/DittoDatabase.ts'; import { DittoDatabase } from '@/db/DittoDatabase.ts';
import { DittoDB } from '@/db/DittoDB.ts'; import { DittoDB } from '@/db/DittoDB.ts';
import { internalSubscriptionsSizeGauge } from '@/metrics.ts'; import { internalSubscriptionsSizeGauge } from '@/metrics.ts';
import { wsUrlSchema } from '@/schema.ts';
import { AdminStore } from '@/storages/AdminStore.ts'; import { AdminStore } from '@/storages/AdminStore.ts';
import { EventsDB } from '@/storages/EventsDB.ts'; import { EventsDB } from '@/storages/EventsDB.ts';
import { SearchStore } from '@/storages/search-store.ts'; import { SearchStore } from '@/storages/search-store.ts';
@ -80,7 +81,9 @@ export class Storages {
const tags = relayList?.tags ?? []; const tags = relayList?.tags ?? [];
const activeRelays = tags.reduce((acc, [name, url, marker]) => { const activeRelays = tags.reduce((acc, [name, url, marker]) => {
if (name === 'r' && (!marker || marker === 'write')) { const valid = wsUrlSchema.safeParse(url).success;
if (valid && name === 'r' && (!marker || marker === 'write')) {
acc.push(url); acc.push(url);
} }
return acc; return acc;