Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/backend/tcp/locked-socket.ts
Views: 687
import { createConnection } from "net";1import type { Socket } from "net";2import { callback } from "awaiting";3import getLogger from "@cocalc/backend/logger";4import { CoCalcSocket } from "./enable-messaging-protocol";56const log = getLogger("locked-socket");78/*9unlockSocket - Wait to receive token over the socket; when it is received, call10cb(false), then send back "y". If any mistake is made (or the socket times out11after 10 seconds), send back "n" and close the connection.12*/1314export async function unlockSocket(15socket: Socket,16token: string17): Promise<void> {18log.debug("unlockSocket: waiting for secret token...");19try {20await callback(unlock, socket, token);21log.debug("unlockSocket: SUCCESS");22} catch (err) {23log.debug("unlockSocket: FAILED");24throw err;25}26}2728function unlock(socket, token, cb: (err?) => void) {29const timeout = setTimeout(() => {30socket.destroy();31cb("Unlock socket -- timed out waiting for secret token");32}, 10000);3334let userToken = "";35function listener(data: Buffer) {36userToken += data.toString();37if (userToken.slice(0, token.length) === token) {38socket.removeListener("data", listener);39// got it!40socket.write("y");41clearTimeout(timeout);42cb();43} else if (44userToken.length > token.length ||45token.slice(0, userToken.length) !== userToken46) {47socket.removeListener("data", listener);48socket.write("n");49socket.write("Invalid secret token.");50socket.destroy();51clearTimeout(timeout);52cb("Invalid secret token.");53}54}55socket.on("data", listener);56}5758/*59Connect to a locked socket on remove server.60WARNING: Use only on a network where you do not have to worry about61an attacker listening to all traffic, since this is not an *encryption*62protocol, and it's just a symmetric key.6364In CoCalc this is used to allow a hub to connect to a project.65It is not used in any other way.66*/67export async function connectToLockedSocket({68port,69host = "127.0.0.1",70token,71timeout = 5, // in seconds (not milliseconds)72}: {73port: number;74host?: string;75token: string;76timeout?: number;77}): Promise<CoCalcSocket> {78if (port <= 0 || port >= 65536) {79// little consistency check80throw Error(`RangeError: port should be > 0 and < 65536: ${port}`);81}82log.debug("connectToLockedSocket:", `${host}:${port}`);83return await callback(connect, port, host, token, timeout);84}8586function connect(port, host, token, timeout, cb) {87let timer: any = null;88function finish(err?) {89// NOTE: we set cb to undefined after calling it, and only90// call it if defined, since the event and timer callback stuff is91// very hard to do right without calling cb more than once92// (which is VERY bad to do).93if (timer != null) {94clearTimeout(timer);95timer = null;96}97if (cb == null) return;98if (err) {99log.debug(`connectToLockedSocket: ERROR - ${err}`);100cb(err);101} else {102log.debug("connectToLockedSocket: SUCCESS");103cb(undefined, socket);104}105cb = null;106}107108const socket = createConnection({ host, port }, function onceConnected() {109socket.once("data", (data: Buffer) => {110log.debug("connectToLockedSocket: got back response");111if (data.toString() === "y") {112finish();113} else {114socket.destroy();115finish(116"Permission denied (invalid secret token) when connecting to the local hub."117);118}119});120log.debug("connectToLockedSocket: connected, now sending secret token");121socket.write(token);122});123124// This is called in case there is an error trying to make the connection, e.g., "connection refused".125socket.on("error", (err) => {126finish(err);127});128129function timedOut() {130timer = null;131finish(132`connectToLockedSocket: timed out trying to connect to locked socket at ${host}:${port}`133);134socket.end();135}136137timer = setTimeout(timedOut, timeout * 1000);138}139140141