From a058f42c5ee413dc35b74c8e83a4f6ce61b5a80c Mon Sep 17 00:00:00 2001 From: Bartosz <2940958+burtek@users.noreply.github.com> Date: Wed, 18 Jan 2023 11:21:51 +0100 Subject: [PATCH 1/3] Fix api/tunnel to not accept malicious hosts It allowed to provide hosts ending with `sentry.io` but not being in `sentry.io` zone, i.e. `malicioussentry.io` --- api/tunnel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/tunnel.ts b/api/tunnel.ts index 081919a..e82e0ee 100644 --- a/api/tunnel.ts +++ b/api/tunnel.ts @@ -12,7 +12,7 @@ export default async function handler(req: Request) { const { host, pathname } = new URL(header.dsn); const projectId = pathname.substring(1); - if (!host.endsWith(sentryHost)) { + if (host !== sentryHost && !host.endsWith(`.${sentryHost}`)) { throw new Error(`invalid host: ${host}`); } From 3790654af1c66c053c2cac81e1c3f7298aae0d77 Mon Sep 17 00:00:00 2001 From: Bartosz Date: Wed, 18 Jan 2023 13:48:24 +0000 Subject: [PATCH 2/3] Add tests for api/image2data --- .codesandbox/tasks.json | 47 ++++++++++++++ .eslintrc | 3 + .../__snapshots__/image2data.test.ts.snap | 7 +++ api/__tests__/image2data.test.ts | 36 +++++++++++ api/image2data.ts | 2 + api/tunnel.ts | 1 + package.json | 7 ++- yarn.lock | 63 +++++++++++++------ 8 files changed, 145 insertions(+), 21 deletions(-) create mode 100644 .codesandbox/tasks.json create mode 100644 api/__tests__/__snapshots__/image2data.test.ts.snap create mode 100644 api/__tests__/image2data.test.ts diff --git a/.codesandbox/tasks.json b/.codesandbox/tasks.json new file mode 100644 index 0000000..c006f1b --- /dev/null +++ b/.codesandbox/tasks.json @@ -0,0 +1,47 @@ +{ + // These tasks will run in order when initializing your CodeSandbox project. + "setupTasks": [ + { + "name": "Install node 18", + "command": "nvm install 18" + }, + { + "name": "Install Dependencies", + "command": "yarn install" + } + ], + + // These tasks can be run from CodeSandbox. Running one will open a log in the app. + "tasks": { + "d": { + "name": "d", + "command": "yarn d", + "runAtStart": false + }, + "start": { + "name": "start", + "command": "yarn start", + "runAtStart": true + }, + "build": { + "name": "build", + "command": "yarn build", + "runAtStart": false + }, + "preview": { + "name": "preview", + "command": "yarn preview", + "runAtStart": false + }, + "test": { + "name": "test", + "command": "yarn test", + "runAtStart": false + }, + "coverage": { + "name": "coverage", + "command": "yarn coverage", + "runAtStart": false + } + } +} diff --git a/.eslintrc b/.eslintrc index 1c928bb..4abcc1c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -12,6 +12,9 @@ "import/resolver": { "typescript": true, "node": true + }, + "jest": { + "version": 27 } }, "rules": { diff --git a/api/__tests__/__snapshots__/image2data.test.ts.snap b/api/__tests__/__snapshots__/image2data.test.ts.snap new file mode 100644 index 0000000..fbfb1a2 --- /dev/null +++ b/api/__tests__/__snapshots__/image2data.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1 + +exports[`api/image2data > should generate correct string 1`] = ` +{ + "dataUrl": "data:text/html; charset=UTF-8;base64,PCFET0NUWVBFIGh0bWw+CjwhLS1baWYgbHQgSUUgN10+IDxodG1sIGNsYXNzPSJuby1qcyBpZTYgb2xkaWUiIGxhbmc9ImVuLVVTIj4gPCFbZW5kaWZdLS0+CjwhLS1baWYgSUUgN10+ICAgIDxodG1sIGNsYXNzPSJuby1qcyBpZTcgb2xkaWUiIGxhbmc9ImVuLVVTIj4gPCFbZW5kaWZdLS0+CjwhLS1baWYgSUUgOF0+ICAgIDxodG1sIGNsYXNzPSJuby1qcyBpZTggb2xkaWUiIGxhbmc9ImVuLVVTIj4gPCFbZW5kaWZdLS0+CjwhLS1baWYgZ3QgSUUgOF0+PCEtLT4gPGh0bWwgY2xhc3M9Im5vLWpzIiBsYW5nPSJlbi1VUyI+IDwhLS08IVtlbmRpZl0tLT4KPGhlYWQ+Cjx0aXRsZT5BdHRlbnRpb24gUmVxdWlyZWQhIHwgQ2xvdWRmbGFyZTwvdGl0bGU+CjxtZXRhIGNoYXJzZXQ9IlVURi04IiAvPgo8bWV0YSBodHRwLWVxdWl2PSJDb250ZW50LVR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD1VVEYtOCIgLz4KPG1ldGEgaHR0cC1lcXVpdj0iWC1VQS1Db21wYXRpYmxlIiBjb250ZW50PSJJRT1FZGdlIiAvPgo8bWV0YSBuYW1lPSJyb2JvdHMiIGNvbnRlbnQ9Im5vaW5kZXgsIG5vZm9sbG93IiAvPgo8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLGluaXRpYWwtc2NhbGU9MSIgLz4KPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBpZD0iY2Zfc3R5bGVzLWNzcyIgaHJlZj0iL2Nkbi1jZ2kvc3R5bGVzL2NmLmVycm9ycy5jc3MiIC8+CjwhLS1baWYgbHQgSUUgOV0+PGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBpZD0nY2Zfc3R5bGVzLWllLWNzcycgaHJlZj0iL2Nkbi1jZ2kvc3R5bGVzL2NmLmVycm9ycy5pZS5jc3MiIC8+PCFbZW5kaWZdLS0+CjxzdHlsZT5ib2R5e21hcmdpbjowO3BhZGRpbmc6MH08L3N0eWxlPgoKCjwhLS1baWYgZ3RlIElFIDEwXT48IS0tPgo8c2NyaXB0PgogIGlmICghbmF2aWdhdG9yLmNvb2tpZUVuYWJsZWQpIHsKICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgZnVuY3Rpb24gKCkgewogICAgICB2YXIgY29va2llRWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY29va2llLWFsZXJ0Jyk7CiAgICAgIGNvb2tpZUVsLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snOwogICAgfSkKICB9Cjwvc2NyaXB0Pgo8IS0tPCFbZW5kaWZdLS0+CgoKPC9oZWFkPgo8Ym9keT4KICA8ZGl2IGlkPSJjZi13cmFwcGVyIj4KICAgIDxkaXYgY2xhc3M9ImNmLWFsZXJ0IGNmLWFsZXJ0LWVycm9yIGNmLWNvb2tpZS1lcnJvciIgaWQ9ImNvb2tpZS1hbGVydCIgZGF0YS10cmFuc2xhdGU9ImVuYWJsZV9jb29raWVzIj5QbGVhc2UgZW5hYmxlIGNvb2tpZXMuPC9kaXY+CiAgICA8ZGl2IGlkPSJjZi1lcnJvci1kZXRhaWxzIiBjbGFzcz0iY2YtZXJyb3ItZGV0YWlscy13cmFwcGVyIj4KICAgICAgPGRpdiBjbGFzcz0iY2Ytd3JhcHBlciBjZi1oZWFkZXIgY2YtZXJyb3Itb3ZlcnZpZXciPgogICAgICAgIDxoMSBkYXRhLXRyYW5zbGF0ZT0iYmxvY2tfaGVhZGxpbmUiPlNvcnJ5LCB5b3UgaGF2ZSBiZWVuIGJsb2NrZWQ8L2gxPgogICAgICAgIDxoMiBjbGFzcz0iY2Ytc3ViaGVhZGxpbmUiPjxzcGFuIGRhdGEtdHJhbnNsYXRlPSJ1bmFibGVfdG9fYWNjZXNzIj5Zb3UgYXJlIHVuYWJsZSB0byBhY2Nlc3M8L3NwYW4+IHBsYWNlaG9sZGVyLmNvbTwvaDI+CiAgICAgIDwvZGl2PjwhLS0gLy5oZWFkZXIgLS0+CgogICAgICA8ZGl2IGNsYXNzPSJjZi1zZWN0aW9uIGNmLWhpZ2hsaWdodCI+CiAgICAgICAgPGRpdiBjbGFzcz0iY2Ytd3JhcHBlciI+CiAgICAgICAgICA8ZGl2IGNsYXNzPSJjZi1zY3JlZW5zaG90LWNvbnRhaW5lciBjZi1zY3JlZW5zaG90LWZ1bGwiPgogICAgICAgICAgICAKICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0iY2Ytbm8tc2NyZWVuc2hvdCBlcnJvciI+PC9zcGFuPgogICAgICAgICAgICAKICAgICAgICAgIDwvZGl2PgogICAgICAgIDwvZGl2PgogICAgICA8L2Rpdj48IS0tIC8uY2FwdGNoYS1jb250YWluZXIgLS0+CgogICAgICA8ZGl2IGNsYXNzPSJjZi1zZWN0aW9uIGNmLXdyYXBwZXIiPgogICAgICAgIDxkaXYgY2xhc3M9ImNmLWNvbHVtbnMgdHdvIj4KICAgICAgICAgIDxkaXYgY2xhc3M9ImNmLWNvbHVtbiI+CiAgICAgICAgICAgIDxoMiBkYXRhLXRyYW5zbGF0ZT0iYmxvY2tlZF93aHlfaGVhZGxpbmUiPldoeSBoYXZlIEkgYmVlbiBibG9ja2VkPzwvaDI+CgogICAgICAgICAgICA8cCBkYXRhLXRyYW5zbGF0ZT0iYmxvY2tlZF93aHlfZGV0YWlsIj5UaGlzIHdlYnNpdGUgaXMgdXNpbmcgYSBzZWN1cml0eSBzZXJ2aWNlIHRvIHByb3RlY3QgaXRzZWxmIGZyb20gb25saW5lIGF0dGFja3MuIFRoZSBhY3Rpb24geW91IGp1c3QgcGVyZm9ybWVkIHRyaWdnZXJlZCB0aGUgc2VjdXJpdHkgc29sdXRpb24uIFRoZXJlIGFyZSBzZXZlcmFsIGFjdGlvbnMgdGhhdCBjb3VsZCB0cmlnZ2VyIHRoaXMgYmxvY2sgaW5jbHVkaW5nIHN1Ym1pdHRpbmcgYSBjZXJ0YWluIHdvcmQgb3IgcGhyYXNlLCBhIFNRTCBjb21tYW5kIG9yIG1hbGZvcm1lZCBkYXRhLjwvcD4KICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgIDxkaXYgY2xhc3M9ImNmLWNvbHVtbiI+CiAgICAgICAgICAgIDxoMiBkYXRhLXRyYW5zbGF0ZT0iYmxvY2tlZF9yZXNvbHZlX2hlYWRsaW5lIj5XaGF0IGNhbiBJIGRvIHRvIHJlc29sdmUgdGhpcz88L2gyPgoKICAgICAgICAgICAgPHAgZGF0YS10cmFuc2xhdGU9ImJsb2NrZWRfcmVzb2x2ZV9kZXRhaWwiPllvdSBjYW4gZW1haWwgdGhlIHNpdGUgb3duZXIgdG8gbGV0IHRoZW0ga25vdyB5b3Ugd2VyZSBibG9ja2VkLiBQbGVhc2UgaW5jbHVkZSB3aGF0IHlvdSB3ZXJlIGRvaW5nIHdoZW4gdGhpcyBwYWdlIGNhbWUgdXAgYW5kIHRoZSBDbG91ZGZsYXJlIFJheSBJRCBmb3VuZCBhdCB0aGUgYm90dG9tIG9mIHRoaXMgcGFnZS48L3A+CiAgICAgICAgICA8L2Rpdj4KICAgICAgICA8L2Rpdj4KICAgICAgPC9kaXY+PCEtLSAvLnNlY3Rpb24gLS0+CgogICAgICA8ZGl2IGNsYXNzPSJjZi1lcnJvci1mb290ZXIgY2Ytd3JhcHBlciB3LTI0MCBsZzp3LWZ1bGwgcHktMTAgc206cHktNCBzbTpweC04IG14LWF1dG8gdGV4dC1jZW50ZXIgc206dGV4dC1sZWZ0IGJvcmRlci1zb2xpZCBib3JkZXItMCBib3JkZXItdCBib3JkZXItZ3JheS0zMDAiPgogIDxwIGNsYXNzPSJ0ZXh0LTEzIj4KICAgIDxzcGFuIGNsYXNzPSJjZi1mb290ZXItaXRlbSBzbTpibG9jayBzbTptYi0xIj5DbG91ZGZsYXJlIFJheSBJRDogPHN0cm9uZyBjbGFzcz0iZm9udC1zZW1pYm9sZCI+NzhiN2M1MjMzOGNhNzgxYzwvc3Ryb25nPjwvc3Bhbj4KICAgIDxzcGFuIGNsYXNzPSJjZi1mb290ZXItc2VwYXJhdG9yIHNtOmhpZGRlbiI+JmJ1bGw7PC9zcGFuPgogICAgPHNwYW4gaWQ9ImNmLWZvb3Rlci1pdGVtLWlwIiBjbGFzcz0iY2YtZm9vdGVyLWl0ZW0gaGlkZGVuIHNtOmJsb2NrIHNtOm1iLTEiPgogICAgICBZb3VyIElQOgogICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgaWQ9ImNmLWZvb3Rlci1pcC1yZXZlYWwiIGNsYXNzPSJjZi1mb290ZXItaXAtcmV2ZWFsLWJ0biI+Q2xpY2sgdG8gcmV2ZWFsPC9idXR0b24+CiAgICAgIDxzcGFuIGNsYXNzPSJoaWRkZW4iIGlkPSJjZi1mb290ZXItaXAiPjE2Ny4yMzUuOC4yNTE8L3NwYW4+CiAgICAgIDxzcGFuIGNsYXNzPSJjZi1mb290ZXItc2VwYXJhdG9yIHNtOmhpZGRlbiI+JmJ1bGw7PC9zcGFuPgogICAgPC9zcGFuPgogICAgPHNwYW4gY2xhc3M9ImNmLWZvb3Rlci1pdGVtIHNtOmJsb2NrIHNtOm1iLTEiPjxzcGFuPlBlcmZvcm1hbmNlICZhbXA7IHNlY3VyaXR5IGJ5PC9zcGFuPiA8YSByZWw9Im5vb3BlbmVyIG5vcmVmZXJyZXIiIGhyZWY9Imh0dHBzOi8vd3d3LmNsb3VkZmxhcmUuY29tLzV4eC1lcnJvci1sYW5kaW5nIiBpZD0iYnJhbmRfbGluayIgdGFyZ2V0PSJfYmxhbmsiPkNsb3VkZmxhcmU8L2E+PC9zcGFuPgogICAgCiAgPC9wPgogIDxzY3JpcHQ+KGZ1bmN0aW9uKCl7ZnVuY3Rpb24gZCgpe3ZhciBiPWEuZ2V0RWxlbWVudEJ5SWQoImNmLWZvb3Rlci1pdGVtLWlwIiksYz1hLmdldEVsZW1lbnRCeUlkKCJjZi1mb290ZXItaXAtcmV2ZWFsIik7YiYmImNsYXNzTGlzdCJpbiBiJiYoYi5jbGFzc0xpc3QucmVtb3ZlKCJoaWRkZW4iKSxjLmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIixmdW5jdGlvbigpe2MuY2xhc3NMaXN0LmFkZCgiaGlkZGVuIik7YS5nZXRFbGVtZW50QnlJZCgiY2YtZm9vdGVyLWlwIikuY2xhc3NMaXN0LnJlbW92ZSgiaGlkZGVuIil9KSl9dmFyIGE9ZG9jdW1lbnQ7ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciYmYS5hZGRFdmVudExpc3RlbmVyKCJET01Db250ZW50TG9hZGVkIixkKX0pKCk7PC9zY3JpcHQ+CjwvZGl2PjwhLS0gLy5lcnJvci1mb290ZXIgLS0+CgoKICAgIDwvZGl2PjwhLS0gLyNjZi1lcnJvci1kZXRhaWxzIC0tPgogIDwvZGl2PjwhLS0gLyNjZi13cmFwcGVyIC0tPgoKICA8c2NyaXB0PgogIHdpbmRvdy5fY2ZfdHJhbnNsYXRpb24gPSB7fTsKICAKICAKPC9zY3JpcHQ+Cgo8L2JvZHk+CjwvaHRtbD4K", +} +`; diff --git a/api/__tests__/image2data.test.ts b/api/__tests__/image2data.test.ts new file mode 100644 index 0000000..8ab4038 --- /dev/null +++ b/api/__tests__/image2data.test.ts @@ -0,0 +1,36 @@ +import { kill as killChild } from "node:process"; +import { join } from "node:path"; + +// @ts-ignore +import { startDevServer } from "@vercel/node"; + +const IMAGE_URL = "https://local.dev"; + +describe("api/image2data", () => { + let pid: number; + let port: number; + + beforeAll(async () => { + const devServer: { pid: number; port: number } = await startDevServer({ + entrypoint: "image2data.ts", + workPath: join(__dirname, ".."), + config: {}, + }); + + console.log(__dirname, devServer); + + ({ pid, port } = devServer); + }); + + afterAll(() => { + killChild(pid); + }); + + it("should generate correct string", async () => { + const data = await fetch( + `http://localhost:${port}/api/image2data?url=https://via.placeholder.com/150` + ); + + await expect(data.json()).resolves.toMatchSnapshot(); + }); +}); diff --git a/api/image2data.ts b/api/image2data.ts index 36a5f29..f88bafc 100644 --- a/api/image2data.ts +++ b/api/image2data.ts @@ -23,6 +23,8 @@ export type ImageResponseData = { dataUrl: string } | { error: string }; export async function downloadAndEncode(url: URL) { const imageResp = await fetch(url); const image = Buffer.from(await imageResp.arrayBuffer()).toString('base64'); + + // TODO: get file type - https://via.placeholder.com/150 has no content-type header return `data:${imageResp.headers.get('content-type')};base64,${image}`; } diff --git a/api/tunnel.ts b/api/tunnel.ts index e82e0ee..a54a92d 100644 --- a/api/tunnel.ts +++ b/api/tunnel.ts @@ -12,6 +12,7 @@ export default async function handler(req: Request) { const { host, pathname } = new URL(header.dsn); const projectId = pathname.substring(1); + // todo: tool if (host !== sentryHost && !host.endsWith(`.${sentryHost}`)) { throw new Error(`invalid host: ${host}`); } diff --git a/package.json b/package.json index a86546d..4b538dd 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@reduxjs/toolkit": "^1.9.1", "@sentry/react": "^7.30.0", "@sentry/tracing": "^7.30.0", - "@vercel/node": "^2.8.6", + "@vercel/node": "^2.8.13", "cheerio": "1.0.0-rc.12", "i18next": "^22.4.9", "i18next-browser-languagedetector": "^7.0.1", @@ -41,6 +41,8 @@ "eslint": "^8.31.0", "jest-extended": "^3.2.3", "jsdom": "^21.0.0", + "nock": "^13.3.0", + "path-to-regexp": "^6.2.1", "typescript": "^4.9.4", "vite": "^4.0.4", "vite-plugin-pwa": "^0.14.1", @@ -53,6 +55,7 @@ "build": "tsc && vite build", "preview": "vite preview", "test": "vitest", - "coverage": "vitest run --coverage" + "coverage": "vitest run --coverage", + "lint": "eslint \"src/**\" \"api/**\"" } } diff --git a/yarn.lock b/yarn.lock index dbeea72..4bc6583 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2046,26 +2046,26 @@ "@typescript-eslint/types" "5.47.0" eslint-visitor-keys "^3.3.0" -"@vercel/build-utils@5.7.5": - version "5.7.5" - resolved "https://registry.yarnpkg.com/@vercel/build-utils/-/build-utils-5.7.5.tgz#8ce3476d3b288b7377d6389b39ac7c1d463a8a93" - integrity sha512-tpQgaklH+6FslzUIyRYpTI637URSw9AI4Lwu23JXzdtVqYiApYAP/ub5zzQK2WT2KrNdrioAgHvMFkSDUjY0UA== +"@vercel/build-utils@5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@vercel/build-utils/-/build-utils-5.9.0.tgz#54b91e5b369c852d4a0d1bcba98d4c352d290643" + integrity sha512-LJRhd/ritLGHH+YvZ+DC7AW3Jr87UZHFHz2h2ENULDZ8qAo5LJH+y+Cg11uxfXkhQKK2f/AZQJXyKVyu1BBwdQ== -"@vercel/node-bridge@3.1.3": - version "3.1.3" - resolved "https://registry.yarnpkg.com/@vercel/node-bridge/-/node-bridge-3.1.3.tgz#7c8d83e18a4cb327def776810df182ecb148fbc0" - integrity sha512-NIuiwktIsvCWZ7aToQ4sFWNYKQbojghJ2OobjTL14nj25cuxP3XsV8LkMarIsiWG/vQxiSADBLwr/7fOh8znGg== +"@vercel/node-bridge@3.1.9": + version "3.1.9" + resolved "https://registry.yarnpkg.com/@vercel/node-bridge/-/node-bridge-3.1.9.tgz#5c49f107593a7d334e287351ea3a37a806770b0b" + integrity sha512-07Bgb6jm8OMTlxGRC4kOY0ewi4xLtMcK3z45T+GKRO7oKeA4vhRGFbT5BsJKF3V5/nj6TYAsWsErBf4RGVSBcw== -"@vercel/node@^2.8.6": - version "2.8.6" - resolved "https://registry.yarnpkg.com/@vercel/node/-/node-2.8.6.tgz#9bd2ed77699d44636c68def9b9fa4191a843951e" - integrity sha512-jcobbF9yIT+WmrY9u7BDtjlsHR4W/EqiK7sskayruwo34D2+4h8oTISHtbVKoN+RU6MTMnL4oYZIoIoVADfuvA== +"@vercel/node@^2.8.13": + version "2.8.13" + resolved "https://registry.yarnpkg.com/@vercel/node/-/node-2.8.13.tgz#3aabe8805759b6f114ad4dd77c444e55c054ec4f" + integrity sha512-RI0Ig2v7MK4N3EVPHKNEj3IK+D0/GtIbMFZB0WcUgE77UvdD++tf5JWTlqrwxPOYOxO/J0/0L8WZXTAzpPgdGA== dependencies: "@edge-runtime/vm" "2.0.0" "@types/node" "14.18.33" - "@vercel/build-utils" "5.7.5" - "@vercel/node-bridge" "3.1.3" - "@vercel/static-config" "2.0.6" + "@vercel/build-utils" "5.9.0" + "@vercel/node-bridge" "3.1.9" + "@vercel/static-config" "2.0.11" edge-runtime "2.0.0" esbuild "0.14.47" exit-hook "2.2.1" @@ -2073,10 +2073,10 @@ ts-node "10.9.1" typescript "4.3.4" -"@vercel/static-config@2.0.6": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@vercel/static-config/-/static-config-2.0.6.tgz#9e963eaf9eeebb28d729c963039bb9caf617ae4b" - integrity sha512-P0kh9ZBA9RrP4u0pDENxsuU/PAOw/ph+CoGgS5ZfDNa7P0qYhi9TfgVAtjFnGxi0dImq/S49uTVW5NPYWwc+ww== +"@vercel/static-config@2.0.11": + version "2.0.11" + resolved "https://registry.yarnpkg.com/@vercel/static-config/-/static-config-2.0.11.tgz#5d210e62479f1a847028f5b50ac18bccf8732585" + integrity sha512-dw6CAJ7U2AcQpjZV9YfOyz2wTseSFdkT3qivBg2GjHtVyd5wdY7vkQ9seLKEckYhFx3CjQ29IhzhDND9F5oINw== dependencies: ajv "8.6.3" json-schema-to-ts "1.6.4" @@ -4351,6 +4351,11 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + json5@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" @@ -4653,6 +4658,16 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +nock@^13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/nock/-/nock-13.3.0.tgz#b13069c1a03f1ad63120f994b04bfd2556925768" + integrity sha512-HHqYQ6mBeiMc+N038w8LkMpDCRquCHWeNmN3v6645P3NhN2+qXOBqvPqo7Rt1VyCMzKhJ733wZqw5B7cQVFNPg== + dependencies: + debug "^4.1.0" + json-stringify-safe "^5.0.1" + lodash "^4.17.21" + propagate "^2.0.0" + node-fetch@2.6.7, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -4866,6 +4881,11 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-to-regexp@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" + integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw== + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -4973,6 +4993,11 @@ prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" +propagate@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" + integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" From b3a423026d87a94a891f3f06c45f6aac67ede4e8 Mon Sep 17 00:00:00 2001 From: Bartosz Date: Wed, 18 Jan 2023 16:20:27 +0000 Subject: [PATCH 3/3] Update 4 files --- api/__tests__/image2data.test.ts | 2 - api/image2data.ts | 9 +++- package.json | 1 + yarn.lock | 72 +++++++++++++++++++++++++++++++- 4 files changed, 78 insertions(+), 6 deletions(-) diff --git a/api/__tests__/image2data.test.ts b/api/__tests__/image2data.test.ts index 8ab4038..7f15295 100644 --- a/api/__tests__/image2data.test.ts +++ b/api/__tests__/image2data.test.ts @@ -4,8 +4,6 @@ import { join } from "node:path"; // @ts-ignore import { startDevServer } from "@vercel/node"; -const IMAGE_URL = "https://local.dev"; - describe("api/image2data", () => { let pid: number; let port: number; diff --git a/api/image2data.ts b/api/image2data.ts index f88bafc..c5beffa 100644 --- a/api/image2data.ts +++ b/api/image2data.ts @@ -1,6 +1,7 @@ import type { ServerResponse } from 'node:http'; import type { VercelRequest } from '@vercel/node'; +import { fileTypeFromBuffer } from 'file-type' interface RequestData { url?: string; @@ -21,8 +22,12 @@ export const enum Image2DataError { export type ImageResponseData = { dataUrl: string } | { error: string }; export async function downloadAndEncode(url: URL) { - const imageResp = await fetch(url); - const image = Buffer.from(await imageResp.arrayBuffer()).toString('base64'); + const imageResp = await fetch(url, { headers: { 'accept': 'image/*' } }); + const imageBuffer = Buffer.from(await imageResp.arrayBuffer()); + const imageType = await fileTypeFromBuffer(imageBuffer) + const image = imageBuffer.toString('base64'); + + console.log(imageType, imageResp.type, imageResp.headers.get('content-type')); // TODO: get file type - https://via.placeholder.com/150 has no content-type header return `data:${imageResp.headers.get('content-type')};base64,${image}`; diff --git a/package.json b/package.json index 4b538dd..0a69adb 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@sentry/tracing": "^7.30.0", "@vercel/node": "^2.8.13", "cheerio": "1.0.0-rc.12", + "file-type": "^18.2.0", "i18next": "^22.4.9", "i18next-browser-languagedetector": "^7.0.1", "i18next-http-backend": "^2.1.1", diff --git a/yarn.lock b/yarn.lock index 4bc6583..7278e19 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1755,6 +1755,11 @@ resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.4.3.tgz#af975e367743fa91989cd666666aec31a8f50591" integrity sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q== +"@tokenizer/token@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276" + integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A== + "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -3518,6 +3523,15 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-type@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-18.2.0.tgz#c2abec00d1af0f09151e1549e3588aab0bac5001" + integrity sha512-M3RQMWY3F2ykyWZ+IHwNCjpnUmukYhtdkGGC1ZVEUb0ve5REGF7NNJ4Q9ehCUabtQKtSVFOMbFTXgJlFb0DQIg== + dependencies: + readable-web-to-node-stream "^3.0.2" + strtok3 "^7.0.0" + token-types "^5.0.1" + filelist@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" @@ -3883,6 +3897,11 @@ idb@^7.0.1: resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^5.1.1, ignore@^5.2.0: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" @@ -3919,7 +3938,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4906,6 +4925,11 @@ pathval@^1.1.1: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== +peek-readable@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-5.0.0.tgz#7ead2aff25dc40458c60347ea76cfdfd63efdfec" + integrity sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A== + picocolors@1.0.0, picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -5095,6 +5119,22 @@ react@^18.2.0: dependencies: loose-envify "^1.1.0" +readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-web-to-node-stream@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz#5d52bb5df7b54861fd48d015e93a2cb87b3ee0bb" + integrity sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw== + dependencies: + readable-stream "^3.6.0" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -5270,7 +5310,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@^5.1.0: +safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -5437,6 +5477,13 @@ string.prototype.trimstart@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + stringify-object@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" @@ -5482,6 +5529,14 @@ strip-literal@^1.0.0: dependencies: acorn "^8.8.1" +strtok3@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-7.0.0.tgz#868c428b4ade64a8fd8fee7364256001c1a4cbe5" + integrity sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ== + dependencies: + "@tokenizer/token" "^0.3.0" + peek-readable "^5.0.0" + stylis@4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" @@ -5605,6 +5660,14 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +token-types@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/token-types/-/token-types-5.0.1.tgz#aa9d9e6b23c420a675e55413b180635b86a093b4" + integrity sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg== + dependencies: + "@tokenizer/token" "^0.3.0" + ieee754 "^1.2.1" + tough-cookie@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" @@ -5835,6 +5898,11 @@ use-sync-external-store@^1.0.0: resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"