From c1c5b81c04758fa8ce06ad6b00d5c0ab06343e37 Mon Sep 17 00:00:00 2001 From: J-onasJones Date: Sun, 18 Aug 2024 05:44:11 +0200 Subject: [PATCH 1/3] added analytics tracking --- src/index.js | 156 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 130 insertions(+), 26 deletions(-) diff --git a/src/index.js b/src/index.js index 8247808..5b721ee 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,7 @@ import { nanoid } from "nanoid"; addEventListener("fetch", event => { - event.respondWith(handleRequest(event.request)); + event.respondWith(handleRequest(event)); }); const headersCORS = { @@ -10,7 +10,36 @@ const headersCORS = { 'Access-Control-Allow-Headers': 'Content-Type, x-Custom-Auth-Key', }; -async function handleRequest(request) { +async function recordRequest(request) { + + const analyticsData = { + timestamp: Date.now(), + domain: new URL(request.url).hostname, + method: request.method, + path: new URL(request.url).pathname, + ipcountry: request.cf.country, + } + const ANALYTICS_URL = 'https://analytics.jonasjones.dev/requests/record'; + + const response = await fetch(ANALYTICS_URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': ANALYTICS_API_KEY, + }, + body: JSON.stringify(analyticsData) + }); + + if (response.ok) { + console.log('Request recorded successfully'); + } else { + console.error('Failed to record request:', response.status, await response.text()); + } +} + +async function handleRequest(event) { + const request = event.request; + event.waitUntil(recordRequest(request)); const url = new URL(request.url); const { pathname } = url; @@ -28,6 +57,10 @@ async function handleRequest(request) { return handleUpload(request); } + if (request.method === 'POST' && pathname === '/upload-url') { + return handleUrlUpload(request); + } + if (request.method === 'GET' && pathname.startsWith('/download/')) { const filename = pathname.replace('/download/', ''); return handleDownload(filename); @@ -44,11 +77,59 @@ async function handleRequest(request) { if (request.method === 'GET' && pathname === '/') { return new Response(htmlForm, { - headers: { 'content-type': 'text/html;charset=UTF-8' , ...headersCORS}, + headers: { 'content-type': 'text/html;charset=UTF-8', ...headersCORS }, }); } - return new Response('Not Found', { status: 404 }, headersCORS); + return new Response('Not Found', { status: 404, headers: headersCORS }); +} + +async function handleUrlUpload(request) { + const { url, authKey } = await request.json(); + if (!url || !authKey) { + return new Response('Bad Request', { status: 400, headers: headersCORS }); + } + + if (authKey !== `Bearer ${AUTH_KEY_SECRET}`) { + return new Response('Unauthorized', { status: 401, headers: headersCORS }); + } + + try { + const fileResponse = await fetch(url); + if (!fileResponse.ok) { + throw new Error('Failed to fetch the file'); + } + + const fileBlob = await fileResponse.blob(); + const hash = nanoid(); + const contentType = fileResponse.headers.get('Content-Type') || 'application/octet-stream'; + const originalName = url.split('/').pop(); + const deletionTimestamp = Date.now() + 24 * 60 * 60 * 1000; // 24 hours + + await CDN_BUCKET.put(`tempupload/content/${hash}`, fileBlob.stream(), { + httpMetadata: { contentType }, + }); + + const indexData = await CDN_BUCKET.get('tempupload/index.json'); + const index = indexData ? await indexData.json() : []; + + index.push({ + hash, + contentType, + originalName, + deletionTimestamp, + }); + + await CDN_BUCKET.put('tempupload/index.json', JSON.stringify(index), { + httpMetadata: { contentType: 'application/json' }, + }); + + return new Response(JSON.stringify({ downloadLink: `https://fileshare.jonasjones.dev/download/${hash}` }), { + headers: { 'Content-Type': 'application/json', ...headersCORS }, + }); + } catch (error) { + return new Response(`Error: ${error.message}`, { status: 500, headers: headersCORS }); + } } async function cleanUpExpiredFiles() { @@ -77,17 +158,15 @@ async function cleanUpExpiredFiles() { } async function handleUpload(request) { - - // Password protection const password = request.headers.get('X-Custom-Auth-Key'); if (password !== `Bearer ${AUTH_KEY_SECRET}`) { - return new Response('Unauthorized', { status: 401 }, headersCORS); + return new Response('Unauthorized', { status: 401, headers: headersCORS }); } const formData = await request.formData(); const file = formData.get('file'); if (!file) { - return new Response('Bad Request', { status: 400 }, headersCORS); + return new Response('Bad Request', { status: 400, headers: headersCORS }); } const hash = nanoid(); @@ -121,18 +200,18 @@ async function handleUpload(request) { async function handleDownload(hash) { const indexData = await CDN_BUCKET.get('tempupload/index.json'); if (!indexData) { - return new Response('Not Found', { status: 404 }, headersCORS); + return new Response('Not Found', { status: 404, headers: headersCORS }); } const index = await indexData.json(); const fileRecord = index.find(file => file.hash === hash); if (!fileRecord) { - return new Response('Not Found', { status: 404 }, headersCORS); + return new Response('Not Found', { status: 404, headers: headersCORS }); } const file = await CDN_BUCKET.get(`tempupload/content/${hash}`); if (!file) { - return new Response('Not Found', { status: 404 }, headersCORS); + return new Response('Not Found', { status: 404, headers: headersCORS }); } const response = new Response(file.body, { @@ -147,32 +226,23 @@ async function handleDownload(hash) { } async function handleDelete(request) { - - // get pathname const url = new URL(request.url); - const filehash = url.pathname.replace('/delete/', ''); - console.log('filename', filehash) - - // Password protection const password = request.headers.get('X-Custom-Auth-Key'); if (password !== `Bearer ${AUTH_KEY_SECRET}`) { - return new Response('Unauthorized', { status: 401 }, headersCORS); + return new Response('Unauthorized', { status: 401, headers: headersCORS }); } const indexData = await CDN_BUCKET.get('tempupload/index.json'); if (await !indexData) { - console.log('indexData', indexData) - return new Response('Not Found', { status: 404 }, headersCORS); + return new Response('Not Found', { status: 404, headers: headersCORS }); } let index = await indexData.json(); const fileRecord = index.find(file => file.hash === filehash); if (!fileRecord) { - console.log('indexData', indexData) - console.log('fileRecord', fileRecord) - return new Response('Not Found', { status: 404 }, headersCORS); + return new Response('Not Found', { status: 404, headers: headersCORS }); } await CDN_BUCKET.delete(`tempupload/content/${fileRecord.hash}`); @@ -182,10 +252,9 @@ async function handleDelete(request) { httpMetadata: { contentType: 'application/json' }, }); - return new Response('File deleted', { status: 200 }, headersCORS); + return new Response('File deleted', { status: 200, headers: headersCORS }); } - const htmlForm = ` @@ -224,6 +293,14 @@ const htmlForm = `
+

Upload from URL

+
+ + + +
+
+

Delete a File

+ + + Set to delete 7 days from now
@@ -297,6 +304,9 @@ const htmlForm = `
+ + + Set to delete 7 days from now
@@ -316,7 +326,7 @@ const htmlForm = ` Original Name - Deletion Timestamp + Deletion Date Download Link (Hash) @@ -324,6 +334,20 @@ const htmlForm = `