@tsed/formio
Version:
Formio package for Ts.ED framework
229 lines (192 loc) • 5.3 kB
text/typescript
import {promisify} from "node:util";
import {isFunction} from "@tsed/core";
import {Inject, Injectable} from "@tsed/di";
import {BadRequest, NotFound, Unauthorized} from "@tsed/exceptions";
import {PlatformContext, Req} from "@tsed/platform-http";
import {FormioPayloadToken} from "../domain/FormioDecodedToken.js";
import {FormioForm, FormioSubmission, WithID} from "../domain/FormioModels.js";
import {FormioDatabase} from "./FormioDatabase.js";
import {FormioHooksService} from "./FormioHooksService.js";
import {FormioService} from "./FormioService.js";
export class FormioAuthService {
formio: FormioService;
hooks: FormioHooksService;
db: FormioDatabase;
get currentUser() {
return promisify(this.formio.auth.currentUser);
}
get getToken() {
return this.formio.auth.getToken;
}
get tempToken() {
return this.formio.auth.tempToken;
}
get logout() {
return this.formio.auth.logout;
}
setCurrentUser<User = any>(user: WithID<FormioSubmission<User>>, token: FormioPayloadToken, ctx: PlatformContext) {
const request = ctx.getRequest();
const response = ctx.getResponse();
request.submission.data = user.data;
request.user = user;
request.token = token.decoded;
response.token = token.token;
request["x-jwt-token"] = token.token;
return this;
}
/**
* Generate the payload token for the session
* @param user
* @param ctx
*/
async generatePayloadToken<User = any>(
user: WithID<FormioSubmission<User>>,
ctx: PlatformContext
): Promise<{user: WithID<FormioSubmission<User>>; token: FormioPayloadToken}> {
const req = ctx.getRequest();
const audit = this.formio.audit;
let form: FormioForm | null;
try {
form = (await this.db.getForm(user.form)) as any;
} catch (err) {
audit(
"EAUTH_USERFORM",
{
...req,
userId: user._id
},
user.form,
err
);
throw err;
}
if (!form) {
audit(
"EAUTH_USERFORM",
{
...req,
userId: user._id
},
user.form,
{message: "User form not found"}
);
throw new NotFound("User form not found.");
}
try {
user = await this.hooks.alterAsync("user", user);
} catch (err) {
// istanbul ignore next
ctx.logger.debug(err);
}
await this.hooks.alterAsync("login", user, req);
// Allow anyone to hook and modify the token.
const token = this.hooks.alter(
"token",
{
user: {
_id: user._id
},
form: {
_id: form?._id
}
},
form,
req
);
const decoded = this.hooks.alter("tokenDecode", token, req);
return {
user,
token: {
token: this.getToken(token) as string,
decoded
}
};
}
/**
* Generate session from the given authenticated user.
* @param user
* @param ctx
*/
async generateSession<User = any>(user: WithID<FormioSubmission<User>>, ctx: PlatformContext) {
try {
const {user: userSession, token} = await this.generatePayloadToken(user, ctx);
this.setCurrentUser(userSession, token, ctx);
await this.currentUser(ctx.getRequest(), ctx.getResponse());
} catch (err) {
ctx.logger.error({event: "Error on OAuthActions", error: err});
throw new Unauthorized(err.message);
}
}
/**
* Retrieve roles
* @param req
*/
async getRoles(req?: Req) {
try {
const query = this.hooks.alter("roleQuery", {deleted: {$eq: null}}, req);
return await this.db.roleModel.find(query).sort({title: 1}).lean().exec();
} catch (err) {
throw new BadRequest(this.formio.util.errorCodes.role.EROLESLOAD);
}
}
/**
* Update the role of the current user submission
* @param _id
* @param role
* @param req
*/
async updateUserRole(_id: string | any, role: string, req?: Req) {
const query = this.hooks.alter(
"submissionQuery",
{
_id: this.formio.util.idToBson(_id),
deleted: {$eq: null}
},
req
);
const user = await this.db.submissionModel.findOne(query).exec();
if (!user) {
throw new BadRequest("No Submission was found with the given setting `submission`.");
}
user.roles = [this.formio.util.idToBson(role)];
if (isFunction(user.save)) {
await user.save();
}
return user;
}
/**
* Create a user submission in formio
* @param user
*/
async createUser<User = any>(user: Partial<FormioSubmission<User>>) {
const submission = new this.db.submissionModel({
owner: null,
deleted: null,
roles: [],
externalsIds: [],
...user,
created: new Date().toISOString(),
modified: new Date().toISOString()
});
user.form && (submission.form = this.db.idToBson(user.form));
await submission.save();
return submission.toObject();
}
/**
* Update user submission in formio
* @param user
*/
async updateUser<User = any>(user: WithID<FormioSubmission<User>>) {
await this.db.submissionModel.updateOne(
{
_id: user._id
},
{$set: user}
);
return user;
}
}