mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
update
This commit is contained in:
parent
2191e1c023
commit
9bbd3b6816
@ -5,3 +5,4 @@ ALTER TYPE "VerificationCodeType" RENAME VALUE 'NEON_INTEGRATION_PROJECT_TRANSFE
|
||||
ALTER TABLE "NeonProvisionedProject" RENAME TO "ProvisionedProject";
|
||||
ALTER TABLE "ProvisionedProject" RENAME CONSTRAINT "NeonProvisionedProject_pkey" TO "ProvisionedProject_pkey";
|
||||
ALTER TABLE "ProvisionedProject" RENAME CONSTRAINT "NeonProvisionedProject_projectId_fkey" TO "ProvisionedProject_projectId_fkey";
|
||||
ALTER TABLE "ProvisionedProject" RENAME COLUMN "neonClientId" TO "externalProjectId";
|
||||
|
||||
@ -641,7 +641,7 @@ model ProvisionedProject {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
neonClientId String?
|
||||
externalProjectId String
|
||||
}
|
||||
|
||||
//#region Events
|
||||
|
||||
@ -18,7 +18,7 @@ export const POST = createSmartRouteHandler({
|
||||
body: yupObject({
|
||||
interaction_uid: yupString().defined(),
|
||||
project_id: yupString().defined(),
|
||||
neon_project_name: yupString().optional(),
|
||||
external_project_name: yupString().optional(),
|
||||
}).defined(),
|
||||
}),
|
||||
response: yupObject({
|
||||
@ -33,7 +33,7 @@ export const POST = createSmartRouteHandler({
|
||||
const set = await prismaClient.apiKeySet.create({
|
||||
data: {
|
||||
projectId: req.body.project_id,
|
||||
description: `Auto-generated for Neon${req.body.neon_project_name ? ` (${req.body.neon_project_name})` : ""}`,
|
||||
description: `Auto-generated for ${req.body.external_project_name ? `"${req.body.external_project_name}"` : "an external project"}`,
|
||||
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 100),
|
||||
superSecretAdminKey: `sak_${generateSecureRandomString()}`,
|
||||
},
|
||||
|
||||
@ -54,7 +54,7 @@ export const POST = createSmartRouteHandler({
|
||||
await prismaClient.provisionedProject.create({
|
||||
data: {
|
||||
projectId: createdProject.id,
|
||||
neonClientId: clientId,
|
||||
externalProjectId: clientId,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
import { neonIntegrationProjectTransferCodeHandler } from "../verification-code-handler";
|
||||
import { integrationProjectTransferCodeHandler } from "../verification-code-handler";
|
||||
|
||||
export const POST = neonIntegrationProjectTransferCodeHandler.checkHandler;
|
||||
export const POST = integrationProjectTransferCodeHandler.checkHandler;
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
import { neonIntegrationProjectTransferCodeHandler } from "./verification-code-handler";
|
||||
import { integrationProjectTransferCodeHandler } from "./verification-code-handler";
|
||||
|
||||
export const POST = neonIntegrationProjectTransferCodeHandler.postHandler;
|
||||
export const POST = integrationProjectTransferCodeHandler.postHandler;
|
||||
|
||||
@ -5,7 +5,7 @@ import { KnownErrors } from "@stackframe/stack-shared";
|
||||
import { yupNumber, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
|
||||
import { StatusError, throwErr } from "@stackframe/stack-shared/dist/utils/errors";
|
||||
|
||||
export const neonIntegrationProjectTransferCodeHandler = createVerificationCodeHandler({
|
||||
export const integrationProjectTransferCodeHandler = createVerificationCodeHandler({
|
||||
metadata: {
|
||||
post: {
|
||||
hidden: true,
|
||||
@ -16,7 +16,7 @@ export const neonIntegrationProjectTransferCodeHandler = createVerificationCodeH
|
||||
},
|
||||
type: VerificationCodeType.INTEGRATION_PROJECT_TRANSFER,
|
||||
data: yupObject({
|
||||
neon_client_id: yupString().defined(),
|
||||
external_project_id: yupString().defined(),
|
||||
project_id: yupString().defined(),
|
||||
}).defined(),
|
||||
method: yupObject({}),
|
||||
@ -34,7 +34,7 @@ export const neonIntegrationProjectTransferCodeHandler = createVerificationCodeH
|
||||
const provisionedProjects = await prismaClient.provisionedProject.findMany({
|
||||
where: {
|
||||
projectId: data.project_id,
|
||||
neonClientId: data.neon_client_id,
|
||||
externalProjectId: data.external_project_id,
|
||||
},
|
||||
});
|
||||
if (provisionedProjects.length === 0) throw new StatusError(400, "The project to transfer was not provisioned by Neon or has already been transferred.");
|
||||
@ -48,7 +48,7 @@ export const neonIntegrationProjectTransferCodeHandler = createVerificationCodeH
|
||||
const provisionedProject = await tx.provisionedProject.deleteMany({
|
||||
where: {
|
||||
projectId: data.project_id,
|
||||
neonClientId: data.neon_client_id,
|
||||
externalProjectId: data.external_project_id,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import { neonAuthorizationHeaderSchema, urlSchema, yupNumber, yupObject, yupStri
|
||||
import { getEnvVariable } from "@stackframe/stack-shared/dist/utils/env";
|
||||
import { StatusError, throwErr } from "@stackframe/stack-shared/dist/utils/errors";
|
||||
import { decodeBasicAuthorizationHeader } from "@stackframe/stack-shared/dist/utils/http";
|
||||
import { neonIntegrationProjectTransferCodeHandler } from "./confirm/verification-code-handler";
|
||||
import { integrationProjectTransferCodeHandler } from "./confirm/verification-code-handler";
|
||||
|
||||
async function validateAndGetTransferInfo(authorizationHeader: string, projectId: string) {
|
||||
const [clientId, clientSecret] = decodeBasicAuthorizationHeader(authorizationHeader)!;
|
||||
@ -15,7 +15,7 @@ async function validateAndGetTransferInfo(authorizationHeader: string, projectId
|
||||
const provisionedProject = await prismaClient.provisionedProject.findUnique({
|
||||
where: {
|
||||
projectId,
|
||||
neonClientId: clientId,
|
||||
externalProjectId: clientId,
|
||||
},
|
||||
});
|
||||
if (!provisionedProject) {
|
||||
@ -84,12 +84,12 @@ export const POST = createSmartRouteHandler({
|
||||
handler: async (req) => {
|
||||
const { provisionedProject } = await validateAndGetTransferInfo(req.headers.authorization[0], req.body.project_id);
|
||||
|
||||
const transferCodeObj = await neonIntegrationProjectTransferCodeHandler.createCode({
|
||||
const transferCodeObj = await integrationProjectTransferCodeHandler.createCode({
|
||||
tenancy: await getSoleTenancyFromProjectBranch("internal", DEFAULT_BRANCH_ID),
|
||||
method: {},
|
||||
data: {
|
||||
project_id: provisionedProject.projectId,
|
||||
neon_client_id: provisionedProject.neonClientId,
|
||||
external_project_id: provisionedProject.externalProjectId,
|
||||
},
|
||||
callbackUrl: new URL("/integrations/custom/projects/transfer/confirm", getEnvVariable("NEXT_PUBLIC_STACK_DASHBOARD_URL")),
|
||||
expiresInMs: 1000 * 60 * 60,
|
||||
|
||||
@ -367,13 +367,13 @@ export async function createOidcProvider(options: { id: string, baseUrl: string,
|
||||
if (typeof state !== 'string') {
|
||||
throwErr(`state is not a string`);
|
||||
}
|
||||
let neonProjectName: string | undefined;
|
||||
let externalProjectName: string | undefined;
|
||||
try {
|
||||
const base64Decoded = new TextDecoder().decode(decodeBase64OrBase64Url(state));
|
||||
const json = JSON.parse(base64Decoded);
|
||||
neonProjectName = json?.details?.neon_project_name;
|
||||
if (typeof neonProjectName !== 'string') {
|
||||
throwErr(`neon_project_name is not a string`, { type: typeof neonProjectName, neonProjectName });
|
||||
externalProjectName = json?.details?.external_project_name ?? json?.details?.neon_project_name;
|
||||
if (typeof externalProjectName !== 'string') {
|
||||
throwErr(`external_project_name is not a string`, { type: typeof externalProjectName, externalProjectName });
|
||||
}
|
||||
} catch (e) {
|
||||
// this probably shouldn't happen, because it means Neon messed up the configuration
|
||||
@ -385,8 +385,8 @@ export async function createOidcProvider(options: { id: string, baseUrl: string,
|
||||
const uid = ctx.path.split('/')[2];
|
||||
const interactionUrl = new URL(options.clientInteractionUrl);
|
||||
interactionUrl.searchParams.set("interaction_uid", uid);
|
||||
if (neonProjectName) {
|
||||
interactionUrl.searchParams.set("neon_project_name", neonProjectName);
|
||||
if (externalProjectName) {
|
||||
interactionUrl.searchParams.set("external_project_name", externalProjectName);
|
||||
}
|
||||
return ctx.redirect(interactionUrl.toString());
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ export const POST = createSmartRouteHandler({
|
||||
body: yupObject({
|
||||
interaction_uid: yupString().defined(),
|
||||
project_id: yupString().defined(),
|
||||
neon_project_name: yupString().optional(),
|
||||
external_project_name: yupString().optional(),
|
||||
}).defined(),
|
||||
}),
|
||||
response: yupObject({
|
||||
@ -33,7 +33,7 @@ export const POST = createSmartRouteHandler({
|
||||
const set = await prismaClient.apiKeySet.create({
|
||||
data: {
|
||||
projectId: req.body.project_id,
|
||||
description: `Auto-generated for Neon${req.body.neon_project_name ? ` (${req.body.neon_project_name})` : ""}`,
|
||||
description: `Auto-generated for ${req.body.external_project_name ? `"${req.body.external_project_name}"` : "an external project"}`,
|
||||
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 100),
|
||||
superSecretAdminKey: `sak_${generateSecureRandomString()}`,
|
||||
},
|
||||
|
||||
@ -54,7 +54,7 @@ export const POST = createSmartRouteHandler({
|
||||
await prismaClient.provisionedProject.create({
|
||||
data: {
|
||||
projectId: createdProject.id,
|
||||
neonClientId: clientId,
|
||||
externalProjectId: clientId,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ export const neonIntegrationProjectTransferCodeHandler = createVerificationCodeH
|
||||
const provisionedProjects = await prismaClient.provisionedProject.findMany({
|
||||
where: {
|
||||
projectId: data.project_id,
|
||||
neonClientId: data.neon_client_id,
|
||||
externalProjectId: data.neon_client_id,
|
||||
},
|
||||
});
|
||||
if (provisionedProjects.length === 0) throw new StatusError(400, "The project to transfer was not provisioned by Neon or has already been transferred.");
|
||||
@ -48,7 +48,7 @@ export const neonIntegrationProjectTransferCodeHandler = createVerificationCodeH
|
||||
const provisionedProject = await tx.provisionedProject.deleteMany({
|
||||
where: {
|
||||
projectId: data.project_id,
|
||||
neonClientId: data.neon_client_id,
|
||||
externalProjectId: data.neon_client_id,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ async function validateAndGetTransferInfo(authorizationHeader: string, projectId
|
||||
const provisionedProject = await prismaClient.provisionedProject.findUnique({
|
||||
where: {
|
||||
projectId,
|
||||
neonClientId: clientId,
|
||||
externalProjectId: clientId,
|
||||
},
|
||||
});
|
||||
if (!provisionedProject) {
|
||||
@ -89,7 +89,7 @@ export const POST = createSmartRouteHandler({
|
||||
method: {},
|
||||
data: {
|
||||
project_id: provisionedProject.projectId,
|
||||
neon_client_id: provisionedProject.neonClientId,
|
||||
neon_client_id: provisionedProject.externalProjectId,
|
||||
},
|
||||
callbackUrl: new URL("/integrations/neon/projects/transfer/confirm", getEnvVariable("NEXT_PUBLIC_STACK_DASHBOARD_URL")),
|
||||
expiresInMs: 1000 * 60 * 60,
|
||||
|
||||
@ -12,7 +12,7 @@ async function authorizePart1(redirectUri: string = "http://localhost:30000/api/
|
||||
response_type: "code",
|
||||
client_id: "custom-local",
|
||||
redirect_uri: redirectUri,
|
||||
state: encodeBase64Url(new TextEncoder().encode(JSON.stringify({ details: { neon_project_name: 'custom-project' } }))),
|
||||
state: encodeBase64Url(new TextEncoder().encode(JSON.stringify({ details: { external_project_name: 'custom-project' } }))),
|
||||
code_challenge: "xf6HY7PIgoaCf_eMniSt-45brYE2J_05C9BnfIbueik",
|
||||
code_challenge_method: "S256",
|
||||
},
|
||||
@ -95,7 +95,7 @@ async function authorize(projectId: string) {
|
||||
"status": 307,
|
||||
"body": "http://localhost:8101/integrations/custom/confirm?interaction_uid=%3Cstripped+query+param%3E&=",
|
||||
"headers": Headers {
|
||||
"location": "http://localhost:8101/integrations/custom/confirm?interaction_uid=%3Cstripped+query+param%3E&neon_project_name=custom-project",
|
||||
"location": "http://localhost:8101/integrations/custom/confirm?interaction_uid=%3Cstripped+query+param%3E&external_project_name=custom-project",
|
||||
<some fields may have been hidden>,
|
||||
},
|
||||
},
|
||||
@ -179,7 +179,7 @@ it(`should not redirect to the incorrect callback URL`, async ({}) => {
|
||||
"error": "invalid_redirect_uri",
|
||||
"error_description": "redirect_uri did not match any of the client's registered redirect_uris",
|
||||
"iss": "http://localhost:8102/api/v1/integrations/custom/oauth/idp",
|
||||
"state": "eyJkZXRhaWxzIjp7Im5lb25fcHJvamVjdF9uYW1lIjoiY3VzdG9tLXByb2plY3QifX0",
|
||||
"state": "eyJkZXRhaWxzIjp7ImV4dGVybmFsX3Byb2plY3RfbmFtZSI6ImN1c3RvbS1wcm9qZWN0In19",
|
||||
},
|
||||
"headers": Headers { <some fields may have been hidden> },
|
||||
},
|
||||
@ -233,7 +233,7 @@ it(`should exchange the authorization code for an admin API key that works`, asy
|
||||
"items": [
|
||||
{
|
||||
"created_at_millis": <stripped field 'created_at_millis'>,
|
||||
"description": "Auto-generated for Neon",
|
||||
"description": "Auto-generated for an external project",
|
||||
"expires_at_millis": <stripped field 'expires_at_millis'>,
|
||||
"id": "<stripped UUID>",
|
||||
"super_secret_admin_key": { "last_four": <stripped field 'last_four'> },
|
||||
|
||||
@ -95,7 +95,7 @@ async function authorize(projectId: string) {
|
||||
"status": 307,
|
||||
"body": "http://localhost:8101/integrations/neon/confirm?interaction_uid=%3Cstripped+query+param%3E&=",
|
||||
"headers": Headers {
|
||||
"location": "http://localhost:8101/integrations/neon/confirm?interaction_uid=%3Cstripped+query+param%3E&neon_project_name=neon-project",
|
||||
"location": "http://localhost:8101/integrations/neon/confirm?interaction_uid=%3Cstripped+query+param%3E&external_project_name=neon-project",
|
||||
<some fields may have been hidden>,
|
||||
},
|
||||
},
|
||||
@ -233,7 +233,7 @@ it(`should exchange the authorization code for an admin API key that works`, asy
|
||||
"items": [
|
||||
{
|
||||
"created_at_millis": <stripped field 'created_at_millis'>,
|
||||
"description": "Auto-generated for Neon",
|
||||
"description": "Auto-generated for an external project",
|
||||
"expires_at_millis": <stripped field 'expires_at_millis'>,
|
||||
"id": "<stripped UUID>",
|
||||
"super_secret_admin_key": { "last_four": <stripped field 'last_four'> },
|
||||
|
||||
Loading…
Reference in New Issue
Block a user