Skip to content

Commit 73f522d

Browse files
committed
chore: update-routes,fix-cookie,etc
1 parent bb81839 commit 73f522d

6 files changed

Lines changed: 199 additions & 106 deletions

File tree

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) 2025 Ping Identity Corporation. All rights reserved.
3+
*
4+
* This software may be modified and distributed under the terms
5+
* of the MIT license. See the LICENSE file for details.
6+
*/
7+
8+
export const addStepCookie = (spec: any) => {
9+
const FLOW_TAGS = new Set(['Authorization', 'Capabilities']);
10+
const FLOW_PATH_MATCHERS = [
11+
/\/davinci\/authorize\b/,
12+
/\/davinci\/connections\/[^/]+\/capabilities\//,
13+
];
14+
15+
const shouldAnnotate = (path: string, op: any) =>
16+
(Array.isArray(op?.tags) && op.tags.some((t: string) => FLOW_TAGS.has(t))) ||
17+
FLOW_PATH_MATCHERS.some((rx) => rx.test(path));
18+
19+
const addCookieParam = (op: any) => {
20+
op.parameters ||= [];
21+
const already = op.parameters.some(
22+
(p: any) => p && p.in === 'cookie' && p.name === 'stepIndex',
23+
);
24+
if (!already) {
25+
op.parameters.push({
26+
name: 'stepIndex',
27+
in: 'cookie',
28+
required: false,
29+
description:
30+
'Current flow step. Server initializes on first request and increments thereafter.',
31+
schema: { type: 'integer', minimum: 0 },
32+
example: 2,
33+
});
34+
}
35+
};
36+
37+
const ensureSetCookie = (op: any, status: string) => {
38+
op.responses ||= {};
39+
const resp = (op.responses[status] ||= { description: 'Success' });
40+
resp.headers ||= {};
41+
if (!resp.headers['Set-Cookie']) {
42+
resp.headers['Set-Cookie'] = {
43+
description:
44+
'Updated step cookie (e.g., `stepIndex=3; Path=/; HttpOnly; Secure; SameSite=Lax`). ' +
45+
'May be removed on completion.',
46+
schema: { type: 'string' },
47+
example: 'stepIndex=3; Path=/; HttpOnly; Secure; SameSite=Lax',
48+
};
49+
}
50+
};
51+
52+
for (const [path, methods] of Object.entries(spec.paths ?? {})) {
53+
for (const [, op] of Object.entries<any>(methods as any)) {
54+
if (!op || typeof op !== 'object') continue;
55+
if (!shouldAnnotate(path, op)) continue;
56+
addCookieParam(op);
57+
// Add for common success statuses you use
58+
ensureSetCookie(op, '200');
59+
ensureSetCookie(op, '302');
60+
}
61+
}
62+
63+
return spec;
64+
};
65+
66+
export default addStepCookie;

e2e/mock-api-v2/src/handlers/capabilities.handler.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
66
*/
7-
import { Effect, pipe } from 'effect';
7+
import { Console, Effect, pipe } from 'effect';
88
import { MockApi } from '../spec.js';
99
import {
1010
HttpApiBuilder,
@@ -25,6 +25,7 @@ const CapabilitiesHandlerMock = HttpApiBuilder.group(MockApi, 'Capabilities', (h
2525
* If it is not present, we return a 404 Not Found error.
2626
*/
2727
const acr_value = urlParams?.acr_values ?? '';
28+
console.log('acr_value', acr_value);
2829

2930
if (!acr_value) {
3031
return yield* Effect.fail(new HttpApiError.NotFound());
@@ -38,12 +39,14 @@ const CapabilitiesHandlerMock = HttpApiBuilder.group(MockApi, 'Capabilities', (h
3839
const req = yield* HttpServerRequest.HttpServerRequest;
3940

4041
const stepIndexCookie = req.cookies['stepIndex'];
42+
console.log(req.cookies);
4143

4244
/**
4345
* If we are here with no step index that means we can't continue through a flow.
4446
* We should error
4547
*/
4648
if (!stepIndexCookie) {
49+
console.log('no step index');
4750
return yield* Effect.fail(new HttpApiError.NotFound());
4851
}
4952

@@ -89,6 +92,7 @@ const CapabilitiesHandlerMock = HttpApiBuilder.group(MockApi, 'Capabilities', (h
8992
* and we have no more steps to process.
9093
*/
9194
const body = yield* HttpBody.json(returnSuccessResponseRedirect).pipe(
95+
Effect.tap(Console.log(`here stepIndex: ${stepIndex}`)),
9296
/**
9397
* Decide on a better way to handle this error possibiltiy
9498
*/

e2e/mock-api-v2/src/middleware/CookieMiddleware.ts

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,74 @@
1+
/**
2+
* Copyright (c) 2025 Ping Identity Corporation.
3+
* MIT License
4+
*/
15
import {
2-
HttpServerResponse,
36
HttpApiMiddleware,
47
HttpApp,
58
HttpServerRequest,
9+
HttpServerResponse,
610
} from '@effect/platform';
711
import { ResponseError } from '@effect/platform/HttpServerError';
812
import { Console, Effect, Layer } from 'effect';
913

10-
class IncrementStepIndex extends HttpApiMiddleware.Tag<IncrementStepIndex>()(
14+
// Export the tag so you can .middleware(IncrementStepIndex) in your spec if desired
15+
export class IncrementStepIndex extends HttpApiMiddleware.Tag<IncrementStepIndex>()(
1116
'IncrementStepIndex',
1217
) {}
13-
const IncrementStepIndexMock = Layer.effect(
18+
19+
export const IncrementStepIndexMock = Layer.effect(
1420
IncrementStepIndex,
1521
Effect.gen(function* () {
16-
yield* Console.log('In middleware');
22+
yield* Console.log('IncrementStepIndex: init');
1723

1824
return Effect.gen(function* () {
19-
// Get the current request to read cookies
25+
// Read cookies from the current request
2026
const request = yield* HttpServerRequest.HttpServerRequest;
2127

2228
// Parse existing stepIndex cookie or default to 0
2329
const cookies = request.cookies;
24-
const currentStepIndex = cookies.stepIndex ? parseInt(cookies.stepIndex) : 0;
30+
const currentStepIndex = cookies.stepIndex ? parseInt(cookies.stepIndex, 10) : 0;
2531

26-
// Get the request URL path
27-
const urlPath = request.url.split('?')[0];
28-
// Check if this is an end-session request
29-
const isEndSessionRequest = urlPath.includes('/end_session');
30-
// Determine the new stepIndex based on the request type
32+
// Normalize URL (strip query) and detect special flows
33+
const urlPath = request.url.split('?')[0] ?? '';
34+
const isEndSessionRequest =
35+
urlPath.includes('/endSession') || urlPath.includes('/end_session');
36+
const isAuthFlowRequest = urlPath.includes('/authorize') || urlPath.includes('/authenticate');
37+
38+
// Decide next value
3139
let newStepIndex = currentStepIndex;
3240
if (isEndSessionRequest) {
33-
// Reset the stepIndex for end_session requests
3441
newStepIndex = 0;
35-
yield* Console.log('End session request detected, resetting stepIndex to: ' + newStepIndex);
36-
} else if (urlPath.includes('/authorize') || urlPath.includes('/authenticate')) {
37-
// Increment the stepIndex for authorization flow requests
42+
yield* Console.log(
43+
`IncrementStepIndex: end-session detected → resetting stepIndex to ${newStepIndex}`,
44+
);
45+
} else if (isAuthFlowRequest) {
3846
newStepIndex = currentStepIndex + 1;
3947
yield* Console.log(
40-
'Current stepIndex: ' + currentStepIndex + ', incrementing to: ' + newStepIndex,
48+
`IncrementStepIndex: auth flow → ${currentStepIndex} -> ${newStepIndex}`,
4149
);
4250
} else {
43-
// For other requests, keep the stepIndex the same
44-
yield* Console.log('Request to ' + urlPath + ', keeping stepIndex at: ' + currentStepIndex);
51+
yield* Console.log(
52+
`IncrementStepIndex: other route ${urlPath} → keeping stepIndex ${currentStepIndex}`,
53+
);
4554
}
4655

47-
// Set the appropriate stepIndex cookie in the response
48-
yield* HttpApp.appendPreResponseHandler((request, response) =>
49-
HttpServerResponse.setCookie(response, 'stepIndex', String(newStepIndex), {
50-
// Optional cookie options
56+
// Write cookie just before the response is sent
57+
yield* HttpApp.appendPreResponseHandler((req, res) =>
58+
HttpServerResponse.setCookie(res, 'stepIndex', String(newStepIndex), {
59+
// NOTE: mock defaults; tighten in prod (httpOnly: true, secure: true, sameSite: 'lax')
5160
httpOnly: false,
5261
secure: false,
5362
sameSite: 'strict',
63+
path: '/',
5464
}).pipe(
65+
// If cookie setting fails, convert to a typed ResponseError for consistent diagnostics
5566
Effect.catchTag(
5667
'CookieError',
5768
() =>
5869
new ResponseError({
59-
request,
60-
response,
70+
request: req,
71+
response: res,
6172
reason: 'Decode',
6273
cause: 'error updating the stepIndex cookie',
6374
}),
@@ -67,5 +78,3 @@ const IncrementStepIndexMock = Layer.effect(
6778
});
6879
}),
6980
);
70-
71-
export { IncrementStepIndexMock };
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { Schema } from 'effect';
22

33
export const CapabilitiesHeaders = Schema.Struct({
4-
'X-Requested-With': Schema.String,
5-
interactionId: Schema.String,
6-
interactionToken: Schema.String,
7-
'Content-Type': Schema.String,
4+
'X-Requested-With': Schema.optional(Schema.String),
5+
interactionId: Schema.optional(Schema.String),
6+
interactionToken: Schema.optional(Schema.String),
7+
'Content-Type': Schema.optional(Schema.String),
88
});

0 commit comments

Comments
 (0)