@accounts/magic-link
Version:
[](https://www.npmjs.com/package/@accounts/magic-link) [](https://www.npmjs.com/package/@accounts/magic-link) [;
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