diff options
Diffstat (limited to 'src/routes')
| -rw-r--r-- | src/routes/api/badges/+server.ts | 14 | ||||
| -rw-r--r-- | src/routes/api/notifications/subscribe/+server.ts | 17 | ||||
| -rw-r--r-- | src/routes/updates/+page.svelte | 34 | ||||
| -rw-r--r-- | src/routes/user/[user]/badges/+page.svelte | 13 |
4 files changed, 55 insertions, 23 deletions
diff --git a/src/routes/api/badges/+server.ts b/src/routes/api/badges/+server.ts index 2673273c..10b63125 100644 --- a/src/routes/api/badges/+server.ts +++ b/src/routes/api/badges/+server.ts @@ -16,6 +16,7 @@ import { import { decodeAuthCookieOrNull } from "$lib/Effect/authCookie"; import { decodeRequestJsonOrThrow } from "$lib/Effect/requestBody"; import { appOrigin, appOriginHeaders } from "$lib/Utility/appOrigin"; +import { isOwnerOrPrivileged } from "$lib/Utility/authorisation"; import privilegedUser from "$lib/Utility/privilegedUser"; const unauthorised = () => new Response("Unauthorised", { status: 401 }); @@ -76,11 +77,14 @@ export const PUT = async ({ cookies, url, request }) => { if (!identity) return unauthorised(); const authorised = privilegedUser(identity.id); - if (url.searchParams.get("shadowHide")) - await setShadowHidden( - Number(url.searchParams.get("shadowHide")), - authorised, - ); + if (url.searchParams.get("shadowHide")) { + const targetUserId = Number(url.searchParams.get("shadowHide")); + + if (!isOwnerOrPrivileged(identity.id, targetUserId, authorised)) + return unauthorised(); + + await setShadowHidden(targetUserId, authorised); + } if (url.searchParams.get("import") || undefined) { const importedBadges = await decodeRequestJsonOrThrow( diff --git a/src/routes/api/notifications/subscribe/+server.ts b/src/routes/api/notifications/subscribe/+server.ts index 51dbf340..b1913e5d 100644 --- a/src/routes/api/notifications/subscribe/+server.ts +++ b/src/routes/api/notifications/subscribe/+server.ts @@ -3,6 +3,7 @@ import { safeUserIdentity } from "$lib/Data/AniList/identity"; import { setUserSubscription } from "$lib/Database/SB/User/notifications"; import { decodeAuthCookieOrNull } from "$lib/Effect/authCookie"; import { decodeRequestJsonOrThrow } from "$lib/Effect/requestBody"; +import { isAllowedPushEndpoint } from "$lib/Utility/pushEndpoint"; const unauthorised = new Response("Unauthorised", { status: 401 }); @@ -20,12 +21,20 @@ export const POST = async ({ cookies, request, url }) => { if (!userId) return unauthorised; + const subscription = await decodeRequestJsonOrThrow( + request, + Schema.Record(Schema.String, Schema.Unknown), + ); + + if ( + typeof subscription.endpoint !== "string" || + !isAllowedPushEndpoint(subscription.endpoint) + ) + return new Response("Invalid push endpoint", { status: 400 }); + await setUserSubscription( userId, - (await decodeRequestJsonOrThrow( - request, - Schema.Record(Schema.String, Schema.Unknown), - )) as unknown as JSON, + subscription as unknown as JSON, fingerprint, ); diff --git a/src/routes/updates/+page.svelte b/src/routes/updates/+page.svelte index 357a5906..bbcb087d 100644 --- a/src/routes/updates/+page.svelte +++ b/src/routes/updates/+page.svelte @@ -5,6 +5,7 @@ import HeadTitle from "$lib/Home/HeadTitle.svelte"; import Skeleton from "$lib/Loading/Skeleton.svelte"; import { createHeightObserver } from "$lib/Utility/html"; import root from "$lib/Utility/root"; +import { sanitizeFeedHtml } from "$lib/Utility/sanitizeHtml"; import locale from "$stores/locale"; let feed: @@ -22,6 +23,7 @@ let novelFeed: }[]; }; } + | null | undefined; let startTime: number; let mangaEndTime: number; @@ -31,14 +33,42 @@ let directLink = browser : false; let removeHeightObserver: (() => void) | undefined; +const fetchJson = async (path: string) => { + try { + const response = await fetch(root(path)); + + return response.ok ? await response.json() : null; + } catch { + return null; + } +}; + onMount(async () => { removeHeightObserver = createHeightObserver(false); startTime = performance.now(); - novelFeed = await (await fetch(root("/api/updates/all-novels"))).json(); + + const allNovels = await fetchJson("/api/updates/all-novels"); + + if (allNovels?.data?.items) + for (const item of allNovels.data.items) { + if (item.postfix) item.postfix = sanitizeFeedHtml(item.postfix); + if (item.series) item.series.name = sanitizeFeedHtml(item.series.name); + } + + novelFeed = allNovels?.data?.items ? allNovels : null; novelEndTime = performance.now() - startTime; startTime = performance.now(); - feed = await (await fetch(root("/api/updates/manga"))).json(); + + const mangaFeed = await fetchJson("/api/updates/manga"); + + if (mangaFeed?.items) + for (const item of mangaFeed.items) { + item.title = sanitizeFeedHtml(item.title); + item.content = sanitizeFeedHtml(item.content); + } + + feed = mangaFeed?.items ? mangaFeed : null; mangaEndTime = performance.now() - startTime; }); diff --git a/src/routes/user/[user]/badges/+page.svelte b/src/routes/user/[user]/badges/+page.svelte index dc43fc08..605f5675 100644 --- a/src/routes/user/[user]/badges/+page.svelte +++ b/src/routes/user/[user]/badges/+page.svelte @@ -40,21 +40,10 @@ $: preferences = $BadgeWallUser.fetching : ($BadgeWallUser.data?.User?.preferences as Preferences | undefined); $: if (browser && preferences && preferences.badge_wall_css) { - const sanitise = (css: string) => - css - .replace(/\/\*[\s\S]*?\*\//g, "") - .replace(/<\/?[^>]+(>|$)/g, "") - .replace( - /(expression|javascript|vbscript|onerror|onload|onclick|onmouseover|onmouseout|onmouseup|onmousedown|onkeydown|onkeyup|onkeypress|onblur|onfocus|onsubmit|onreset|onselect|onchange|ondblclick):/gi, - "", - ) - .replace(/(behaviour|behavior|moz-binding|content):/gi, "") - .replace(/\s+/g, " ") - .trim(); const style = document.createElement("style"); style.dataset.badgeWall = "true"; - style.innerHTML = sanitise(preferences.badge_wall_css); + style.textContent = preferences.badge_wall_css; document.head.appendChild(style); } |