@accounts/server
Advanced tools
Comparing version 0.26.0-alpha.2 to 0.26.0-alpha.3
@@ -1,2 +0,2 @@ | ||
import { DatabaseInterface, Authenticator, AuthenticatorService, ConnectionInformations } from '@accounts/types'; | ||
import { DatabaseInterface, Authenticator, AuthenticatorService, ConnectionInformations, MfaChallenge } from '@accounts/types'; | ||
export declare class AccountsMFA { | ||
@@ -9,3 +9,3 @@ private db; | ||
/** | ||
* @description Request a challenge for the MFA authentication | ||
* @description Request a challenge for the MFA authentication. | ||
* @param {string} mfaToken - A valid mfa token you obtained during the login process. | ||
@@ -15,5 +15,5 @@ * @param {string} authenticatorId - The ID of the authenticator to challenge. | ||
*/ | ||
challenge(mfaToken: string, authenticatorId: string, infos: ConnectionInformations): Promise<void>; | ||
challenge(mfaToken: string, authenticatorId: string, infos: ConnectionInformations): Promise<any>; | ||
/** | ||
* @description Start the association of a new authenticator | ||
* @description Start the association of a new authenticator. | ||
* @param {string} userId - User id to link the new authenticator. | ||
@@ -26,2 +26,11 @@ * @param {string} serviceName - Service name of the authenticator service. | ||
/** | ||
* @description Associate a new authenticator, this method is called when the user is enforced to | ||
* associate an authenticator before the first login. | ||
* @param {string} userId - User id to link the new authenticator. | ||
* @param {string} serviceName - Service name of the authenticator service. | ||
* @param {any} params - Params for the the authenticator service. | ||
* @param {ConnectionInformations} infos - User connection informations. | ||
*/ | ||
associateByMfaToken(mfaToken: string, serviceName: string, params: any, infos: ConnectionInformations): Promise<any>; | ||
/** | ||
* @description Return the list of the active and inactive authenticators for this user. | ||
@@ -38,2 +47,3 @@ * The authenticators objects are whitelisted to not expose any sensitive informations to the client. | ||
findUserAuthenticatorsByMfaToken(mfaToken: string): Promise<Authenticator[]>; | ||
isMfaChallengeValid(mfaChallenge: MfaChallenge): boolean; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
var tokens_1 = require("./utils/tokens"); | ||
var AccountsMFA = /** @class */ (function () { | ||
@@ -11,3 +10,3 @@ function AccountsMFA(db, authenticators) { | ||
/** | ||
* @description Request a challenge for the MFA authentication | ||
* @description Request a challenge for the MFA authentication. | ||
* @param {string} mfaToken - A valid mfa token you obtained during the login process. | ||
@@ -33,3 +32,3 @@ * @param {string} authenticatorId - The ID of the authenticator to challenge. | ||
// TODO need to check that the challenge is not expired | ||
if (!mfaChallenge || mfaChallenge.deactivated) { | ||
if (!mfaChallenge || !this.isMfaChallengeValid(mfaChallenge)) { | ||
throw new Error('Mfa token invalid'); | ||
@@ -51,16 +50,10 @@ } | ||
} | ||
if (!authenticatorService.challenge) return [3 /*break*/, 4]; | ||
return [4 /*yield*/, authenticatorService.challenge(mfaChallenge, authenticator, infos)]; | ||
if (!!authenticatorService.challenge) return [3 /*break*/, 4]; | ||
return [4 /*yield*/, this.db.updateMfaChallenge(mfaChallenge.id, { | ||
authenticatorId: authenticator.id, | ||
})]; | ||
case 3: | ||
_a.sent(); | ||
_a.label = 4; | ||
case 4: | ||
// Then we attach the authenticator id that will be used to resolve the challenge | ||
return [4 /*yield*/, this.db.updateMfaChallenge(mfaChallenge.id, { | ||
authenticatorId: authenticator.id, | ||
})]; | ||
case 5: | ||
// Then we attach the authenticator id that will be used to resolve the challenge | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
return [2 /*return*/, null]; | ||
case 4: return [2 /*return*/, authenticatorService.challenge(mfaChallenge, authenticator, infos)]; | ||
} | ||
@@ -71,3 +64,3 @@ }); | ||
/** | ||
* @description Start the association of a new authenticator | ||
* @description Start the association of a new authenticator. | ||
* @param {string} userId - User id to link the new authenticator. | ||
@@ -80,3 +73,3 @@ * @param {string} serviceName - Service name of the authenticator service. | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var associate, mfaChallengeToken; | ||
var associate; | ||
return tslib_1.__generator(this, function (_a) { | ||
@@ -91,14 +84,39 @@ switch (_a.label) { | ||
associate = _a.sent(); | ||
mfaChallengeToken = tokens_1.generateRandomToken(); | ||
// associate.id refer to the authenticator id | ||
return [4 /*yield*/, this.db.createMfaChallenge({ | ||
userId: userId, | ||
authenticatorId: associate.id, | ||
token: mfaChallengeToken, | ||
scope: 'associate', | ||
})]; | ||
return [2 /*return*/, associate]; | ||
} | ||
}); | ||
}); | ||
}; | ||
/** | ||
* @description Associate a new authenticator, this method is called when the user is enforced to | ||
* associate an authenticator before the first login. | ||
* @param {string} userId - User id to link the new authenticator. | ||
* @param {string} serviceName - Service name of the authenticator service. | ||
* @param {any} params - Params for the the authenticator service. | ||
* @param {ConnectionInformations} infos - User connection informations. | ||
*/ | ||
AccountsMFA.prototype.associateByMfaToken = function (mfaToken, serviceName, params, infos) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var mfaChallenge, associate; | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (!this.authenticators[serviceName]) { | ||
throw new Error("No authenticator with the name " + serviceName + " was registered."); | ||
} | ||
if (!mfaToken) { | ||
throw new Error('Mfa token invalid'); | ||
} | ||
return [4 /*yield*/, this.db.findMfaChallengeByToken(mfaToken)]; | ||
case 1: | ||
mfaChallenge = _a.sent(); | ||
if (!mfaChallenge || | ||
!this.isMfaChallengeValid(mfaChallenge) || | ||
mfaChallenge.scope !== 'associate') { | ||
throw new Error('Mfa token invalid'); | ||
} | ||
return [4 /*yield*/, this.authenticators[serviceName].associate(mfaChallenge, params, infos)]; | ||
case 2: | ||
// associate.id refer to the authenticator id | ||
_a.sent(); | ||
return [2 /*return*/, tslib_1.__assign(tslib_1.__assign({}, associate), { mfaToken: mfaChallengeToken })]; | ||
associate = _a.sent(); | ||
return [2 /*return*/, associate]; | ||
} | ||
@@ -151,4 +169,3 @@ }); | ||
mfaChallenge = _a.sent(); | ||
// TODO need to check that the challenge is not expired | ||
if (!mfaChallenge || mfaChallenge.deactivated) { | ||
if (!mfaChallenge || !this.isMfaChallengeValid(mfaChallenge)) { | ||
throw new Error('Mfa token invalid'); | ||
@@ -172,2 +189,9 @@ } | ||
}; | ||
AccountsMFA.prototype.isMfaChallengeValid = function (mfaChallenge) { | ||
// TODO need to check that the challenge is not expired | ||
if (mfaChallenge.deactivated) { | ||
return false; | ||
} | ||
return true; | ||
}; | ||
return AccountsMFA; | ||
@@ -174,0 +198,0 @@ }()); |
@@ -23,5 +23,6 @@ import Emittery from 'emittery'; | ||
useInternalUserObjectSanitizer: boolean; | ||
enforceMfaForLogin: boolean; | ||
}; | ||
export declare class AccountsServer { | ||
options: AccountsServerOptions & typeof defaultOptions; | ||
export declare class AccountsServer<CustomUser extends User = User> { | ||
options: AccountsServerOptions<CustomUser> & typeof defaultOptions; | ||
mfa: AccountsMFA; | ||
@@ -32,4 +33,4 @@ private services; | ||
private hooks; | ||
constructor(options: AccountsServerOptions, services: { | ||
[key: string]: AuthenticationService; | ||
constructor(options: AccountsServerOptions<CustomUser>, services: { | ||
[key: string]: AuthenticationService<CustomUser>; | ||
}, authenticators?: { | ||
@@ -70,3 +71,3 @@ [key: string]: AuthenticatorService; | ||
*/ | ||
loginWithUser(user: User, infos: ConnectionInformations): Promise<LoginResult>; | ||
loginWithUser(user: CustomUser, infos: ConnectionInformations): Promise<LoginResult>; | ||
/** | ||
@@ -115,3 +116,3 @@ * @description Impersonate to another user. | ||
*/ | ||
resumeSession(accessToken: string): Promise<User>; | ||
resumeSession(accessToken: string): Promise<CustomUser>; | ||
/** | ||
@@ -129,3 +130,3 @@ * @description Find a session by his token. | ||
*/ | ||
findUserById(userId: string): Promise<User | null>; | ||
findUserById(userId: string): Promise<CustomUser | null>; | ||
/** | ||
@@ -143,4 +144,4 @@ * @description Deactivate a user, the user will not be able to login until his account is reactivated. | ||
activateUser(userId: string): Promise<void>; | ||
prepareMail(to: string, token: string, user: User, pathFragment: string, emailTemplate: EmailTemplateType, from: string): any; | ||
sanitizeUser(user: User): User; | ||
prepareMail(to: string, token: string, user: CustomUser, pathFragment: string, emailTemplate: EmailTemplateType, from: string): any; | ||
sanitizeUser(user: CustomUser): CustomUser; | ||
/** | ||
@@ -147,0 +148,0 @@ * Private methods |
@@ -30,2 +30,3 @@ "use strict"; | ||
useInternalUserObjectSanitizer: true, | ||
enforceMfaForLogin: false, | ||
}; | ||
@@ -135,3 +136,3 @@ var AccountsServer = /** @class */ (function () { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var hooksInfo, mfaToken, mfaChallenge, authenticator, user_1, loginResult_1, user, authenticators, activeAuthenticator, mfaChallengeToken, loginResult, err_2; | ||
var hooksInfo, mfaToken, mfaChallenge, authenticator, user_1, loginResult_1, user, authenticators, activeAuthenticator, mfaChallengeToken, mfaChallengeToken, loginResult, err_2; | ||
return tslib_1.__generator(this, function (_a) { | ||
@@ -150,3 +151,3 @@ switch (_a.label) { | ||
case 1: | ||
_a.trys.push([1, 18, , 19]); | ||
_a.trys.push([1, 20, , 21]); | ||
if (!(serviceName === 'mfa')) return [3 /*break*/, 11]; | ||
@@ -235,18 +236,29 @@ mfaToken = params.mfaToken; | ||
return [2 /*return*/, { mfaToken: mfaChallengeToken }]; | ||
case 15: | ||
case 15: | ||
if (!this.options.enforceMfaForLogin) return [3 /*break*/, 17]; | ||
mfaChallengeToken = tokens_1.generateRandomToken(); | ||
return [4 /*yield*/, this.db.createMfaChallenge({ | ||
userId: user.id, | ||
token: mfaChallengeToken, | ||
scope: 'associate', | ||
})]; | ||
case 16: | ||
_a.sent(); | ||
return [2 /*return*/, { mfaToken: mfaChallengeToken }]; | ||
case 17: | ||
// Let the user validate the login attempt | ||
return [4 /*yield*/, this.hooks.emitSerial(server_hooks_1.ServerHooks.ValidateLogin, hooksInfo)]; | ||
case 16: | ||
case 18: | ||
// Let the user validate the login attempt | ||
_a.sent(); | ||
return [4 /*yield*/, this.loginWithUser(user, infos)]; | ||
case 17: | ||
case 19: | ||
loginResult = _a.sent(); | ||
this.hooks.emit(server_hooks_1.ServerHooks.LoginSuccess, hooksInfo); | ||
return [2 /*return*/, loginResult]; | ||
case 18: | ||
case 20: | ||
err_2 = _a.sent(); | ||
this.hooks.emit(server_hooks_1.ServerHooks.LoginError, tslib_1.__assign(tslib_1.__assign({}, hooksInfo), { error: err_2 })); | ||
throw err_2; | ||
case 19: return [2 /*return*/]; | ||
case 21: return [2 /*return*/]; | ||
} | ||
@@ -253,0 +265,0 @@ }); |
@@ -9,3 +9,3 @@ import * as jwt from 'jsonwebtoken'; | ||
import { TokenCreator } from './token-creator'; | ||
export interface AccountsServerOptions { | ||
export interface AccountsServerOptions<CustomUser extends User = User> { | ||
/** | ||
@@ -15,3 +15,3 @@ * Return ambiguous error messages from login failures to prevent user enumeration. Defaults to true. | ||
ambiguousErrorMessages?: boolean; | ||
db?: DatabaseInterface; | ||
db?: DatabaseInterface<CustomUser>; | ||
tokenSecret: string | { | ||
@@ -47,2 +47,7 @@ publicKey: jwt.Secret; | ||
useInternalUserObjectSanitizer?: boolean; | ||
/** | ||
* If set to true, the user will be asked to register a new MFA authenticator the first time | ||
* he tries to login. | ||
*/ | ||
enforceMfaForLogin?: boolean; | ||
} |
{ | ||
"name": "@accounts/server", | ||
"version": "0.26.0-alpha.2", | ||
"version": "0.26.0-alpha.3", | ||
"description": "Fullstack authentication and accounts-management", | ||
@@ -43,3 +43,3 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"@accounts/types": "^0.26.0-alpha.2", | ||
"@accounts/types": "^0.26.0-alpha.3", | ||
"@types/jsonwebtoken": "8.3.5", | ||
@@ -59,3 +59,3 @@ "emittery": "0.5.1", | ||
}, | ||
"gitHead": "ad0914817551b832a11600613981ae5dba11c09d" | ||
"gitHead": "c117b8980f2153d497be744f1280bb2db2470514" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
105027
1652