mirror of
https://github.com/documenso/documenso.git
synced 2026-06-22 04:12:06 +10:00
feat: add granular signup disable flags (#2765)
This commit is contained in:
+9
-1
@@ -160,8 +160,16 @@ NEXT_PRIVATE_REDIS_PREFIX="documenso"
|
|||||||
NEXT_PUBLIC_POSTHOG_KEY=""
|
NEXT_PUBLIC_POSTHOG_KEY=""
|
||||||
# OPTIONAL: Leave blank to disable billing.
|
# OPTIONAL: Leave blank to disable billing.
|
||||||
NEXT_PUBLIC_FEATURE_BILLING_ENABLED=
|
NEXT_PUBLIC_FEATURE_BILLING_ENABLED=
|
||||||
# OPTIONAL: Leave blank to allow users to signup through /signup page.
|
# OPTIONAL: Set to "true" to disable all signup methods (email, Google, Microsoft, OIDC, including the organisation OIDC portal).
|
||||||
NEXT_PUBLIC_DISABLE_SIGNUP=
|
NEXT_PUBLIC_DISABLE_SIGNUP=
|
||||||
|
# OPTIONAL: Set to "true" to disable email/password signup only.
|
||||||
|
NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP=
|
||||||
|
# OPTIONAL: Set to "true" to block new-account creation through Google. Existing linked users can still sign in.
|
||||||
|
NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP=
|
||||||
|
# OPTIONAL: Set to "true" to block new-account creation through Microsoft. Existing linked users can still sign in.
|
||||||
|
NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP=
|
||||||
|
# OPTIONAL: Set to "true" to block new-account creation through OIDC (including the organisation portal).
|
||||||
|
NEXT_PUBLIC_DISABLE_OIDC_SIGNUP=
|
||||||
# OPTIONAL: Comma-separated list of email domains allowed to sign up (e.g., example.com,acme.org).
|
# OPTIONAL: Comma-separated list of email domains allowed to sign up (e.g., example.com,acme.org).
|
||||||
NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS=
|
NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS=
|
||||||
# OPTIONAL: Set to true to use internal webapp url in browserless requests.
|
# OPTIONAL: Set to true to use internal webapp url in browserless requests.
|
||||||
|
|||||||
@@ -225,27 +225,40 @@ For detailed certificate setup, see [Signing Certificate](/docs/self-hosting/con
|
|||||||
## Feature Flags
|
## Feature Flags
|
||||||
|
|
||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
| ------------------------------------- | ----------------------------------------------------------------------------------- | ------- |
|
| -------------------------------------------- | ----------------------------------------------------------------------------------- | ------- |
|
||||||
| `NEXT_PUBLIC_DISABLE_SIGNUP` | Disable public user registration entirely | `false` |
|
| `NEXT_PUBLIC_DISABLE_SIGNUP` | Master switch. Disable all signup methods application-wide | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP` | Disable email/password signup only. SSO signup is unaffected | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP` | Block new accounts via Google. Existing Google-linked users can still sign in | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP` | Block new accounts via Microsoft. Existing linked users can still sign in | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_OIDC_SIGNUP` | Block new accounts via OIDC, including the organisation portal | `false` |
|
||||||
| `NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS` | Comma-separated list of email domains allowed to sign up (e.g., `example.com,acme.org`) | |
|
| `NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS` | Comma-separated list of email domains allowed to sign up (e.g., `example.com,acme.org`) | |
|
||||||
| `NEXT_PUBLIC_POSTHOG_KEY` | PostHog API key for analytics and feature flags | |
|
| `NEXT_PUBLIC_POSTHOG_KEY` | PostHog API key for analytics and feature flags | |
|
||||||
| `NEXT_PUBLIC_FEATURE_BILLING_ENABLED` | Enable billing features | `false` |
|
| `NEXT_PUBLIC_FEATURE_BILLING_ENABLED` | Enable billing features | `false` |
|
||||||
|
|
||||||
### Signup Restrictions
|
### Signup Restrictions
|
||||||
|
|
||||||
You can control who is allowed to create accounts on your instance using two environment variables:
|
You can control who is allowed to create accounts on your instance with the following environment variables:
|
||||||
|
|
||||||
- **`NEXT_PUBLIC_DISABLE_SIGNUP`**: Set to `true` to block all new signups. Existing users can still sign in. This applies to both email/password and OAuth signups.
|
- **`NEXT_PUBLIC_DISABLE_SIGNUP`** (master switch): Set to `true` to block all new signups across every method (email/password, Google, Microsoft, OIDC). When set, this also blocks new-account creation through the organisation OIDC authentication portal.
|
||||||
|
- **`NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP`**: Set to `true` to disable email/password signup only. SSO signup is still allowed.
|
||||||
|
- **`NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP`**, **`NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP`**, **`NEXT_PUBLIC_DISABLE_OIDC_SIGNUP`**: Set to `true` to block brand-new account creation through the matching SSO provider. Existing users with the provider already linked can still sign in, and existing users can still link the provider to their account. `NEXT_PUBLIC_DISABLE_OIDC_SIGNUP` also blocks new-account creation through the organisation authentication portal.
|
||||||
- **`NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS`**: Restrict signups to specific email domains. When set, only users whose email address matches one of the listed domains can create an account. Leave empty to allow all domains.
|
- **`NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS`**: Restrict signups to specific email domains. When set, only users whose email address matches one of the listed domains can create an account. Leave empty to allow all domains.
|
||||||
|
|
||||||
Both restrictions apply to email/password registration and OAuth (Google, Microsoft, OIDC). If a user attempts to sign up via OAuth with a disallowed domain, they are redirected to the sign-in page with an error.
|
Sign-in for existing users is never affected — only the creation of brand-new accounts.
|
||||||
|
|
||||||
When both variables are set, `NEXT_PUBLIC_DISABLE_SIGNUP` takes precedence. Signups are blocked regardless of the domain list.
|
Both the master switch and the domain allowlist apply to email/password registration and OAuth (Google, Microsoft, OIDC). If a user attempts to sign up via OAuth with a disallowed domain, they are redirected to the sign-in page with an error.
|
||||||
|
|
||||||
|
When both the master switch and the domain allowlist are set, the master switch takes precedence. Signups are blocked regardless of the domain list.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Allow signups only from specific domains
|
# Allow signups only from specific domains
|
||||||
NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS="example.com,acme.org"
|
NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS="example.com,acme.org"
|
||||||
|
|
||||||
|
# Allow OIDC signup only; block email/password, Google, Microsoft
|
||||||
|
NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP="true"
|
||||||
|
NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP="true"
|
||||||
|
NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP="true"
|
||||||
|
|
||||||
# Or disable signups entirely
|
# Or disable signups entirely
|
||||||
NEXT_PUBLIC_DISABLE_SIGNUP="true"
|
NEXT_PUBLIC_DISABLE_SIGNUP="true"
|
||||||
```
|
```
|
||||||
@@ -371,6 +384,10 @@ NEXT_PRIVATE_SIGNING_PASSPHRASE="your-certificate-password"
|
|||||||
|
|
||||||
# Signup restrictions (optional)
|
# Signup restrictions (optional)
|
||||||
# NEXT_PUBLIC_DISABLE_SIGNUP="true"
|
# NEXT_PUBLIC_DISABLE_SIGNUP="true"
|
||||||
|
# NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP="true"
|
||||||
|
# NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP="true"
|
||||||
|
# NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP="true"
|
||||||
|
# NEXT_PUBLIC_DISABLE_OIDC_SIGNUP="true"
|
||||||
# NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS="example.com,acme.org"
|
# NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS="example.com,acme.org"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -155,7 +155,13 @@ PORT=3000
|
|||||||
NEXT_PRIVATE_SIGNING_PASSPHRASE=your-certificate-password
|
NEXT_PRIVATE_SIGNING_PASSPHRASE=your-certificate-password
|
||||||
|
|
||||||
# Signup restrictions (optional)
|
# Signup restrictions (optional)
|
||||||
|
# Master switch — disables every signup method
|
||||||
NEXT_PUBLIC_DISABLE_SIGNUP=false
|
NEXT_PUBLIC_DISABLE_SIGNUP=false
|
||||||
|
# Per-method switches (optional). Each disables brand-new account creation through that method.
|
||||||
|
# NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP=true
|
||||||
|
# NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP=true
|
||||||
|
# NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP=true
|
||||||
|
# NEXT_PUBLIC_DISABLE_OIDC_SIGNUP=true
|
||||||
# NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS=example.com,acme.org
|
# NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS=example.com,acme.org
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -252,7 +258,10 @@ Navigate to the signup page and create your account. Verify your email address
|
|||||||
<Callout type="info">
|
<Callout type="info">
|
||||||
All accounts created through signup are regular user accounts. Admin access must be granted
|
All accounts created through signup are regular user accounts. Admin access must be granted
|
||||||
directly in the database. Once your accounts are set up, consider disabling public signups by
|
directly in the database. Once your accounts are set up, consider disabling public signups by
|
||||||
setting `NEXT_PUBLIC_DISABLE_SIGNUP=true`, or restrict signups to specific email domains with
|
setting `NEXT_PUBLIC_DISABLE_SIGNUP=true`. For finer control, use the per-method switches
|
||||||
|
`NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP`, `NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP`,
|
||||||
|
`NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP`, `NEXT_PUBLIC_DISABLE_OIDC_SIGNUP`, or restrict
|
||||||
|
signups to specific email domains with
|
||||||
`NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS`.
|
`NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS`.
|
||||||
</Callout>
|
</Callout>
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,11 @@ See [Email Configuration](/docs/self-hosting/configuration/email) for other tran
|
|||||||
| `NEXT_PRIVATE_SIGNING_PASSPHRASE` | Passphrase for the signing certificate | - |
|
| `NEXT_PRIVATE_SIGNING_PASSPHRASE` | Passphrase for the signing certificate | - |
|
||||||
| `NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS` | Base64-encoded `.p12` certificate (alternative to file path) | - |
|
| `NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS` | Base64-encoded `.p12` certificate (alternative to file path) | - |
|
||||||
| `NEXT_PUBLIC_UPLOAD_TRANSPORT` | Document storage: `database` or `s3` | `database` |
|
| `NEXT_PUBLIC_UPLOAD_TRANSPORT` | Document storage: `database` or `s3` | `database` |
|
||||||
| `NEXT_PUBLIC_DISABLE_SIGNUP` | Disable public signups | `false` |
|
| `NEXT_PUBLIC_DISABLE_SIGNUP` | Master switch — disable all signup methods | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP` | Disable email/password signup only | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP` | Block new accounts via Google OAuth | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP` | Block new accounts via Microsoft OAuth | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_OIDC_SIGNUP` | Block new accounts via OIDC (incl. organisation portal) | `false` |
|
||||||
| `NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS` | Comma-separated list of allowed signup email domains | |
|
| `NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS` | Comma-separated list of allowed signup email domains | |
|
||||||
|
|
||||||
For the complete list, see [Environment Variables](/docs/self-hosting/configuration/environment).
|
For the complete list, see [Environment Variables](/docs/self-hosting/configuration/environment).
|
||||||
|
|||||||
@@ -153,7 +153,11 @@ NEXT_PRIVATE_SMTP_FROM_ADDRESS=noreply@yourdomain.com
|
|||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
| --------------------------------- | ---------------------------------- | ------- |
|
| --------------------------------- | ---------------------------------- | ------- |
|
||||||
| `PORT` | Application port | `3000` |
|
| `PORT` | Application port | `3000` |
|
||||||
| `NEXT_PUBLIC_DISABLE_SIGNUP` | Disable public signups | `false` |
|
| `NEXT_PUBLIC_DISABLE_SIGNUP` | Master switch — disable all signup methods | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP` | Disable email/password signup only | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP` | Block new accounts via Google OAuth | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP`| Block new accounts via Microsoft OAuth | `false` |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_OIDC_SIGNUP` | Block new accounts via OIDC (incl. organisation portal)| `false` |
|
||||||
| `NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS` | Comma-separated list of allowed signup email domains | |
|
| `NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS` | Comma-separated list of allowed signup email domains | |
|
||||||
| `NEXT_PRIVATE_SIGNING_PASSPHRASE` | Passphrase for signing certificate | - |
|
| `NEXT_PRIVATE_SIGNING_PASSPHRASE` | Passphrase for signing certificate | - |
|
||||||
| `DOCUMENSO_DISABLE_TELEMETRY` | Disable anonymous telemetry | `false` |
|
| `DOCUMENSO_DISABLE_TELEMETRY` | Disable anonymous telemetry | `false` |
|
||||||
|
|||||||
@@ -58,18 +58,20 @@ export type TSignUpFormSchema = z.infer<typeof ZSignUpFormSchema>;
|
|||||||
export type SignUpFormProps = {
|
export type SignUpFormProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
initialEmail?: string;
|
initialEmail?: string;
|
||||||
isGoogleSSOEnabled?: boolean;
|
isEmailPasswordSignupEnabled?: boolean;
|
||||||
isMicrosoftSSOEnabled?: boolean;
|
isGoogleSignupEnabled?: boolean;
|
||||||
isOIDCSSOEnabled?: boolean;
|
isMicrosoftSignupEnabled?: boolean;
|
||||||
|
isOidcSignupEnabled?: boolean;
|
||||||
returnTo?: string;
|
returnTo?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SignUpForm = ({
|
export const SignUpForm = ({
|
||||||
className,
|
className,
|
||||||
initialEmail,
|
initialEmail,
|
||||||
isGoogleSSOEnabled,
|
isEmailPasswordSignupEnabled = true,
|
||||||
isMicrosoftSSOEnabled,
|
isGoogleSignupEnabled,
|
||||||
isOIDCSSOEnabled,
|
isMicrosoftSignupEnabled,
|
||||||
|
isOidcSignupEnabled,
|
||||||
returnTo,
|
returnTo,
|
||||||
}: SignUpFormProps) => {
|
}: SignUpFormProps) => {
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
@@ -86,7 +88,7 @@ export const SignUpForm = ({
|
|||||||
|
|
||||||
const [captchaToken, setCaptchaToken] = useState<string | null>(null);
|
const [captchaToken, setCaptchaToken] = useState<string | null>(null);
|
||||||
|
|
||||||
const hasSocialAuthEnabled = isGoogleSSOEnabled || isMicrosoftSSOEnabled || isOIDCSSOEnabled;
|
const hasSocialAuthEnabled = isGoogleSignupEnabled || isMicrosoftSignupEnabled || isOidcSignupEnabled;
|
||||||
|
|
||||||
const form = useForm<TSignUpFormSchema>({
|
const form = useForm<TSignUpFormSchema>({
|
||||||
values: {
|
values: {
|
||||||
@@ -145,7 +147,7 @@ export const SignUpForm = ({
|
|||||||
const onSignUpWithGoogleClick = async () => {
|
const onSignUpWithGoogleClick = async () => {
|
||||||
try {
|
try {
|
||||||
await authClient.google.signIn();
|
await authClient.google.signIn();
|
||||||
} catch (err) {
|
} catch {
|
||||||
toast({
|
toast({
|
||||||
title: _(msg`An unknown error occurred`),
|
title: _(msg`An unknown error occurred`),
|
||||||
description: _(msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`),
|
description: _(msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`),
|
||||||
@@ -157,7 +159,7 @@ export const SignUpForm = ({
|
|||||||
const onSignUpWithMicrosoftClick = async () => {
|
const onSignUpWithMicrosoftClick = async () => {
|
||||||
try {
|
try {
|
||||||
await authClient.microsoft.signIn();
|
await authClient.microsoft.signIn();
|
||||||
} catch (err) {
|
} catch {
|
||||||
toast({
|
toast({
|
||||||
title: _(msg`An unknown error occurred`),
|
title: _(msg`An unknown error occurred`),
|
||||||
description: _(msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`),
|
description: _(msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`),
|
||||||
@@ -169,7 +171,7 @@ export const SignUpForm = ({
|
|||||||
const onSignUpWithOIDCClick = async () => {
|
const onSignUpWithOIDCClick = async () => {
|
||||||
try {
|
try {
|
||||||
await authClient.oidc.signIn();
|
await authClient.oidc.signIn();
|
||||||
} catch (err) {
|
} catch {
|
||||||
toast({
|
toast({
|
||||||
title: _(msg`An unknown error occurred`),
|
title: _(msg`An unknown error occurred`),
|
||||||
description: _(msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`),
|
description: _(msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`),
|
||||||
@@ -235,6 +237,8 @@ export const SignUpForm = ({
|
|||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form className="flex w-full flex-1 flex-col gap-y-4" onSubmit={form.handleSubmit(onFormSubmit)}>
|
<form className="flex w-full flex-1 flex-col gap-y-4" onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||||
<fieldset className="flex w-full flex-col gap-y-4" disabled={isSubmitting}>
|
<fieldset className="flex w-full flex-col gap-y-4" disabled={isSubmitting}>
|
||||||
|
{isEmailPasswordSignupEnabled && (
|
||||||
|
<>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="name"
|
name="name"
|
||||||
@@ -294,13 +298,19 @@ export const SignUpForm = ({
|
|||||||
<Trans>Sign Here</Trans>
|
<Trans>Sign Here</Trans>
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SignaturePadDialog disabled={isSubmitting} value={value} onChange={(v) => onChange(v ?? '')} />
|
<SignaturePadDialog
|
||||||
|
disabled={isSubmitting}
|
||||||
|
value={value}
|
||||||
|
onChange={(v) => onChange(v ?? '')}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{turnstileSiteKey && (
|
{turnstileSiteKey && (
|
||||||
<Turnstile
|
<Turnstile
|
||||||
@@ -325,7 +335,7 @@ export const SignUpForm = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isGoogleSSOEnabled && (
|
{isGoogleSignupEnabled && (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
size="lg"
|
size="lg"
|
||||||
@@ -339,7 +349,7 @@ export const SignUpForm = ({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isMicrosoftSSOEnabled && (
|
{isMicrosoftSignupEnabled && (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
size="lg"
|
size="lg"
|
||||||
@@ -353,7 +363,7 @@ export const SignUpForm = ({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isOIDCSSOEnabled && (
|
{isOidcSignupEnabled && (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
size="lg"
|
size="lg"
|
||||||
@@ -377,9 +387,11 @@ export const SignUpForm = ({
|
|||||||
</p>
|
</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
{isEmailPasswordSignupEnabled && (
|
||||||
<Button loading={form.formState.isSubmitting} type="submit" size="lg" className="mt-6 w-full">
|
<Button loading={form.formState.isSubmitting} type="submit" size="lg" className="mt-6 w-full">
|
||||||
<Trans>Create account</Trans>
|
<Trans>Create account</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
<p className="mt-6 text-muted-foreground text-xs">
|
<p className="mt-6 text-muted-foreground text-xs">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import signingCelebration from '@documenso/assets/images/signing-celebration.png';
|
import signingCelebration from '@documenso/assets/images/signing-celebration.png';
|
||||||
import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session';
|
import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session';
|
||||||
import { useOptionalSession } from '@documenso/lib/client-only/providers/session';
|
import { useOptionalSession } from '@documenso/lib/client-only/providers/session';
|
||||||
|
import { isSignupEnabledForProvider } from '@documenso/lib/constants/auth';
|
||||||
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
|
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
|
||||||
import { isRecipientAuthorized } from '@documenso/lib/server-only/document/is-recipient-authorized';
|
import { isRecipientAuthorized } from '@documenso/lib/server-only/document/is-recipient-authorized';
|
||||||
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
|
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
|
||||||
@@ -8,7 +9,6 @@ import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-re
|
|||||||
import { getRecipientSignatures } from '@documenso/lib/server-only/recipient/get-recipient-signatures';
|
import { getRecipientSignatures } from '@documenso/lib/server-only/recipient/get-recipient-signatures';
|
||||||
import { getUserByEmail } from '@documenso/lib/server-only/user/get-user-by-email';
|
import { getUserByEmail } from '@documenso/lib/server-only/user/get-user-by-email';
|
||||||
import { isDocumentCompleted } from '@documenso/lib/utils/document';
|
import { isDocumentCompleted } from '@documenso/lib/utils/document';
|
||||||
import { env } from '@documenso/lib/utils/env';
|
|
||||||
import { trpc } from '@documenso/trpc/react';
|
import { trpc } from '@documenso/trpc/react';
|
||||||
import { DocumentShareButton } from '@documenso/ui/components/document/document-share-button';
|
import { DocumentShareButton } from '@documenso/ui/components/document/document-share-button';
|
||||||
import { SigningCard3D } from '@documenso/ui/components/signing-card';
|
import { SigningCard3D } from '@documenso/ui/components/signing-card';
|
||||||
@@ -77,7 +77,7 @@ export async function loader({ params, request }: Route.LoaderArgs) {
|
|||||||
const recipientName =
|
const recipientName =
|
||||||
recipient.name || fields.find((field) => field.type === FieldType.NAME)?.customText || recipient.email;
|
recipient.name || fields.find((field) => field.type === FieldType.NAME)?.customText || recipient.email;
|
||||||
|
|
||||||
const canSignUp = !isExistingUser && env('NEXT_PUBLIC_DISABLE_SIGNUP') !== 'true';
|
const canSignUp = !isExistingUser && isSignupEnabledForProvider('email');
|
||||||
|
|
||||||
const canRedirectToFolder = user && document.userId === user.id && document.folderId && document.team?.url;
|
const canRedirectToFolder = user && document.userId === user.id && document.folderId && document.team?.url;
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import {
|
|||||||
IS_GOOGLE_SSO_ENABLED,
|
IS_GOOGLE_SSO_ENABLED,
|
||||||
IS_MICROSOFT_SSO_ENABLED,
|
IS_MICROSOFT_SSO_ENABLED,
|
||||||
IS_OIDC_SSO_ENABLED,
|
IS_OIDC_SSO_ENABLED,
|
||||||
|
isSignupEnabledForProvider,
|
||||||
OIDC_PROVIDER_LABEL,
|
OIDC_PROVIDER_LABEL,
|
||||||
} from '@documenso/lib/constants/auth';
|
} from '@documenso/lib/constants/auth';
|
||||||
import { env } from '@documenso/lib/utils/env';
|
|
||||||
import { isValidReturnTo, normalizeReturnTo } from '@documenso/lib/utils/is-valid-return-to';
|
import { isValidReturnTo, normalizeReturnTo } from '@documenso/lib/utils/is-valid-return-to';
|
||||||
import { Alert, AlertDescription } from '@documenso/ui/primitives/alert';
|
import { Alert, AlertDescription } from '@documenso/ui/primitives/alert';
|
||||||
import { msg } from '@lingui/core/macro';
|
import { msg } from '@lingui/core/macro';
|
||||||
@@ -32,6 +32,11 @@ export async function loader({ request }: Route.LoaderArgs) {
|
|||||||
const isMicrosoftSSOEnabled = IS_MICROSOFT_SSO_ENABLED;
|
const isMicrosoftSSOEnabled = IS_MICROSOFT_SSO_ENABLED;
|
||||||
const isOIDCSSOEnabled = IS_OIDC_SSO_ENABLED;
|
const isOIDCSSOEnabled = IS_OIDC_SSO_ENABLED;
|
||||||
const oidcProviderLabel = OIDC_PROVIDER_LABEL;
|
const oidcProviderLabel = OIDC_PROVIDER_LABEL;
|
||||||
|
const isSignupEnabled =
|
||||||
|
isSignupEnabledForProvider('email') ||
|
||||||
|
(IS_GOOGLE_SSO_ENABLED && isSignupEnabledForProvider('google')) ||
|
||||||
|
(IS_MICROSOFT_SSO_ENABLED && isSignupEnabledForProvider('microsoft')) ||
|
||||||
|
(IS_OIDC_SSO_ENABLED && isSignupEnabledForProvider('oidc'));
|
||||||
|
|
||||||
let returnTo = new URL(request.url).searchParams.get('returnTo') ?? undefined;
|
let returnTo = new URL(request.url).searchParams.get('returnTo') ?? undefined;
|
||||||
|
|
||||||
@@ -45,13 +50,15 @@ export async function loader({ request }: Route.LoaderArgs) {
|
|||||||
isGoogleSSOEnabled,
|
isGoogleSSOEnabled,
|
||||||
isMicrosoftSSOEnabled,
|
isMicrosoftSSOEnabled,
|
||||||
isOIDCSSOEnabled,
|
isOIDCSSOEnabled,
|
||||||
|
isSignupEnabled,
|
||||||
oidcProviderLabel,
|
oidcProviderLabel,
|
||||||
returnTo,
|
returnTo,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SignIn({ loaderData }: Route.ComponentProps) {
|
export default function SignIn({ loaderData }: Route.ComponentProps) {
|
||||||
const { isGoogleSSOEnabled, isMicrosoftSSOEnabled, isOIDCSSOEnabled, oidcProviderLabel, returnTo } = loaderData;
|
const { isGoogleSSOEnabled, isMicrosoftSSOEnabled, isOIDCSSOEnabled, isSignupEnabled, oidcProviderLabel, returnTo } =
|
||||||
|
loaderData;
|
||||||
|
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
|
|
||||||
@@ -95,7 +102,7 @@ export default function SignIn({ loaderData }: Route.ComponentProps) {
|
|||||||
returnTo={returnTo}
|
returnTo={returnTo}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!isEmbeddedRedirect && env('NEXT_PUBLIC_DISABLE_SIGNUP') !== 'true' && (
|
{!isEmbeddedRedirect && isSignupEnabled && (
|
||||||
<p className="mt-6 text-center text-muted-foreground text-sm">
|
<p className="mt-6 text-center text-muted-foreground text-sm">
|
||||||
<Trans>
|
<Trans>
|
||||||
Don't have an account?{' '}
|
Don't have an account?{' '}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { IS_GOOGLE_SSO_ENABLED, IS_MICROSOFT_SSO_ENABLED, IS_OIDC_SSO_ENABLED } from '@documenso/lib/constants/auth';
|
import {
|
||||||
import { env } from '@documenso/lib/utils/env';
|
IS_GOOGLE_SSO_ENABLED,
|
||||||
|
IS_MICROSOFT_SSO_ENABLED,
|
||||||
|
IS_OIDC_SSO_ENABLED,
|
||||||
|
isSignupEnabledForProvider,
|
||||||
|
} from '@documenso/lib/constants/auth';
|
||||||
import { isValidReturnTo, normalizeReturnTo } from '@documenso/lib/utils/is-valid-return-to';
|
import { isValidReturnTo, normalizeReturnTo } from '@documenso/lib/utils/is-valid-return-to';
|
||||||
import { msg } from '@lingui/core/macro';
|
import { msg } from '@lingui/core/macro';
|
||||||
import { redirect } from 'react-router';
|
import { redirect } from 'react-router';
|
||||||
@@ -14,14 +18,15 @@ export function meta() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function loader({ request }: Route.LoaderArgs) {
|
export function loader({ request }: Route.LoaderArgs) {
|
||||||
const NEXT_PUBLIC_DISABLE_SIGNUP = env('NEXT_PUBLIC_DISABLE_SIGNUP');
|
const isEmailPasswordSignupEnabled = isSignupEnabledForProvider('email');
|
||||||
|
const isGoogleSignupEnabled = IS_GOOGLE_SSO_ENABLED && isSignupEnabledForProvider('google');
|
||||||
|
const isMicrosoftSignupEnabled = IS_MICROSOFT_SSO_ENABLED && isSignupEnabledForProvider('microsoft');
|
||||||
|
const isOidcSignupEnabled = IS_OIDC_SSO_ENABLED && isSignupEnabledForProvider('oidc');
|
||||||
|
|
||||||
// SSR env variables.
|
const isAnySignupEnabled =
|
||||||
const isGoogleSSOEnabled = IS_GOOGLE_SSO_ENABLED;
|
isEmailPasswordSignupEnabled || isGoogleSignupEnabled || isMicrosoftSignupEnabled || isOidcSignupEnabled;
|
||||||
const isMicrosoftSSOEnabled = IS_MICROSOFT_SSO_ENABLED;
|
|
||||||
const isOIDCSSOEnabled = IS_OIDC_SSO_ENABLED;
|
|
||||||
|
|
||||||
if (NEXT_PUBLIC_DISABLE_SIGNUP === 'true') {
|
if (!isAnySignupEnabled) {
|
||||||
throw redirect('/signin');
|
throw redirect('/signin');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,22 +35,30 @@ export function loader({ request }: Route.LoaderArgs) {
|
|||||||
returnTo = isValidReturnTo(returnTo) ? normalizeReturnTo(returnTo) : undefined;
|
returnTo = isValidReturnTo(returnTo) ? normalizeReturnTo(returnTo) : undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isGoogleSSOEnabled,
|
isEmailPasswordSignupEnabled,
|
||||||
isMicrosoftSSOEnabled,
|
isGoogleSignupEnabled,
|
||||||
isOIDCSSOEnabled,
|
isMicrosoftSignupEnabled,
|
||||||
|
isOidcSignupEnabled,
|
||||||
returnTo,
|
returnTo,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SignUp({ loaderData }: Route.ComponentProps) {
|
export default function SignUp({ loaderData }: Route.ComponentProps) {
|
||||||
const { isGoogleSSOEnabled, isMicrosoftSSOEnabled, isOIDCSSOEnabled, returnTo } = loaderData;
|
const {
|
||||||
|
isEmailPasswordSignupEnabled,
|
||||||
|
isGoogleSignupEnabled,
|
||||||
|
isMicrosoftSignupEnabled,
|
||||||
|
isOidcSignupEnabled,
|
||||||
|
returnTo,
|
||||||
|
} = loaderData;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SignUpForm
|
<SignUpForm
|
||||||
className="w-screen max-w-screen-2xl px-4 md:px-16 lg:-my-16"
|
className="w-screen max-w-screen-2xl px-4 md:px-16 lg:-my-16"
|
||||||
isGoogleSSOEnabled={isGoogleSSOEnabled}
|
isEmailPasswordSignupEnabled={isEmailPasswordSignupEnabled}
|
||||||
isMicrosoftSSOEnabled={isMicrosoftSSOEnabled}
|
isGoogleSignupEnabled={isGoogleSignupEnabled}
|
||||||
isOIDCSSOEnabled={isOIDCSSOEnabled}
|
isMicrosoftSignupEnabled={isMicrosoftSignupEnabled}
|
||||||
|
isOidcSignupEnabled={isOidcSignupEnabled}
|
||||||
returnTo={returnTo}
|
returnTo={returnTo}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
+5
-1
@@ -253,5 +253,9 @@ Here's a markdown table documenting all the provided environment variables:
|
|||||||
| `NEXT_PRIVATE_MAILCHANNELS_DKIM_PRIVATE_KEY` | The private key for DKIM signing with MailChannels for the `mailchannels` transport. |
|
| `NEXT_PRIVATE_MAILCHANNELS_DKIM_PRIVATE_KEY` | The private key for DKIM signing with MailChannels for the `mailchannels` transport. |
|
||||||
| `NEXT_PUBLIC_DOCUMENT_SIZE_UPLOAD_LIMIT` | The maximum document upload limit displayed to the user (in MB). |
|
| `NEXT_PUBLIC_DOCUMENT_SIZE_UPLOAD_LIMIT` | The maximum document upload limit displayed to the user (in MB). |
|
||||||
| `NEXT_PUBLIC_POSTHOG_KEY` | The optional PostHog key for analytics and feature flags. |
|
| `NEXT_PUBLIC_POSTHOG_KEY` | The optional PostHog key for analytics and feature flags. |
|
||||||
| `NEXT_PUBLIC_DISABLE_SIGNUP` | Whether to disable user signups through the /signup page. |
|
| `NEXT_PUBLIC_DISABLE_SIGNUP` | Master switch. Set to `true` to disable all signup methods (incl. organisation OIDC portal). |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP` | Set to `true` to disable email/password signup only. SSO signup is unaffected. |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP` | Set to `true` to block new accounts via Google. Existing Google-linked users can still sign in. |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP` | Set to `true` to block new accounts via Microsoft. Existing linked users can still sign in. |
|
||||||
|
| `NEXT_PUBLIC_DISABLE_OIDC_SIGNUP` | Set to `true` to block new accounts via OIDC (incl. organisation portal). Existing users unaffected.|
|
||||||
| `NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS` | Comma-separated list of email domains allowed to sign up (e.g., `example.com,acme.org`). |
|
| `NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS` | Comma-separated list of email domains allowed to sign up (e.g., `example.com,acme.org`). |
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ services:
|
|||||||
- NEXT_PUBLIC_DOCUMENT_SIZE_UPLOAD_LIMIT=${NEXT_PUBLIC_DOCUMENT_SIZE_UPLOAD_LIMIT}
|
- NEXT_PUBLIC_DOCUMENT_SIZE_UPLOAD_LIMIT=${NEXT_PUBLIC_DOCUMENT_SIZE_UPLOAD_LIMIT}
|
||||||
- NEXT_PUBLIC_POSTHOG_KEY=${NEXT_PUBLIC_POSTHOG_KEY}
|
- NEXT_PUBLIC_POSTHOG_KEY=${NEXT_PUBLIC_POSTHOG_KEY}
|
||||||
- NEXT_PUBLIC_DISABLE_SIGNUP=${NEXT_PUBLIC_DISABLE_SIGNUP}
|
- NEXT_PUBLIC_DISABLE_SIGNUP=${NEXT_PUBLIC_DISABLE_SIGNUP}
|
||||||
|
- NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP=${NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP}
|
||||||
|
- NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP=${NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP}
|
||||||
|
- NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP=${NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP}
|
||||||
|
- NEXT_PUBLIC_DISABLE_OIDC_SIGNUP=${NEXT_PUBLIC_DISABLE_OIDC_SIGNUP}
|
||||||
- NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS=${NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS}
|
- NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS=${NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS}
|
||||||
- NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH=${NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH:-/opt/documenso/cert.p12}
|
- NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH=${NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH:-/opt/documenso/cert.p12}
|
||||||
- NEXT_PRIVATE_SIGNING_PASSPHRASE=${NEXT_PRIVATE_SIGNING_PASSPHRASE}
|
- NEXT_PRIVATE_SIGNING_PASSPHRASE=${NEXT_PRIVATE_SIGNING_PASSPHRASE}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||||
import { isEmailDomainAllowedForSignup } from '@documenso/lib/constants/auth';
|
import {
|
||||||
|
isEmailDomainAllowedForSignup,
|
||||||
|
isSignupEnabledForProvider,
|
||||||
|
} from '@documenso/lib/constants/auth';
|
||||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||||
import { onCreateUserHook } from '@documenso/lib/server-only/user/create-user';
|
import { onCreateUserHook } from '@documenso/lib/server-only/user/create-user';
|
||||||
import { deletedServiceAccountEmail } from '@documenso/lib/server-only/user/service-accounts/deleted-account';
|
import { deletedServiceAccountEmail } from '@documenso/lib/server-only/user/service-accounts/deleted-account';
|
||||||
import { legacyServiceAccountEmail } from '@documenso/lib/server-only/user/service-accounts/legacy-service-account';
|
import { legacyServiceAccountEmail } from '@documenso/lib/server-only/user/service-accounts/legacy-service-account';
|
||||||
import { env } from '@documenso/lib/utils/env';
|
|
||||||
import { isValidReturnTo, normalizeReturnTo } from '@documenso/lib/utils/is-valid-return-to';
|
import { isValidReturnTo, normalizeReturnTo } from '@documenso/lib/utils/is-valid-return-to';
|
||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
import { UserSecurityAuditLogType } from '@prisma/client';
|
import { UserSecurityAuditLogType } from '@prisma/client';
|
||||||
@@ -115,8 +117,8 @@ export const handleOAuthCallbackUrl = async (options: HandleOAuthCallbackUrlOpti
|
|||||||
return c.redirect(redirectPath, 302);
|
return c.redirect(redirectPath, 302);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if signups are disabled.
|
// Check if signups are disabled for this provider.
|
||||||
if (env('NEXT_PUBLIC_DISABLE_SIGNUP') === 'true') {
|
if (!isSignupEnabledForProvider(clientOptions.id as 'google' | 'microsoft' | 'oidc')) {
|
||||||
const errorUrl = new URL('/signin', NEXT_PUBLIC_WEBAPP_URL());
|
const errorUrl = new URL('/signin', NEXT_PUBLIC_WEBAPP_URL());
|
||||||
|
|
||||||
errorUrl.searchParams.set('error', AuthenticationErrorCode.SignupDisabled);
|
errorUrl.searchParams.set('error', AuthenticationErrorCode.SignupDisabled);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { sendOrganisationAccountLinkConfirmationEmail } from '@documenso/ee/server-only/lib/send-organisation-account-link-confirmation-email';
|
import { sendOrganisationAccountLinkConfirmationEmail } from '@documenso/ee/server-only/lib/send-organisation-account-link-confirmation-email';
|
||||||
|
import { isSignupEnabledForProvider } from '@documenso/lib/constants/auth';
|
||||||
import { AppError } from '@documenso/lib/errors/app-error';
|
import { AppError } from '@documenso/lib/errors/app-error';
|
||||||
import { onCreateUserHook } from '@documenso/lib/server-only/user/create-user';
|
import { onCreateUserHook } from '@documenso/lib/server-only/user/create-user';
|
||||||
import { formatOrganisationLoginUrl } from '@documenso/lib/utils/organisation-authentication-portal';
|
import { formatOrganisationLoginUrl } from '@documenso/lib/utils/organisation-authentication-portal';
|
||||||
@@ -65,6 +66,14 @@ export const handleOAuthOrganisationCallbackUrl = async (options: HandleOAuthOrg
|
|||||||
|
|
||||||
// Handle new user.
|
// Handle new user.
|
||||||
if (!userToLink) {
|
if (!userToLink) {
|
||||||
|
if (!isSignupEnabledForProvider('oidc')) {
|
||||||
|
const errorUrl = new URL(formatOrganisationLoginUrl(orgUrl));
|
||||||
|
|
||||||
|
errorUrl.searchParams.set('error', AuthenticationErrorCode.SignupDisabled);
|
||||||
|
|
||||||
|
return c.redirect(errorUrl.toString(), 302);
|
||||||
|
}
|
||||||
|
|
||||||
userToLink = await prisma.user.create({
|
userToLink = await prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
email: email,
|
email: email,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { isEmailDomainAllowedForSignup } from '@documenso/lib/constants/auth';
|
import { isEmailDomainAllowedForSignup, isSignupEnabledForProvider } from '@documenso/lib/constants/auth';
|
||||||
import { EMAIL_VERIFICATION_STATE } from '@documenso/lib/constants/email';
|
import { EMAIL_VERIFICATION_STATE } from '@documenso/lib/constants/email';
|
||||||
import { AppError } from '@documenso/lib/errors/app-error';
|
import { AppError } from '@documenso/lib/errors/app-error';
|
||||||
import { jobsClient } from '@documenso/lib/jobs/client';
|
import { jobsClient } from '@documenso/lib/jobs/client';
|
||||||
@@ -27,7 +27,6 @@ import { deletedServiceAccountEmail } from '@documenso/lib/server-only/user/serv
|
|||||||
import { legacyServiceAccountEmail } from '@documenso/lib/server-only/user/service-accounts/legacy-service-account';
|
import { legacyServiceAccountEmail } from '@documenso/lib/server-only/user/service-accounts/legacy-service-account';
|
||||||
import { updatePassword } from '@documenso/lib/server-only/user/update-password';
|
import { updatePassword } from '@documenso/lib/server-only/user/update-password';
|
||||||
import { verifyEmail } from '@documenso/lib/server-only/user/verify-email';
|
import { verifyEmail } from '@documenso/lib/server-only/user/verify-email';
|
||||||
import { env } from '@documenso/lib/utils/env';
|
|
||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
import { sValidator } from '@hono/standard-validator';
|
import { sValidator } from '@hono/standard-validator';
|
||||||
import { compare } from '@node-rs/bcrypt';
|
import { compare } from '@node-rs/bcrypt';
|
||||||
@@ -184,7 +183,7 @@ export const emailPasswordRoute = new Hono<HonoAuthContext>()
|
|||||||
.post('/signup', sValidator('json', ZSignUpSchema), async (c) => {
|
.post('/signup', sValidator('json', ZSignUpSchema), async (c) => {
|
||||||
const requestMetadata = c.get('requestMetadata');
|
const requestMetadata = c.get('requestMetadata');
|
||||||
|
|
||||||
if (env('NEXT_PUBLIC_DISABLE_SIGNUP') === 'true') {
|
if (!isSignupEnabledForProvider('email')) {
|
||||||
throw new AppError(AuthenticationErrorCode.SignupDisabled, {
|
throw new AppError(AuthenticationErrorCode.SignupDisabled, {
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -119,3 +119,24 @@ export const isEmailDomainAllowedForSignup = (email: string): boolean => {
|
|||||||
|
|
||||||
return allowedDomains.includes(emailDomain);
|
return allowedDomains.includes(emailDomain);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if signup is enabled for the given provider.
|
||||||
|
* The master switch takes precedence over the per-provider flags.
|
||||||
|
*/
|
||||||
|
export const isSignupEnabledForProvider = (
|
||||||
|
provider: 'email' | 'google' | 'microsoft' | 'oidc',
|
||||||
|
): boolean => {
|
||||||
|
if (env('NEXT_PUBLIC_DISABLE_SIGNUP') === 'true') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const flagMap = {
|
||||||
|
email: 'NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP',
|
||||||
|
google: 'NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP',
|
||||||
|
microsoft: 'NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP',
|
||||||
|
oidc: 'NEXT_PUBLIC_DISABLE_OIDC_SIGNUP',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
return env(flagMap[provider]) !== 'true';
|
||||||
|
};
|
||||||
|
|||||||
Vendored
+4
@@ -74,6 +74,10 @@ declare namespace NodeJS {
|
|||||||
NEXT_PRIVATE_SMTP_FROM_ADDRESS?: string;
|
NEXT_PRIVATE_SMTP_FROM_ADDRESS?: string;
|
||||||
|
|
||||||
NEXT_PUBLIC_DISABLE_SIGNUP?: string;
|
NEXT_PUBLIC_DISABLE_SIGNUP?: string;
|
||||||
|
NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP?: string;
|
||||||
|
NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP?: string;
|
||||||
|
NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP?: string;
|
||||||
|
NEXT_PUBLIC_DISABLE_OIDC_SIGNUP?: string;
|
||||||
NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS?: string;
|
NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS?: string;
|
||||||
|
|
||||||
NEXT_PRIVATE_BROWSERLESS_URL?: string;
|
NEXT_PRIVATE_BROWSERLESS_URL?: string;
|
||||||
|
|||||||
@@ -155,6 +155,14 @@ services:
|
|||||||
# Features Optional
|
# Features Optional
|
||||||
- key: NEXT_PUBLIC_DISABLE_SIGNUP
|
- key: NEXT_PUBLIC_DISABLE_SIGNUP
|
||||||
sync: false
|
sync: false
|
||||||
|
- key: NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP
|
||||||
|
sync: false
|
||||||
|
- key: NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP
|
||||||
|
sync: false
|
||||||
|
- key: NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP
|
||||||
|
sync: false
|
||||||
|
- key: NEXT_PUBLIC_DISABLE_OIDC_SIGNUP
|
||||||
|
sync: false
|
||||||
- key: NEXT_PUBLIC_USE_INTERNAL_URL_BROWSERLESS
|
- key: NEXT_PUBLIC_USE_INTERNAL_URL_BROWSERLESS
|
||||||
sync: false
|
sync: false
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,10 @@
|
|||||||
"NEXT_PUBLIC_POSTHOG_KEY",
|
"NEXT_PUBLIC_POSTHOG_KEY",
|
||||||
"NEXT_PUBLIC_FEATURE_BILLING_ENABLED",
|
"NEXT_PUBLIC_FEATURE_BILLING_ENABLED",
|
||||||
"NEXT_PUBLIC_DISABLE_SIGNUP",
|
"NEXT_PUBLIC_DISABLE_SIGNUP",
|
||||||
|
"NEXT_PUBLIC_DISABLE_EMAIL_PASSWORD_SIGNUP",
|
||||||
|
"NEXT_PUBLIC_DISABLE_GOOGLE_SIGNUP",
|
||||||
|
"NEXT_PUBLIC_DISABLE_MICROSOFT_SIGNUP",
|
||||||
|
"NEXT_PUBLIC_DISABLE_OIDC_SIGNUP",
|
||||||
"NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS",
|
"NEXT_PRIVATE_ALLOWED_SIGNUP_DOMAINS",
|
||||||
"NEXT_PRIVATE_PLAIN_API_KEY",
|
"NEXT_PRIVATE_PLAIN_API_KEY",
|
||||||
"NEXT_PUBLIC_DOCUMENT_SIZE_UPLOAD_LIMIT",
|
"NEXT_PUBLIC_DOCUMENT_SIZE_UPLOAD_LIMIT",
|
||||||
|
|||||||
Reference in New Issue
Block a user