UNPKG

@accounts/magic-link

Version:

[![npm](https://img.shields.io/npm/v/@accounts/magic-link)](https://www.npmjs.com/package/@accounts/magic-link) [![npm downloads](https://img.shields.io/npm/dm/@accounts/magic-link)](https://www.npmjs.com/package/@accounts/magic-link) [![codecov](https://

90 lines 4.02 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const server_1 = require("@accounts/server"); const types_1 = require("./types"); const errors_1 = require("./errors"); const validation_1 = require("./utils/validation"); const errors_2 = require("./errors"); const user_1 = require("./utils/user"); const graphql_modules_1 = require("graphql-modules"); const defaultOptions = { errors: errors_1.errors, // 15 minutes - 15 * 60 * 1000 loginTokenExpiration: 900000, }; let AccountsMagicLink = class AccountsMagicLink { serviceName = 'magicLink'; server; options; db; constructor(options = {}, server, db) { this.options = { ...defaultOptions, ...options }; if (db) { this.db = db; } if (server) { this.server = server; } } setUserStore(store) { this.db = store; } setSessionsStore() { // Empty } async requestMagicLinkEmail(email) { if (!email || !(0, validation_1.isString)(email)) { throw new server_1.AccountsJsError(this.options.errors.invalidEmail, errors_2.RequestMagicLinkEmailErrors.InvalidEmail); } const user = await this.db.findUserByEmail(email); if (!user) { throw new server_1.AccountsJsError(this.options.errors.userNotFound, errors_2.RequestMagicLinkEmailErrors.UserNotFound); } // Remove pre-existing login tokens on user await this.db.removeAllLoginTokens(user.id); const token = (0, server_1.generateRandomToken)(); await this.db.addLoginToken(user.id, email, token); const requestMagicLinkMail = this.server.prepareMail(email, token, this.server.sanitizeUser(user), 'magiclink', this.server.options.emailTemplates.magicLink, this.server.options.emailTemplates.from); await this.server.options.sendMail(requestMagicLinkMail); } async authenticate(params) { const { token } = params; if (!token) { throw new server_1.AccountsJsError(this.options.errors.unrecognizedOptionsForLogin, errors_1.AuthenticateErrors.UnrecognizedOptionsForLogin); } if (!(0, validation_1.isString)(token)) { throw new server_1.AccountsJsError(this.options.errors.matchFailed, errors_1.AuthenticateErrors.MatchFailed); } const foundUser = await this.magicLinkAuthenticator(token); // Remove all login tokens for user after login await this.db.removeAllLoginTokens(foundUser.id); return foundUser; } isTokenExpired(tokenRecord, expiryDate) { return Number(tokenRecord.when) + expiryDate < Date.now(); } async magicLinkAuthenticator(token) { const foundUser = await this.db.findUserByLoginToken(token); if (!foundUser) { throw new server_1.AccountsJsError(this.options.errors.loginTokenExpired, errors_1.MagicLinkAuthenticatorErrors.LoginTokenExpired); } const loginTokens = (0, user_1.getUserLoginTokens)(foundUser); const tokenRecord = loginTokens.find((t) => t.token === token); if (!tokenRecord || this.isTokenExpired(tokenRecord, this.options.loginTokenExpiration)) { throw new server_1.AccountsJsError(this.options.errors.loginTokenExpired, errors_1.MagicLinkAuthenticatorErrors.LoginTokenExpired); } return foundUser; } }; AccountsMagicLink = tslib_1.__decorate([ (0, graphql_modules_1.Injectable)({ global: true, }), tslib_1.__param(0, (0, graphql_modules_1.Inject)(types_1.AccountsMagicLinkConfigToken)), tslib_1.__param(1, (0, graphql_modules_1.Inject)(server_1.AccountsServer)), tslib_1.__param(2, (0, graphql_modules_1.Inject)(server_1.DatabaseInterfaceUserToken)), tslib_1.__metadata("design:paramtypes", [Object, server_1.AccountsServer, Object]) ], AccountsMagicLink); exports.default = AccountsMagicLink; //# sourceMappingURL=accounts-magic-link.js.map