mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
fix validateRedirectUrl
This commit is contained in:
parent
a9ceab2fb4
commit
6390832ac4
@ -44,7 +44,7 @@ async function createProjectUserOAuthAccount(prisma: PrismaClient, params: {
|
||||
}
|
||||
|
||||
const redirectOrThrowError = (error: KnownError, tenancy: Tenancy, errorRedirectUrl?: string) => {
|
||||
if (!errorRedirectUrl || !validateRedirectUrl(errorRedirectUrl, Object.values(tenancy.config.domains), tenancy.config.domains.allowLocalhost)) {
|
||||
if (!errorRedirectUrl || !validateRedirectUrl(errorRedirectUrl, tenancy)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
|
||||
@ -36,15 +36,11 @@ export const POST = createSmartRouteHandler({
|
||||
}).defined(),
|
||||
}),
|
||||
async handler({ auth: { tenancy }, body: { email, password, verification_callback_url: verificationCallbackUrl } }, fullReq) {
|
||||
if (!tenancy.config.credential_enabled) {
|
||||
if (!tenancy.config.auth.password.allowSignIn) {
|
||||
throw new KnownErrors.PasswordAuthenticationNotEnabled();
|
||||
}
|
||||
|
||||
if (!validateRedirectUrl(
|
||||
verificationCallbackUrl,
|
||||
tenancy.config.domains,
|
||||
tenancy.config.allow_localhost,
|
||||
)) {
|
||||
if (!validateRedirectUrl(verificationCallbackUrl, tenancy)) {
|
||||
throw new KnownErrors.RedirectUrlNotWhitelisted();
|
||||
}
|
||||
|
||||
@ -53,7 +49,7 @@ export const POST = createSmartRouteHandler({
|
||||
throw passwordError;
|
||||
}
|
||||
|
||||
if (!tenancy.config.sign_up_enabled) {
|
||||
if (!tenancy.config.auth.allowSignUp) {
|
||||
throw new KnownErrors.SignUpNotEnabled();
|
||||
}
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ export const POST = createSmartRouteHandler({
|
||||
if (!getEnvVariable("STACK_FREESTYLE_API_KEY")) {
|
||||
throw new StatusError(500, "STACK_FREESTYLE_API_KEY is not set");
|
||||
}
|
||||
if (auth.tenancy.config.email_config.type === "shared") {
|
||||
if (auth.tenancy.config.emails.server.isShared) {
|
||||
throw new StatusError(400, "Cannot send custom emails when using shared email config");
|
||||
}
|
||||
const emailConfig = await getEmailConfig(auth.tenancy);
|
||||
@ -56,11 +56,11 @@ export const POST = createSmartRouteHandler({
|
||||
if (!notificationCategory) {
|
||||
throw new StatusError(404, "Notification category not found");
|
||||
}
|
||||
const themeList = auth.tenancy.completeConfig.emails.themeList;
|
||||
if (!Object.keys(themeList).includes(auth.tenancy.completeConfig.emails.theme)) {
|
||||
const themeList = auth.tenancy.config.emails.themeList;
|
||||
if (!Object.keys(themeList).includes(auth.tenancy.config.emails.theme)) {
|
||||
throw new StatusError(400, "No active theme found");
|
||||
}
|
||||
const activeTheme = themeList[auth.tenancy.completeConfig.emails.theme];
|
||||
const activeTheme = themeList[auth.tenancy.config.emails.theme];
|
||||
|
||||
const prisma = await getPrismaClientForTenancy(auth.tenancy);
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { overrideEnvironmentConfigOverride } from "@/lib/config";
|
||||
import { renderEmailWithTemplate } from "@/lib/email-rendering";
|
||||
import { globalPrismaClient } from "@/prisma-client";
|
||||
import { createSmartRouteHandler } from "@/route-handlers/smart-route-handler";
|
||||
import { KnownErrors } from "@stackframe/stack-shared/dist/known-errors";
|
||||
import { adaptSchema, yupNumber, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
|
||||
import { StatusError } from "@stackframe/stack-shared/dist/utils/errors";
|
||||
import { renderEmailWithTemplate } from "@/lib/email-rendering";
|
||||
import { KnownErrors } from "@stackframe/stack-shared/dist/known-errors";
|
||||
|
||||
|
||||
export const PATCH = createSmartRouteHandler({
|
||||
@ -31,11 +31,11 @@ export const PATCH = createSmartRouteHandler({
|
||||
}).defined(),
|
||||
}),
|
||||
async handler({ auth: { tenancy }, params: { templateId }, body }) {
|
||||
const templateList = tenancy.completeConfig.emails.templateList;
|
||||
const templateList = tenancy.config.emails.templateList;
|
||||
if (!Object.keys(templateList).includes(templateId)) {
|
||||
throw new StatusError(StatusError.NotFound, "No template found with given id");
|
||||
}
|
||||
const theme = tenancy.completeConfig.emails.themeList[tenancy.completeConfig.emails.theme];
|
||||
const theme = tenancy.config.emails.themeList[tenancy.config.emails.theme];
|
||||
const result = await renderEmailWithTemplate(body.tsx_source, theme.tsxSource, { projectDisplayName: tenancy.project.display_name });
|
||||
if (result.status === "error") {
|
||||
throw new KnownErrors.EmailRenderingError(result.error);
|
||||
|
||||
@ -25,7 +25,7 @@ export const GET = createSmartRouteHandler({
|
||||
}).defined(),
|
||||
}),
|
||||
async handler({ auth: { tenancy } }) {
|
||||
const templates = Object.entries(tenancy.completeConfig.emails.templateList).map(([id, template]) => ({
|
||||
const templates = Object.entries(tenancy.config.emails.templateList).map(([id, template]) => ({
|
||||
id,
|
||||
subject: template.subject,
|
||||
display_name: template.displayName,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { overrideEnvironmentConfigOverride } from "@/lib/config";
|
||||
import { globalPrismaClient } from "@/prisma-client";
|
||||
import { renderEmailWithTemplate } from "@/lib/email-rendering";
|
||||
import { previewTemplateSource } from "@stackframe/stack-shared/dist/helpers/emails";
|
||||
import { globalPrismaClient } from "@/prisma-client";
|
||||
import { createSmartRouteHandler } from "@/route-handlers/smart-route-handler";
|
||||
import { previewTemplateSource } from "@stackframe/stack-shared/dist/helpers/emails";
|
||||
import { KnownErrors } from "@stackframe/stack-shared/dist/known-errors";
|
||||
import { adaptSchema, yupNumber, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
|
||||
import { StatusError } from "@stackframe/stack-shared/dist/utils/errors";
|
||||
@ -29,7 +29,7 @@ export const GET = createSmartRouteHandler({
|
||||
}).defined(),
|
||||
}),
|
||||
async handler({ auth: { tenancy }, params: { id } }) {
|
||||
const themeList = tenancy.completeConfig.emails.themeList;
|
||||
const themeList = tenancy.config.emails.themeList;
|
||||
if (!Object.keys(themeList).includes(id)) {
|
||||
throw new StatusError(404, "No theme found with given id");
|
||||
}
|
||||
@ -69,7 +69,7 @@ export const PATCH = createSmartRouteHandler({
|
||||
}).defined(),
|
||||
}),
|
||||
async handler({ auth: { tenancy }, params: { id }, body }) {
|
||||
const themeList = tenancy.completeConfig.emails.themeList;
|
||||
const themeList = tenancy.config.emails.themeList;
|
||||
if (!Object.keys(themeList).includes(id)) {
|
||||
throw new StatusError(404, "No theme found with given id");
|
||||
}
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { overrideEnvironmentConfigOverride } from "@/lib/config";
|
||||
import { LightEmailTheme } from "@stackframe/stack-shared/dist/helpers/emails";
|
||||
import { globalPrismaClient } from "@/prisma-client";
|
||||
import { createSmartRouteHandler } from "@/route-handlers/smart-route-handler";
|
||||
import { DEFAULT_EMAIL_THEME_ID } from "@stackframe/stack-shared/dist/helpers/emails";
|
||||
import { DEFAULT_EMAIL_THEME_ID, LightEmailTheme } from "@stackframe/stack-shared/dist/helpers/emails";
|
||||
import { adaptSchema, yupArray, yupNumber, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
|
||||
import { generateUuid } from "@stackframe/stack-shared/dist/utils/uuids";
|
||||
|
||||
@ -69,8 +68,8 @@ export const GET = createSmartRouteHandler({
|
||||
}).defined(),
|
||||
}),
|
||||
async handler({ auth: { tenancy } }) {
|
||||
const themeList = tenancy.completeConfig.emails.themeList;
|
||||
const currentActiveTheme = tenancy.completeConfig.emails.theme;
|
||||
const themeList = tenancy.config.emails.themeList;
|
||||
const currentActiveTheme = tenancy.config.emails.theme;
|
||||
if (!(currentActiveTheme in themeList)) {
|
||||
let newActiveTheme: string;
|
||||
if (DEFAULT_EMAIL_THEME_ID in themeList) {
|
||||
|
||||
@ -13,7 +13,7 @@ export const environmentConfigCrudHandlers = createLazyProxy(() => createCrudHan
|
||||
project_id: auth.project.id,
|
||||
branch_id: auth.tenancy.branchId,
|
||||
organization_id: auth.tenancy.organization?.id,
|
||||
config: auth.tenancy.completeConfig,
|
||||
config: auth.tenancy.config,
|
||||
};
|
||||
},
|
||||
onUpdate: async ({ auth, data }) => {
|
||||
@ -33,7 +33,7 @@ export const environmentConfigCrudHandlers = createLazyProxy(() => createCrudHan
|
||||
project_id: auth.project.id,
|
||||
branch_id: auth.tenancy.branchId,
|
||||
organization_id: auth.tenancy.organization?.id,
|
||||
config: auth.tenancy.completeConfig,
|
||||
config: auth.tenancy.config,
|
||||
};
|
||||
},
|
||||
}));
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { renderedOrganizationConfigToProjectCrud } from "@/lib/config";
|
||||
import { createOrUpdateProject } from "@/lib/projects";
|
||||
import { getTenancy } from "@/lib/tenancies";
|
||||
import { getPrismaClientForTenancy, globalPrismaClient } from "@/prisma-client";
|
||||
@ -12,7 +13,7 @@ export const projectsCrudHandlers = createLazyProxy(() => createCrudHandlers(pro
|
||||
onUpdate: async ({ auth, data }) => {
|
||||
if (
|
||||
data.config?.email_theme &&
|
||||
!Object.keys(auth.tenancy.completeConfig.emails.themeList).includes(data.config.email_theme)
|
||||
!Object.keys(auth.tenancy.config.emails.themeList).includes(data.config.email_theme)
|
||||
) {
|
||||
throw new StatusError(400, "Invalid email theme");
|
||||
}
|
||||
@ -25,13 +26,13 @@ export const projectsCrudHandlers = createLazyProxy(() => createCrudHandlers(pro
|
||||
const tenancy = await getTenancy(auth.tenancy.id) ?? throwErr("Tenancy not found after project update?"); // since we updated the project, we need to re-fetch the new tenancy config
|
||||
return {
|
||||
...project,
|
||||
config: tenancy.config,
|
||||
config: renderedOrganizationConfigToProjectCrud(tenancy.config),
|
||||
};
|
||||
},
|
||||
onRead: async ({ auth }) => {
|
||||
return {
|
||||
...auth.project,
|
||||
config: auth.tenancy.config,
|
||||
config: renderedOrganizationConfigToProjectCrud(auth.tenancy.config),
|
||||
};
|
||||
},
|
||||
onDelete: async ({ auth }) => {
|
||||
|
||||
@ -28,7 +28,7 @@ export const POST = createSmartRouteHandler({
|
||||
}).defined(),
|
||||
}),
|
||||
async handler({ auth, body }) {
|
||||
if (!validateRedirectUrl(body.callback_url, auth.tenancy.config.domains, auth.tenancy.config.allow_localhost)) {
|
||||
if (!validateRedirectUrl(body.callback_url, auth.tenancy)) {
|
||||
throw new KnownErrors.RedirectUrlNotWhitelisted();
|
||||
}
|
||||
|
||||
|
||||
@ -108,7 +108,7 @@ async function ensureProviderExists(tenancy: Tenancy, userId: string, providerId
|
||||
}
|
||||
|
||||
function getProviderConfig(tenancy: Tenancy, providerConfigId: string) {
|
||||
const config = tenancy.completeConfig;
|
||||
const config = tenancy.config;
|
||||
let providerConfig: (typeof config.auth.oauth.providers)[number] & { id: string } | undefined;
|
||||
for (const [providerId, provider] of Object.entries(config.auth.oauth.providers)) {
|
||||
if (providerId === providerConfigId) {
|
||||
|
||||
@ -474,7 +474,7 @@ export const usersCrudHandlers = createLazyProxy(() => createCrudHandlers(usersC
|
||||
primaryEmailAuthEnabled: !!data.primary_email_auth_enabled,
|
||||
});
|
||||
|
||||
const config = auth.tenancy.completeConfig;
|
||||
const config = auth.tenancy.config;
|
||||
|
||||
const newUser = await tx.projectUser.create({
|
||||
data: {
|
||||
@ -642,7 +642,7 @@ export const usersCrudHandlers = createLazyProxy(() => createCrudHandlers(usersC
|
||||
const result = await retryTransaction(prisma, async (tx) => {
|
||||
await ensureUserExists(tx, { tenancyId: auth.tenancy.id, userId: params.user_id });
|
||||
|
||||
const config = auth.tenancy.completeConfig;
|
||||
const config = auth.tenancy.config;
|
||||
|
||||
if (data.selected_team_id !== undefined) {
|
||||
if (data.selected_team_id !== null) {
|
||||
|
||||
@ -21,7 +21,7 @@ export const emailTemplateAdapter = (context: ChatAdapterContext) => ({
|
||||
|
||||
|
||||
const CREATE_EMAIL_TEMPLATE_TOOL_DESCRIPTION = (context: ChatAdapterContext) => {
|
||||
const currentEmailTemplate = context.tenancy.completeConfig.emails.templateList[context.threadId];
|
||||
const currentEmailTemplate = context.tenancy.config.emails.templateList[context.threadId];
|
||||
|
||||
return `
|
||||
Create a new email template.
|
||||
|
||||
@ -18,7 +18,7 @@ export const emailThemeAdapter = (context: ChatAdapterContext) => ({
|
||||
});
|
||||
|
||||
const CREATE_EMAIL_THEME_TOOL_DESCRIPTION = (context: ChatAdapterContext) => {
|
||||
const currentEmailTheme = context.tenancy.completeConfig.emails.themeList[context.threadId].tsxSource || "";
|
||||
const currentEmailTheme = context.tenancy.config.emails.themeList[context.threadId].tsxSource || "";
|
||||
|
||||
return `
|
||||
Create a new email theme.
|
||||
|
||||
@ -103,7 +103,7 @@ export async function grantTeamPermission(
|
||||
}
|
||||
) {
|
||||
// sanity check: make sure that the permission exists
|
||||
const permissionDefinition = getOrUndefined(options.tenancy.completeConfig.rbac.permissions, options.permissionId);
|
||||
const permissionDefinition = getOrUndefined(options.tenancy.config.rbac.permissions, options.permissionId);
|
||||
if (permissionDefinition === undefined) {
|
||||
if (!has(teamSystemPermissionMap, options.permissionId)) {
|
||||
throw new KnownErrors.PermissionNotFound(options.permissionId);
|
||||
@ -164,7 +164,7 @@ export async function listPermissionDefinitions(
|
||||
tenancy: Tenancy,
|
||||
}
|
||||
): Promise<(TeamPermissionDefinitionsCrud["Admin"]["Read"])[]> {
|
||||
const renderedConfig = options.tenancy.completeConfig;
|
||||
const renderedConfig = options.tenancy.config;
|
||||
|
||||
const permissions = typedEntries(renderedConfig.rbac.permissions).filter(([_, p]) => p.scope === options.scope);
|
||||
|
||||
@ -194,7 +194,7 @@ export async function createPermissionDefinition(
|
||||
},
|
||||
}
|
||||
) {
|
||||
const oldConfig = options.tenancy.completeConfig;
|
||||
const oldConfig = options.tenancy.config;
|
||||
|
||||
const existingPermission = oldConfig.rbac.permissions[options.data.id] as OrganizationRenderedConfig['rbac']['permissions'][string] | undefined;
|
||||
const allIds = Object.keys(oldConfig.rbac.permissions)
|
||||
@ -256,7 +256,7 @@ export async function updatePermissionDefinition(
|
||||
}
|
||||
) {
|
||||
const newId = options.data.id ?? options.oldId;
|
||||
const oldConfig = options.tenancy.completeConfig;
|
||||
const oldConfig = options.tenancy.config;
|
||||
|
||||
const existingPermission = oldConfig.rbac.permissions[options.oldId] as OrganizationRenderedConfig['rbac']['permissions'][string] | undefined;
|
||||
|
||||
@ -351,7 +351,7 @@ export async function deletePermissionDefinition(
|
||||
permissionId: string,
|
||||
}
|
||||
) {
|
||||
const oldConfig = options.tenancy.completeConfig;
|
||||
const oldConfig = options.tenancy.config;
|
||||
|
||||
const existingPermission = oldConfig.rbac.permissions[options.permissionId] as OrganizationRenderedConfig['rbac']['permissions'][string] | undefined;
|
||||
|
||||
@ -414,7 +414,7 @@ export async function grantProjectPermission(
|
||||
}
|
||||
) {
|
||||
// sanity check: make sure that the permission exists
|
||||
const permissionDefinition = getOrUndefined(options.tenancy.completeConfig.rbac.permissions, options.permissionId);
|
||||
const permissionDefinition = getOrUndefined(options.tenancy.config.rbac.permissions, options.permissionId);
|
||||
if (permissionDefinition === undefined) {
|
||||
throw new KnownErrors.PermissionNotFound(options.permissionId);
|
||||
} else if (permissionDefinition.scope !== "project") {
|
||||
@ -473,7 +473,7 @@ export async function grantDefaultProjectPermissions(
|
||||
userId: string,
|
||||
}
|
||||
) {
|
||||
const config = options.tenancy.completeConfig;
|
||||
const config = options.tenancy.config;
|
||||
|
||||
for (const permissionId of Object.keys(config.rbac.defaultPermissions.signUp)) {
|
||||
await grantProjectPermission(tx, {
|
||||
@ -501,7 +501,7 @@ export async function grantDefaultTeamPermissions(
|
||||
type: "creator" | "member",
|
||||
}
|
||||
) {
|
||||
const config = options.tenancy.completeConfig;
|
||||
const config = options.tenancy.config;
|
||||
|
||||
const defaultPermissions = config.rbac.defaultPermissions[options.type === "creator" ? "teamCreator" : "teamMember"];
|
||||
|
||||
|
||||
@ -1,13 +1,21 @@
|
||||
import { StackAssertionError, captureError } from "@stackframe/stack-shared/dist/utils/errors";
|
||||
import { createUrlIfValid, isLocalhost } from "@stackframe/stack-shared/dist/utils/urls";
|
||||
import { Tenancy } from "./tenancies";
|
||||
|
||||
export function validateRedirectUrl(urlOrString: string | URL, domains: { baseUrl: string }[], allowLocalhost: boolean): boolean {
|
||||
export function validateRedirectUrl(
|
||||
urlOrString: string | URL,
|
||||
tenancy: Tenancy,
|
||||
): boolean {
|
||||
const url = createUrlIfValid(urlOrString);
|
||||
if (!url) return false;
|
||||
if (allowLocalhost && isLocalhost(url)) {
|
||||
if (tenancy.config.domains.allowLocalhost && isLocalhost(url)) {
|
||||
return true;
|
||||
}
|
||||
return domains.some((domain) => {
|
||||
return Object.values(tenancy.config.domains.trustedDomains).some((domain) => {
|
||||
if (!domain.baseUrl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const testUrl = url;
|
||||
const baseUrl = createUrlIfValid(domain.baseUrl);
|
||||
if (!baseUrl) {
|
||||
|
||||
@ -26,7 +26,7 @@ export async function tenancyPrismaToCrud(prisma: Prisma.TenancyGetPayload<{}>)
|
||||
|
||||
const projectCrud = await getProject(prisma.projectId) ?? throwErr("Project in tenancy not found");
|
||||
|
||||
const completeConfig = await rawQuery(globalPrismaClient, getRenderedOrganizationConfigQuery({
|
||||
const config = await rawQuery(globalPrismaClient, getRenderedOrganizationConfigQuery({
|
||||
projectId: projectCrud.id,
|
||||
branchId: prisma.branchId,
|
||||
organizationId: prisma.organizationId,
|
||||
@ -34,7 +34,7 @@ export async function tenancyPrismaToCrud(prisma: Prisma.TenancyGetPayload<{}>)
|
||||
|
||||
return {
|
||||
id: prisma.id,
|
||||
config: completeConfig,
|
||||
config,
|
||||
branchId: prisma.branchId,
|
||||
organization: prisma.organizationId === null ? null : {
|
||||
// TODO actual organization type
|
||||
|
||||
@ -52,8 +52,8 @@ export class OAuthModel implements AuthorizationCodeModel {
|
||||
|
||||
let redirectUris: string[] = [];
|
||||
try {
|
||||
redirectUris = tenancy.config.domains.map(
|
||||
({ domain, handler_path }) => new URL(handler_path, domain).toString()
|
||||
redirectUris = Object.entries(tenancy.config.domains.trustedDomains).map(
|
||||
([_, domain]) => new URL(domain.handlerPath, domain.baseUrl).toString()
|
||||
);
|
||||
} catch (e) {
|
||||
captureError("get redirect uris", {
|
||||
@ -64,7 +64,7 @@ export class OAuthModel implements AuthorizationCodeModel {
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (redirectUris.length === 0 && tenancy.config.allow_localhost) {
|
||||
if (redirectUris.length === 0 && tenancy.config.domains.allowLocalhost) {
|
||||
redirectUris.push("http://localhost");
|
||||
}
|
||||
|
||||
@ -267,7 +267,7 @@ export class OAuthModel implements AuthorizationCodeModel {
|
||||
assertScopeIsValid(code.scope);
|
||||
const tenancy = await getSoleTenancyFromProjectBranch(...getProjectBranchFromClientId(client.id));
|
||||
|
||||
if (!validateRedirectUrl(code.redirectUri, tenancy.config.domains, tenancy.config.allow_localhost)) {
|
||||
if (!validateRedirectUrl(code.redirectUri, tenancy)) {
|
||||
throw new KnownErrors.RedirectUrlNotWhitelisted();
|
||||
}
|
||||
|
||||
@ -353,10 +353,6 @@ export class OAuthModel implements AuthorizationCodeModel {
|
||||
async validateRedirectUri(redirect_uri: string, client: Client): Promise<boolean> {
|
||||
const tenancy = await getSoleTenancyFromProjectBranch(...getProjectBranchFromClientId(client.id));
|
||||
|
||||
return validateRedirectUrl(
|
||||
redirect_uri,
|
||||
tenancy.config.domains,
|
||||
tenancy.config.allow_localhost,
|
||||
);
|
||||
return validateRedirectUrl(redirect_uri, tenancy);
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,11 +48,11 @@ function getSchemaFromConnectionString(connectionString: string) {
|
||||
}
|
||||
|
||||
export async function getPrismaClientForTenancy(tenancy: Tenancy) {
|
||||
return await getPrismaClientForSourceOfTruth(tenancy.completeConfig.sourceOfTruth, tenancy.branchId);
|
||||
return await getPrismaClientForSourceOfTruth(tenancy.config.sourceOfTruth, tenancy.branchId);
|
||||
}
|
||||
|
||||
export function getPrismaSchemaForTenancy(tenancy: Tenancy) {
|
||||
return getPrismaSchemaForSourceOfTruth(tenancy.completeConfig.sourceOfTruth, tenancy.branchId);
|
||||
return getPrismaSchemaForSourceOfTruth(tenancy.config.sourceOfTruth, tenancy.branchId);
|
||||
}
|
||||
|
||||
function getPostgresPrismaClient(connectionString: string) {
|
||||
|
||||
@ -228,11 +228,7 @@ export function createVerificationCodeHandler<
|
||||
});
|
||||
const tenancy = await getSoleTenancyFromProjectBranch(project.id, branchId);
|
||||
|
||||
if (callbackUrl !== undefined && !validateRedirectUrl(
|
||||
callbackUrl,
|
||||
tenancy.config.domains,
|
||||
tenancy.config.allow_localhost,
|
||||
)) {
|
||||
if (callbackUrl !== undefined && !validateRedirectUrl(callbackUrl, tenancy)) {
|
||||
throw new KnownErrors.RedirectUrlNotWhitelisted();
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user