diff options
Diffstat (limited to 'src/server')
-rw-r--r-- | src/server/ApiManagers/DeleteManager.ts | 12 | ||||
-rw-r--r-- | src/server/ApiManagers/DownloadManager.ts | 2 | ||||
-rw-r--r-- | src/server/ApiManagers/UploadManager.ts | 74 | ||||
-rw-r--r-- | src/server/ApiManagers/UtilManager.ts | 3 | ||||
-rw-r--r-- | src/server/DashUploadUtils.ts | 12 | ||||
-rw-r--r-- | src/server/RouteManager.ts | 15 | ||||
-rw-r--r-- | src/server/apis/google/CredentialsLoader.ts | 40 | ||||
-rw-r--r-- | src/server/index.ts | 64 | ||||
-rw-r--r-- | src/server/remapUrl.ts | 3 | ||||
-rw-r--r-- | src/server/server_Initialization.ts | 53 | ||||
-rw-r--r-- | src/server/websocket.ts | 35 |
11 files changed, 248 insertions, 65 deletions
diff --git a/src/server/ApiManagers/DeleteManager.ts b/src/server/ApiManagers/DeleteManager.ts index 7fbb37658..46c0d8a8a 100644 --- a/src/server/ApiManagers/DeleteManager.ts +++ b/src/server/ApiManagers/DeleteManager.ts @@ -14,24 +14,20 @@ export default class DeleteManager extends ApiManager { register({ method: Method.GET, + requireAdminInRelease: true, subscription: new RouteSubscriber("delete").add("target?"), - secureHandler: async ({ req, res, isRelease }) => { - if (isRelease) { - return _permission_denied(res, "Cannot perform a delete operation outside of the development environment!"); - } - + secureHandler: async ({ req, res }) => { const { target } = req.params; - const { doDelete } = WebSocket; if (!target) { - await doDelete(); + await WebSocket.doDelete(); } else { let all = false; switch (target) { case "all": all = true; case "database": - await doDelete(false); + await WebSocket.doDelete(false); if (!all) break; case "files": rimraf.sync(filesDirectory); diff --git a/src/server/ApiManagers/DownloadManager.ts b/src/server/ApiManagers/DownloadManager.ts index 01d2dfcad..c5f3ca717 100644 --- a/src/server/ApiManagers/DownloadManager.ts +++ b/src/server/ApiManagers/DownloadManager.ts @@ -246,7 +246,7 @@ async function writeHierarchyRecursive(file: Archiver.Archiver, hierarchy: Hiera if (typeof result === "string") { let path: string; let matches: RegExpExecArray | null; - if ((matches = /\:1050\/files\/images\/(upload\_[\da-z]{32}.*)/g.exec(result)) !== null) { + if ((matches = /\:\d+\/files\/images\/(upload\_[\da-z]{32}.*)/g.exec(result)) !== null) { // image already exists on our server path = serverPathToFile(Directory.images, matches[1]); } else { diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index b185d3b55..756bde738 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -4,14 +4,18 @@ import * as formidable from 'formidable'; import v4 = require('uuid/v4'); const AdmZip = require('adm-zip'); import { extname, basename, dirname } from 'path'; -import { createReadStream, createWriteStream, unlink } from "fs"; +import { createReadStream, createWriteStream, unlink, writeFile } from "fs"; import { publicDirectory, filesDirectory } from ".."; import { Database } from "../database"; import { DashUploadUtils, InjectSize, SizeSuffix } from "../DashUploadUtils"; import * as sharp from 'sharp'; import { AcceptibleMedia, Upload } from "../SharedMediaTypes"; import { normalize } from "path"; +import RouteSubscriber from "../RouteSubscriber"; const imageDataUri = require('image-data-uri'); +import { isWebUri } from "valid-url"; +import { launch } from "puppeteer"; +import { Opt } from "../../fields/Doc"; export enum Directory { parsed_files = "parsed_files", @@ -61,10 +65,38 @@ export default class UploadManager extends ApiManager { }); register({ - method: Method.GET, - subscription: "/hello", - secureHandler: ({ req, res }) => { - res.send("<h1>world!</h1>"); + method: Method.POST, + subscription: new RouteSubscriber("youtubeScreenshot"), + secureHandler: async ({ req, res }) => { + const { id, timecode } = req.body; + const convert = (raw: string) => { + const number = Math.floor(Number(raw)); + const seconds = number % 60; + const minutes = (number - seconds) / 60; + return `${minutes}m${seconds}s`; + }; + const suffix = timecode ? `&t=${convert(timecode)}` : ``; + const targetUrl = `https://www.youtube.com/watch?v=${id}${suffix}`; + const buffer = await captureYoutubeScreenshot(targetUrl); + if (!buffer) { + return res.send(); + } + const resolvedName = `youtube_capture_${id}_${suffix}.png`; + const resolvedPath = serverPathToFile(Directory.images, resolvedName); + return new Promise<void>(resolve => { + writeFile(resolvedPath, buffer, async error => { + if (error) { + return res.send(); + } + await DashUploadUtils.outputResizedImages(() => createReadStream(resolvedPath), resolvedName, pathToDirectory(Directory.images)); + res.send({ + accessPaths: { + agnostic: DashUploadUtils.getAccessPaths(Directory.images, resolvedName) + } + } as Upload.FileInformation); + resolve(); + }); + }); } }); @@ -244,4 +276,36 @@ export default class UploadManager extends ApiManager { } +} +function delay(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} +/** + * On success, returns a buffer containing the bytes of a screenshot + * of the video (optionally, at a timecode) specified by @param targetUrl. + * + * On failure, returns undefined. + */ +async function captureYoutubeScreenshot(targetUrl: string): Promise<Opt<Buffer>> { + const browser = await launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }); + const page = await browser.newPage(); + await page.setViewport({ width: 1920, height: 1080 }); + + await page.goto(targetUrl, { waitUntil: 'domcontentloaded' as any }); + + const videoPlayer = await page.$('.html5-video-player'); + videoPlayer && await page.focus("video"); + await delay(7000); + const ad = await page.$('.ytp-ad-skip-button-text'); + await ad?.click(); + await videoPlayer?.click(); + await delay(1000); + // hide youtube player controls. + await page.evaluate(() => + (document.querySelector('.ytp-chrome-bottom') as any).style.display = 'none'); + + const buffer = await videoPlayer?.screenshot({ encoding: "binary" }); + await browser.close(); + + return buffer; }
\ No newline at end of file diff --git a/src/server/ApiManagers/UtilManager.ts b/src/server/ApiManagers/UtilManager.ts index aec523cd0..e2cd88726 100644 --- a/src/server/ApiManagers/UtilManager.ts +++ b/src/server/ApiManagers/UtilManager.ts @@ -1,8 +1,6 @@ import ApiManager, { Registration } from "./ApiManager"; import { Method } from "../RouteManager"; import { exec } from 'child_process'; -import RouteSubscriber from "../RouteSubscriber"; -import { red } from "colors"; // import { IBM_Recommender } from "../../client/apis/IBM_Recommender"; // import { Recommender } from "../Recommender"; @@ -34,7 +32,6 @@ export default class UtilManager extends ApiManager { // } // }); - register({ method: Method.GET, subscription: "/pull", diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index b74904ada..2bf4c1956 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -15,7 +15,9 @@ const parse = require('pdf-parse'); import { Directory, serverPathToFile, clientPathToFile, pathToDirectory } from './ApiManagers/UploadManager'; import { red } from 'colors'; import { Stream } from 'stream'; +import { resolvedPorts } from './server_Initialization'; const requestImageSize = require("../client/util/request-image-size"); +import { resolvedServerUrl } from "./server_Initialization"; export enum SizeSuffix { Small = "_s", @@ -184,7 +186,7 @@ export namespace DashUploadUtils { if (error !== null) { return error; } - source = `http://localhost:1050${clientPathToFile(Directory.images, resolved)}`; + source = `${resolvedServerUrl}${clientPathToFile(Directory.images, resolved)}`; } let resolvedUrl: string; /** @@ -194,14 +196,14 @@ export namespace DashUploadUtils { * basename subtree (i.e. /images/<some_guid>.<ext>) and put it on the end of the server's url. * * This can always be localhost, regardless of whether this is on the server or not, since we (the server, not the client) - * will be the ones making the request, and from the perspective of dash-release or dash-web, localhost:1050 refers to the same thing - * as the full dash-release.eastus.cloudapp.azure.com:1050. + * will be the ones making the request, and from the perspective of dash-release or dash-web, localhost:<port> refers to the same thing + * as the full dash-release.eastus.cloudapp.azure.com:<port>. */ const matches = isLocal().exec(source); if (matches === null) { resolvedUrl = source; } else { - resolvedUrl = `http://localhost:1050/${matches[1].split("\\").join("/")}`; + resolvedUrl = `${resolvedServerUrl}/${matches[1].split("\\").join("/")}`; } // See header comments: not all image files have exif data (I believe only JPG is the only format that can have it) const exifData = await parseExifData(resolvedUrl); @@ -257,7 +259,7 @@ export namespace DashUploadUtils { }); } - function getAccessPaths(directory: Directory, fileName: string) { + export function getAccessPaths(directory: Directory, fileName: string) { return { client: clientPathToFile(directory, fileName), server: serverPathToFile(directory, fileName) diff --git a/src/server/RouteManager.ts b/src/server/RouteManager.ts index b23215996..1a2340afc 100644 --- a/src/server/RouteManager.ts +++ b/src/server/RouteManager.ts @@ -2,6 +2,7 @@ import RouteSubscriber from "./RouteSubscriber"; import { DashUserModel } from "./authentication/DashUserModel"; import { Request, Response, Express } from 'express'; import { cyan, red, green } from 'colors'; +import { AdminPriviliges } from "."; export enum Method { GET, @@ -25,6 +26,7 @@ export interface RouteInitializer { secureHandler: SecureHandler; publicHandler?: PublicHandler; errorHandler?: ErrorHandler; + requireAdminInRelease?: true; } const registered = new Map<string, Set<Method>>(); @@ -84,7 +86,7 @@ export default class RouteManager { * @param initializer */ addSupervisedRoute = (initializer: RouteInitializer): void => { - const { method, subscription, secureHandler, publicHandler, errorHandler } = initializer; + const { method, subscription, secureHandler, publicHandler, errorHandler, requireAdminInRelease: requireAdmin } = initializer; typeof (initializer.subscription) === "string" && RouteManager.routes.push(initializer.subscription); initializer.subscription instanceof RouteSubscriber && RouteManager.routes.push(initializer.subscription.root); @@ -94,7 +96,7 @@ export default class RouteManager { }); const isRelease = this._isRelease; const supervised = async (req: Request, res: Response) => { - let { user } = req; + let user = req.user as Partial<DashUserModel> | undefined; const { originalUrl: target } = req; if (process.env.DB === "MEM" && !user) { user = { id: "guest", email: "", userDocumentId: "guestDocId" }; @@ -113,6 +115,13 @@ export default class RouteManager { } }; if (user) { + if (requireAdmin && isRelease && process.env.PASSWORD) { + if (AdminPriviliges.get(user.id)) { + AdminPriviliges.delete(user.id); + } else { + return res.redirect(`/admin/${req.originalUrl.substring(1).replace("/", ":")}`); + } + } await tryExecute(secureHandler, { ...core, user }); } else { req.session!.target = target; @@ -205,5 +214,5 @@ export function _permission_denied(res: Response, message?: string) { if (message) { res.statusMessage = message; } - res.status(STATUS.PERMISSION_DENIED).send("Permission Denied!"); + res.status(STATUS.PERMISSION_DENIED).send(`Permission Denied! ${message}`); } diff --git a/src/server/apis/google/CredentialsLoader.ts b/src/server/apis/google/CredentialsLoader.ts index e3f4d167b..ef1f9a91e 100644 --- a/src/server/apis/google/CredentialsLoader.ts +++ b/src/server/apis/google/CredentialsLoader.ts @@ -1,4 +1,7 @@ -import { readFile } from "fs"; +import { readFile, readFileSync } from "fs"; +import { pathFromRoot } from "../../ActionUtilities"; +import { SecureContextOptions } from "tls"; +import { blue, red } from "colors"; export namespace GoogleCredentialsLoader { @@ -27,3 +30,38 @@ export namespace GoogleCredentialsLoader { } } + +export namespace SSL { + + export let Credentials: SecureContextOptions = {}; + export let Loaded = false; + + const suffixes = { + privateKey: ".key", + certificate: ".crt", + caBundle: "-ca.crt" + }; + + export async function loadCredentials() { + const { serverName } = process.env; + const cert = (suffix: string) => readFileSync(pathFromRoot(`./${serverName}${suffix}`)).toString(); + try { + Credentials.key = cert(suffixes.privateKey); + Credentials.cert = cert(suffixes.certificate); + Credentials.ca = cert(suffixes.caBundle); + Loaded = true; + } catch (e) { + Credentials = {}; + Loaded = false; + } + } + + export function exit() { + console.log(red("Running this server in release mode requires the following SSL credentials in the project root:")); + const serverName = process.env.serverName ? process.env.serverName : "{process.env.serverName}"; + Object.values(suffixes).forEach(suffix => console.log(blue(`${serverName}${suffix}`))); + console.log(red("Please ensure these files exist and restart, or run this in development mode.")); + process.exit(0); + } + +} diff --git a/src/server/index.ts b/src/server/index.ts index af8f95a5e..590affd06 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -5,15 +5,14 @@ import * as path from 'path'; import { Database } from './database'; import { DashUploadUtils } from './DashUploadUtils'; import RouteSubscriber from './RouteSubscriber'; -import initializeServer from './server_Initialization'; +import initializeServer, { resolvedPorts } from './server_Initialization'; import RouteManager, { Method, _success, _permission_denied, _error, _invalid, PublicHandler } from './RouteManager'; import * as qs from 'query-string'; import UtilManager from './ApiManagers/UtilManager'; import { SearchManager } from './ApiManagers/SearchManager'; import UserManager from './ApiManagers/UserManager'; -import { WebSocket } from './websocket'; import DownloadManager from './ApiManagers/DownloadManager'; -import { GoogleCredentialsLoader } from './apis/google/CredentialsLoader'; +import { GoogleCredentialsLoader, SSL } from './apis/google/CredentialsLoader'; import DeleteManager from "./ApiManagers/DeleteManager"; import PDFManager from "./ApiManagers/PDFManager"; import UploadManager from "./ApiManagers/UploadManager"; @@ -26,6 +25,7 @@ import { DashSessionAgent } from "./DashSession/DashSessionAgent"; import SessionManager from "./ApiManagers/SessionManager"; import { AppliedSessionAgent } from "./DashSession/Session/agents/applied_session_agent"; +export const AdminPriviliges: Map<string, boolean> = new Map(); export const onWindows = process.platform === "win32"; export let sessionAgent: AppliedSessionAgent; export const publicDirectory = path.resolve(__dirname, "public"); @@ -41,6 +41,7 @@ async function preliminaryFunctions() { await DashUploadUtils.buildFileDirectories(); await Logger.initialize(); await GoogleCredentialsLoader.loadCredentials(); + SSL.loadCredentials(); GoogleApiServerUtils.processProjectCredentials(); if (process.env.DB !== "MEM") { await log_execution({ @@ -94,6 +95,11 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }: secureHandler: ({ res }) => res.send(true) }); + addSupervisedRoute({ + method: Method.GET, + subscription: "/resolvedPorts", + secureHandler: ({ res }) => res.send(resolvedPorts) + }); const serve: PublicHandler = ({ req, res }) => { const detector = new mobileDetect(req.headers['user-agent'] || ""); @@ -101,6 +107,42 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }: res.sendFile(path.join(__dirname, '../../deploy/' + filename)); }; + /** + * Serves a simple password input box for any + */ + addSupervisedRoute({ + method: Method.GET, + subscription: new RouteSubscriber("admin").add("previous_target"), + secureHandler: ({ res, isRelease }) => { + const { PASSWORD } = process.env; + if (!(isRelease && PASSWORD)) { + return res.redirect("/home"); + } + res.render("admin.pug", { title: "Enter Administrator Password" }); + } + }); + + addSupervisedRoute({ + method: Method.POST, + subscription: new RouteSubscriber("admin").add("previous_target"), + secureHandler: async ({ req, res, isRelease, user: { id } }) => { + const { PASSWORD } = process.env; + if (!(isRelease && PASSWORD)) { + return res.redirect("/home"); + } + const { password } = req.body; + const { previous_target } = req.params; + let redirect: string; + if (password === PASSWORD) { + AdminPriviliges.set(id, true); + redirect = `/${previous_target.replace(":", "/")}`; + } else { + redirect = `/admin/${previous_target}`; + } + res.redirect(redirect); + } + }); + addSupervisedRoute({ method: Method.GET, subscription: ["/home", new RouteSubscriber("doc").add("docId")], @@ -121,10 +163,6 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }: }); logRegistrationOutcome(); - - // initialize the web socket (bidirectional communication: if a user changes - // a field on one client, that change must be broadcast to all other clients) - WebSocket.initialize(isRelease); } @@ -149,9 +187,9 @@ export async function launchServer() { * log the output of the server process, so it's not ideal for development. * So, the 'else' clause is exactly what we've always run when executing npm start. */ -if (process.env.RELEASE) { - (sessionAgent = new DashSessionAgent()).launch(); -} else { - (Database.Instance as Database.Database).doConnect(); - launchServer(); -} +// if (process.env.RELEASE) { +// (sessionAgent = new DashSessionAgent()).launch(); +// } else { +(Database.Instance as Database.Database).doConnect(); +launchServer(); +// } diff --git a/src/server/remapUrl.ts b/src/server/remapUrl.ts index 91a3cb6bf..7178add93 100644 --- a/src/server/remapUrl.ts +++ b/src/server/remapUrl.ts @@ -1,4 +1,5 @@ import { Database } from "./database"; +import { resolvedPorts } from "./server_Initialization"; //npx ts-node src/server/remapUrl.ts @@ -34,7 +35,7 @@ async function update() { if (url.href.includes("localhost") && url.href.includes("Bill")) { dynfield = true; - update.$set = { ["fields." + key + ".url"]: `${url.protocol}//dash-web.eastus2.cloudapp.azure.com:1050${url.pathname}` }; + update.$set = { ["fields." + key + ".url"]: `${url.protocol}//dash-web.eastus2.cloudapp.azure.com:${resolvedPorts.server}${url.pathname}` }; } } } diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 4b3094616..744d4547b 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -10,6 +10,7 @@ import { Database } from './database'; import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLogin, postReset, postSignup } from './authentication/AuthenticationManager'; const MongoStore = require('connect-mongo')(session); import RouteManager from './RouteManager'; +import { WebSocket } from './websocket'; import * as webpack from 'webpack'; const config = require('../../webpack.config'); const compiler = webpack(config); @@ -19,15 +20,21 @@ import * as fs from 'fs'; import * as request from 'request'; import RouteSubscriber from './RouteSubscriber'; import { publicDirectory } from '.'; -import { logPort, } from './ActionUtilities'; +import { logPort } from './ActionUtilities'; import { blue, yellow } from 'colors'; import * as cors from "cors"; +import { createServer, Server as HttpsServer } from "https"; +import { Server as HttpServer } from "http"; +import { SSL } from './apis/google/CredentialsLoader'; /* RouteSetter is a wrapper around the server that prevents the server from being exposed. */ export type RouteSetter = (server: RouteManager) => void; export let disconnect: Function; +export let resolvedPorts: { server: number, socket: number } = { server: 1050, socket: 4321 }; +export let resolvedServerUrl: string; + export default async function InitializeServer(routeSetter: RouteSetter) { const app = buildWithMiddleware(express()); @@ -45,16 +52,27 @@ export default async function InitializeServer(routeSetter: RouteSetter) { const isRelease = determineEnvironment(); + isRelease && !SSL.Loaded && SSL.exit(); + routeSetter(new RouteManager(app, isRelease)); registerRelativePath(app); - const serverPort = isRelease ? Number(process.env.serverPort) : 1050; - const server = app.listen(serverPort, () => { - logPort("server", serverPort); - console.log(); - }); - disconnect = async () => new Promise<Error>(resolve => server.close(resolve)); + let server: HttpServer | HttpsServer; + const { serverPort, serverName } = process.env; + isRelease && serverPort && (resolvedPorts.server = Number(serverPort)); + await new Promise<void>(resolve => server = isRelease ? + createServer(SSL.Credentials, app).listen(resolvedPorts.server, resolve) : + app.listen(resolvedPorts.server, resolve) + ); + logPort("server", resolvedPorts.server); + + resolvedServerUrl = `${isRelease && serverName ? `https://${serverName}.com` : "http://localhost"}:${resolvedPorts.server}`; + // initialize the web socket (bidirectional communication: if a user changes + // a field on one client, that change must be broadcast to all other clients) + await WebSocket.initialize(isRelease, app); + + disconnect = async () => new Promise<Error>(resolve => server.close(resolve)); return isRelease; } @@ -122,7 +140,7 @@ function registerAuthenticationRoutes(server: express.Express) { function registerCorsProxy(server: express.Express) { const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/; - server.use("/corsProxy", (req, res) => { + server.use("/corsProxy", async (req, res) => { const requrl = decodeURIComponent(req.url.substring(1)); const referer = req.headers.referer ? decodeURIComponent(req.headers.referer) : ""; @@ -131,8 +149,15 @@ function registerCorsProxy(server: express.Express) { // then we redirect again to the cors referer and just add the relative path. if (!requrl.startsWith("http") && req.originalUrl.startsWith("/corsProxy") && referer?.includes("corsProxy")) { res.redirect(referer + (referer.endsWith("/") ? "" : "/") + requrl); - } - else { + } else { + try { + await new Promise<void>((resolve, reject) => { + request(requrl).on("response", resolve).on("error", reject); + }); + } catch { + console.log(`Malformed CORS url: ${requrl}`); + return res.send(); + } req.pipe(request(requrl)).on("response", res => { const headers = Object.keys(res.headers); headers.forEach(headerName => { @@ -145,7 +170,7 @@ function registerCorsProxy(server: express.Express) { } } }); - }).pipe(res); + }).on("error", () => console.log(`Malformed CORS url: ${requrl}`)).pipe(res); } }); } @@ -154,11 +179,11 @@ function registerRelativePath(server: express.Express) { server.use("*", (req, res) => { const relativeUrl = req.originalUrl; if (!res.headersSent && req.headers.referer?.includes("corsProxy")) { // a request for something by a proxied referrer means it must be a relative reference. So construct a proxied absolute reference here. - const proxiedRefererUrl = decodeURIComponent(req.headers.referer); // (e.g., http://localhost:1050/corsProxy/https://en.wikipedia.org/wiki/Engelbart) - const dashServerUrl = proxiedRefererUrl.match(/.*corsProxy\//)![0]; // the dash server url (e.g.: http://localhost:1050/corsProxy/ ) + const proxiedRefererUrl = decodeURIComponent(req.headers.referer); // (e.g., http://localhost:<port>/corsProxy/https://en.wikipedia.org/wiki/Engelbart) + const dashServerUrl = proxiedRefererUrl.match(/.*corsProxy\//)![0]; // the dash server url (e.g.: http://localhost:<port>/corsProxy/ ) const actualReferUrl = proxiedRefererUrl.replace(dashServerUrl, ""); // the url of the referer without the proxy (e.g., : http:s//en.wikipedia.org/wiki/Engelbart) const absoluteTargetBaseUrl = actualReferUrl.match(/http[s]?:\/\/[^\/]*/)![0]; // the base of the original url (e.g., https://en.wikipedia.org) - const redirectedProxiedUrl = dashServerUrl + encodeURIComponent(absoluteTargetBaseUrl + relativeUrl); // the new proxied full url (e..g, http://localhost:1050/corsProxy/https://en.wikipedia.org/<somethingelse>) + const redirectedProxiedUrl = dashServerUrl + encodeURIComponent(absoluteTargetBaseUrl + relativeUrl); // the new proxied full url (e..g, http://localhost:<port>/corsProxy/https://en.wikipedia.org/<somethingelse>) res.redirect(redirectedProxiedUrl); } else if (relativeUrl.startsWith("/search")) { // detect search query and use default search engine res.redirect(req.headers.referer + "corsProxy/" + encodeURIComponent("http://www.google.com" + relativeUrl)); diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 7278bdc32..d55c2e198 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -1,18 +1,22 @@ +import * as fs from 'fs'; +import { logPort } from './ActionUtilities'; import { Utils } from "../Utils"; import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent, RoomMessage } from "./Message"; import { Client } from "./Client"; import { Socket } from "socket.io"; import { Database } from "./database"; import { Search } from "./Search"; -import * as io from 'socket.io'; +import * as sio from 'socket.io'; import YoutubeApi from "./apis/youtube/youtubeApiSample"; -import { GoogleCredentialsLoader } from "./apis/google/CredentialsLoader"; -import { logPort } from "./ActionUtilities"; +import { GoogleCredentialsLoader, SSL } from "./apis/google/CredentialsLoader"; import { timeMap } from "./ApiManagers/UserManager"; import { green } from "colors"; import { networkInterfaces } from "os"; import executeImport from "../scraping/buxton/final/BuxtonImporter"; import { DocumentsCollection } from "./IDatabase"; +import { createServer, Server } from "https"; +import * as express from "express"; +import { resolvedPorts } from './server_Initialization'; export namespace WebSocket { @@ -21,11 +25,24 @@ export namespace WebSocket { export const socketMap = new Map<SocketIO.Socket, string>(); export let disconnect: Function; - export function initialize(isRelease: boolean) { - const endpoint = io(); - endpoint.on("connection", function (socket: Socket) { - _socket = socket; + export async function initialize(isRelease: boolean, app: express.Express) { + let io: sio.Server; + if (isRelease) { + const { socketPort } = process.env; + if (socketPort) { + resolvedPorts.socket = Number(socketPort); + } + let socketEndpoint: Server; + await new Promise<void>(resolve => socketEndpoint = createServer(SSL.Credentials, app).listen(resolvedPorts.socket, resolve)); + io = sio(socketEndpoint!, SSL.Credentials as any); + } else { + io = sio().listen(resolvedPorts.socket); + } + logPort("websocket", resolvedPorts.socket); + console.log(); + io.on("connection", function (socket: Socket) { + _socket = socket; socket.use((_packet, next) => { const userEmail = socketMap.get(socket); if (userEmail) { @@ -121,10 +138,6 @@ export namespace WebSocket { socket.disconnect(true); }; }); - - const socketPort = isRelease ? Number(process.env.socketPort) : 4321; - endpoint.listen(socketPort); - logPort("websocket", socketPort); } function processGesturePoints(socket: Socket, content: GestureContent) { |