UNPKG

networking

Version:

Library for typed, event-based networking between a server and clients.

91 lines (90 loc) 4.2 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const errors_1 = require("../common/errors"); const authQueue_1 = require("../common/authQueue"); const encryption_1 = require("../common/encryption"); class Auth { constructor(socket) { this.socket = socket; this.queue = new authQueue_1.AuthQueue(socket); } /** * Waits for the client to send login credentials and returns them. To accept the credentials, use the `accept` * method. To reject them, use the `reject` method. Throws an `AuthError` if the client fails does not send any * login credentials. */ login() { return __awaiter(this, void 0, void 0, function* () { return yield this.queue.getPacket('login'); }); } /** * Performs an encryption test against the client. In short, the client must also provide the same secret for * authentication to be successful, meaning both sides must know the secret key beforehand. This is rarely an * appropriate option for authentication, but when it is, it's a powerful way to prove the identities of both the * client and server. Throws an `AuthError` if the server fails the test. * * @param key */ encrypt(secret) { return __awaiter(this, void 0, void 0, function* () { let key = encryption_1.Encryption.generateKey(secret); let token = (yield encryption_1.Encryption.generateRandom(256)).toString('hex'); let cipherText = yield encryption_1.Encryption.encrypt(key, token); // Wait for the client to start the process let init = yield this.queue.getPacket('encrypt/start'); // Decrypt the client's cipher text and send it back with our own cipher try { let remoteToken = yield encryption_1.Encryption.decrypt(key, Buffer.from(init.cipher, 'base64')); this.queue.sendPacket('encrypt/step', { token: remoteToken, cipher: cipherText.toString('base64') }); } catch (err) { this.queue.sendPacket('encrypt/step', { error: true }); throw new errors_1.AuthError('Error decrypting the client\'s cipher text: ' + err.message); } // Wait for the client to signal acceptance of the token we sent if (!(yield this.queue.getResolution())) { throw new errors_1.AuthError('Client rejected our encryption test key'); } // Wait for the client to send back our token let finish = yield this.queue.getPacket('encrypt/finish'); if (finish.error) throw new errors_1.AuthError('Decryption failed on client'); if (token !== Buffer.from(finish.token, 'base64').toString()) { this.queue.sendResolution(false); throw new errors_1.AuthError('Decrypted token sent by the client did not match'); } // Send acceptance this.queue.sendResolution(true); return true; }); } /** * Sends an acceptance or rejection packet to the client. */ success(success) { this.queue.sendResolution(success); } /** * Sends an acceptance packet to the client. */ accept() { this.queue.sendResolution(true); } /** * Sends a rejection packet to the client. */ reject() { this.queue.sendResolution(false); } } exports.Auth = Auth;