This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// An organization's logo, served to its members from this app's own origin.
|
||||
//
|
||||
// It goes through the same caller as every page, so only a member of the organization reads it
|
||||
// (`branding.logo.get`, `branding.brand.read`), and what comes back is bytes a checker approved when
|
||||
// they were uploaded. The response is still treated as hostile: `nosniff` so a browser does not
|
||||
// reinterpret it, a content security policy that allows nothing -- no script, no request, no
|
||||
// framing -- so even an SVG that slipped past the checker runs nothing when it is opened directly,
|
||||
// and `sandbox` for the same reason.
|
||||
|
||||
import { logoGet } from "@app/modules/branding"
|
||||
import { AppError } from "@conusai-kit/core"
|
||||
import { pageContext } from "../../../../../src/server/page"
|
||||
|
||||
export const dynamic = "force-dynamic"
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ org: string; variant: string }> },
|
||||
): Promise<Response> {
|
||||
const { org, variant } = await params
|
||||
if (variant !== "light" && variant !== "dark") return new Response(null, { status: 404 })
|
||||
// `?s=1x` or `?s=2x`: the 1x or the 2x rendition of a raster logo (2x when absent; an SVG has one size).
|
||||
const size = new URL(request.url).searchParams.get("s")
|
||||
if (size !== null && size !== "1x" && size !== "2x") return new Response(null, { status: 404 })
|
||||
try {
|
||||
const { caller } = await pageContext()
|
||||
const logo = await caller.call(logoGet, { org, variant, ...(size === null ? {} : { size }) })
|
||||
return new Response(Buffer.from(logo.body, "base64"), {
|
||||
headers: {
|
||||
"content-type": logo.contentType,
|
||||
"x-content-type-options": "nosniff",
|
||||
"content-security-policy": "default-src 'none'; style-src 'unsafe-inline'; sandbox",
|
||||
// The logo's path carries its own content tag (`?v=`), so a changed logo is a new URL.
|
||||
"cache-control": "private, max-age=31536000, immutable",
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
// A non-member, a missing organization and a missing logo are all the same answer.
|
||||
return new Response(null, { status: error instanceof AppError && error.status < 500 ? 404 : 500 })
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// An organization's share image (spec §10.3): its display name and its logo for the dark page (its own, or
|
||||
// the one it has when it has only one, or the app brand's), in the brandbook's treatment, 1200x630.
|
||||
//
|
||||
// It goes through the same caller as every page, so only a member of the organization draws it, and a
|
||||
// non-member and a missing organization get the same 404. The logo is checked by the kit's rules wherever
|
||||
// it comes from; one that cannot be drawn is replaced by the app brand's, and the image is still served.
|
||||
|
||||
import { appBrand } from "@app/config"
|
||||
import { brandGet, renderShareImage, shareBrand } from "@app/modules/branding"
|
||||
import { AppError } from "@conusai-kit/core"
|
||||
import { orgGet } from "@conusai-kit/tenancy"
|
||||
import { appIdentity, readersFor } from "../../../../src/server/brand-assets"
|
||||
import { pageContext } from "../../../../src/server/page"
|
||||
|
||||
export const dynamic = "force-dynamic"
|
||||
|
||||
export async function GET(_request: Request, { params }: { params: Promise<{ org: string }> }): Promise<Response> {
|
||||
const { org } = await params
|
||||
try {
|
||||
const { caller } = await pageContext()
|
||||
const organization = await caller.call(orgGet, { org })
|
||||
const brand = await caller.call(brandGet, { org })
|
||||
const share = await shareBrand({
|
||||
app: appIdentity(),
|
||||
tenant: { name: organization.name, brand },
|
||||
readers: readersFor(caller, org),
|
||||
})
|
||||
const png = await renderShareImage(share, { title: share.name, footer: appBrand.name })
|
||||
return new Response(Buffer.from(png), {
|
||||
headers: {
|
||||
"content-type": "image/png",
|
||||
"x-content-type-options": "nosniff",
|
||||
"cache-control": "private, max-age=300",
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
// A non-member, a missing organization and a logo nobody can draw are not told apart.
|
||||
return new Response(null, { status: error instanceof AppError && error.status < 500 ? 404 : 500 })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user