feat: 🔒 Add crossorigin attributes to every image element

This commit is contained in:
Jesse Wierzbinski 2024-05-04 19:22:47 -10:00
parent 74425cd62e
commit cafe272429
No known key found for this signature in database
16 changed files with 29 additions and 25 deletions

View file

@ -14,7 +14,8 @@
<nav class="flex items-center justify-between p-6 lg:px-8" aria-label="Global"> <nav class="flex items-center justify-between p-6 lg:px-8" aria-label="Global">
<div class="flex lg:flex-1"> <div class="flex lg:flex-1">
<NuxtLink href="/" class="-m-1.5 p-1.5"> <NuxtLink href="/" class="-m-1.5 p-1.5">
<img class="h-8 w-auto" src="https://cdn.lysand.org/logo.webp" alt="Lysand logo" /> <img crossorigin="anonymous" class="h-8 w-auto" src="https://cdn.lysand.org/logo.webp"
alt="Lysand logo" />
</NuxtLink> </NuxtLink>
</div> </div>
<div class="flex lg:hidden"> <div class="flex lg:hidden">
@ -39,7 +40,8 @@
class="fixed inset-y-0 right-0 z-50 w-full overflow-y-auto bg-dark-800 px-6 py-6 sm:max-w-sm sm:ring-1 sm:ring-gray-50/10"> class="fixed inset-y-0 right-0 z-50 w-full overflow-y-auto bg-dark-800 px-6 py-6 sm:max-w-sm sm:ring-1 sm:ring-gray-50/10">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<NuxtLink href="/" class="-m-1.5 p-1.5"> <NuxtLink href="/" class="-m-1.5 p-1.5">
<img class="h-8 w-auto" src="https://cdn.lysand.org/logo.webp" alt="Lysand Logo" /> <img crossorigin="anonymous" class="h-8 w-auto" src="https://cdn.lysand.org/logo.webp"
alt="Lysand Logo" />
</NuxtLink> </NuxtLink>
<button type="button" class="-m-2.5 rounded-md p-2.5 text-gray-200" @click="mobileMenuOpen = false"> <button type="button" class="-m-2.5 rounded-md p-2.5 text-gray-200" @click="mobileMenuOpen = false">
<span class="sr-only">Close menu</span> <span class="sr-only">Close menu</span>

View file

@ -2,7 +2,7 @@
<aside <aside
class="fixed h-dvh z-20 md:flex hidden flex-col p-4 bg-dark-800 gap-10 max-w-20 hover:max-w-72 duration-200 group"> class="fixed h-dvh z-20 md:flex hidden flex-col p-4 bg-dark-800 gap-10 max-w-20 hover:max-w-72 duration-200 group">
<NuxtLink class="rounded w-11 h-11 ring-1 ring-white/10 hover:scale-105 duration-200" href="/"> <NuxtLink class="rounded w-11 h-11 ring-1 ring-white/10 hover:scale-105 duration-200" href="/">
<img src="https://cdn.lysand.org/logo.webp" alt="Lysand logo" /> <img crossorigin="anonymous" src="https://cdn.lysand.org/logo.webp" alt="Lysand logo" />
</NuxtLink> </NuxtLink>
<div class="flex flex-col gap-3"> <div class="flex flex-col gap-3">

View file

@ -2,8 +2,8 @@
<div class="flex flex-col p-10 gap-4 h-full"> <div class="flex flex-col p-10 gap-4 h-full">
<div <div
class="aspect-video shrink-0 w-full rounded ring-white/5 bg-dark-800 shadow overflow-hidden ring-1 hover:ring-2 duration-100"> class="aspect-video shrink-0 w-full rounded ring-white/5 bg-dark-800 shadow overflow-hidden ring-1 hover:ring-2 duration-100">
<img class="object-cover w-full h-full duration-150 hover:scale-[102%] ease-in-out" v-if="instance?.banner" <img crossorigin="anonymous" class="object-cover w-full h-full duration-150 hover:scale-[102%] ease-in-out"
alt="Instance banner" :src="instance.banner" /> v-if="instance?.banner" alt="Instance banner" :src="instance.banner" />
</div> </div>
<div class="prose prose-invert prose-sm"> <div class="prose prose-invert prose-sm">

View file

@ -1,7 +1,7 @@
<template> <template>
<div @click="lightbox = true" tabindex="0" aria-label="Open attachment in lightbox" @keydown="lightbox = true" <div @click="lightbox = true" tabindex="0" aria-label="Open attachment in lightbox" @keydown="lightbox = true"
class="aspect-video w-full rounded ring-white/5 shadow overflow-hidden ring-1 hover:ring-2 duration-100"> class="aspect-video w-full rounded ring-white/5 shadow overflow-hidden ring-1 hover:ring-2 duration-100">
<img v-if="attachment.type === 'image'" tabindex="-1" <img crossorigin="anonymous" v-if="attachment.type === 'image'" tabindex="-1"
class="object-cover w-full h-full rounded duration-150 hover:scale-[102%] ease-in-out" :src="attachment.url" class="object-cover w-full h-full rounded duration-150 hover:scale-[102%] ease-in-out" :src="attachment.url"
:alt="attachment.description ?? ''" :title="attachment.description ?? ''" /> :alt="attachment.description ?? ''" :title="attachment.description ?? ''" />
<video v-else-if="attachment.type === 'video'" class="object-cover w-full h-full rounded" controls <video v-else-if="attachment.type === 'video'" class="object-cover w-full h-full rounded" controls
@ -29,7 +29,7 @@
<span class="sr-only">Close</span> <span class="sr-only">Close</span>
</button> </button>
</div> </div>
<img @click.stop v-if="attachment.type === 'image'" <img crossorigin="anonymous" @click.stop v-if="attachment.type === 'image'"
class="rounded max-w-full min-w-[30%] max-h-[70%]" :src="attachment.url" class="rounded max-w-full min-w-[30%] max-h-[70%]" :src="attachment.url"
:alt="attachment.description ?? ''" :title="attachment.description ?? ''" /> :alt="attachment.description ?? ''" :title="attachment.description ?? ''" />
<span @click.stop v-if="attachment.description" <span @click.stop v-if="attachment.description"

View file

@ -2,8 +2,8 @@
<div v-if="small" class="flex flex-row"> <div v-if="small" class="flex flex-row">
<Skeleton :enabled="!note" shape="rect" class="!h-6 w-6"> <Skeleton :enabled="!note" shape="rect" class="!h-6 w-6">
<NuxtLink :href="accountUrl" class="shrink-0"> <NuxtLink :href="accountUrl" class="shrink-0">
<img class="h-6 w-6 rounded ring-1 ring-white/5 shrink-0" :src="note?.account.avatar" <img crossorigin="anonymous" class="h-6 w-6 rounded ring-1 ring-white/5 shrink-0"
:alt="`${note?.account.acct}'s avatar`" /> :src="note?.account.avatar" :alt="`${note?.account.acct}'s avatar`" />
</NuxtLink> </NuxtLink>
</Skeleton> </Skeleton>
<div class="flex flex-col items-start justify-around ml-4 grow overflow-hidden"> <div class="flex flex-col items-start justify-around ml-4 grow overflow-hidden">
@ -25,7 +25,7 @@
<div v-else class="flex flex-row"> <div v-else class="flex flex-row">
<Skeleton :enabled="!note" shape="rect" class="!h-12 w-12"> <Skeleton :enabled="!note" shape="rect" class="!h-12 w-12">
<NuxtLink :href="accountUrl" class="shrink-0"> <NuxtLink :href="accountUrl" class="shrink-0">
<img class="h-12 w-12 rounded ring-1 ring-white/5" :src="note?.account.avatar" <img crossorigin="anonymous" class="h-12 w-12 rounded ring-1 ring-white/5" :src="note?.account.avatar"
:alt="`${note?.account.acct}'s avatar`" /> :alt="`${note?.account.acct}'s avatar`" />
</NuxtLink> </NuxtLink>
</Skeleton> </Skeleton>

View file

@ -1,8 +1,8 @@
<template> <template>
<a :href="`/@${account.acct}`" <a :href="`/@${account.acct}`"
class="shrink break-all rounded bg-pink-700/80 text-pink-200 px-2 py-1 not-prose font-semibold cursor-pointer [&:not(:last-child)]:mr-1 duration-200 hover:bg-pink-600/30"> class="shrink break-all rounded bg-pink-700/80 text-pink-200 px-2 py-1 not-prose font-semibold cursor-pointer [&:not(:last-child)]:mr-1 duration-200 hover:bg-pink-600/30">
<img class="h-[1em] w-[1em] rounded ring-1 ring-white/5 inline align-middle mb-1 mr-1" :src="account.avatar" <img crossorigin="anonymous" class="h-[1em] w-[1em] rounded ring-1 ring-white/5 inline align-middle mb-1 mr-1"
:alt="`${account.acct}'s avatar'`" /> :src="account.avatar" :alt="`${account.acct}'s avatar'`" />
{{ account.display_name }} {{ account.display_name }}
</a> </a>
</template> </template>

View file

@ -7,7 +7,7 @@
<div v-if="reblog" class="mb-4 flex flex-row gap-2 items-center text-pink-500"> <div v-if="reblog" class="mb-4 flex flex-row gap-2 items-center text-pink-500">
<Skeleton :enabled="!loaded" shape="rect" class="!h-6" :min-width="40" :max-width="100" width-unit="%"> <Skeleton :enabled="!loaded" shape="rect" class="!h-6" :min-width="40" :max-width="100" width-unit="%">
<Icon name="tabler:repeat" class="h-6 w-6" aria-hidden="true" /> <Icon name="tabler:repeat" class="h-6 w-6" aria-hidden="true" />
<img v-if="reblog.avatar" :src="reblog.avatar" :alt="`${reblog.acct}'s avatar'`" <img crossorigin="anonymous" v-if="reblog.avatar" :src="reblog.avatar" :alt="`${reblog.acct}'s avatar'`"
class="h-6 w-6 rounded shrink-0 ring-1 ring-white/10" /> class="h-6 w-6 rounded shrink-0 ring-1 ring-white/10" />
<span><strong v-html="reblogDisplayName"></strong> reblogged</span> <span><strong v-html="reblogDisplayName"></strong> reblogged</span>
</Skeleton> </Skeleton>

View file

@ -4,7 +4,7 @@
<Skeleton :enabled="!notification" shape="rect" class="!h-6" :min-width="40" :max-width="100" <Skeleton :enabled="!notification" shape="rect" class="!h-6" :min-width="40" :max-width="100"
width-unit="%"> width-unit="%">
<Icon :name="icon" class="h-6 w-6 text-gray-200" aria-hidden="true" /> <Icon :name="icon" class="h-6 w-6 text-gray-200" aria-hidden="true" />
<img v-if="notification?.account?.avatar" :src="notification?.account.avatar" <img crossorigin="anonymous" v-if="notification?.account?.avatar" :src="notification?.account.avatar"
:alt="`${notification?.account.acct}'s avatar'`" :alt="`${notification?.account.acct}'s avatar'`"
class="h-6 w-6 shrink-0 rounded ring-1 ring-white/10" /> class="h-6 w-6 shrink-0 rounded ring-1 ring-white/10" />
<span class="text-gray-200"><strong v-html="accountName"></strong> {{ text <span class="text-gray-200"><strong v-html="accountName"></strong> {{ text

View file

@ -3,16 +3,16 @@
<div class="w-full rounded ring-1 ring-white/10 pb-10"> <div class="w-full rounded ring-1 ring-white/10 pb-10">
<Skeleton :enabled="skeleton" class="!w-full !h-full !aspect-[8/3]"> <Skeleton :enabled="skeleton" class="!w-full !h-full !aspect-[8/3]">
<div class="w-full aspect-[8/3] border-b border-white/10 bg-dark-700"> <div class="w-full aspect-[8/3] border-b border-white/10 bg-dark-700">
<img v-if="account?.header" :src="account.header" class="object-cover w-full h-full" <img crossorigin="anonymous" v-if="account?.header" :src="account.header"
:alt="`${account.acct}'s header image'`" /> class="object-cover w-full h-full" :alt="`${account.acct}'s header image'`" />
</div> </div>
</Skeleton> </Skeleton>
<div class="flex items-start justify-between px-4 py-3"> <div class="flex items-start justify-between px-4 py-3">
<div class="h-32 w-32 -mt-[4.5rem] z-10 bg-dark-700 rounded shrink-0 overflow-hidden"> <div class="h-32 w-32 -mt-[4.5rem] z-10 bg-dark-700 rounded shrink-0 overflow-hidden">
<Skeleton :enabled="skeleton" class="!h-full !w-full"> <Skeleton :enabled="skeleton" class="!h-full !w-full">
<img class="cursor-pointer bg-dark-700 ring-1 ring-white/10" :src="account?.avatar" <img crossorigin="anonymous" class="cursor-pointer bg-dark-700 ring-1 ring-white/10"
:alt="`${account?.acct}'s avatar'`" /> :src="account?.avatar" :alt="`${account?.acct}'s avatar'`" />
</Skeleton> </Skeleton>
</div> </div>

View file

@ -2,7 +2,7 @@
<NuxtLink :href="accountUrl" class="flex flex-row"> <NuxtLink :href="accountUrl" class="flex flex-row">
<Skeleton :enabled="!account" shape="rect" class="!h-12 w-12"> <Skeleton :enabled="!account" shape="rect" class="!h-12 w-12">
<div class="shrink-0"> <div class="shrink-0">
<img class="h-12 w-12 rounded ring-1 ring-white/5" :src="account?.avatar" <img crossorigin="anonymous" class="h-12 w-12 rounded ring-1 ring-white/5" :src="account?.avatar"
:alt="`${account?.acct}'s avatar'`" /> :alt="`${account?.acct}'s avatar'`" />
</div> </div>
</Skeleton> </Skeleton>

View file

@ -36,6 +36,7 @@ export const useParsedContent = (
return match; return match;
} }
const image = document.createElement("img"); const image = document.createElement("img");
image.crossOrigin = "anonymous";
image.src = emojiData.url; image.src = emojiData.url;
image.alt = `:${emoji}:`; image.alt = `:${emoji}:`;
image.title = emojiData.shortcode; image.title = emojiData.shortcode;

View file

@ -22,6 +22,7 @@ export default defineNuxtConfig({
"img-src": ["'self'", "data:", "https:"], "img-src": ["'self'", "data:", "https:"],
"script-src": ["'nonce-{{nonce}}'", "'strict-dynamic'"], "script-src": ["'nonce-{{nonce}}'", "'strict-dynamic'"],
}, },
crossOriginResourcePolicy: "cross-origin",
xFrameOptions: "DENY", xFrameOptions: "DENY",
}, },
rateLimiter: { rateLimiter: {

View file

@ -8,7 +8,7 @@
<li v-for="client of useConfig().RECOMMENDED_CLIENTS" :key="client.name" class="w-full"> <li v-for="client of useConfig().RECOMMENDED_CLIENTS" :key="client.name" class="w-full">
<a :href="client.link" target="_blank" <a :href="client.link" target="_blank"
class="rounded-sm ring-2 ring-white/10 px-4 py-2 w-full flex flex-row gap-3 items-center"> class="rounded-sm ring-2 ring-white/10 px-4 py-2 w-full flex flex-row gap-3 items-center">
<img :src="client.icon" class="h-10 w-10" :alt="`${client.name}'s logo'`" /> <img crossorigin="anonymous" :src="client.icon" class="h-10 w-10" :alt="`${client.name}'s logo'`" />
<div class="flex flex-col justify-between items-start"> <div class="flex flex-col justify-between items-start">
<h2 class="text-gray-100 font-semibold">{{ client.name }}</h2> <h2 class="text-gray-100 font-semibold">{{ client.name }}</h2>
<span class="underline text-pink-700">{{ client.link }}</span> <span class="underline text-pink-700">{{ client.link }}</span>

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="flex min-h-screen relative flex-col justify-center py-12 lg:px-8"> <div class="flex min-h-screen relative flex-col justify-center py-12 lg:px-8">
<img src="https://camo.githubusercontent.com/353460d1fdb1667ec993159270dcece12c491fb38165460215a519ab93f4e554/68747470733a2f2f63646e2d7765622e63706c757370617463682e636f6d2f6c7973616e642e77656270" <img crossorigin="anonymous" src="https://camo.githubusercontent.com/353460d1fdb1667ec993159270dcece12c491fb38165460215a519ab93f4e554/68747470733a2f2f63646e2d7765622e63706c757370617463682e636f6d2f6c7973616e642e77656270"
alt="Lysand logo" class="mx-auto h-24 hidden md:block" /> alt="Lysand logo" class="mx-auto h-24 hidden md:block" />
<div v-if="validUrlParameters" <div v-if="validUrlParameters"
class="mt-10 sm:mx-auto w-full sm:max-w-md md:bg-dark-900 px-10 py-10 rounded md:ring-1 md:ring-white/10"> class="mt-10 sm:mx-auto w-full sm:max-w-md md:bg-dark-900 px-10 py-10 rounded md:ring-1 md:ring-white/10">
@ -35,7 +35,7 @@
<a v-for="provider of oauthProviders" :key="provider.id" <a v-for="provider of oauthProviders" :key="provider.id"
:href="`/oauth/authorize-external?issuer=${provider.id}&redirect_uri=${redirect_uri}&response_type=${response_type}&clientId=${client_id}&scope=${scope}`"> :href="`/oauth/authorize-external?issuer=${provider.id}&redirect_uri=${redirect_uri}&response_type=${response_type}&clientId=${client_id}&scope=${scope}`">
<ButtonsSecondary class="flex flex-row w-full items-center justify-center gap-3"> <ButtonsSecondary class="flex flex-row w-full items-center justify-center gap-3">
<img :src="provider.icon" :alt="`${provider.name}'s logo'`" class="w-6 h-6" /> <img crossorigin="anonymous" :src="provider.icon" :alt="`${provider.name}'s logo'`" class="w-6 h-6" />
<div class="flex flex-col gap-0 justify-center"> <div class="flex flex-col gap-0 justify-center">
<h3 class="font-bold">{{ provider.name }}</h3> <h3 class="font-bold">{{ provider.name }}</h3>
</div> </div>
@ -60,7 +60,7 @@
<li v-for="client of useConfig().RECOMMENDED_CLIENTS" :key="client.name" class="w-full"> <li v-for="client of useConfig().RECOMMENDED_CLIENTS" :key="client.name" class="w-full">
<a :href="client.link" target="_blank" <a :href="client.link" target="_blank"
class="rounded-sm ring-2 ring-white/10 px-4 py-2 w-full flex flex-row gap-3 items-center"> class="rounded-sm ring-2 ring-white/10 px-4 py-2 w-full flex flex-row gap-3 items-center">
<img :src="client.icon" :alt="`${client.name}'s logo'`" class="h-10 w-10" /> <img crossorigin="anonymous" :src="client.icon" :alt="`${client.name}'s logo'`" class="h-10 w-10" />
<div class="flex flex-col justify-between items-start"> <div class="flex flex-col justify-between items-start">
<h2 class="font-bold text-gray-100">{{ client.name }}</h2> <h2 class="font-bold text-gray-100">{{ client.name }}</h2>
<span class="underline text-pink-700">{{ client.link }}</span> <span class="underline text-pink-700">{{ client.link }}</span>

View file

@ -68,7 +68,7 @@
<li v-for="client of useConfig().RECOMMENDED_CLIENTS" :key="client.name" class="w-full"> <li v-for="client of useConfig().RECOMMENDED_CLIENTS" :key="client.name" class="w-full">
<a :href="client.link" target="_blank" <a :href="client.link" target="_blank"
class="rounded-sm ring-2 ring-white/10 px-4 py-2 w-full flex flex-row gap-3 items-center"> class="rounded-sm ring-2 ring-white/10 px-4 py-2 w-full flex flex-row gap-3 items-center">
<img :src="client.icon" :alt="`${client.name}'s logo'`" class="h-10 w-10" /> <img crossorigin="anonymous" :src="client.icon" :alt="`${client.name}'s logo'`" class="h-10 w-10" />
<div class="flex flex-col justify-between items-start"> <div class="flex flex-col justify-between items-start">
<h2 class="font-bold text-gray-100">{{ client.name }}</h2> <h2 class="font-bold text-gray-100">{{ client.name }}</h2>
<span class="underline text-pink-700">{{ client.link }}</span> <span class="underline text-pink-700">{{ client.link }}</span>

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="flex min-h-screen flex-col justify-center px-6 py-12 gap-10 lg:px-8 relative"> <div class="flex min-h-screen flex-col justify-center px-6 py-12 gap-10 lg:px-8 relative">
<img src="https://camo.githubusercontent.com/353460d1fdb1667ec993159270dcece12c491fb38165460215a519ab93f4e554/68747470733a2f2f63646e2d7765622e63706c757370617463682e636f6d2f6c7973616e642e77656270" <img crossorigin="anonymous" src="https://camo.githubusercontent.com/353460d1fdb1667ec993159270dcece12c491fb38165460215a519ab93f4e554/68747470733a2f2f63646e2d7765622e63706c757370617463682e636f6d2f6c7973616e642e77656270"
alt="Lysand logo" class="mx-auto h-24 hidden md:block" /> alt="Lysand logo" class="mx-auto h-24 hidden md:block" />
<div v-if="instance && instance.registrations" class="mx-auto w-full max-w-md"> <div v-if="instance && instance.registrations" class="mx-auto w-full max-w-md">
<div v-if="Object.keys(errors).length > 0" <div v-if="Object.keys(errors).length > 0"