@linkedmink/passport-mutual-key-challenge
Version:
Implements a Passport strategy to authenticate the public key of a user by issuing a dynamic generated challenge
85 lines • 4.16 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MutualKeyChallengeStrategy = void 0;
const passport_strategy_1 = require("passport-strategy");
const MessageVerifier_1 = require("./MessageVerifier");
const MutualKeyChallengeOptions_1 = require("./MutualKeyChallengeOptions");
const TypeCheck_1 = require("./Helpers/TypeCheck");
const Types_1 = require("./Types");
class MutualKeyChallengeStrategy extends passport_strategy_1.Strategy {
constructor(options) {
super();
this.options = {
...(0, MutualKeyChallengeOptions_1.getDefaultOptions)(),
...options,
};
this.verifier = new MessageVerifier_1.MessageVerifier(this.options.serverKey, this.options.cryptography);
}
async authenticate(req, options) {
const request = this.options.challengeOrResponseFunc(req);
if (Types_1.ChallengeError.isType(request)) {
return this.error(request);
}
if ((0, TypeCheck_1.isClientResponse)(request)) {
return this.handleChallengeResponse(req, request);
}
return this.handleChallengeRequest(req, request);
}
async handleChallengeResponse(req, message) {
const user = await this.getUserResult(req, message.userId);
if (Types_1.ChallengeError.isType(user)) {
return this.error(user);
}
if (!(await this.verifier.verify(user.publicKey, message.clientResponsed))) {
return this.error(new Types_1.ChallengeError("The response could not be verified", Types_1.ChallengeStage.ServerChallenge));
}
const challengeGet = this.options.challengeCache.get(message.userId);
const challenge = (0, TypeCheck_1.isPromise)(challengeGet) ? await challengeGet : challengeGet;
if (!challenge) {
return this.error(new Types_1.ChallengeError("Challenge is not initiated or expired", Types_1.ChallengeStage.ServerChallenge));
}
if (!challenge.clientChallenged.equals(message.clientResponsed.message)) {
return this.error(new Types_1.ChallengeError("Challenge is incorrect", Types_1.ChallengeStage.ServerChallenge));
}
this.success(user.user, user.publicKey);
}
async handleChallengeRequest(req, message) {
const user = await this.getUserResult(req, message.userId);
if (Types_1.ChallengeError.isType(user)) {
return this.error(user);
}
const decrypted = await this.verifier.decryptAndVerify(user.publicKey, message.clientRequested);
if (!decrypted) {
return this.error(new Types_1.ChallengeError("The response could not be verified", Types_1.ChallengeStage.ServerChallenge));
}
const decryptedMessage = await this.verifier.sign(decrypted);
const nonce = this.verifier.getNonce();
const nonceMessage = await this.verifier.encryptAndSign(user.publicKey, nonce);
const challengeSet = this.options.challengeCache.set(message.userId, {
userId: message.userId,
clientChallenged: nonce,
requestDateTime: message.requestDateTime,
});
if ((0, TypeCheck_1.isPromise)(challengeSet)) {
await challengeSet;
}
const challenge = {
clientRequested: decryptedMessage,
serverRequested: nonceMessage,
};
this.fail(challenge, 401);
}
async getUserResult(req, userId) {
const userResult = this.options.userFunc(req, userId);
if (!userResult) {
return new Types_1.ChallengeError("No user could be found", Types_1.ChallengeStage.ServerChallenge);
}
const user = (0, TypeCheck_1.isPromise)(userResult) ? await userResult : userResult;
if (!user) {
return new Types_1.ChallengeError("No user could be found", Types_1.ChallengeStage.ServerChallenge);
}
return user;
}
}
exports.MutualKeyChallengeStrategy = MutualKeyChallengeStrategy;
//# sourceMappingURL=MutualKeyChallengeStrategy.js.map