mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: allow installing libs from excal github (#9041)
This commit is contained in:
parent
0bf234fcc9
commit
f87c2cde09
2 changed files with 139 additions and 12 deletions
105
packages/excalidraw/data/library.test.ts
Normal file
105
packages/excalidraw/data/library.test.ts
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
import { validateLibraryUrl } from "./library";
|
||||||
|
|
||||||
|
describe("validateLibraryUrl", () => {
|
||||||
|
it("should validate hostname & pathname", () => {
|
||||||
|
// valid hostnames
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://www.excalidraw.com", ["excalidraw.com"]),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://excalidraw.com", ["excalidraw.com"]),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://library.excalidraw.com", ["excalidraw.com"]),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://library.excalidraw.com", [
|
||||||
|
"library.excalidraw.com",
|
||||||
|
]),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://excalidraw.com/", ["excalidraw.com/"]),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://excalidraw.com", ["excalidraw.com/"]),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://excalidraw.com/", ["excalidraw.com"]),
|
||||||
|
).toBe(true);
|
||||||
|
|
||||||
|
// valid pathnames
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://excalidraw.com/path", ["excalidraw.com"]),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://excalidraw.com/path/", ["excalidraw.com"]),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://excalidraw.com/specific/path", [
|
||||||
|
"excalidraw.com/specific/path",
|
||||||
|
]),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://excalidraw.com/specific/path/", [
|
||||||
|
"excalidraw.com/specific/path",
|
||||||
|
]),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://excalidraw.com/specific/path", [
|
||||||
|
"excalidraw.com/specific/path/",
|
||||||
|
]),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
validateLibraryUrl("https://excalidraw.com/specific/path/other", [
|
||||||
|
"excalidraw.com/specific/path",
|
||||||
|
]),
|
||||||
|
).toBe(true);
|
||||||
|
|
||||||
|
// invalid hostnames
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
expect(() =>
|
||||||
|
validateLibraryUrl("https://xexcalidraw.com", ["excalidraw.com"]),
|
||||||
|
).toThrow();
|
||||||
|
expect(() =>
|
||||||
|
validateLibraryUrl("https://x-excalidraw.com", ["excalidraw.com"]),
|
||||||
|
).toThrow();
|
||||||
|
expect(() =>
|
||||||
|
validateLibraryUrl("https://excalidraw.comx", ["excalidraw.com"]),
|
||||||
|
).toThrow();
|
||||||
|
expect(() =>
|
||||||
|
validateLibraryUrl("https://excalidraw.comx", ["excalidraw.com"]),
|
||||||
|
).toThrow();
|
||||||
|
expect(() =>
|
||||||
|
validateLibraryUrl("https://excalidraw.com.mx", ["excalidraw.com"]),
|
||||||
|
).toThrow();
|
||||||
|
// protocol must be https
|
||||||
|
expect(() =>
|
||||||
|
validateLibraryUrl("http://excalidraw.com.mx", ["excalidraw.com"]),
|
||||||
|
).toThrow();
|
||||||
|
|
||||||
|
// invalid pathnames
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
expect(() =>
|
||||||
|
validateLibraryUrl("https://excalidraw.com/specific/other/path", [
|
||||||
|
"excalidraw.com/specific/path",
|
||||||
|
]),
|
||||||
|
).toThrow();
|
||||||
|
expect(() =>
|
||||||
|
validateLibraryUrl("https://excalidraw.com/specific/paths", [
|
||||||
|
"excalidraw.com/specific/path",
|
||||||
|
]),
|
||||||
|
).toThrow();
|
||||||
|
expect(() =>
|
||||||
|
validateLibraryUrl("https://excalidraw.com/specific/path-s", [
|
||||||
|
"excalidraw.com/specific/path",
|
||||||
|
]),
|
||||||
|
).toThrow();
|
||||||
|
expect(() =>
|
||||||
|
validateLibraryUrl("https://excalidraw.com/some/specific/path", [
|
||||||
|
"excalidraw.com/specific/path",
|
||||||
|
]),
|
||||||
|
).toThrow();
|
||||||
|
});
|
||||||
|
});
|
|
@ -36,7 +36,18 @@ import { Queue } from "../queue";
|
||||||
import { hashElementsVersion, hashString } from "../element";
|
import { hashElementsVersion, hashString } from "../element";
|
||||||
import { toValidURL } from "./url";
|
import { toValidURL } from "./url";
|
||||||
|
|
||||||
const ALLOWED_LIBRARY_HOSTNAMES = ["excalidraw.com"];
|
/**
|
||||||
|
* format: hostname or hostname/pathname
|
||||||
|
*
|
||||||
|
* Both hostname and pathname are matched partially,
|
||||||
|
* hostname from the end, pathname from the start, with subdomain/path
|
||||||
|
* boundaries
|
||||||
|
**/
|
||||||
|
const ALLOWED_LIBRARY_URLS = [
|
||||||
|
"excalidraw.com",
|
||||||
|
// when installing from github PRs
|
||||||
|
"raw.githubusercontent.com/excalidraw/excalidraw-libraries",
|
||||||
|
];
|
||||||
|
|
||||||
type LibraryUpdate = {
|
type LibraryUpdate = {
|
||||||
/** deleted library items since last onLibraryChange event */
|
/** deleted library items since last onLibraryChange event */
|
||||||
|
@ -469,26 +480,37 @@ export const distributeLibraryItemsOnSquareGrid = (
|
||||||
return resElements;
|
return resElements;
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateLibraryUrl = (
|
export const validateLibraryUrl = (
|
||||||
libraryUrl: string,
|
libraryUrl: string,
|
||||||
/**
|
/**
|
||||||
* If supplied, takes precedence over the default whitelist.
|
* @returns `true` if the URL is valid, throws otherwise.
|
||||||
* Return `true` if the URL is valid.
|
|
||||||
*/
|
*/
|
||||||
validator?: (libraryUrl: string) => boolean,
|
validator:
|
||||||
): boolean => {
|
| ((libraryUrl: string) => boolean)
|
||||||
|
| string[] = ALLOWED_LIBRARY_URLS,
|
||||||
|
): true => {
|
||||||
if (
|
if (
|
||||||
validator
|
typeof validator === "function"
|
||||||
? validator(libraryUrl)
|
? validator(libraryUrl)
|
||||||
: ALLOWED_LIBRARY_HOSTNAMES.includes(
|
: validator.some((allowedUrlDef) => {
|
||||||
new URL(libraryUrl).hostname.split(".").slice(-2).join("."),
|
const allowedUrl = new URL(
|
||||||
)
|
`https://${allowedUrlDef.replace(/^https?:\/\//, "")}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { hostname, pathname } = new URL(libraryUrl);
|
||||||
|
|
||||||
|
return (
|
||||||
|
new RegExp(`(^|\\.)${allowedUrl.hostname}$`).test(hostname) &&
|
||||||
|
new RegExp(
|
||||||
|
`^${allowedUrl.pathname.replace(/\/+$/, "")}(/+|$)`,
|
||||||
|
).test(pathname)
|
||||||
|
);
|
||||||
|
})
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error(`Invalid or disallowed library URL: "${libraryUrl}"`);
|
throw new Error(`Invalid or disallowed library URL: "${libraryUrl}"`);
|
||||||
throw new Error("Invalid or disallowed library URL");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const parseLibraryTokensFromUrl = () => {
|
export const parseLibraryTokensFromUrl = () => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue