mirror of
https://git.v0l.io/Kieran/void.cat.git
synced 2025-04-09 22:29:03 +02:00
set filename in header
This commit is contained in:
parent
4a2c4edafd
commit
c51f8d093a
3
.gitignore
vendored
3
.gitignore
vendored
@ -10,4 +10,5 @@ Debug/
|
||||
Release/
|
||||
node_modules/
|
||||
package-lock.json
|
||||
out/
|
||||
out/
|
||||
sw.js
|
@ -7,7 +7,7 @@
|
||||
"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",
|
||||
"build": "sass src/css/style.scss dist/style.css && webpack-cli --entry ./src/js/index.js --mode production --output ./dist/bundle.js && webpack-cli --entry ./src/js/Worker.js --mode production --output ./sw.js",
|
||||
"debug": "webpack-cli --entry ./src/js/index.js --mode development --watch --output ./dist/bundle.js",
|
||||
"debug-worker": "webpack-cli --entry ./src/js/Worker.js --mode development --watch --output ./sw.js"
|
||||
},
|
||||
|
@ -15,7 +15,18 @@ const VoidFetch = function (event) {
|
||||
let fi = await Api.GetFileInfo(hs.id);
|
||||
if (fi.ok) {
|
||||
let fd = new FileDownloader(fi.data, hs.key, hs.iv);
|
||||
return await fd.StreamResponse();
|
||||
fd.onprogress = function(x) {
|
||||
if(client !== null && client !== undefined){
|
||||
client.postMessage({
|
||||
type: 'progress',
|
||||
x
|
||||
});
|
||||
}
|
||||
};
|
||||
let resp = await fd.StreamResponse();
|
||||
resp.headers.set("Content-Type", fd.fileHeader.mime != "" ? fd.fileHeader.mime : "application/octet-stream");
|
||||
resp.headers.set("Content-Disposition", `inline; filename="${fd.fileHeader.name}"`);
|
||||
return resp;
|
||||
} else {
|
||||
return Response.error();
|
||||
}
|
||||
|
@ -81,126 +81,144 @@ function FileDownloader(fileinfo, key, iv) {
|
||||
});
|
||||
|
||||
let void_download = {
|
||||
SetFileHeader: function (fh) { this.fileHeader = fh; }.bind(this),
|
||||
HandleProgress: this.HandleProgress.bind(this),
|
||||
downloadStats: this.downloadStats,
|
||||
isStart: true,
|
||||
decOffset: 0,
|
||||
headerLen: 0,
|
||||
fileHeader: null,
|
||||
hmacBytes: null,
|
||||
body: response.body,
|
||||
fileinfo: this.fileinfo,
|
||||
aes: new AES_CBC(new Uint8Array(Utils.HexToArray(this.key)), new Uint8Array(Utils.HexToArray(this.iv)), true),
|
||||
hmac: new HmacSha256(new Uint8Array(Utils.HexToArray(this.key))),
|
||||
buff: new Uint8Array(),
|
||||
start(controller) {
|
||||
this.reader = this.body.getReader();
|
||||
return this.readOnce(controller);
|
||||
},
|
||||
pull(controller) {
|
||||
if (this.reader === undefined) {
|
||||
this.reader = this.body.getReader();
|
||||
}
|
||||
return (async function () {
|
||||
Log.I(`${this.fileinfo.FileId} Starting..`);
|
||||
var isStart = true;
|
||||
var decOffset = 0;
|
||||
var headerLen = 0;
|
||||
var fileHeader = null;
|
||||
var hmacBytes = null;
|
||||
while (true) {
|
||||
let { done, value } = await this.reader.read();
|
||||
if (done) {
|
||||
if (this.buff.byteLength > 0) {
|
||||
//pad the remaining data with PKCS#7
|
||||
var toDecrypt = null;
|
||||
let padding = 16 - (this.buff.byteLength % 16);
|
||||
if(padding !== 0){
|
||||
let tmpBuff = new Uint8Array(this.buff.byteLength + padding);
|
||||
tmpBuff.fill(padding);
|
||||
tmpBuff.set(this.buff, 0);
|
||||
this.buff = null;
|
||||
this.buff = tmpBuff;
|
||||
}
|
||||
let decBytes = this.aes.AES_Decrypt_process(this.buff);
|
||||
this.hmac.process(decBytes);
|
||||
controller.enqueue(decBytes);
|
||||
this.buff = null;
|
||||
}
|
||||
let last = this.aes.AES_Decrypt_finish();
|
||||
this.hmac.process(last);
|
||||
this.hmac.finish();
|
||||
controller.enqueue(last);
|
||||
|
||||
//check hmac
|
||||
let h1 = Utils.ArrayToHex(hmacBytes);
|
||||
let h2 = Utils.ArrayToHex(this.hmac.result)
|
||||
if (h1 === h2) {
|
||||
Log.I(`HMAC verify ok!`);
|
||||
} else {
|
||||
Log.E(`HMAC verify failed (${h1} !== ${h2})`);
|
||||
//controller.cancel();
|
||||
//return;
|
||||
}
|
||||
Log.I(`${this.fileinfo.FileId} Download complete!`);
|
||||
controller.close();
|
||||
return;
|
||||
}
|
||||
|
||||
var sliceStart = 0;
|
||||
var sliceEnd = value.byteLength;
|
||||
|
||||
//!Slice this only once!!
|
||||
var toDecrypt = value;
|
||||
if (isStart) {
|
||||
let header = VBF.ParseStart(value.buffer);
|
||||
if (header !== null) {
|
||||
Log.I(`${this.fileinfo.FileId} blob header version is ${header.version} uploaded on ${header.uploaded} (Magic: ${Utils.ArrayToHex(header.magic)})`);
|
||||
sliceStart = VBF.SliceToEncryptedPart(header.version, value);
|
||||
} else {
|
||||
throw "Invalid VBF header";
|
||||
}
|
||||
} else if (fileHeader != null && decOffset + toDecrypt.byteLength + headerLen + 2 >= fileHeader.len) {
|
||||
sliceEnd -= 32; //hash is on the end (un-encrypted)
|
||||
hmacBytes = toDecrypt.slice(sliceEnd);
|
||||
}
|
||||
|
||||
const GetAdjustedLen = function () {
|
||||
return sliceEnd - sliceStart;
|
||||
};
|
||||
|
||||
//decrypt
|
||||
//append last remaining buffer if any
|
||||
if (this.buff.byteLength > 0) {
|
||||
let tmpd = new Uint8Array(this.buff.byteLength + GetAdjustedLen());
|
||||
tmpd.set(this.buff, 0);
|
||||
tmpd.set(toDecrypt.slice(sliceStart, sliceEnd), this.buff.byteLength);
|
||||
sliceEnd += this.buff.byteLength;
|
||||
toDecrypt = tmpd;
|
||||
this.buff = new Uint8Array();
|
||||
}
|
||||
|
||||
let blkRem = GetAdjustedLen() % 16;
|
||||
if (blkRem !== 0) {
|
||||
//save any remaining data into our buffer
|
||||
this.buff = toDecrypt.slice(sliceEnd - blkRem, sliceEnd);
|
||||
sliceEnd -= blkRem;
|
||||
}
|
||||
|
||||
let encBytes = toDecrypt.slice(sliceStart, sliceEnd);
|
||||
let decBytes = this.aes.AES_Decrypt_process(encBytes);
|
||||
decOffset += decBytes.byteLength;
|
||||
|
||||
//read header
|
||||
if (isStart) {
|
||||
headerLen = new Uint16Array(decBytes.slice(0, 2))[0];
|
||||
let header = new TextDecoder('utf-8').decode(decBytes.slice(2, 2 + headerLen));
|
||||
Log.I(`${this.fileinfo.FileId} got header ${header}`);
|
||||
fileHeader = JSON.parse(header);
|
||||
decBytes = decBytes.slice(2 + headerLen);
|
||||
}
|
||||
|
||||
//Log.I(`${this.fileinfo.FileId} Decrypting ${toDecrypt.byteLength} bytes, got ${decBytes.byteLength} bytes`);
|
||||
this.hmac.process(decBytes);
|
||||
controller.enqueue(decBytes);
|
||||
|
||||
isStart = false;
|
||||
await this.readOnce(controller);
|
||||
}
|
||||
}.bind(this))();
|
||||
},
|
||||
async readOnce(controller) {
|
||||
let { done, value } = await this.reader.read();
|
||||
if (done) {
|
||||
if (this.buff.byteLength > 0) {
|
||||
//pad the remaining data with PKCS#7
|
||||
var toDecrypt = null;
|
||||
let padding = 16 - (this.buff.byteLength % 16);
|
||||
if (padding !== 0) {
|
||||
let tmpBuff = new Uint8Array(this.buff.byteLength + padding);
|
||||
tmpBuff.fill(padding);
|
||||
tmpBuff.set(this.buff, 0);
|
||||
this.buff = null;
|
||||
this.buff = tmpBuff;
|
||||
}
|
||||
let decBytes = this.aes.AES_Decrypt_process(this.buff);
|
||||
this.hmac.process(decBytes);
|
||||
controller.enqueue(decBytes);
|
||||
this.buff = null;
|
||||
}
|
||||
let last = this.aes.AES_Decrypt_finish();
|
||||
this.hmac.process(last);
|
||||
this.hmac.finish();
|
||||
controller.enqueue(last);
|
||||
|
||||
//check hmac
|
||||
let h1 = Utils.ArrayToHex(this.hmacBytes);
|
||||
let h2 = Utils.ArrayToHex(this.hmac.result)
|
||||
if (h1 === h2) {
|
||||
Log.I(`HMAC verify ok!`);
|
||||
} else {
|
||||
Log.E(`HMAC verify failed (${h1} !== ${h2})`);
|
||||
controller.cancel();
|
||||
return;
|
||||
}
|
||||
Log.I(`${this.fileinfo.FileId} Download complete!`);
|
||||
controller.close();
|
||||
return;
|
||||
}
|
||||
|
||||
var sliceStart = 0;
|
||||
var sliceEnd = value.byteLength;
|
||||
|
||||
//!Slice this only once!!
|
||||
var toDecrypt = value;
|
||||
if (this.isStart) {
|
||||
let header = VBF.ParseStart(value.buffer);
|
||||
if (header !== null) {
|
||||
Log.I(`${this.fileinfo.FileId} blob header version is ${header.version} uploaded on ${header.uploaded} (Magic: ${Utils.ArrayToHex(header.magic)})`);
|
||||
sliceStart = VBF.SliceToEncryptedPart(header.version, value);
|
||||
} else {
|
||||
throw "Invalid VBF header";
|
||||
}
|
||||
} else if (this.fileHeader != null && this.decOffset + toDecrypt.byteLength + this.headerLen + 2 >= this.fileHeader.len) {
|
||||
sliceEnd -= 32; //hash is on the end (un-encrypted)
|
||||
this.hmacBytes = toDecrypt.slice(sliceEnd);
|
||||
}
|
||||
|
||||
const GetAdjustedLen = function () {
|
||||
return sliceEnd - sliceStart;
|
||||
};
|
||||
|
||||
//decrypt
|
||||
//append last remaining buffer if any
|
||||
if (this.buff.byteLength > 0) {
|
||||
let tmpd = new Uint8Array(this.buff.byteLength + GetAdjustedLen());
|
||||
tmpd.set(this.buff, 0);
|
||||
tmpd.set(toDecrypt.slice(sliceStart, sliceEnd), this.buff.byteLength);
|
||||
sliceEnd += this.buff.byteLength;
|
||||
toDecrypt = tmpd;
|
||||
this.buff = new Uint8Array();
|
||||
}
|
||||
|
||||
let blkRem = GetAdjustedLen() % 16;
|
||||
if (blkRem !== 0) {
|
||||
//save any remaining data into our buffer
|
||||
this.buff = toDecrypt.slice(sliceEnd - blkRem, sliceEnd);
|
||||
sliceEnd -= blkRem;
|
||||
}
|
||||
|
||||
let encBytes = toDecrypt.slice(sliceStart, sliceEnd);
|
||||
let decBytes = this.aes.AES_Decrypt_process(encBytes);
|
||||
this.decOffset += decBytes.byteLength;
|
||||
|
||||
//read header
|
||||
if (this.isStart) {
|
||||
this.headerLen = new Uint16Array(decBytes.slice(0, 2))[0];
|
||||
let header = new TextDecoder('utf-8').decode(decBytes.slice(2, 2 + this.headerLen));
|
||||
Log.I(`${this.fileinfo.FileId} got header ${header}`);
|
||||
this.fileHeader = JSON.parse(header);
|
||||
this.SetFileHeader(this.fileHeader);
|
||||
decBytes = decBytes.slice(2 + this.headerLen);
|
||||
}
|
||||
|
||||
//Log.I(`${this.fileinfo.FileId} Decrypting ${toDecrypt.byteLength} bytes, got ${decBytes.byteLength} bytes`);
|
||||
this.hmac.process(decBytes);
|
||||
controller.enqueue(decBytes);
|
||||
|
||||
//report progress
|
||||
let now = new Date().getTime();
|
||||
let dxLoaded = decBytes.byteLength - this.downloadStats.lastLoaded;
|
||||
let dxTime = now - this.downloadStats.lastProgress;
|
||||
|
||||
this.downloadStats.lastLoaded = decBytes.byteLength;
|
||||
this.downloadStats.lastProgress = now;
|
||||
|
||||
this.HandleProgress('progress-speed', `${Utils.FormatBytes(dxLoaded / (dxTime / 1000.0), 2)}/s`);
|
||||
this.HandleProgress('progress-download', this.decOffset / parseFloat(this.fileHeader.len));
|
||||
|
||||
this.isStart = false;
|
||||
}
|
||||
}
|
||||
|
||||
let sr = new ReadableStream(void_download);
|
||||
return new Response(sr);
|
||||
return new Response(new ReadableStream(void_download));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -94,7 +94,7 @@ function ViewManager() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
let swreg = await navigator.serviceWorker.getRegistration();
|
||||
if (swreg !== null) {
|
||||
Log.I(`Service worker detected, using ${swreg.scope} for download..`);
|
||||
Log.I(`Service worker detected, using it for download..`);
|
||||
let elm_bar_label = document.querySelector('.view-download-progress div:nth-child(1)');
|
||||
let elm_bar = document.querySelector('.view-download-progress div:nth-child(2)');
|
||||
navigator.serviceWorker.addEventListener('message', event => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user