started adding video streaming support with cookies
This commit is contained in:
+42
-16
@@ -6,6 +6,7 @@ import S3Service from "../services/ChunkService/S3Service";
|
||||
import {UserInterface} from "../models/user";
|
||||
import tempStorage from "../tempStorage/tempStorage";
|
||||
import sendShareEmail from "../utils/sendShareEmail";
|
||||
import { createStreamVideoCookie } from "../cookies/createCookies";
|
||||
|
||||
const fileService = new FileService()
|
||||
|
||||
@@ -330,30 +331,55 @@ class FileController {
|
||||
}
|
||||
}
|
||||
|
||||
getDownloadTokenVideo = async(req: RequestTypeFullUser, res: Response) => {
|
||||
getAccessTokenStreamVideo = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) return;
|
||||
|
||||
if (!req.user) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
|
||||
const user = req.user;
|
||||
const cookie = req.headers.uuid as string;
|
||||
|
||||
const tempToken = await fileService.getDownloadTokenVideo(user, cookie);
|
||||
|
||||
res.send({tempToken});
|
||||
|
||||
|
||||
const ipAddress = req.clientIp;
|
||||
|
||||
const streamVideoAccessToken = await user.generateAuthTokenStreamVideo(ipAddress);
|
||||
|
||||
createStreamVideoCookie(res, streamVideoAccessToken);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nGet Access Token Stream Video Fle Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// getDownloadTokenVideo = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
// if (!req.user) {
|
||||
// return
|
||||
// }
|
||||
|
||||
// try {
|
||||
|
||||
// const user = req.user;
|
||||
// const cookie = req.headers.uuid as string;
|
||||
|
||||
// const tempToken = await fileService.getDownloadTokenVideo(user, cookie);
|
||||
|
||||
// res.send({tempToken});
|
||||
|
||||
// } catch (e) {
|
||||
|
||||
// const code = e.code || 500;
|
||||
|
||||
// console.log(e);
|
||||
// res.status(code).send()
|
||||
// }
|
||||
// }
|
||||
|
||||
removeTempToken = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import {Response } from "express";
|
||||
|
||||
const maxAgeAccess = 1000 * 5;//60 * 1000 * 20;
|
||||
const maxAgeRefresh = 60 * 1000 * 60 * 24 * 30;
|
||||
const maxAgeStreamVideo = 60 * 1000 * 60 * 24;
|
||||
|
||||
export const createLoginCookie = (res: Response, accessToken: string, refreshToken: string) => {
|
||||
|
||||
@@ -35,4 +36,14 @@ export const createLogoutCookie = (res: Response) => {
|
||||
sameSite: "strict",
|
||||
secure: process.env.NODE_ENV === "production"
|
||||
})
|
||||
}
|
||||
|
||||
export const createStreamVideoCookie = (res: Response, streamVideoAccessToken: string) => {
|
||||
|
||||
res.cookie("video-access-token", streamVideoAccessToken, {
|
||||
httpOnly: true,
|
||||
maxAge: maxAgeStreamVideo,
|
||||
sameSite: "strict",
|
||||
secure: process.env.NODE_ENV === "production"
|
||||
})
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import FileSystemService from "../services/ChunkService/FileSystemService";
|
||||
import S3Service from "../services/ChunkService/S3Service";
|
||||
import ChunkInterface from "../services/ChunkService/utils/ChunkInterface";
|
||||
import authFullUser from "../middleware/authFullUser";
|
||||
import authStreamVideo from "../middleware/authStreamVideo";
|
||||
|
||||
let fileController: FileController;
|
||||
let chunkService: ChunkInterface;
|
||||
@@ -48,11 +49,17 @@ router.get("/file-service/quick-list", auth, fileController.getQuickList);
|
||||
|
||||
router.get("/file-service/list", auth, fileController.getList);
|
||||
|
||||
router.get("/file-service/download/get-token", authFullUser, fileController.getDownloadToken);
|
||||
//router.get("/file-service/download/get-token", authFullUser, fileController.getDownloadToken);
|
||||
|
||||
router.get("/file-service/download/get-token-video", auth, fileController.getDownloadTokenVideo);
|
||||
//router.get("/file-service/download/get-token-video", auth, fileController.getDownloadTokenVideo);
|
||||
|
||||
router.get("/file-service/stream-video/:id/:tempToken/:uuid", auth, fileController.streamVideo);
|
||||
router.get("/file-service/download/access-token-stream-video", authFullUser, fileController.getAccessTokenStreamVideo)
|
||||
|
||||
router.get("/file-service/stream-video/:id", authStreamVideo, fileController.streamVideo);
|
||||
|
||||
//router.get("/file-service/stream-video/:id/:tempToken/:uuid", auth, fileController.streamVideo);
|
||||
|
||||
//router.get("/file-service/stream-video/:id", auth, fileController.streamVideo);
|
||||
|
||||
router.get("/file-service/download/:id", authFullUser, fileController.downloadFile);
|
||||
|
||||
@@ -68,7 +75,9 @@ router.patch("/file-service/move", auth, fileController.moveFile);
|
||||
|
||||
router.delete("/file-service/remove-link/:id", auth, fileController.removeLink);
|
||||
|
||||
router.delete("/file-service/remove/token-video/:tempToken/:uuid", auth, fileController.removeTempToken);
|
||||
//router.delete("/file-service/remove/token-video/:tempToken/:uuid", auth, fileController.removeTempToken);
|
||||
|
||||
router.delete("/file-service/remove/token-video/:id", auth, fileController.removeTempToken);
|
||||
|
||||
router.delete("/file-service/remove", auth, fileController.deleteFile);
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import User, {UserInterface} from "../models/user";
|
||||
import env from "../enviroment/env";
|
||||
import {Request, Response, NextFunction} from "express";
|
||||
import { ObjectID } from "mongodb";
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: UserInterface,
|
||||
token?: string,
|
||||
encryptedToken?: string,
|
||||
}
|
||||
|
||||
// type jwtType = {
|
||||
// iv: Buffer,
|
||||
// user: userAccessType
|
||||
// }
|
||||
|
||||
type jwtType = {
|
||||
iv: Buffer,
|
||||
_id: string,
|
||||
time: number
|
||||
}
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
admin: boolean,
|
||||
botChecked: boolean,
|
||||
username: string,
|
||||
}
|
||||
|
||||
const removeOldTokens = async(userID: string, ipAddress: string | undefined, oldTime: number) => {
|
||||
|
||||
try {
|
||||
|
||||
const minusTime = oldTime - (60 * 1000 * 60 * 24);
|
||||
|
||||
ipAddress = ipAddress ? ipAddress : "";
|
||||
|
||||
if (ipAddress === "") return;
|
||||
|
||||
await User.updateOne({_id: userID}, {$pull: {tempTokens: {ipAddress, time: {$lt: minusTime}}}})
|
||||
|
||||
} catch (e) {
|
||||
console.log("cannot remove old tokens", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const authStreamVideo = async(req: RequestType, res: Response, next: NextFunction) => {
|
||||
|
||||
try {
|
||||
|
||||
const accessTokenStreamVideo = req.cookies["video-access-token"];
|
||||
|
||||
if (!accessTokenStreamVideo) throw new Error("No Stream Video Access Token");
|
||||
|
||||
const decoded = jwt.verify(accessTokenStreamVideo, env.passwordAccess!) as jwtType;
|
||||
|
||||
const time = decoded.time;
|
||||
|
||||
const user = await User.findById(new ObjectID(decoded._id));
|
||||
|
||||
if (!user) throw new Error("No User Stream Video");
|
||||
|
||||
const encrpytionKey = user.getEncryptionKey();
|
||||
const encryptedToken = user.encryptToken(accessTokenStreamVideo, encrpytionKey, decoded.iv);
|
||||
|
||||
let tokenFound = false;
|
||||
|
||||
for (let i = 0; i < user.tempTokens.length; i++) {
|
||||
|
||||
const currentEncryptedToken = user.tempTokens[i].token;
|
||||
|
||||
if (currentEncryptedToken === encryptedToken) {
|
||||
|
||||
tokenFound = true;
|
||||
removeOldTokens(user._id, req.clientIp, time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tokenFound) throw new Error("Refresh Token Not Found");
|
||||
|
||||
req.user = user;
|
||||
|
||||
next();
|
||||
|
||||
} catch (e) {
|
||||
console.log("\nAuthorization Middleware Error:", e.message);
|
||||
res.status(401).send("Error Authenticating");
|
||||
}
|
||||
}
|
||||
|
||||
export default authStreamVideo;
|
||||
+34
-1
@@ -51,6 +51,14 @@ const userSchema = new mongoose.Schema({
|
||||
token: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
ipAddress: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
time: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
}],
|
||||
privateKey: {
|
||||
@@ -187,11 +195,12 @@ export interface UserInterface extends Document {
|
||||
|
||||
getEncryptionKey: () => Buffer | undefined;
|
||||
generateTempAuthToken: () => any;
|
||||
generateTempAuthTokenVideo: (cookie: string) => any;
|
||||
// generateTempAuthTokenVideo: (cookie: string) => any;
|
||||
encryptToken: (tempToken: any, key: any, publicKey: any) => any;
|
||||
decryptToken: (encryptedToken: any, key: any, publicKey: any) => any;
|
||||
findByCreds: (email: string, password: string) => UserInterface;
|
||||
generateAuthToken: (ipAddress: string | undefined) => Promise<{accessToken: string, refreshToken: string}>
|
||||
generateAuthTokenStreamVideo: (ipAddress: string | undefined) => Promise<string>
|
||||
generateEncryptionKeys: () => Promise<void>;
|
||||
changeEncryptionKey: (randomKey: Buffer) => void;
|
||||
generateEmailVerifyToken: () => string;
|
||||
@@ -211,6 +220,8 @@ export interface UserInterface extends Document {
|
||||
const maxAgeAccess = 1000 * 5 * 10; //60 * 1000 * 20 + (1000 * 60);
|
||||
const maxAgeRefresh = 60 * 1000 * 60 * 24 * 30 + (1000 * 60);
|
||||
|
||||
const maxAgeAccessStreamVideo = 60 * 1000 * 60 * 24;
|
||||
|
||||
userSchema.pre("save", async function(this: any, next: any) {
|
||||
|
||||
const user = this;
|
||||
@@ -254,6 +265,28 @@ userSchema.methods.toJSON = function() {
|
||||
return userObject;
|
||||
}
|
||||
|
||||
userSchema.methods.generateAuthTokenStreamVideo = async function(ipAddress: string | undefined) {
|
||||
|
||||
const iv = crypto.randomBytes(16);
|
||||
|
||||
const user = this;
|
||||
|
||||
const date = new Date();
|
||||
const time = date.getTime();
|
||||
|
||||
let accessTokenStreamVideo = jwt.sign({_id:user._id.toString(), iv, time}, env.passwordAccess!, {expiresIn: maxAgeAccessStreamVideo.toString()});
|
||||
|
||||
const encryptionKey = user.getEncryptionKey();
|
||||
|
||||
const encryptedToken = user.encryptToken(accessTokenStreamVideo, encryptionKey, iv);
|
||||
|
||||
ipAddress = ipAddress ? ipAddress : "";
|
||||
|
||||
await User.updateOne({_id: user._id}, {$push: {"tempTokens": {token: encryptedToken, ipAddress, time}}});
|
||||
|
||||
return accessTokenStreamVideo;
|
||||
}
|
||||
|
||||
userSchema.methods.generateAuthToken = async function(ipAddress: string | undefined) {
|
||||
|
||||
const iv = crypto.randomBytes(16);
|
||||
|
||||
@@ -161,17 +161,21 @@ class MongoFileService {
|
||||
return tempToken;
|
||||
}
|
||||
|
||||
getDownloadTokenVideo = async(user: UserInterface, cookie: string) => {
|
||||
|
||||
if (!cookie) throw new NotAuthorizedError("Get Download Token Video Cookie Not Authorized Error");
|
||||
|
||||
const tempToken = await user.generateTempAuthTokenVideo(cookie);
|
||||
|
||||
if (!tempToken) throw new NotAuthorizedError("Get Download Token Video Not Authorized Error");
|
||||
|
||||
return tempToken;
|
||||
getAccessTokenStreamVideo = async() => {
|
||||
|
||||
}
|
||||
|
||||
// getDownloadTokenVideo = async(user: UserInterface, cookie: string) => {
|
||||
|
||||
// if (!cookie) throw new NotAuthorizedError("Get Download Token Video Cookie Not Authorized Error");
|
||||
|
||||
// const tempToken = await user.generateTempAuthTokenVideo(cookie);
|
||||
|
||||
// if (!tempToken) throw new NotAuthorizedError("Get Download Token Video Not Authorized Error");
|
||||
|
||||
// return tempToken;
|
||||
// }
|
||||
|
||||
removeTempToken = async(user: UserInterface, tempToken: any, currentUUID: string) => {
|
||||
|
||||
const key = user.getEncryptionKey();
|
||||
|
||||
@@ -5,6 +5,7 @@ import env from "../../enviroment/envFrontEnd";
|
||||
import {connect} from "react-redux";
|
||||
import React from "react";
|
||||
import { setPhotoID } from "../../actions/photoViewer";
|
||||
import axiosNonInterceptor from "axios";
|
||||
|
||||
const currentURL = env.url;
|
||||
|
||||
@@ -94,36 +95,57 @@ class PopupWindowContainer extends React.Component {
|
||||
|
||||
getVideo = () => {
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
uuid: window.sessionStorage.getItem("uuid")
|
||||
}
|
||||
// const config = {
|
||||
// headers: {
|
||||
// uuid: window.sessionStorage.getItem("uuid")
|
||||
// }
|
||||
|
||||
};
|
||||
// };
|
||||
|
||||
axios.get("/file-service/download/access-token-stream-video").then(() => {
|
||||
|
||||
axios.get(currentURL +'/file-service/download/get-token-video',config)
|
||||
.then((response) => {
|
||||
|
||||
this.tempToken = response.data.tempToken;
|
||||
|
||||
const uuidID = window.sessionStorage.getItem("uuid");
|
||||
console.log("stream video got token")
|
||||
|
||||
const isDrive = this.props.popupFile.metadata.drive;
|
||||
const isPersonal = this.props.popupFile.metadata.personalFile;
|
||||
|
||||
|
||||
const finalUrl = isDrive ?
|
||||
currentURL + `/file-service-google/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
: !isPersonal ? currentURL + `/file-service/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
: currentURL + `/file-service-personal/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
|
||||
currentURL + `/file-service-google/stream-video/${this.props.popupFile._id}`
|
||||
: !isPersonal ? currentURL + `/file-service/stream-video/${this.props.popupFile._id}`
|
||||
: currentURL + `/file-service-personal/stream-video/${this.props.popupFile._id}`
|
||||
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
video: finalUrl
|
||||
}))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
}).catch((e) => {
|
||||
console.log("Stream Video Error", e.message);
|
||||
})
|
||||
|
||||
// axios.get(currentURL +'/file-service/download/get-token-video',config)
|
||||
// .then((response) => {
|
||||
|
||||
// this.tempToken = response.data.tempToken;
|
||||
|
||||
// const uuidID = window.sessionStorage.getItem("uuid");
|
||||
|
||||
// const isDrive = this.props.popupFile.metadata.drive;
|
||||
// const isPersonal = this.props.popupFile.metadata.personalFile;
|
||||
|
||||
// const finalUrl = isDrive ?
|
||||
// currentURL + `/file-service-google/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
// : !isPersonal ? currentURL + `/file-service/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
// : currentURL + `/file-service-personal/stream-video/${this.props.popupFile._id}/${this.tempToken}/${uuidID}`
|
||||
|
||||
// this.setState(() => ({
|
||||
// ...this.state,
|
||||
// video: finalUrl
|
||||
// }))
|
||||
|
||||
// }).catch((err) => {
|
||||
// console.log(err)
|
||||
// })
|
||||
}
|
||||
|
||||
componentWillUnmount = () => {
|
||||
|
||||
Reference in New Issue
Block a user