Skip to content

Commit 8950fda

Browse files
committed
Fix Neon malformed Basic auth validation
Fixes STACK-BACKEND-1A3
1 parent 37e70ca commit 8950fda

2 files changed

Lines changed: 39 additions & 3 deletions

File tree

apps/e2e/tests/backend/endpoints/api/v1/integrations/neon/projects/transfer.test.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,38 @@ it("should fail if the neon client details are missing", async ({ expect }) => {
215215
`);
216216
});
217217

218+
it("should fail if the neon client authorization header is malformed", async ({ expect }) => {
219+
const projectId = "73782539-cf39-486b-a9f8-9b2893f79ef2";
220+
const response = await niceBackendFetch(urlString`/api/v1/integrations/neon/projects/transfer?project_id=${projectId}`, {
221+
method: "GET",
222+
headers: {
223+
"Authorization": "Basic",
224+
},
225+
});
226+
expect(response).toMatchInlineSnapshot(`
227+
NiceResponse {
228+
"status": 400,
229+
"body": {
230+
"code": "SCHEMA_ERROR",
231+
"details": {
232+
"message": deindent\`
233+
Request validation failed on GET /api/v1/integrations/neon/projects/transfer:
234+
- Authorization header must be in the format "Basic <base64>"
235+
\`,
236+
},
237+
"error": deindent\`
238+
Request validation failed on GET /api/v1/integrations/neon/projects/transfer:
239+
- Authorization header must be in the format "Basic <base64>"
240+
\`,
241+
},
242+
"headers": Headers {
243+
"x-stack-known-error": "SCHEMA_ERROR",
244+
<some fields may have been hidden>,
245+
},
246+
}
247+
`);
248+
});
249+
218250
it("should fail to transfer project if the user is not signed in", async ({ expect }) => {
219251
const provisioned = await provisionProject();
220252
const projectId = provisioned.body.project_id;
@@ -305,4 +337,3 @@ it("should fail the check if project was already transferred", async ({ expect }
305337
}
306338
`);
307339
});
308-

packages/stack-shared/src/schema-fields.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { KnownErrors } from "./known-errors";
33
import { isBase64 } from "./utils/bytes";
44
import { SUPPORTED_CURRENCIES, type Currency, type MoneyAmount } from "./utils/currency-constants";
55
import type { DayInterval, Interval } from "./utils/dates";
6-
import { StackAssertionError, throwErr } from "./utils/errors";
6+
import { StackAssertionError } from "./utils/errors";
77
import { decodeBasicAuthorizationHeader } from "./utils/http";
88
import { allProviders } from "./utils/oauth";
99
import { deepPlainClone, omit, typedFromEntries } from "./utils/objects";
@@ -878,12 +878,17 @@ export const basicAuthorizationHeaderSchema = yupString().test('is-basic-authori
878878
// Neon integration
879879
export const neonAuthorizationHeaderSchema = basicAuthorizationHeaderSchema.test('is-authorization-header', 'Invalid client_id:client_secret values; did you use the correct values for the integration?', (value) => {
880880
if (!value) return true;
881-
const [clientId, clientSecret] = decodeBasicAuthorizationHeader(value) ?? throwErr(`Authz header invalid? This should've been validated by basicAuthorizationHeaderSchema: ${value}`);
881+
const decoded = decodeBasicAuthorizationHeader(value);
882+
if (decoded === null) return true;
883+
const [clientId, clientSecret] = decoded;
882884
for (const neonClientConfig of JSON.parse(process.env.STACK_INTEGRATION_CLIENTS_CONFIG || '[]')) {
883885
if (clientId === neonClientConfig.client_id && clientSecret === neonClientConfig.client_secret) return true;
884886
}
885887
return false;
886888
});
889+
import.meta.vitest?.test("neonAuthorizationHeaderSchema handles malformed Basic auth as a validation error", async ({ expect }) => {
890+
await expect(neonAuthorizationHeaderSchema.validate("Basic")).rejects.toThrow('Authorization header must be in the format "Basic <base64>"');
891+
});
887892

888893
// Utils
889894
export function yupDefinedWhen<S extends yup.AnyObject>(

0 commit comments

Comments
 (0)