added analytics tracking

This commit is contained in:
J-onasJones 2024-08-18 05:44:11 +02:00
parent 162863b80a
commit c1c5b81c04

View file

@ -1,7 +1,7 @@
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
addEventListener("fetch", event => { addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request)); event.respondWith(handleRequest(event));
}); });
const headersCORS = { const headersCORS = {
@ -10,7 +10,36 @@ const headersCORS = {
'Access-Control-Allow-Headers': 'Content-Type, x-Custom-Auth-Key', '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 url = new URL(request.url);
const { pathname } = url; const { pathname } = url;
@ -28,6 +57,10 @@ async function handleRequest(request) {
return handleUpload(request); return handleUpload(request);
} }
if (request.method === 'POST' && pathname === '/upload-url') {
return handleUrlUpload(request);
}
if (request.method === 'GET' && pathname.startsWith('/download/')) { if (request.method === 'GET' && pathname.startsWith('/download/')) {
const filename = pathname.replace('/download/', ''); const filename = pathname.replace('/download/', '');
return handleDownload(filename); return handleDownload(filename);
@ -44,11 +77,59 @@ async function handleRequest(request) {
if (request.method === 'GET' && pathname === '/') { if (request.method === 'GET' && pathname === '/') {
return new Response(htmlForm, { 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() { async function cleanUpExpiredFiles() {
@ -77,17 +158,15 @@ async function cleanUpExpiredFiles() {
} }
async function handleUpload(request) { async function handleUpload(request) {
// Password protection
const password = request.headers.get('X-Custom-Auth-Key'); const password = request.headers.get('X-Custom-Auth-Key');
if (password !== `Bearer ${AUTH_KEY_SECRET}`) { 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 formData = await request.formData();
const file = formData.get('file'); const file = formData.get('file');
if (!file) { if (!file) {
return new Response('Bad Request', { status: 400 }, headersCORS); return new Response('Bad Request', { status: 400, headers: headersCORS });
} }
const hash = nanoid(); const hash = nanoid();
@ -121,18 +200,18 @@ async function handleUpload(request) {
async function handleDownload(hash) { async function handleDownload(hash) {
const indexData = await CDN_BUCKET.get('tempupload/index.json'); const indexData = await CDN_BUCKET.get('tempupload/index.json');
if (!indexData) { 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 index = await indexData.json();
const fileRecord = index.find(file => file.hash === hash); const fileRecord = index.find(file => file.hash === hash);
if (!fileRecord) { 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}`); const file = await CDN_BUCKET.get(`tempupload/content/${hash}`);
if (!file) { 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, { const response = new Response(file.body, {
@ -147,32 +226,23 @@ async function handleDownload(hash) {
} }
async function handleDelete(request) { async function handleDelete(request) {
// get pathname
const url = new URL(request.url); const url = new URL(request.url);
const filehash = url.pathname.replace('/delete/', ''); const filehash = url.pathname.replace('/delete/', '');
console.log('filename', filehash)
// Password protection
const password = request.headers.get('X-Custom-Auth-Key'); const password = request.headers.get('X-Custom-Auth-Key');
if (password !== `Bearer ${AUTH_KEY_SECRET}`) { 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'); const indexData = await CDN_BUCKET.get('tempupload/index.json');
if (await !indexData) { if (await !indexData) {
console.log('indexData', indexData) return new Response('Not Found', { status: 404, headers: headersCORS });
return new Response('Not Found', { status: 404 }, headersCORS);
} }
let index = await indexData.json(); let index = await indexData.json();
const fileRecord = index.find(file => file.hash === filehash); const fileRecord = index.find(file => file.hash === filehash);
if (!fileRecord) { if (!fileRecord) {
console.log('indexData', indexData) return new Response('Not Found', { status: 404, headers: headersCORS });
console.log('fileRecord', fileRecord)
return new Response('Not Found', { status: 404 }, headersCORS);
} }
await CDN_BUCKET.delete(`tempupload/content/${fileRecord.hash}`); await CDN_BUCKET.delete(`tempupload/content/${fileRecord.hash}`);
@ -182,10 +252,9 @@ async function handleDelete(request) {
httpMetadata: { contentType: 'application/json' }, httpMetadata: { contentType: 'application/json' },
}); });
return new Response('File deleted', { status: 200 }, headersCORS); return new Response('File deleted', { status: 200, headers: headersCORS });
} }
const htmlForm = ` const htmlForm = `
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
@ -224,6 +293,14 @@ const htmlForm = `
</form> </form>
<div id="uploadResponse"></div> <div id="uploadResponse"></div>
<h1>Upload from URL</h1>
<form id="urlUploadForm">
<input type="url" id="fileUrl" placeholder="Enter file URL" required>
<input type="password" id="urlAuthKey" placeholder="Enter password" required>
<button type="submit">Upload</button>
</form>
<div id="urlUploadResponse"></div>
<h1>Delete a File</h1> <h1>Delete a File</h1>
<form id="deleteForm"> <form id="deleteForm">
<select id="fileSelect" required> <select id="fileSelect" required>
@ -276,6 +353,33 @@ const htmlForm = `
} }
}); });
document.getElementById('urlUploadForm').addEventListener('submit', async (e) => {
e.preventDefault();
const fileUrl = document.getElementById('fileUrl').value;
const authKey = document.getElementById('urlAuthKey').value;
const responseElement = document.getElementById('urlUploadResponse');
responseElement.textContent = 'Downloading and uploading...';
try {
const response = await fetch('https://fileshare.jonasjones.dev/upload-url', {
method: 'POST',
headers: {
'X-Custom-Auth-Key': \`Bearer \${authKey}\`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ url: fileUrl, authKey: \`Bearer \${authKey}\` })
});
const result = await response.json();
responseElement.textContent = \`Download Link: \${result.downloadLink}\`;
fetchFileList();
fetchFileTable();
} catch (error) {
responseElement.textContent = \`Error: \${error.message}\`;
}
});
document.getElementById('deleteForm').addEventListener('submit', async (e) => { document.getElementById('deleteForm').addEventListener('submit', async (e) => {
e.preventDefault(); e.preventDefault();
@ -333,7 +437,7 @@ const htmlForm = `
row.innerHTML = \` row.innerHTML = \`
<td>\${file.originalName}</td> <td>\${file.originalName}</td>
<td>\${deletionDate}</td> <td>\${deletionDate}</td>
<td><a href="https://fileshare.jonasjones.dev/download/\${file.hash}" >\${file.hash}</a></td> <td><a href="https://fileshare.jonasjones.dev/download/\${file.hash}">\${file.hash}</a></td>
\`; \`;
fileTableBody.appendChild(row); fileTableBody.appendChild(row);
}); });