aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/ApiManagers/DeleteManager.ts12
-rw-r--r--src/server/ApiManagers/DownloadManager.ts2
-rw-r--r--src/server/ApiManagers/UploadManager.ts74
-rw-r--r--src/server/ApiManagers/UtilManager.ts3
-rw-r--r--src/server/DashUploadUtils.ts12
-rw-r--r--src/server/RouteManager.ts15
-rw-r--r--src/server/apis/google/CredentialsLoader.ts40
-rw-r--r--src/server/index.ts64
-rw-r--r--src/server/remapUrl.ts3
-rw-r--r--src/server/server_Initialization.ts53
-rw-r--r--src/server/websocket.ts35
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) {