2021-10-31 14:01:27 -07:00
|
|
|
// OmegaUpload Web Frontend
|
|
|
|
// Copyright (C) 2021 Edward Shen
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
2022-01-18 01:39:56 -08:00
|
|
|
import './main.scss';
|
2022-01-18 02:46:07 -08:00
|
|
|
import ReactDom from 'react-dom';
|
|
|
|
import React from 'react';
|
2022-01-18 01:39:56 -08:00
|
|
|
|
|
|
|
const hljs = require('highlight.js');
|
2022-01-18 01:52:44 -08:00
|
|
|
(window as any).hljs = hljs;
|
2022-01-18 01:39:56 -08:00
|
|
|
require('highlightjs-line-numbers.js');
|
|
|
|
|
2022-01-15 22:47:56 -08:00
|
|
|
function loadFromDb(mimeType: string, name?: string, language?: string) {
|
2022-01-16 01:01:38 -08:00
|
|
|
let resolvedName;
|
|
|
|
if (name) {
|
|
|
|
resolvedName = name;
|
|
|
|
} else {
|
|
|
|
const pathName = window.location.pathname;
|
|
|
|
const leafIndex = pathName.indexOf("/");
|
|
|
|
resolvedName = pathName.slice(leafIndex + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log("[js] Resolved name:", resolvedName);
|
2022-01-15 22:47:56 -08:00
|
|
|
console.log("[js] Got language:", language);
|
|
|
|
console.log("[js] Got mime type:", mimeType);
|
|
|
|
|
2021-10-24 02:25:42 -07:00
|
|
|
const dbReq = window.indexedDB.open("omegaupload", 1);
|
|
|
|
dbReq.onsuccess = (evt) => {
|
|
|
|
const db = (evt.target as IDBRequest).result;
|
|
|
|
const obj_store = db
|
2021-10-24 11:40:19 -07:00
|
|
|
.transaction("decrypted data")
|
|
|
|
.objectStore("decrypted data");
|
2022-01-15 22:47:56 -08:00
|
|
|
const fetchReq = obj_store.get(window.location.pathname);
|
2021-10-24 11:40:19 -07:00
|
|
|
fetchReq.onsuccess = (evt) => {
|
2021-10-24 02:25:42 -07:00
|
|
|
const data = (evt.target as IDBRequest).result;
|
|
|
|
switch (data.type) {
|
|
|
|
case "string":
|
2022-01-16 19:34:28 -08:00
|
|
|
console.info("[js] Rendering string UI.");
|
2022-01-16 01:01:38 -08:00
|
|
|
createStringPasteUi(data, mimeType, resolvedName, language);
|
2021-10-24 02:25:42 -07:00
|
|
|
break;
|
|
|
|
case "blob":
|
2022-01-16 19:34:28 -08:00
|
|
|
console.info("[js] Rendering blob UI.");
|
2022-01-16 01:01:38 -08:00
|
|
|
createBlobPasteUi(data, resolvedName);
|
2021-10-24 02:25:42 -07:00
|
|
|
break;
|
|
|
|
case "image":
|
2022-01-16 19:34:28 -08:00
|
|
|
console.info("[js] Rendering image UI.");
|
|
|
|
createImagePasteUi(data, resolvedName, mimeType);
|
2021-10-24 02:25:42 -07:00
|
|
|
break;
|
2021-10-24 11:40:19 -07:00
|
|
|
case "audio":
|
2022-01-16 19:34:28 -08:00
|
|
|
console.info("[js] Rendering audio UI.");
|
|
|
|
createAudioPasteUi(data, resolvedName, mimeType);
|
2021-10-24 11:40:19 -07:00
|
|
|
break;
|
|
|
|
case "video":
|
2022-01-16 19:34:28 -08:00
|
|
|
console.info("[js] Rendering video UI.");
|
|
|
|
createVideoPasteUi(data, resolvedName, mimeType);
|
2021-10-24 11:40:19 -07:00
|
|
|
break;
|
2021-10-26 18:19:14 -07:00
|
|
|
case "archive":
|
2022-01-16 19:34:28 -08:00
|
|
|
console.info("[js] Rendering archive UI.");
|
2022-01-16 01:01:38 -08:00
|
|
|
createArchivePasteUi(data, resolvedName);
|
2021-10-26 18:19:14 -07:00
|
|
|
break;
|
2021-10-24 02:25:42 -07:00
|
|
|
default:
|
2022-01-16 19:34:28 -08:00
|
|
|
console.info("[js] Rendering unknown UI.");
|
2021-10-25 02:42:20 -07:00
|
|
|
renderMessage("Something went wrong. Try clearing local data.");
|
2021-10-24 02:25:42 -07:00
|
|
|
break;
|
|
|
|
}
|
2021-10-24 11:40:19 -07:00
|
|
|
|
|
|
|
// IDB was only used as a temporary medium;
|
2022-01-15 23:59:39 -08:00
|
|
|
window.onbeforeunload = (_e) => {
|
2021-10-24 11:40:19 -07:00
|
|
|
// See https://link.eddie.sh/NrIIq on why .commit is necessary.
|
|
|
|
const transaction = db.transaction("decrypted data", "readwrite");
|
|
|
|
transaction
|
|
|
|
.objectStore("decrypted data")
|
|
|
|
.delete(window.location.pathname);
|
|
|
|
transaction.commit();
|
|
|
|
transaction.oncomplete = () => {
|
|
|
|
console.log("Item deleted from cache");
|
|
|
|
}
|
|
|
|
};
|
2021-10-24 02:25:42 -07:00
|
|
|
};
|
|
|
|
|
2021-10-24 11:40:19 -07:00
|
|
|
fetchReq.onerror = (evt) => {
|
2021-10-24 02:25:42 -07:00
|
|
|
console.log("err");
|
|
|
|
console.log(evt);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-01-16 01:01:38 -08:00
|
|
|
function createStringPasteUi(data, mimeType: string, name: string, lang?: string) {
|
2022-01-18 02:46:07 -08:00
|
|
|
const html = <main>
|
|
|
|
<pre className='paste'>
|
|
|
|
<p className='unselectable centered'>{data.expiration}</p>
|
|
|
|
<a href={getObjectUrl([data.data], mimeType)} download={name} className='hljs-meta centered'>
|
|
|
|
Download file.
|
|
|
|
</a>
|
|
|
|
<hr />
|
|
|
|
<code>
|
|
|
|
{data.data}
|
|
|
|
</code>
|
|
|
|
</pre>
|
|
|
|
</main>;
|
|
|
|
|
|
|
|
ReactDom.render(html, document.body);
|
2021-10-24 02:25:42 -07:00
|
|
|
|
2022-01-15 23:49:51 -08:00
|
|
|
let languages = undefined;
|
|
|
|
|
2022-01-15 22:47:56 -08:00
|
|
|
if (!hljs.getLanguage(lang)) {
|
2022-01-16 00:03:34 -08:00
|
|
|
if (lang) {
|
|
|
|
console.warn(`[js] User provided language (${lang}) is not known.`);
|
|
|
|
} else {
|
|
|
|
console.info(`[js] Language hint not provided.`);
|
|
|
|
}
|
2022-01-15 23:49:51 -08:00
|
|
|
} else {
|
|
|
|
languages = [lang];
|
|
|
|
}
|
|
|
|
|
|
|
|
// If a language wasn't provided, see if we can use the file extension to give
|
|
|
|
// us a better hint for hljs
|
|
|
|
if (!languages) {
|
|
|
|
if (name) {
|
|
|
|
console.log("[js] Trying to infer from file name...");
|
|
|
|
const periodIndex = name.indexOf(".");
|
|
|
|
if (periodIndex === -1) {
|
|
|
|
console.warn("[js] Did not find file extension.")
|
|
|
|
} else {
|
|
|
|
let extension = name.slice(periodIndex + 1);
|
|
|
|
console.info(`[js] Found extension ${extension}.`);
|
|
|
|
if (!hljs.getLanguage(extension)) {
|
|
|
|
console.warn(`[js] Extension was not recognized by hljs. Giving up.`);
|
|
|
|
} else {
|
|
|
|
console.info("[js] Successfully inferred language from file extension.");
|
|
|
|
languages = [extension];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
console.log("[js] No file name hint provided.");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
console.info(`[js] Selecting user provided language ${languages[0]} for highlighting.`);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we still haven't set languages here, then we're leaving it up to the
|
|
|
|
if (!languages) {
|
|
|
|
console.log("[js] Deferring to hljs inference for syntax highlighting.");
|
2022-01-15 22:47:56 -08:00
|
|
|
} else {
|
2022-01-15 23:49:51 -08:00
|
|
|
hljs.configure({ languages });
|
2022-01-15 22:47:56 -08:00
|
|
|
}
|
|
|
|
|
2021-10-24 02:25:42 -07:00
|
|
|
hljs.highlightAll();
|
2022-01-18 01:39:56 -08:00
|
|
|
|
|
|
|
|
|
|
|
(hljs as any).initLineNumbersOnLoad();
|
2021-10-24 02:25:42 -07:00
|
|
|
}
|
|
|
|
|
2022-01-16 01:01:38 -08:00
|
|
|
function createBlobPasteUi(data, name: string) {
|
2022-01-18 02:46:07 -08:00
|
|
|
const html = <main className='hljs centered fullscreen'>
|
|
|
|
<div className='centered'>
|
|
|
|
<p>{data.expiration}</p>
|
|
|
|
<a href={getObjectUrl(data.data, name)} download={name} className='hljs-meta'>
|
|
|
|
Download binary file.
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
<p className='display-anyways hljs-comment' onClick={() => {
|
|
|
|
data.data.text().then(text => {
|
|
|
|
data.data = text;
|
|
|
|
createStringPasteUi(data, "application/octet-stream", name);
|
|
|
|
})
|
|
|
|
}}>Display anyways?</p>
|
|
|
|
</main>;
|
|
|
|
|
|
|
|
ReactDom.render(html, document.body);
|
2021-10-24 02:25:42 -07:00
|
|
|
}
|
|
|
|
|
2022-01-16 19:34:28 -08:00
|
|
|
function createImagePasteUi({ expiration, data, file_size }, name: string, mimeType: string) {
|
|
|
|
createMultiMediaPasteUi("img", expiration, data, name, mimeType, (downloadEle, imgEle) => {
|
2021-10-25 17:31:30 -07:00
|
|
|
imgEle.onload = () => {
|
2022-01-15 22:47:56 -08:00
|
|
|
const width = imgEle.naturalWidth || imgEle.width;
|
|
|
|
const height = imgEle.naturalHeight || imgEle.height;
|
2021-10-27 02:27:44 -07:00
|
|
|
downloadEle.textContent = "Download " + file_size + " \u2014 " + width + " by " + height;
|
2021-10-25 17:31:30 -07:00
|
|
|
}
|
|
|
|
});
|
2021-10-24 11:40:19 -07:00
|
|
|
}
|
|
|
|
|
2022-01-16 19:34:28 -08:00
|
|
|
function createAudioPasteUi({ expiration, data }, name: string, mimeType: string) {
|
|
|
|
createMultiMediaPasteUi("audio", expiration, data, name, mimeType, "Download");
|
2021-10-24 11:40:19 -07:00
|
|
|
}
|
|
|
|
|
2022-01-16 19:34:28 -08:00
|
|
|
function createVideoPasteUi({ expiration, data }, name: string, mimeType: string) {
|
|
|
|
createMultiMediaPasteUi("video", expiration, data, name, mimeType, "Download");
|
2021-10-24 11:40:19 -07:00
|
|
|
}
|
|
|
|
|
2022-01-16 01:01:38 -08:00
|
|
|
function createArchivePasteUi({ expiration, data, entries }, name: string) {
|
2021-10-27 01:49:06 -07:00
|
|
|
// Because it's a stable sort, we can first sort by name (to get all folder
|
|
|
|
// items grouped together) and then sort by if there's a / or not.
|
|
|
|
entries.sort((a, b) => {
|
|
|
|
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
|
|
|
});
|
|
|
|
|
2021-10-27 02:23:28 -07:00
|
|
|
// This doesn't get sub directories and their folders, but hey it's close
|
|
|
|
// enough
|
2021-10-27 01:49:06 -07:00
|
|
|
entries.sort((a, b) => {
|
|
|
|
return b.name.includes("/") - a.name.includes("/");
|
|
|
|
});
|
|
|
|
|
2022-01-18 02:46:07 -08:00
|
|
|
const html = <main>
|
|
|
|
<section className='paste'>
|
|
|
|
<p className='centered'>{expiration}</p>
|
|
|
|
<a href={getObjectUrl(data)} download={name} className='hljs-meta centered'>Download</a>
|
|
|
|
<hr />
|
|
|
|
<table className='archive-table'>
|
|
|
|
<thead>
|
|
|
|
<tr className='hljs-title'><th>Name</th><th className='align-right'>File Size</th></tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
{
|
|
|
|
entries.map(({ name, file_size }) => {
|
|
|
|
return <tr><td>{name}</td><td className='align-right hljs-number'>{file_size}</td></tr>;
|
|
|
|
})
|
|
|
|
}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
</section>
|
|
|
|
</main>;
|
|
|
|
|
|
|
|
ReactDom.render(html, document.body);
|
2021-10-26 18:19:14 -07:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-01-16 19:34:28 -08:00
|
|
|
function createMultiMediaPasteUi(tag, expiration, data, name: string, mimeType: string, on_create?: Function | string) {
|
2022-01-18 02:46:07 -08:00
|
|
|
const bodyEle = document.body;
|
2021-10-24 11:40:19 -07:00
|
|
|
bodyEle.textContent = '';
|
|
|
|
|
2022-01-15 22:47:56 -08:00
|
|
|
const mainEle = document.createElement("main");
|
2021-10-24 11:40:19 -07:00
|
|
|
mainEle.classList.add("hljs");
|
|
|
|
mainEle.classList.add("centered");
|
|
|
|
mainEle.classList.add("fullscreen");
|
|
|
|
|
2022-01-16 19:34:28 -08:00
|
|
|
const downloadLink = getObjectUrl(data, mimeType);
|
2021-10-24 11:40:19 -07:00
|
|
|
|
2022-01-15 22:47:56 -08:00
|
|
|
const expirationEle = document.createElement("p");
|
2021-10-24 11:40:19 -07:00
|
|
|
expirationEle.textContent = expiration;
|
|
|
|
mainEle.appendChild(expirationEle);
|
|
|
|
|
2022-01-15 22:47:56 -08:00
|
|
|
const mediaEle = document.createElement(tag);
|
2021-10-25 17:31:30 -07:00
|
|
|
mediaEle.src = downloadLink;
|
|
|
|
mediaEle.controls = true;
|
|
|
|
mainEle.appendChild(mediaEle);
|
2021-10-24 11:40:19 -07:00
|
|
|
|
2022-01-15 22:47:56 -08:00
|
|
|
const downloadEle = document.createElement("a");
|
2021-10-24 11:40:19 -07:00
|
|
|
downloadEle.href = downloadLink;
|
2022-01-15 22:47:56 -08:00
|
|
|
downloadEle.download = name;
|
2021-10-24 11:40:19 -07:00
|
|
|
downloadEle.classList.add("hljs-meta");
|
|
|
|
mainEle.appendChild(downloadEle);
|
|
|
|
|
|
|
|
bodyEle.appendChild(mainEle);
|
2021-10-25 17:31:30 -07:00
|
|
|
|
|
|
|
if (on_create instanceof Function) {
|
|
|
|
on_create(downloadEle, mediaEle);
|
|
|
|
} else {
|
|
|
|
downloadEle.textContent = on_create;
|
|
|
|
}
|
2021-10-24 11:40:19 -07:00
|
|
|
}
|
|
|
|
|
2021-10-25 02:42:20 -07:00
|
|
|
function renderMessage(message) {
|
2022-01-18 02:46:07 -08:00
|
|
|
ReactDom.render(
|
|
|
|
<main className='hljs centered fullscreen'>
|
|
|
|
{message}
|
|
|
|
</main>,
|
|
|
|
document.body,
|
|
|
|
);
|
2021-10-24 02:25:42 -07:00
|
|
|
}
|
|
|
|
|
2022-01-15 22:47:56 -08:00
|
|
|
function getObjectUrl(data, mimeType?: string) {
|
2022-01-16 19:34:28 -08:00
|
|
|
return URL.createObjectURL(new Blob([data], { type: mimeType }));
|
2022-01-15 22:47:56 -08:00
|
|
|
}
|
|
|
|
|
2021-10-26 18:19:14 -07:00
|
|
|
window.addEventListener("hashchange", () => location.reload());
|
2022-01-18 01:39:56 -08:00
|
|
|
|
|
|
|
export { renderMessage, loadFromDb };
|