added new streaming video code to other chunk services, removed console.logs, and added comments

This commit is contained in:
kyle hoell
2020-11-27 17:07:12 -05:00
parent 1764a8c01c
commit 9dbddb244e
4 changed files with 149 additions and 203 deletions
@@ -261,6 +261,14 @@ class FileSystemService implements ChunkInterface {
streamVideo = async(user: UserInterface, fileID: string, headers: any, res: Response, req: Request) => {
// To get this all working correctly with encryption and across
// All browsers took many days, tears, and some of my sanity.
// Shoutout to Tyzoid for helping me with the decryption
// And and helping me understand how the IVs work.
// Also fuck you Apple, Safari is turning into
// Internet explorer at this point.
// Thanks Tim Apple
const userID = user._id;
const currentFile: FileInterface = await dbUtilsFile.getFileInfo(fileID, userID);
@@ -289,71 +297,60 @@ class FileSystemService implements ChunkInterface {
let currentIV = IV;
//let fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
let fixedStart = 0;
let fixedEnd = currentFile.length;
if (start === 0 && end === 1) {
console.log("safari request");
// This is for Safari/iOS, Safari will request the first
// Byte before actually playing the video. Needs to be
// 16 bytes.
fixedStart = 0;
fixedEnd = 15;
} else {
// If you're a normal browser, or this isn't Safari's first request
// We need to make it so start is divisible by 16, since AES256
// Has a block size of 16 bytes.
fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
}
if (+start === 0) {
// This math will not work if the start is 0
// So if it is we just change fixed start back
// To 0.
fixedStart = 0;
}
// We also need to calculate the difference between the start and the
// Fixed start position. Since there will be an offset if the original
// Request is not divisible by 16, it will not return the right part
// Of the file, you will see how we do this in the awaitStreamVideo
// code.
const differenceStart = start - fixedStart;
if (fixedStart !== 0 && start !== 0) {
// If this isn't the first request, the way AES256 works is when you try to
// Decrypt a certain part of the file that isn't the start, the IV will
// Actually be the 16 bytes ahead of where you are trying to
// Start the decryption.
currentIV = await getPrevIVFS(fixedStart - 16, currentFile.metadata.filePath!) as Buffer;
}
console.log("start", start, fixedStart, end, fixedEnd, differenceStart);
let readStream;
if (start === 0 && end === 1) {
readStream = fs.createReadStream(currentFile.metadata.filePath!, {
start: fixedStart,
end: fixedEnd,
});
} else {
readStream = fs.createReadStream(currentFile.metadata.filePath!, {
start: fixedStart,
end: fixedEnd,
// highWaterMark: 1024
})
}
// } else if (fixedStart !== 0 && start !== 0) {
// readStream = fs.createReadStream(currentFile.metadata.filePath!, {
// start: fixedStart + differenceStart,
// end: fixedEnd,
// });
// } else {
// readStream = fs.createReadStream(currentFile.metadata.filePath!, {
// start: fixedStart,
// end: fixedEnd,
// });
// }
// const readStream = fs.createReadStream(currentFile.metadata.filePath!, {
// start: fixedStart,
// end: fixedEnd,
// });
const readStream = fs.createReadStream(currentFile.metadata.filePath!, {
start: fixedStart,
end: fixedEnd,
});
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
@@ -367,31 +364,8 @@ class FileSystemService implements ChunkInterface {
readStream.pipe(decipher);
// readStream.on("close", () => {
// console.log("read stream closed")
// })
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, allStreamsToErrorCatch, readStream);
// req.on("close", () => {
// // console.log("req closed");
// readStream.destroy();
// })
const tempUUID = req.params.uuid;
//console.log("temp uuid", tempUUID);
// return;
// if (start === 0 && end === 1) {
// await awaitStreamVideo(start, end, differenceStart, decipher, res, req, tempUUID, allStreamsToErrorCatch);
// } else {
// await awaitStreamVideo(start, end, differenceStart, decipher, res, req, tempUUID, allStreamsToErrorCatch);
// }
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, tempUUID, allStreamsToErrorCatch, readStream);
console.log("await stream finished")
readStream.destroy();
}
+45 -11
View File
@@ -277,6 +277,14 @@ class MongoService implements ChunkInterface {
streamVideo = async(user: UserInterface, fileID: string, headers: any, res: Response, req: Request) => {
// To get this all working correctly with encryption and across
// All browsers took many days, tears, and some of my sanity.
// Shoutout to Tyzoid for helping me with the decryption
// And and helping me understand how the IVs work.
// Also fuck you Apple, Safari is turning into
// Internet explorer at this point.
// Thanks Tim Apple
const userID = user._id;
const currentFile = await dbUtilsFile.getFileInfo(fileID, userID);
@@ -305,18 +313,51 @@ class MongoService implements ChunkInterface {
let currentIV = IV;
let fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
let fixedStart = 0;
let fixedEnd = currentFile.length;
if (start === 0 && end === 1) {
// This is for Safari/iOS, Safari will request the first
// Byte before actually playing the video. Needs to be
// 16 bytes.
fixedStart = 0;
fixedEnd = 15;
} else {
// If you're a normal browser, or this isn't Safari's first request
// We need to make it so start is divisible by 16, since AES256
// Has a block size of 16 bytes.
fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
}
if (+start === 0) {
// This math will not work if the start is 0
// So if it is we just change fixed start back
// To 0.
fixedStart = 0;
}
const fixedEnd = currentFile.length;
// We also need to calculate the difference between the start and the
// Fixed start position. Since there will be an offset if the original
// Request is not divisible by 16, it will not return the right part
// Of the file, you will see how we do this in the awaitStreamVideo
// code.
const differenceStart = start - fixedStart;
if (fixedStart !== 0 && start !== 0) {
// If this isn't the first request, the way AES256 works is when you try to
// Decrypt a certain part of the file that isn't the start, the IV will
// Actually be the 16 bytes ahead of where you are trying to
// Start the decryption.
currentIV = await getPrevIVMongo(fixedStart - 16, fileID) as Buffer;
}
@@ -341,15 +382,8 @@ class MongoService implements ChunkInterface {
readStream.pipe(decipher);
// req.on("close", () => {
// // console.log("req closed");
// readStream.destroy();
// })
const tempUUID = req.params.uuid;
//await awaitStreamVideo(start, end, differenceStart, decipher, res, req, tempUUID, allStreamsToErrorCatch);
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, allStreamsToErrorCatch, readStream);
readStream.destroy();
}
+47 -9
View File
@@ -241,6 +241,14 @@ class S3Service implements ChunkInterface {
streamVideo = async(user: UserInterface, fileID: string, headers: any, res: Response, req: Request) => {
// To get this all working correctly with encryption and across
// All browsers took many days, tears, and some of my sanity.
// Shoutout to Tyzoid for helping me with the decryption
// And and helping me understand how the IVs work.
// Also fuck you Apple, Safari is turning into
// Internet explorer at this point.
// Thanks Tim Apple
const userID = user._id;
const currentFile: FileInterface = await dbUtilsFile.getFileInfo(fileID, userID);
@@ -271,18 +279,51 @@ class S3Service implements ChunkInterface {
let currentIV = IV;
let fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
let fixedStart = 0;
let fixedEnd = currentFile.length;
if (start === 0 && end === 1) {
// This is for Safari/iOS, Safari will request the first
// Byte before actually playing the video. Needs to be
// 16 bytes.
fixedStart = 0;
fixedEnd = 15;
} else {
// If you're a normal browser, or this isn't Safari's first request
// We need to make it so start is divisible by 16, since AES256
// Has a block size of 16 bytes.
fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
}
if (+start === 0) {
// This math will not work if the start is 0
// So if it is we just change fixed start back
// To 0.
fixedStart = 0;
}
const fixedEnd = fileSize % 16 === 0 ? fileSize : fixEndChunkLength(fileSize); //end % 16 === 0 ? end + 15: (fixEndChunkLength(end) - 1) + 16;
// We also need to calculate the difference between the start and the
// Fixed start position. Since there will be an offset if the original
// Request is not divisible by 16, it will not return the right part
// Of the file, you will see how we do this in the awaitStreamVideo
// code.
const differenceStart = start - fixedStart;
if (fixedStart !== 0 && start !== 0) {
// If this isn't the first request, the way AES256 works is when you try to
// Decrypt a certain part of the file that isn't the start, the IV will
// Actually be the 16 bytes ahead of where you are trying to
// Start the decryption.
currentIV = await getPrevIVS3(fixedStart - 16, currentFile.metadata.s3ID!, isPersonal, user) as Buffer;
}
@@ -303,11 +344,8 @@ class S3Service implements ChunkInterface {
s3ReadStream.pipe(decipher);
const tempUUID = req.params.uuid;
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, allStreamsToErrorCatch, s3ReadStream);
console.log("temp uuid", tempUUID);
//await awaitStreamVideo(start, end, differenceStart, decipher, res, req, tempUUID, allStreamsToErrorCatch);
s3ReadStream.destroy();
}
@@ -1,31 +1,18 @@
import {Response, Request} from "express"
import tempStorage from "../../../tempStorage/tempStorage";
import uuid from "uuid";
const StreamSkip = require("stream-skip");
const awaitStreamVideo = (start: number, end:number, differenceStart: number,
decipher: any, res: Response, req: Request, tempUUID: string, streamsToErrorCatch: any[], readStream: any) => {
// const currentUUID = uuid.v4();
// tempStorage[tempUUID] = currentUUID;
decipher: any, res: Response, req: Request, streamsToErrorCatch: any[], readStream: any) => {
return new Promise((resolve, reject) => {
let firstBytesRemoved = false;
//let sizeCounter = 0;
req.on("close", () => {
console.log("close resolved");
// streamsToErrorCatch.forEach((stream) => {
// stream.destroy();
// })
readStream.close();
decipher.destroy();
resolve();
})
req.on("end", () => {
console.log("End resolved");
streamsToErrorCatch.forEach((stream) => {
stream.destroy();
})
@@ -33,130 +20,43 @@ const awaitStreamVideo = (start: number, end:number, differenceStart: number,
})
readStream.on("close", () => {
console.log("read stream closed")
decipher.destroy();
})
if (+start === 0 && +end === 1) {
console.log("safari first byte request");
// This is for Safri/iOS, for whatever reason they ask for the
// First byte, but if I actually try to return the first byte
// It will not work ???, but if I return the first 4 bytes it seems
// To work fine.
decipher.on("data", (data: Buffer | string) => {
//console.log("original data size", data.length);
const dataCoverted = data.toString("hex");
let neededData = dataCoverted.substring(0, 8);
const dataBack = Buffer.from(neededData, "hex");
//console.log("safari bytes size", dataBack.length);
res.write(dataBack);
})
} else {
// This is where the differnce start comes into play, as I said before
// There will be an offset caused by the 16 block size of AES256.
// So if there was an offset we need to skip over those bytes
// To make sure it returns the exact position the browser is requesting.
// Most browsers will still work fine without this, such as Chrome and Firefox.
// But one browser needs to be pampered and fed the exact right bytes in
// Order to function correctly, can you guess what browser? If you
// Guessed Safari you would be correct.
const streamSkip = new StreamSkip({skip: differenceStart});
decipher.pipe(streamSkip).pipe(res);
}
//decipher.pipe(res);
// decipher.on("data", (data: Buffer | string) => {
// //console.log("data", uuid.v4());
// // if (tempStorage[tempUUID] !== currentUUID) {
// // streamsToErrorCatch.forEach((stream) => {
// // stream.destroy();
// // })
// // resolve();
// // }
// //console.log("data", currentUUID);
// //console.log("stream passed", currentUUID);
// // if (tempStorage[tempUUID] !== undefined && tempStorage[tempUUID] !== currentUUID) {
// // console.log("New Stream Requested, Desroying old stream");
// // streamsToErrorCatch[0].destroy();
// // console.log("Old Stream Desroyed");
// // delete tempStorage[tempUUID];
// // } else {
// // tempStorage[tempUUID] = currentUUID;
// // }
// //console.log("data size", data.length)
// if (+start === 0 && +end === 1) {
// const dataCoverted = data.toString("hex");
// let neededData = dataCoverted.substring(0, 4);
// const dataBack = Buffer.from(neededData, "hex");
// res.write(dataBack);
// //res.flush();
// // return;
// } else if (!firstBytesRemoved) {
// const dataCoverted = data.toString("hex");
// let neededData = dataCoverted.substring(differenceStart * 2);
// const dataBack = Buffer.from(neededData, "hex");
// firstBytesRemoved = true;
// //sizeCounter += dataBack.length;
// res.write(dataBack);
// //res.flush();
// // return;
// } else {
// res.write(data);
// }
// //res.flush();
// //sizeCounter += data.length;
// })
// decipher.on("close", () => {
// console.log("decipher closed");
// })
// decipher.on("end", () => {
// console.log("decipher resolved");
// //res.end();
// //resolve();
// })
// streamsToErrorCatch.forEach((currentStream) => {
// currentStream.on("error", (e: Error) => {
// reject({
// message: "Await Video Stream Input Error",
// code: 500,
// error: e
// })
// })
// })
})
}