networking
Version:
Library for typed, event-based networking between a server and clients.
91 lines (90 loc) • 4.2 kB
JavaScript
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;
;