mirror of
https://github.com/documenso/documenso.git
synced 2026-07-27 02:15:05 +10:00
chore: disabled account enforcement (#2882)
This commit is contained in:
@@ -30,6 +30,7 @@ import { renderEmailWithI18N } from '../../utils/render-email-with-i18n';
|
||||
import { assertOrgEmailSendAllowed } from '../email/assert-org-email-send-allowed';
|
||||
import { getEmailContext } from '../email/get-email-context';
|
||||
import { getEnvelopeWhereInput } from '../envelope/get-envelope-by-id';
|
||||
import { assertUserNotDisabled } from '../user/assert-user-not-disabled';
|
||||
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
||||
|
||||
export type ResendDocumentOptions = {
|
||||
@@ -49,9 +50,14 @@ export const resendDocument = async ({ id, userId, recipients, teamId, requestMe
|
||||
id: true,
|
||||
email: true,
|
||||
name: true,
|
||||
disabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Refuse to resend on behalf of a disabled account. Guards
|
||||
// document.redistribute / envelope.redistribute and the API v1 equivalent.
|
||||
assertUserNotDisabled(user);
|
||||
|
||||
const { envelopeWhereInput } = await getEnvelopeWhereInput({
|
||||
id,
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
|
||||
@@ -39,6 +39,7 @@ import { toCheckboxCustomText, toRadioCustomText } from '../../utils/fields';
|
||||
import { getRecipientsWithMissingFields, isRecipientEmailValidForSending } from '../../utils/recipients';
|
||||
import { getEnvelopeWhereInput } from '../envelope/get-envelope-by-id';
|
||||
import { insertFormValuesInPdf } from '../pdf/insert-form-values-in-pdf';
|
||||
import { assertUserNotDisabledById } from '../user/assert-user-not-disabled';
|
||||
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
||||
|
||||
export type SendDocumentOptions = {
|
||||
@@ -50,6 +51,11 @@ export type SendDocumentOptions = {
|
||||
};
|
||||
|
||||
export const sendDocument = async ({ id, userId, teamId, sendEmail, requestMetadata }: SendDocumentOptions) => {
|
||||
// Refuse to send on behalf of a disabled account. Guards distribute /
|
||||
// redistribute / template-use routes, the bulk-send job, and direct
|
||||
// templates that auto-send on creation.
|
||||
await assertUserNotDisabledById({ userId });
|
||||
|
||||
const { envelopeWhereInput } = await getEnvelopeWhereInput({
|
||||
id,
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
|
||||
@@ -37,6 +37,7 @@ import { createDocumentAuthOptions, createRecipientAuthOptions } from '../../uti
|
||||
import { buildTeamWhereQuery } from '../../utils/teams';
|
||||
import { incrementDocumentId, incrementTemplateId } from '../envelope/increment-id';
|
||||
import { getTeamSettings } from '../team/get-team-settings';
|
||||
import { assertUserNotDisabledById } from '../user/assert-user-not-disabled';
|
||||
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
||||
|
||||
type CreateEnvelopeRecipientFieldOptions = TFieldAndMeta & {
|
||||
@@ -116,6 +117,11 @@ export const createEnvelope = async ({
|
||||
internalVersion,
|
||||
bypassDefaultRecipients = false,
|
||||
}: CreateEnvelopeOptions) => {
|
||||
// Refuse to create on behalf of a disabled account. Guards every route that
|
||||
// funnels through here (document.create, envelope.use, template create,
|
||||
// embedding template/document create, API v1) and the seed/job paths.
|
||||
await assertUserNotDisabledById({ userId });
|
||||
|
||||
const {
|
||||
type,
|
||||
title,
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
|
||||
/**
|
||||
* Throws if the supplied user object is disabled.
|
||||
*
|
||||
* Synchronous variant for hot paths where the `disabled` field has already
|
||||
* been loaded (e.g. TRPC middleware where the user comes from the session
|
||||
* query or API token lookup).
|
||||
*/
|
||||
export const assertUserNotDisabled = (user: { disabled: boolean }): void => {
|
||||
if (user.disabled) {
|
||||
throw new AppError('ACCOUNT_DISABLED', {
|
||||
message: 'Account disabled',
|
||||
statusCode: 403,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export type AssertUserNotDisabledByIdOptions = {
|
||||
userId: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Throws if the user with the given id does not exist or is disabled.
|
||||
*
|
||||
* Used as a defence-in-depth guard for sign-in chokepoints and server-side
|
||||
* actions that should not be performed on behalf of a disabled account
|
||||
* (e.g. creating or sending documents). It deliberately re-queries from the
|
||||
* database rather than relying on cached context so a freshly-disabled user
|
||||
* cannot continue to act through a stale session or token.
|
||||
*/
|
||||
export const assertUserNotDisabledById = async ({ userId }: AssertUserNotDisabledByIdOptions): Promise<void> => {
|
||||
const user = await prisma.user.findFirst({
|
||||
where: { id: userId },
|
||||
select: { disabled: true },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
message: 'User not found',
|
||||
statusCode: 404,
|
||||
});
|
||||
}
|
||||
|
||||
assertUserNotDisabled(user);
|
||||
};
|
||||
Reference in New Issue
Block a user