prep version 1.2.0

This commit is contained in:
Kieran 2019-05-11 00:44:40 +08:00
parent 196bec4412
commit 7846a85415
17 changed files with 429 additions and 368 deletions

4
.gitignore vendored
View File

@ -7,4 +7,6 @@ obj/
dist/
.vscode/
Debug/
Release/
Release/
node_modules/
package-lock.json

View File

@ -1,12 +0,0 @@
@echo off
call sass src/css/style.scss dist/style.css
call google-closure-compiler ^
src/js/Const.js ^
src/js/Util.js ^
src/js/App.js ^
src/js/DropzoneManager.js ^
src/js/FileDownloader.js ^
src/js/FileUpload.js ^
src/js/VBF.js ^
src/js/ViewManager.js ^
--js_output_file dist/script.min.js --language_out ECMASCRIPT_NEXT

View File

@ -6,33 +6,6 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="dist/style.css" />
<script async type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function () {
var u = "//matomo.trash.lol/";
_paq.push(['setTrackerUrl', u + 'piwik.php']);
_paq.push(['setSiteId', '3']);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.type = 'text/javascript'; g.async = true; g.defer = true; g.src = u + 'piwik.js'; s.parentNode.insertBefore(g, s);
})();
</script>
<!-- Fathom - simple website analytics - https://github.com/usefathom/fathom -->
<script>
(function(f, a, t, h, o, m){
a[h]=a[h]||function(){
(a[h].q=a[h].q||[]).push(arguments)
};
o=f.createElement('script'),
m=f.getElementsByTagName('script')[0];
o.async=1; o.src=t; o.id='fathom-script';
m.parentNode.insertBefore(o,m)
})(document, window, '//fathom.void.cat/tracker.js', 'fathom');
fathom('set', 'siteId', 'ACJOO');
fathom('trackPageview');
</script>
<!-- / Fathom -->
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<script>
(adsbygoogle = window.adsbygoogle || []).push({
@ -187,7 +160,7 @@
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>
<script type="text/javascript" src="dist/script.min.js" async></script>
<script type="text/javascript" src="./dist/bundle.js"></script>
</body>
</html>

31
package.json Normal file
View File

@ -0,0 +1,31 @@
{
"name": "void.cat",
"version": "1.2.0-beta1",
"description": "Free file hosting website",
"repository": {
"type": "git",
"url": "git+https://github.com/v0l/void.cat.git"
},
"scripts": {
"build": "sass src/css/style.scss dist/style.css && webpack-cli --entry ./src/js/index.js --mode production --output ./dist/bundle.js"
},
"keywords": [
"upload",
"host",
"files",
"pomf"
],
"author": "v0l",
"license": "MIT",
"bugs": {
"url": "https://github.com/v0l/void.cat/issues"
},
"homepage": "https://github.com/v0l/void.cat#readme",
"dependencies": {
"asmcrypto.js": "^2.3.2"
},
"devDependencies": {
"saas": "^1.0.0",
"webpack-cli": "^3.3.2"
}
}

View File

@ -1,222 +0,0 @@
/**
* @constant {Object}
*/
const App = {
Loaded: false,
CharJsLoaded: false,
Elements: {
get Dropzone() { return $('#dropzone') },
get Uploads() { return $('#uploads') },
get PageView() { return $('#page-view') },
get PageUpload() { return $('#page-upload') },
get PageFaq() { return $('#page-faq') },
get PageStats() { return $('#page-stats') },
get PageDonate() { return $('#page-donate') }
},
Templates: {
get Upload() { return $("template[id='tmpl-upload']") }
},
get IsEdge() {
return /Edge/.test(navigator.userAgent);
},
get IsChrome() {
return !App.IsEdge && /^Mozilla.*Chrome/.test(navigator.userAgent);
},
get IsFirefox() {
return !App.IsEdge && /^Mozilla.*Firefox/.test(navigator.userAgent);
},
/**
* Uploads the files as selected by the input form
* @param {Element} ctx
* @returns {Promise}
*/
UploadFiles: async function (ctx) {
let files = ctx.files;
let proc_files = [];
for (let x = 0; x < files.length; x++) {
let fu = new FileUpload(files[x]);
proc_files[proc_files.length] = fu.ProcessUpload();
}
await Promise.all(proc_files);
},
ResetView: function () {
App.Elements.PageView.style.display = "none";
App.Elements.PageUpload.style.display = "none";
App.Elements.PageFaq.style.display = "none";
App.Elements.PageStats.style.display = "none";
App.Elements.PageDonate.style.display = "none";
},
ShowStats: async function () {
location.hash = "#stats";
App.ResetView();
if (!App.CharJsLoaded) {
await App.InsertScript("//cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js", () => {
return typeof moment !== "undefined";
});
await App.InsertScript("//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js", () => {
return typeof Chart !== "undefined";
});
}
let api_rsp = await Api.GetTxChart();
if (api_rsp.ok) {
let ctx = $('#weektxgraph').getContext('2d');
new Chart(ctx, {
type: 'line',
data: api_rsp.data,
options: {
scales: {
xAxes: [{
type: 'time',
time: {
source: 'data'
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
callback: function(label, index, labels) {
return Utils.FormatBytes(label);
}
}
}]
}
}
});
}
App.Elements.PageStats.style.display = "block";
},
ShowFAQ: function () {
location.hash = "#faq";
App.ResetView();
App.Elements.PageFaq.style.display = "block";
},
ShowDonate: function () {
location.hash = "#donate";
App.ResetView();
App.Elements.PageDonate.style.display = "block";
},
/**
* Sets up the page
*/
Init: async function () {
App.CheckBrowserSupport();
App.MakePolyfills();
App.ResetView();
if (location.hash !== "") {
if (location.hash == "#faq") {
App.ShowFAQ();
} else if (location.hash == "#stats") {
App.ShowStats();
} else if (location.hash == "#donate") {
App.ShowDonate();
} else {
App.Elements.PageView.style.display = "block";
new ViewManager();
}
window.site_info = await Api.GetSiteInfo();
} else {
window.site_info = await Api.GetSiteInfo();
App.Elements.PageUpload.style.display = "block";
$('#dropzone').innerHTML = `Click me!<br><small>(${Utils.FormatBytes(window.site_info.data.max_upload_size)} max)</small>`;
new DropzoneManager(App.Elements.Dropzone);
}
if (window.site_info.ok) {
let elms = document.querySelectorAll("#footer-stats div span");
elms[0].textContent = window.site_info.data.basic_stats.Files;
elms[1].textContent = Utils.FormatBytes(window.site_info.data.basic_stats.Size, 2);
elms[2].textContent = Utils.FormatBytes(window.site_info.data.basic_stats.Transfer_24h, 2);
}
let faq_headers = document.querySelectorAll('#page-faq .faq-header');
for (let x = 0; x < faq_headers.length; x++) {
faq_headers[x].addEventListener('click', function () {
this.nextElementSibling.classList.toggle("show");
}.bind(faq_headers[x]));
}
App.Loaded = true;
},
/**
* Adds in polyfills for this browser
*/
MakePolyfills: function () {
if (typeof TextEncoder === "undefined" || typeof TextDecoder === "undefined") {
App.InsertScript("//unpkg.com/text-encoding@0.6.4/lib/encoding-indexes.js");
App.InsertScript("//unpkg.com/text-encoding@0.6.4/lib/encoding.js");
}
},
/**
* Adds a script tag at the top of the header
* @param {string} src - The script src url
* @param {function} fnWait - Function to use in promise to test if the script is loaded
*/
InsertScript: async function (src, fnWait) {
var before = document.head.getElementsByTagName('script')[0];
var newlink = document.createElement('script');
newlink.src = src;
document.head.insertBefore(newlink, before);
if (typeof fnWait === "function") {
await new Promise((resolve, reject) => {
let timer = setInterval(() => {
if (fnWait()) {
clearInterval(timer);
resolve();
}
}, 100);
});
}
},
/**
* Checks browser version
*/
CheckBrowserSupport: function () {
if (!App.IsFirefox) {
if (App.IsChrome) {
App.AddNoticeItem("Uploads bigger then 100MiB usually crash Chrome when uploading. Please upload with Firefox. Or check <a target=\"_blank\" href=\"https://github.com/v0l/void.cat/releases\">GitHub</a> for tools.");
}
if (App.IsEdge) {
let edge_version = /Edge\/([0-9]{1,3}\.[0-9]{1,5})/.exec(navigator.userAgent)[1];
Log.I(`Edge version is: ${edge_version}`);
if (parseFloat(edge_version) < 18.18218) {
App.AddNoticeItem("Upload progress isn't reported in the version of Edge you are using, see <a target=\"_blank\" href=\"https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12224510/\">here for more info</a>.");
}
}
document.querySelector('#page-notice').style.display = "block";
}
},
/**
* Adds a notice to the UI notice box
* @param {string} txt - Message to add to notice list
*/
AddNoticeItem: function (txt) {
let ne = document.createElement('li');
ne.innerHTML = txt;
document.querySelector('#page-notice ul').appendChild(ne);
}
};
setTimeout(App.Init);

View File

@ -1,52 +0,0 @@
/**
* @constant {string} - Stores the current app version
*/
const AppVersion = "1.0";
/**
* @constant {string} - The hashing algo to use to verify the file
*/
const HashingAlgo = 'SHA-256';
/**
* @constant {string} - The encryption algoritm to use for file uploads
*/
const EncryptionAlgo = 'AES-CBC';
/**
* @constant {object} - The 'algo' argument for importing/exporting/generating keys
*/
const EncryptionKeyDetails = { name: EncryptionAlgo, length: 128 };
/**
* @constant {object} - The 'algo' argument for importing/exporting/generating hmac keys
*/
const HMACKeyDetails = { name: 'HMAC', hash: HashingAlgo };
/**
* @constant {number} - Size of 1 kiB
*/
const kiB = Math.pow(1024, 1);
/**
* @constant {number} - Size of 1 MiB
*/
const MiB = Math.pow(1024, 2);
/**
* @constant {number} - Size of 1 GiB
*/
const GiB = Math.pow(1024, 3);
/**
* @constant {number} - Size of 1 TiB
*/
const TiB = Math.pow(1024, 4);
/**
* @constant {number} - Size of 1 PiB
*/
const PiB = Math.pow(1024, 5);
/**
* @constant {number} - Size of 1 EiB
*/
const EiB = Math.pow(1024, 6);
/**
* @constant {number} - Size of 1 ZiB
*/
const ZiB = Math.pow(1024, 7);
/**
* @constant {number} - Size of 1 YiB
*/
const YiB = Math.pow(1024, 8);

3
src/js/index.js Normal file
View File

@ -0,0 +1,3 @@
import * as App from './modules/App.js';
App.Init();

222
src/js/modules/App.js Normal file
View File

@ -0,0 +1,222 @@
import { Api, Utils, Log, $ } from './Util.js';
import { ViewManager } from './ViewManager.js';
import { DropzoneManager } from './DropzoneManager.js';
import { FileUpload } from './FileUpload.js';
let ChartJsLoaded = false;
const Elements = {
get Dropzone() { return $('#dropzone') },
get Uploads() { return $('#uploads') },
get PageView() { return $('#page-view') },
get PageUpload() { return $('#page-upload') },
get PageFaq() { return $('#page-faq') },
get PageStats() { return $('#page-stats') },
get PageDonate() { return $('#page-donate') }
};
const Templates = {
get Upload() { return $("template[id='tmpl-upload']") }
};
const Browser = {
get IsEdge() {
return /Edge/.test(navigator.userAgent);
},
get IsChrome() {
return !Browser.IsEdge && /^Mozilla.*Chrome/.test(navigator.userAgent);
},
get IsFirefox() {
return !Browser.IsEdge && /^Mozilla.*Firefox/.test(navigator.userAgent);
}
};
/**
* Uploads the files as selected by the input form
* @param {Element} ctx
* @returns {Promise}
*/
async function UploadFiles(ctx) {
let files = ctx.files;
let proc_files = [];
for (let x = 0; x < files.length; x++) {
let fu = new FileUpload(files[x]);
proc_files[proc_files.length] = fu.ProcessUpload();
}
await Promise.all(proc_files);
}
function ResetView() {
Elements.PageView.style.display = "none";
Elements.PageUpload.style.display = "none";
Elements.PageFaq.style.display = "none";
Elements.PageStats.style.display = "none";
Elements.PageDonate.style.display = "none";
}
async function ShowStats() {
location.hash = "#stats";
ResetView();
if (!ChartJsLoaded) {
await InsertScript("//cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js", () => {
return typeof moment !== "undefined";
});
await InsertScript("//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js", () => {
return typeof Chart !== "undefined";
});
}
let api_rsp = await Api.GetTxChart();
if (api_rsp.ok) {
let ctx = $('#weektxgraph').getContext('2d');
new Chart(ctx, {
type: 'line',
data: api_rsp.data,
options: {
scales: {
xAxes: [{
type: 'time',
time: {
source: 'data'
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
callback: function(label, index, labels) {
return Utils.FormatBytes(label);
}
}
}]
}
}
});
}
Elements.PageStats.style.display = "block";
}
function ShowFAQ() {
location.hash = "#faq";
ResetView();
Elements.PageFaq.style.display = "block";
}
function ShowDonate() {
location.hash = "#donate";
ResetView();
Elements.PageDonate.style.display = "block";
}
/**
* Sets up the page
*/
async function Init() {
CheckBrowserSupport();
MakePolyfills();
ResetView();
if (location.hash !== "") {
if (location.hash == "#faq") {
ShowFAQ();
} else if (location.hash == "#stats") {
ShowStats();
} else if (location.hash == "#donate") {
ShowDonate();
} else {
Elements.PageView.style.display = "block";
let vm = new ViewManager();
vm.LoadView();
}
window.site_info = await Api.GetSiteInfo();
} else {
window.site_info = await Api.GetSiteInfo();
Elements.PageUpload.style.display = "block";
$('#dropzone').innerHTML = `Click me!<br><small>(${Utils.FormatBytes(window.site_info.data.max_upload_size)} max)</small>`;
new DropzoneManager(Elements.Dropzone);
}
if (window.site_info.ok) {
let elms = document.querySelectorAll("#footer-stats div span");
elms[0].textContent = window.site_info.data.basic_stats.Files;
elms[1].textContent = Utils.FormatBytes(window.site_info.data.basic_stats.Size, 2);
elms[2].textContent = Utils.FormatBytes(window.site_info.data.basic_stats.Transfer_24h, 2);
}
let faq_headers = document.querySelectorAll('#page-faq .faq-header');
for (let x = 0; x < faq_headers.length; x++) {
faq_headers[x].addEventListener('click', function () {
this.nextElementSibling.classList.toggle("show");
}.bind(faq_headers[x]));
}
}
/**
* Adds in polyfills for this browser
*/
function MakePolyfills() {
if (typeof TextEncoder === "undefined" || typeof TextDecoder === "undefined") {
InsertScript("//unpkg.com/text-encoding@0.6.4/lib/encoding-indexes.js");
InsertScript("//unpkg.com/text-encoding@0.6.4/lib/encoding.js");
}
}
/**
* Adds a script tag at the top of the header
* @param {string} src - The script src url
* @param {function} fnWait - Function to use in promise to test if the script is loaded
*/
async function InsertScript(src, fnWait) {
var before = document.head.getElementsByTagName('script')[0];
var newlink = document.createElement('script');
newlink.src = src;
document.head.insertBefore(newlink, before);
if (typeof fnWait === "function") {
await new Promise((resolve, reject) => {
let timer = setInterval(() => {
if (fnWait()) {
clearInterval(timer);
resolve();
}
}, 100);
});
}
}
/**
* Checks browser version
*/
function CheckBrowserSupport() {
if (!Browser.IsFirefox) {
if (Browser.IsChrome) {
AddNoticeItem("Uploads bigger then 100MiB usually crash Chrome when uploading. Please upload with Firefox. Or check <a target=\"_blank\" href=\"https://github.com/v0l/void.cat/releases\">GitHub</a> for tools.");
}
if (Browser.IsEdge) {
let edge_version = /Edge\/([0-9]{1,3}\.[0-9]{1,5})/.exec(navigator.userAgent)[1];
Log.I(`Edge version is: ${edge_version}`);
if (parseFloat(edge_version) < 18.18218) {
AddNoticeItem("Upload progress isn't reported in the version of Edge you are using, see <a target=\"_blank\" href=\"https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12224510/\">here for more info</a>.");
}
}
document.querySelector('#page-notice').style.display = "block";
}
}
/**
* Adds a notice to the UI notice box
* @param {string} txt - Message to add to notice list
*/
function AddNoticeItem(txt) {
let ne = document.createElement('li');
ne.innerHTML = txt;
document.querySelector('#page-notice ul').appendChild(ne);
}
export { Init, Templates };

59
src/js/modules/Const.js Normal file
View File

@ -0,0 +1,59 @@
/**
* Change Log
* 1.0 - https://github.com/v0l/void.cat/commit/b0a49e5bc28d62ebd954fe344c6f604b952e905c
* 1.1 - https://github.com/v0l/void.cat/commit/e3f7f2a59e86f86a27a06d8725f4f6401af7f190
* 1.2 - TBC
*/
/**
* @constant {string} - Stores the current app version
*/
export const AppVersion = require('../../../package.json').version;
/**
* @constant {string} - The hashing algo to use to verify the file
*/
export const HashingAlgo = 'SHA-256';
/**
* @constant {string} - The encryption algoritm to use for file uploads
*/
export const EncryptionAlgo = 'AES-CBC';
/**
* @constant {object} - The 'algo' argument for importing/exporting/generating keys
*/
export const EncryptionKeyDetails = { name: EncryptionAlgo, length: 128 };
/**
* @constant {object} - The 'algo' argument for importing/exporting/generating hmac keys
*/
export const HMACKeyDetails = { name: 'HMAC', hash: HashingAlgo };
/**
* @constant {number} - Size of 1 kiB
*/
export const kiB = Math.pow(1024, 1);
/**
* @constant {number} - Size of 1 MiB
*/
export const MiB = Math.pow(1024, 2);
/**
* @constant {number} - Size of 1 GiB
*/
export const GiB = Math.pow(1024, 3);
/**
* @constant {number} - Size of 1 TiB
*/
export const TiB = Math.pow(1024, 4);
/**
* @constant {number} - Size of 1 PiB
*/
export const PiB = Math.pow(1024, 5);
/**
* @constant {number} - Size of 1 EiB
*/
export const EiB = Math.pow(1024, 6);
/**
* @constant {number} - Size of 1 ZiB
*/
export const ZiB = Math.pow(1024, 7);
/**
* @constant {number} - Size of 1 YiB
*/
export const YiB = Math.pow(1024, 8);

View File

@ -1,11 +1,13 @@
import { FileUpload } from './FileUpload.js';
/**
* @constructor Creates an instance of the DropzoneManager
* @param {HTMLElement} dz - Dropzone element
*/
const DropzoneManager = function (dz) {
function DropzoneManager(dz) {
this.dz = dz;
this.SetUI = function() {
this.SetUI = function () {
document.querySelector('#page-upload div:nth-child(1)').removeAttribute("style");
document.querySelector('#uploads').removeAttribute("style");
};
@ -27,4 +29,6 @@ const DropzoneManager = function (dz) {
};
this.dz.addEventListener('click', this.OpenFileSelect.bind(this), false);
};
};
export { DropzoneManager };

View File

@ -1,3 +1,7 @@
import * as Const from './Const.js';
import { VBF } from './VBF.js';
import { XHR, Utils, Log } from './Util.js';
/**
* File download and decryption class
* @class
@ -5,7 +9,7 @@
* @param {string} key - The key to use for decryption
* @param {string} iv - The IV to use for decryption
*/
const FileDownloader = function (fileinfo, key, iv) {
function FileDownloader(fileinfo, key, iv) {
this.fileinfo = fileinfo;
this.key = key;
this.iv = iv;
@ -113,11 +117,11 @@ const FileDownloader = function (fileinfo, key, iv) {
let iv_raw = Utils.HexToArray(this.iv);
Log.I(`${this.fileinfo.FileId} decrypting with key ${this.key} and iv ${this.iv}`);
let key = await crypto.subtle.importKey("raw", key_raw, EncryptionKeyDetails, false, ['decrypt']);
let keyhmac = await crypto.subtle.importKey("raw", key_raw, HMACKeyDetails, false, ['verify']);
let key = await crypto.subtle.importKey("raw", key_raw, Const.EncryptionKeyDetails, false, ['decrypt']);
let keyhmac = await crypto.subtle.importKey("raw", key_raw, Const.HMACKeyDetails, false, ['verify']);
let enc_data = VBF.GetEncryptedPart(header.version, blob);
let decrypted_file = await crypto.subtle.decrypt({ name: EncryptionAlgo, iv: iv_raw }, key, enc_data);
let decrypted_file = await crypto.subtle.decrypt({ name: Const.EncryptionAlgo, iv: iv_raw }, key, enc_data);
//read the header
let json_header_length = new Uint16Array(decrypted_file.slice(0, 2))[0];
@ -126,7 +130,7 @@ const FileDownloader = function (fileinfo, key, iv) {
//hash the file to verify
let file_data = decrypted_file.slice(2 + json_header_length);
let hmac_verify = await crypto.subtle.verify(HMACKeyDetails, keyhmac, header.hmac, file_data);
let hmac_verify = await crypto.subtle.verify(Const.HMACKeyDetails, keyhmac, header.hmac, file_data);
if (hmac_verify) {
Log.I(`${this.fileinfo.FileId} HMAC verified!`);
@ -136,4 +140,6 @@ const FileDownloader = function (fileinfo, key, iv) {
throw "HMAC verify failed";
}
};
};
};
export { FileDownloader };

View File

@ -1,10 +1,16 @@
import * as Const from './Const.js';
import { Templates } from './App.js';
import { XHR, Utils, Log, $ } from './Util.js';
import { VBF } from './VBF.js';
import { bytes_to_base64 } from 'asmcrypto.js';
/**
* File upload handler class
* @class
* @param {File} file - The file handle to upload
* @param {string} host - The hostname to upload to
*/
const FileUpload = function (file, host) {
function FileUpload(file, host) {
this.hasCrypto = typeof window.crypto.subtle === "object";
this.file = file;
this.host = host;
@ -46,6 +52,23 @@ const FileUpload = function (file, host) {
return `${await this.HexKey()}:${this.HexIV()}`;
};
/**
* Retruns the formatted hash fragment for this upload
* @returns {Promise<string>} The id:key:iv concatenated and converted to base64
*/
this.FormatUrl = async (id) => {
let id_hex = new Uint8Array(Utils.HexToArray(id));
let key = new Uint8Array(await crypto.subtle.exportKey('raw', this.key));
let iv = new Uint8Array(this.iv);
let ret = new Uint8Array(id_hex.byteLength + key.byteLength + iv.byteLength);
ret.set(id_hex, 0);
ret.set(key, id_hex.byteLength);
ret.set(iv, id_hex.byteLength + key.byteLength);
return bytes_to_base64(ret);
};
/**
* Loads the file and SHA256 hashes it
* @return {Promise<ArrayBuffer>}
@ -64,7 +87,7 @@ const FileUpload = function (file, host) {
fr.onload = function (ev) {
this.HandleProgress('state-hash-start');
crypto.subtle.sign(HMACKeyDetails, this.hmackey, ev.target.result).then(function (hash) {
crypto.subtle.sign(Const.HMACKeyDetails, this.hmackey, ev.target.result).then(function (hash) {
this.HandleProgress('state-hash-end');
resolve({
hash: hash,
@ -189,7 +212,7 @@ const FileUpload = function (file, host) {
* Creates a template for the upload to show progress
*/
this.CreateNode = function () {
let nelm = document.importNode(App.Templates.Upload.content, true);
let nelm = document.importNode(Templates.Upload.content, true);
nelm.filename = nelm.querySelector('.file-info .file-info-name');
nelm.filesize = nelm.querySelector('.file-info .file-info-size');
@ -213,8 +236,8 @@ const FileUpload = function (file, host) {
* @returns {Promise<CryptoKey>} The new key
*/
this.GenerateKey = async function () {
this.key = await crypto.subtle.generateKey(EncryptionKeyDetails, true, ['encrypt', 'decrypt']);
this.hmackey = await crypto.subtle.importKey("raw", await crypto.subtle.exportKey('raw', this.key), HMACKeyDetails, false, ["sign"]);
this.key = await crypto.subtle.generateKey(Const.EncryptionKeyDetails, true, ['encrypt', 'decrypt']);
this.hmackey = await crypto.subtle.importKey("raw", await crypto.subtle.exportKey('raw', this.key), Const.HMACKeyDetails, false, ["sign"]);
crypto.getRandomValues(this.iv);
@ -230,7 +253,7 @@ const FileUpload = function (file, host) {
this.EncryptFile = async function (fileData) {
this.HandleProgress('state-encrypt-start');
let encryptedData = await crypto.subtle.encrypt({
name: EncryptionAlgo,
name: Const.EncryptionAlgo,
iv: this.iv
}, this.key, fileData);
this.HandleProgress('state-encrypt-end');
@ -288,7 +311,7 @@ const FileUpload = function (file, host) {
Log.I(`${this.file.name} hash is: ${h256}`);
//create blob for encryption
let header_data = new TextEncoder().encode(header);
let header_data = new TextEncoder('utf-8').encode(header);
Log.I(`Using header: ${header} (length=${header_data.byteLength})`);
let encryption_payload = new Uint8Array(2 + header_data.byteLength + hash_data.data.byteLength);
@ -315,7 +338,7 @@ const FileUpload = function (file, host) {
let nl = document.createElement("a");
nl.target = "_blank";
nl.href = `${window.location.protocol}//${window.location.host}/#${uploadResult.id}:${await this.TextKey()}`;
nl.href = `${window.location.protocol}//${window.location.host}/#${await this.FormatUrl(uploadResult.id)}`;
nl.textContent = this.file.name;
this.domNode.links.appendChild(nl);
} else {
@ -324,3 +347,5 @@ const FileUpload = function (file, host) {
}
};
};
export { FileUpload };

View File

@ -1,14 +1,16 @@
import * as Const from './Const.js';
/**
* @constant {function} - Helper function for document.querySelector
* @param {string} selector - The selector to use in the query
* @returns {HTMLElement} The first selected element
*/
const $ = (selector) => document.querySelector(selector);
export const $ = (selector) => document.querySelector(selector);
const Log = {
I: (msg) => console.log(`[App_v ${AppVersion}][I]: ${msg}`),
W: (msg) => console.warn(`[App_v ${AppVersion}][W]: ${msg}`),
E: (msg) => console.error(`[App_v ${AppVersion}][E]: ${msg}`)
export const Log = {
I: (msg) => console.log(`[App_v ${Const.AppVersion}][I]: ${msg}`),
W: (msg) => console.warn(`[App_v ${Const.AppVersion}][W]: ${msg}`),
E: (msg) => console.error(`[App_v ${Const.AppVersion}][E]: ${msg}`)
};
/**
@ -18,7 +20,7 @@ const Log = {
* @param {[object]} data - Request payload (method must be post)
* @returns {Promise<XMLHttpRequest>} The completed request
*/
const JsonXHR = async function (method, url, data) {
export async function JsonXHR(method, url, data) {
return await XHR(method, url, JSON.stringify(data), {
'Content-Type': 'application/json'
});
@ -35,7 +37,7 @@ const JsonXHR = async function (method, url, data) {
* @param {[function]} editrequest - Function that can edit the request before its sent
* @returns {Promise<XMLHttpRequest>} The completed request
*/
const XHR = function (method, url, data, headers, uploadprogress, downloadprogress, editrequest) {
export function XHR(method, url, data, headers, uploadprogress, downloadprogress, editrequest) {
return new Promise(function (resolve, reject) {
let x = new XMLHttpRequest();
x.onreadystatechange = function (ev) {
@ -76,7 +78,7 @@ const XHR = function (method, url, data, headers, uploadprogress, downloadprogre
/**
* Calls api handler
*/
const Api = {
export const Api = {
DoRequest: async function (req) {
return JSON.parse((await JsonXHR('POST', '/api', req)).response);
},
@ -118,7 +120,7 @@ const Api = {
/**
* Generic util functions
*/
const Utils = {
export const Utils = {
/**
* Formats an ArrayBuffer to hex
* @param {ArrayBuffer} buffer - Input data to convert to hex
@ -149,22 +151,22 @@ const Utils = {
*/
FormatBytes: (b, f) => {
f = typeof f === 'number' ? 2 : f;
if (b >= YiB)
return (b / YiB).toFixed(f) + ' YiB';
if (b >= ZiB)
return (b / ZiB).toFixed(f) + ' ZiB';
if (b >= EiB)
return (b / EiB).toFixed(f) + ' EiB';
if (b >= PiB)
return (b / PiB).toFixed(f) + ' PiB';
if (b >= TiB)
return (b / TiB).toFixed(f) + ' TiB';
if (b >= GiB)
return (b / GiB).toFixed(f) + ' GiB';
if (b >= MiB)
return (b / MiB).toFixed(f) + ' MiB';
if (b >= kiB)
return (b / kiB).toFixed(f) + ' KiB';
if (b >= Const.YiB)
return (b / Const.YiB).toFixed(f) + ' YiB';
if (b >= Const.ZiB)
return (b / Const.ZiB).toFixed(f) + ' ZiB';
if (b >= Const.EiB)
return (b / Const.EiB).toFixed(f) + ' EiB';
if (b >= Const.PiB)
return (b / Const.PiB).toFixed(f) + ' PiB';
if (b >= Const.TiB)
return (b / Const.TiB).toFixed(f) + ' TiB';
if (b >= Const.GiB)
return (b / Const.GiB).toFixed(f) + ' GiB';
if (b >= Const.MiB)
return (b / Const.MiB).toFixed(f) + ' MiB';
if (b >= Const.kiB)
return (b / Const.kiB).toFixed(f) + ' KiB';
return b.toFixed(f) + ' B'
}
};

View File

@ -84,4 +84,6 @@ const VBF = {
};
}
}
};
};
export { VBF };

View File

@ -1,16 +1,27 @@
import { Api, Utils, Log, $ } from './Util.js';
import { FileDownloader } from './FileDownloader.js';
import { base64_to_bytes } from 'asmcrypto.js';
/**
* @constructor Creates an instance of the ViewManager
*/
const ViewManager = function () {
export function ViewManager() {
this.id = null;
this.key = null;
this.iv = null;
this.ParseUrlHash = function () {
let hs = window.location.hash.substr(1).split(':');
this.id = hs[0];
this.key = hs[1];
this.iv = hs[2];
if (window.location.hash.indexOf(':') !== -1) {
let hs = window.location.hash.substr(1).split(':');
this.id = hs[0];
this.key = hs[1];
this.iv = hs[2];
} else if (window.location.hash.length === 73) { //base64 encoded #id:key:iv
let hs = base64_to_bytes(window.location.hash.substr(1));
this.id = Utils.ArrayToHex(hs.slice(0, 20));
this.key = Utils.ArrayToHex(hs.slice(20, 36));
this.iv = Utils.ArrayToHex(hs.slice(36));
}
};
this.LoadView = async function () {
@ -104,6 +115,4 @@ const ViewManager = function () {
document.body.appendChild(st);
}
};
this.LoadView();
};

View File

@ -46,10 +46,16 @@
return "$this->DocumentRoot/$this->UploadFolder";
}
/**
* $id should be the ripemd160(hmac-sha256(file, key)) as hex
*/
public function GetRelativeFilePath($id) : string {
return "$this->UploadFolder/$id";
return $this->UploadFolder . "/" . $id;
}
/**
* $id should be the ripemd160(hmac-sha256(file, key)) as hex
*/
public function GetAbsoluteFilePath($id) : string {
return $this->GetUploadDirAbsolute() . "/" . $id;
}
@ -94,7 +100,7 @@
}
public function StoreV1File($bf, $file) : ?string {
$id = gmp_strval(gmp_init("0x" . hash(Config::$Instance->public_hash_algo, $bf->Hash)), 62);
$id = hash(Config::$Instance->public_hash_algo, $bf->Hash);
$input = fopen($file, "rb");
$res = $this->StoreFile($input, $id);
@ -115,7 +121,7 @@
$hash = unpack("H64hash256", fread($input_temp, 32));
fclose($input_temp);
$id = gmp_strval(gmp_init("0x" . hash(Config::$Instance->public_hash_algo, $hash["hash256"])), 62);
$id = hash(Config::$Instance->public_hash_algo, $hash["hash256"]);
$file_path = $this->GetAbsoluteFilePath($id);
if(!file_exists($file_path)){
rename($temp_name, $file_path);
@ -124,6 +130,9 @@
return null;
}
/**
* $id should be formatted base62 filename
*/
public function GetFileSize($id) : int {
return filesize($this->GetAbsoluteFilePath($id));
}