diff --git a/server/storage/files/BaseStorage.ts b/server/storage/files/BaseStorage.ts index d6b72c7f3..d713d9d9d 100644 --- a/server/storage/files/BaseStorage.ts +++ b/server/storage/files/BaseStorage.ts @@ -1,6 +1,7 @@ import { Blob } from "buffer"; import { Readable } from "stream"; import { PresignedPost } from "aws-sdk/clients/s3"; +import { isBase64Url } from "@shared/utils/urls"; import env from "@server/env"; import Logger from "@server/logging/Logger"; import fetch from "@server/utils/fetch"; @@ -132,7 +133,7 @@ export default abstract class BaseStorage { } let buffer, contentType; - const match = url.match(/data:(.*);base64,(.*)/); + const match = isBase64Url(url); if (match) { contentType = match[1]; diff --git a/shared/utils/urls.test.ts b/shared/utils/urls.test.ts index 5ed28a294..227881b8b 100644 --- a/shared/utils/urls.test.ts +++ b/shared/utils/urls.test.ts @@ -1,7 +1,7 @@ import * as urlsUtils from "./urls"; import { urlRegex } from "./urls"; -describe("IsUrl Method", () => { +describe("isUrl", () => { it("should return false for invalid url", () => { expect(urlsUtils.isUrl("")).toBe(false); expect(urlsUtils.isUrl("#invalidurl")).toBe(false); @@ -19,7 +19,33 @@ describe("IsUrl Method", () => { }); }); -describe("isInternalUrl Method", () => { +describe("isBase64Url", () => { + it("should return false for invalid url", () => { + expect(urlsUtils.isBase64Url("")).toBe(false); + expect(urlsUtils.isBase64Url("#invalidurl")).toBe(false); + expect(urlsUtils.isBase64Url("http://example.com")).toBe(false); + expect(urlsUtils.isBase64Url("https://www.example.com")).toBe(false); + expect(urlsUtils.isBase64Url("seafile://openfile")).toBe(false); + expect(urlsUtils.isBase64Url("figma://launch")).toBe(false); + expect(urlsUtils.isBase64Url("outline:https://getoutline.com")).toBe(false); + expect(urlsUtils.isBase64Url("://")).toBe(false); + }); + + it("should return true for valid urls", () => { + expect( + urlsUtils.isBase64Url( + "data:image/png;base64,R0lGODlhPQBEAPeoAJosM//AwO/AwHVYZ/z595kzAP/s7P+goOXMv8+fhw/v739/f+8PD98fH/8mJl+fn/9ZWb8/PzWlwv///6wWGbImAPgTEMImIN9gUFCEm/gDALULDN8PAD6atYdCTX9gUNKlj8wZAKUsAOzZz+UMAOsJAP/Z2ccMDA8PD/95eX5NWvsJCOVNQPtfX/8zM8+QePLl38MGBr8JCP+zs9myn/8GBqwpAP/GxgwJCPny78lzYLgjAJ8vAP9fX/+MjMUcAN8zM/9wcM8ZGcATEL+QePdZWf/29uc/P9cmJu9MTDImIN+/r7+/vz8/P8VNQGNugV8AAF9fX8swMNgTAFlDOICAgPN" + ) + ).toBeTruthy(); + expect( + urlsUtils.isBase64Url( + "data:image/gif;base64,npkM+fOqD6DDj1aZpITp0dtGCDhr+fVuCu3zlg49ijaokTZTo27uG7Gjn2P+hI8+PDPERoUB318bWbfAJ5sUNFcuGRTYUqV/3ogfXp1rWlMc6awJjiAAd2fm4ogXjz56aypOoIde4OE5u/F9x199dlXnnGiHZWEYbGpsAEA3QXYnHwEFliKAgswgJ8LPeiUXGwedCAKABACCN+EA1pYIIYaFlcDhytd51sGAJbo3onOpajiihlO92KHGaUXGwWjUBChjSPiWJuOO/LYIm4v1tXfE6J4gCSJEZ7YgRYUNrkji9P55sF/ogxw5ZkSqIDaZBV6aSGYq/lGZplndkckZ98xoICbTcIJGQAZc" + ) + ).toBeTruthy(); + }); +}); + +describe("isInternalUrl", () => { it("should return false if empty string", () => { expect(urlsUtils.isInternalUrl("")).toBe(false); }); @@ -29,7 +55,7 @@ describe("isInternalUrl Method", () => { }); }); -describe("isExternalUrl Method", () => { +describe("isExternalUrl", () => { it("should return false if empty url", () => { expect(urlsUtils.isExternalUrl("")).toBe(false); }); @@ -39,7 +65,7 @@ describe("isExternalUrl Method", () => { }); }); -describe("sanitizeUrl Method", () => { +describe("sanitizeUrl", () => { it("should return undefined if not url", () => { expect(urlsUtils.sanitizeUrl(undefined)).toBeUndefined(); expect(urlsUtils.sanitizeUrl(null)).toBeUndefined(); diff --git a/shared/utils/urls.ts b/shared/utils/urls.ts index b14d85f64..fa99f17d4 100644 --- a/shared/utils/urls.ts +++ b/shared/utils/urls.ts @@ -86,6 +86,17 @@ export function isExternalUrl(url: string) { return !!url && !isInternalUrl(url) && !url.startsWith(creatingUrlPrefix); } +/** + * Returns match if the given string is a base64 encoded url. + * + * @param url The url to check. + * @returns A RegExp match if the url is base64, false otherwise. + */ +export function isBase64Url(url: string) { + const match = url.match(/^(data:[a-z]+\/[^;]+;base64,(.*))/i); + return match ? match : false; +} + /** * For use in the editor, this function will ensure that a url is * potentially valid, and filter out unsupported and malicious protocols.