@accounts/mikro-orm
Version:
MikroORM adaptor for accounts
286 lines • 10.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AccountsMikroOrm = void 0;
const tslib_1 = require("tslib");
const User_1 = require("./entity/User");
const Email_1 = require("./entity/Email");
const Service_1 = require("./entity/Service");
const Session_1 = require("./entity/Session");
const types_1 = require("./types");
const core_1 = require("@mikro-orm/core");
const graphql_modules_1 = require("graphql-modules");
const lodash_1 = require("lodash");
const hasPassword = (opt) => !!opt.bcrypt;
const toUser = async (user) => user && {
...user,
id: String(user.id),
emails: await user.emails.loadItems(),
services: (await user.services.loadItems()).reduce((acc, { name, token, options }) => {
const multi = ['email.verificationTokens', 'password.reset'];
(0, lodash_1.set)(acc, name, multi.includes(name)
? ((0, lodash_1.get)(acc, name) ?? []).concat({ token, ...options })
: { ...(0, lodash_1.get)(acc, name), token, ...options });
return acc;
}, {}),
};
const toSession = async (session) => session && {
...session,
id: String(session.id),
userId: String(session.user.id), //FIXME
createdAt: session.createdAt.toDateString(),
updatedAt: session.updatedAt.toDateString(),
};
let AccountsMikroOrm = class AccountsMikroOrm {
context;
get em() {
const em = core_1.RequestContext.getEntityManager() ??
this.context?.em ??
this.context?.injector.get(core_1.EntityManager);
if (!em) {
throw new Error('Cannot find EntityManager');
}
return em;
}
UserEntity;
EmailEntity = Email_1.Email;
ServiceEntity = Service_1.Service;
SessionEntity = Session_1.Session;
get userRepository() {
return this.em.getRepository(this.UserEntity);
}
get emailRepository() {
return this.em.getRepository(this.EmailEntity);
}
get serviceRepository() {
return this.em.getRepository(this.ServiceEntity);
}
get sessionRepository() {
return this.em.getRepository(this.SessionEntity);
}
constructor(EmailEntity, ServiceEntity, SessionEntity, UserEntity) {
if (EmailEntity) {
this.EmailEntity = EmailEntity;
}
if (ServiceEntity) {
this.ServiceEntity = ServiceEntity;
}
if (SessionEntity) {
this.SessionEntity = SessionEntity;
}
this.UserEntity = (0, User_1.getUserCtor)({
EmailEntity: this.EmailEntity,
ServiceEntity: this.ServiceEntity,
});
if (UserEntity) {
this.UserEntity = UserEntity;
}
}
async findUserByEmail(email) {
return toUser(await this.userRepository.findOne({
emails: {
address: email.toLocaleLowerCase(),
},
}));
}
async findUserByUsername(username) {
return toUser(await this.userRepository.findOne({ username }));
}
async findUserById(userId) {
return toUser(await this.userRepository.findOne(Number(userId)));
}
async findUserByResetPasswordToken(token) {
return toUser(await this.userRepository.findOne({
services: {
name: 'password.reset',
token,
},
}));
}
async findUserByEmailVerificationToken(token) {
return toUser(await this.userRepository.findOne({
services: {
name: 'email.verificationTokens',
token,
},
}));
}
async createUser({ username, email, password, ...otherFields }) {
const user = new this.UserEntity({
email,
password,
username,
...otherFields,
});
await this.em.persistAndFlush(user);
return String(user.id);
}
async setUsername(userId, newUsername) {
const user = await this.userRepository.findOneOrFail(Number(userId));
user.username = newUsername;
await this.em.flush();
}
async findUserByServiceId(serviceName, serviceId) {
return toUser(await this.userRepository.findOne({ services: Number(serviceId) }));
}
async setService(userId, serviceName, data, token, flush = true) {
const service = (await this.serviceRepository.findOne({
name: serviceName,
user: Number(userId),
})) ??
new this.ServiceEntity({
name: serviceName,
user: this.em.getReference(this.UserEntity, Number(userId), { wrapped: true }),
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { id, ...options } = data;
service.options = options;
if (token) {
service.token = token;
}
this.em.persist(service);
if (flush) {
return this.em.flush();
}
}
async unsetService(userId, serviceName) {
this.em.remove(await this.serviceRepository.findOneOrFail({
name: serviceName,
user: Number(userId),
}));
return this.em.flush();
}
async findPasswordHash(userId) {
const service = await this.serviceRepository.findOne({
name: 'password',
user: Number(userId),
});
return service?.options && hasPassword(service.options) ? service.options.bcrypt : null;
}
async setPassword(userId, newPassword, flush = true) {
return await this.setService(userId, 'password', { bcrypt: newPassword }, undefined, flush);
}
async addResetPasswordToken(userId, email, token, reason) {
await this.setService(userId, 'password.reset', {
address: email.toLocaleLowerCase(),
when: new Date().toJSON(),
reason,
}, token);
}
async setResetPassword(userId, email, newPassword) {
await this.setPassword(userId, newPassword, false);
return this.unsetService(userId, 'password.reset');
}
async addEmail(userId, newEmail, verified) {
return this.em.persistAndFlush(new this.EmailEntity({
user: this.em.getReference(this.UserEntity, Number(userId), { wrapped: true }),
address: newEmail,
verified,
}));
}
async removeEmail(userId, email) {
try {
this.em.remove(await this.emailRepository.findOneOrFail({
address: email.toLocaleLowerCase(),
}));
}
catch {
throw new Error('Email not found');
}
return this.em.flush();
}
async verifyEmail(userId, email) {
const userEmail = await this.emailRepository.findOneOrFail({
address: email.toLocaleLowerCase(),
});
userEmail.verified = true;
return this.unsetService(userId, 'email.verificationTokens');
}
async addEmailVerificationToken(userId, email, token) {
await this.setService(userId, 'email.verificationTokens', {
address: email.toLocaleLowerCase(),
when: new Date(),
}, token);
}
async removeAllResetPasswordTokens(userId) {
await this.unsetService(userId, 'password.reset');
}
async setUserDeactivated(userId, deactivated) {
const user = await this.userRepository.findOneOrFail(Number(userId));
user.deactivated = deactivated;
return this.em.flush();
}
async findSessionById(sessionId) {
return toSession(await this.sessionRepository.findOne(Number(sessionId)));
}
async findSessionByToken(token) {
return toSession(await this.sessionRepository.findOne({ token }));
}
async findUserByLoginToken(token) {
const service = await this.serviceRepository.findOne({
name: 'magicLink.loginTokens',
token,
});
if (service) {
return this.findUserById(service.user.id); //FIXME
}
return null;
}
async addLoginToken(userId, email, token) {
await this.setService(userId, 'magicLink.loginTokens', {
address: email.toLocaleLowerCase(),
when: new Date().toJSON(),
}, token);
}
async removeAllLoginTokens(userId) {
await this.unsetService(userId, 'magicLink.loginTokens');
}
async createSession(userId, token, connection = {}, extra) {
const session = new this.SessionEntity({
user: this.em.getReference(this.UserEntity, Number(userId), { wrapped: true }),
token,
userAgent: connection.userAgent,
ip: connection.ip,
extra,
valid: true,
});
await this.em.persistAndFlush(session);
return String(session.id);
}
async updateSession(sessionId, connection) {
const session = await this.sessionRepository.findOneOrFail(Number(sessionId));
session.userAgent = connection.userAgent ?? undefined;
session.ip = connection.ip ?? undefined;
return this.em.flush();
}
async invalidateSession(sessionId) {
const session = await this.sessionRepository.findOneOrFail(Number(sessionId));
session.valid = false;
return this.em.flush();
}
async invalidateAllSessions(userId, excludedSessionIds) {
const sessions = await this.sessionRepository.find({
user: this.em.getReference(this.UserEntity, Number(userId), { wrapped: true }),
...(excludedSessionIds?.length && {
id: { $nin: excludedSessionIds.map((id) => Number(id)) },
}),
});
sessions.forEach((session) => (session.valid = false));
return this.em.flush();
}
};
exports.AccountsMikroOrm = AccountsMikroOrm;
tslib_1.__decorate([
(0, graphql_modules_1.ExecutionContext)(),
tslib_1.__metadata("design:type", Object)
], AccountsMikroOrm.prototype, "context", void 0);
exports.AccountsMikroOrm = AccountsMikroOrm = tslib_1.__decorate([
(0, graphql_modules_1.Injectable)({
global: true,
}),
tslib_1.__param(0, (0, graphql_modules_1.Inject)(types_1.EmailToken)),
tslib_1.__param(1, (0, graphql_modules_1.Inject)(types_1.ServiceToken)),
tslib_1.__param(2, (0, graphql_modules_1.Inject)(types_1.SessionToken)),
tslib_1.__param(3, (0, graphql_modules_1.Inject)(types_1.UserToken)),
tslib_1.__metadata("design:paramtypes", [Object, Object, Object, Object])
], AccountsMikroOrm);
//# sourceMappingURL=mikro-orm.js.map