mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-10 03:28:53 +00:00
fix(ui): never treat a remote logo URL as a bundled asset
The bundled-path check was an unanchored substring match, so a user-supplied logo URL that happened to carry /assets/logos/ or /_next/static/media/ in its path, and whose filename collided with one of the 36 manifest entries, would pick up a dark-mode treatment meant only for assets we ship. assetPaths already draws this line for resolveLogoSrc, which returns an external src untouched. Export that predicate instead of writing a second one, and require a treated src to clear it. The existing test only covered a remote URL with a bare filename, which passed either way. The new ones fail without the guard.
This commit is contained in:
parent
1a9045efd4
commit
51959feb89
4 changed files with 22 additions and 2 deletions
|
|
@ -81,6 +81,11 @@ describe("Logo", () => {
|
|||
expect(screen.getByRole("img", { name: "Ext logo" })).toHaveClass("w-5 h-5", { exact: true });
|
||||
});
|
||||
|
||||
it("does not treat a user-supplied logo URL that mimics the bundled asset path", () => {
|
||||
render(<Logo src="https://cdn.example.com/assets/logos/github.svg" label="Ext" className="w-5 h-5" />);
|
||||
expect(screen.getByRole("img", { name: "Ext logo" })).toHaveClass("w-5 h-5", { exact: true });
|
||||
});
|
||||
|
||||
it("applies the treatment to a provider logo resolved through the bundler", () => {
|
||||
render(<Logo provider="openrouter" className="w-5 h-5" />);
|
||||
expect(screen.getByRole("img", { name: "openrouter logo" })).toHaveClass("dark:[filter:brightness(0)_invert(1)]");
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { normalizeRootPath } from "@/lib/http/resolveApiBase";
|
|||
|
||||
const EXTERNAL_SRC = /^(https?:|data:|blob:|\/\/)/i;
|
||||
|
||||
export const isExternalAssetSrc = (value: string): boolean => EXTERNAL_SRC.test(value);
|
||||
|
||||
/**
|
||||
* Prefix a root-relative asset path (e.g. "/ui/assets/logos/openai.svg") with the
|
||||
* proxy's server root path so it resolves when the UI is mounted under a sub-path
|
||||
|
|
@ -22,7 +24,7 @@ export const withServerRoot = (path: string, root: string): string => {
|
|||
*/
|
||||
export const resolveLogoSrc = (value: string | null | undefined, root: string = serverRootPath): string | undefined => {
|
||||
if (!value) return undefined;
|
||||
if (EXTERNAL_SRC.test(value)) return value;
|
||||
if (isExternalAssetSrc(value)) return value;
|
||||
if (value.includes("/_next/static/")) return value;
|
||||
const prefix = normalizeRootPath(root);
|
||||
if (prefix && (value === prefix || value.startsWith(`${prefix}/`))) return value;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,17 @@ describe("logoTreatmentFor", () => {
|
|||
expect(logoTreatmentFor("https://cdn.example.com/github.svg")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not treat a remote URL that also carries a bundled-looking path", () => {
|
||||
expect(logoTreatmentFor("https://cdn.example.com/assets/logos/github.svg")).toBeUndefined();
|
||||
expect(logoTreatmentFor("http://cdn.example.com/_next/static/media/github.abc123.svg")).toBeUndefined();
|
||||
expect(logoTreatmentFor("//cdn.example.com/assets/logos/github.svg")).toBeUndefined();
|
||||
expect(logoTreatmentFor("HTTPS://CDN.EXAMPLE.COM/assets/logos/github.svg")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not treat a data URL that happens to contain a bundled-looking path", () => {
|
||||
expect(logoTreatmentFor("data:image/svg+xml,/assets/logos/github.svg")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not treat a non-logo path whose filename collides with a bundled asset", () => {
|
||||
expect(logoTreatmentFor("/uploads/user/github.svg")).toBeUndefined();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { isExternalAssetSrc } from "@/lib/assetPaths";
|
||||
|
||||
export type LogoTreatment = "invert" | "plate";
|
||||
|
||||
const BUNDLED_LOGO_PATH = /(?:\/assets\/logos\/|\/_next\/static\/media\/)/;
|
||||
|
|
@ -49,7 +51,7 @@ const withoutBundlerHash = (basename: string): string | undefined => {
|
|||
};
|
||||
|
||||
export const logoTreatmentFor = (src: string | null | undefined): LogoTreatment | undefined => {
|
||||
if (!src || !BUNDLED_LOGO_PATH.test(src)) return undefined;
|
||||
if (!src || isExternalAssetSrc(src) || !BUNDLED_LOGO_PATH.test(src)) return undefined;
|
||||
const basename = basenameOf(src);
|
||||
const key = basename === undefined ? undefined : withoutBundlerHash(basename);
|
||||
return key === undefined ? undefined : TREATMENT_BY_ASSET[key];
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue