added new streaming video code to other chunk services, removed console.logs, and added comments
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
// })
|
||||
|
||||
// })
|
||||
// })
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user