sst 2.11.17 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bootstrap.js +5 -0
- package/constructs/Stack.js +5 -0
- package/node/future/auth/adapter/link.d.ts +3 -1
- package/node/future/auth/adapter/link.js +13 -16
- package/node/future/auth/handler.d.ts +21 -1
- package/node/future/auth/handler.js +102 -56
- package/package.json +1 -1
- package/project.d.ts +5 -0
- package/sst.mjs +7 -1
- package/stacks/build.js +1 -0
package/bootstrap.js
CHANGED
|
@@ -127,6 +127,11 @@ export async function bootstrapSST() {
|
|
|
127
127
|
synthesizer: new DefaultStackSynthesizer({
|
|
128
128
|
qualifier: cdk?.qualifier,
|
|
129
129
|
fileAssetsBucketName: cdk?.fileAssetsBucketName,
|
|
130
|
+
deployRoleArn: cdk?.deployRoleArn,
|
|
131
|
+
fileAssetPublishingRoleArn: cdk?.fileAssetPublishingRoleArn,
|
|
132
|
+
imageAssetPublishingRoleArn: cdk?.imageAssetPublishingRoleArn,
|
|
133
|
+
cloudFormationExecutionRole: cdk?.cloudFormationExecutionRole,
|
|
134
|
+
lookupRoleArn: cdk?.lookupRoleArn,
|
|
130
135
|
}),
|
|
131
136
|
});
|
|
132
137
|
// Add tags to stack
|
package/constructs/Stack.js
CHANGED
|
@@ -210,6 +210,11 @@ export class Stack extends CDKStack {
|
|
|
210
210
|
return new DefaultStackSynthesizer({
|
|
211
211
|
qualifier: config.cdk?.qualifier,
|
|
212
212
|
fileAssetsBucketName: config.cdk?.fileAssetsBucketName,
|
|
213
|
+
deployRoleArn: config.cdk?.deployRoleArn,
|
|
214
|
+
fileAssetPublishingRoleArn: config.cdk?.fileAssetPublishingRoleArn,
|
|
215
|
+
imageAssetPublishingRoleArn: config.cdk?.imageAssetPublishingRoleArn,
|
|
216
|
+
cloudFormationExecutionRole: config.cdk?.cloudFormationExecutionRole,
|
|
217
|
+
lookupRoleArn: config.cdk?.lookupRoleArn,
|
|
213
218
|
});
|
|
214
219
|
}
|
|
215
220
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { APIGatewayProxyStructuredResultV2 } from "aws-lambda";
|
|
2
2
|
export declare function LinkAdapter(config: {
|
|
3
3
|
onLink: (link: string, claims: Record<string, any>) => Promise<APIGatewayProxyStructuredResultV2>;
|
|
4
|
-
onError: (error: any) => Promise<APIGatewayProxyStructuredResultV2>;
|
|
5
4
|
}): () => Promise<{
|
|
6
5
|
type: "step";
|
|
7
6
|
properties: APIGatewayProxyStructuredResultV2;
|
|
8
7
|
} | {
|
|
9
8
|
type: "success";
|
|
10
9
|
properties: any;
|
|
10
|
+
} | {
|
|
11
|
+
type: "error";
|
|
12
|
+
properties?: undefined;
|
|
11
13
|
}>;
|
|
@@ -2,16 +2,16 @@ import { createSigner, createVerifier } from "fast-jwt";
|
|
|
2
2
|
import { Config } from "../../../config/index.js";
|
|
3
3
|
import { useDomainName, usePathParam, useQueryParam, useQueryParams, } from "../../../api/index.js";
|
|
4
4
|
export function LinkAdapter(config) {
|
|
5
|
-
// @ts-expect-error
|
|
6
|
-
const key = Config[process.env.AUTH_ID + "PrivateKey"];
|
|
7
|
-
// @ts-expect-error
|
|
8
|
-
const publicKey = Config[process.env.AUTH_ID + "PublicKey"];
|
|
9
|
-
const signer = createSigner({
|
|
10
|
-
expiresIn: 1000 * 60 * 10,
|
|
11
|
-
key,
|
|
12
|
-
algorithm: "RS512",
|
|
13
|
-
});
|
|
14
5
|
return async function () {
|
|
6
|
+
// @ts-expect-error
|
|
7
|
+
const key = Config[process.env.AUTH_ID + "PrivateKey"];
|
|
8
|
+
// @ts-expect-error
|
|
9
|
+
const publicKey = Config[process.env.AUTH_ID + "PublicKey"];
|
|
10
|
+
const signer = createSigner({
|
|
11
|
+
expiresIn: 1000 * 60 * 10,
|
|
12
|
+
key,
|
|
13
|
+
algorithm: "RS512",
|
|
14
|
+
});
|
|
15
15
|
const callback = "https://" + useDomainName() + "/callback";
|
|
16
16
|
const step = usePathParam("step");
|
|
17
17
|
if (step === "authorize") {
|
|
@@ -38,13 +38,10 @@ export function LinkAdapter(config) {
|
|
|
38
38
|
properties: jwt,
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
catch (ex) {
|
|
42
|
-
return {
|
|
43
|
-
type: "step",
|
|
44
|
-
properties: await config.onError(ex),
|
|
45
|
-
};
|
|
46
|
-
}
|
|
41
|
+
catch (ex) { }
|
|
47
42
|
}
|
|
48
|
-
|
|
43
|
+
return {
|
|
44
|
+
type: "error",
|
|
45
|
+
};
|
|
49
46
|
};
|
|
50
47
|
}
|
|
@@ -2,6 +2,25 @@ import { APIGatewayProxyEventV2, APIGatewayProxyStructuredResultV2 } from "aws-l
|
|
|
2
2
|
import { Adapter } from "./adapter/adapter.js";
|
|
3
3
|
import { SignerOptions } from "fast-jwt";
|
|
4
4
|
import { SessionValue } from "./session.js";
|
|
5
|
+
declare const onSuccessResponse: {
|
|
6
|
+
session(input: SessionCreateInput): {
|
|
7
|
+
type: "session";
|
|
8
|
+
properties: SessionCreateInput;
|
|
9
|
+
};
|
|
10
|
+
http(input: APIGatewayProxyStructuredResultV2): {
|
|
11
|
+
type: "http";
|
|
12
|
+
properties: APIGatewayProxyStructuredResultV2;
|
|
13
|
+
};
|
|
14
|
+
provider(provider: string): {
|
|
15
|
+
type: "http";
|
|
16
|
+
properties: {
|
|
17
|
+
statusCode: number;
|
|
18
|
+
headers: {
|
|
19
|
+
Location: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
5
24
|
export declare function AuthHandler<Providers extends Record<string, Adapter<any>>, Result = {
|
|
6
25
|
[key in keyof Providers]: {
|
|
7
26
|
provider: key;
|
|
@@ -12,7 +31,8 @@ export declare function AuthHandler<Providers extends Record<string, Adapter<any
|
|
|
12
31
|
providers: Providers;
|
|
13
32
|
clients: () => Promise<Record<string, string>>;
|
|
14
33
|
onAuthorize?: (event: APIGatewayProxyEventV2) => Promise<void | keyof Providers>;
|
|
15
|
-
onSuccess: (input: Result) => Promise<
|
|
34
|
+
onSuccess: (input: Result, response: typeof onSuccessResponse) => Promise<ReturnType<(typeof onSuccessResponse)[keyof typeof onSuccessResponse]>>;
|
|
16
35
|
onError: () => Promise<APIGatewayProxyStructuredResultV2>;
|
|
17
36
|
}): (event: APIGatewayProxyEventV2, context: import("aws-lambda").Context) => Promise<APIGatewayProxyStructuredResultV2>;
|
|
18
37
|
export type SessionCreateInput = SessionValue & Partial<SignerOptions>;
|
|
38
|
+
export {};
|
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
import { createSigner, createVerifier } from "fast-jwt";
|
|
2
2
|
import { ApiHandler, useCookie, useCookies, useFormValue, usePathParam, useQueryParam, useQueryParams, useResponse, } from "../../api/index.js";
|
|
3
3
|
import { Config } from "../../config/index.js";
|
|
4
|
+
const onSuccessResponse = {
|
|
5
|
+
session(input) {
|
|
6
|
+
return {
|
|
7
|
+
type: "session",
|
|
8
|
+
properties: input,
|
|
9
|
+
};
|
|
10
|
+
},
|
|
11
|
+
http(input) {
|
|
12
|
+
return {
|
|
13
|
+
type: "http",
|
|
14
|
+
properties: input,
|
|
15
|
+
};
|
|
16
|
+
},
|
|
17
|
+
provider(provider) {
|
|
18
|
+
return {
|
|
19
|
+
type: "http",
|
|
20
|
+
properties: {
|
|
21
|
+
statusCode: 302,
|
|
22
|
+
headers: {
|
|
23
|
+
Location: "/authorize?" +
|
|
24
|
+
new URLSearchParams({
|
|
25
|
+
provider,
|
|
26
|
+
response_type: useCookie("response_type"),
|
|
27
|
+
client_id: useCookie("client_id"),
|
|
28
|
+
redirect_uri: useCookie("redirect_uri"),
|
|
29
|
+
}).toString(),
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
};
|
|
4
35
|
export function AuthHandler(input) {
|
|
5
36
|
return ApiHandler(async (evt) => {
|
|
6
37
|
const step = usePathParam("step");
|
|
@@ -13,6 +44,9 @@ export function AuthHandler(input) {
|
|
|
13
44
|
},
|
|
14
45
|
body: `
|
|
15
46
|
<html>
|
|
47
|
+
<head>
|
|
48
|
+
<link rel="icon" href="data:,">
|
|
49
|
+
</head>
|
|
16
50
|
<body>
|
|
17
51
|
<table>
|
|
18
52
|
<tr>${Object.keys(clients).map((client) => `<td>${client}</td>`)}</tr>
|
|
@@ -30,6 +64,11 @@ export function AuthHandler(input) {
|
|
|
30
64
|
`,
|
|
31
65
|
};
|
|
32
66
|
}
|
|
67
|
+
if (step === "favicon.ico") {
|
|
68
|
+
return {
|
|
69
|
+
statusCode: 404,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
33
72
|
if (step === "token") {
|
|
34
73
|
if (useFormValue("grant_type") !== "authorization_code") {
|
|
35
74
|
return {
|
|
@@ -139,70 +178,77 @@ export function AuthHandler(input) {
|
|
|
139
178
|
return result.properties;
|
|
140
179
|
}
|
|
141
180
|
if (result.type === "success") {
|
|
142
|
-
const
|
|
181
|
+
const onSuccess = await input.onSuccess({
|
|
143
182
|
provider,
|
|
144
183
|
...result.properties,
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const token = signer({
|
|
154
|
-
type,
|
|
155
|
-
properties,
|
|
156
|
-
});
|
|
157
|
-
useResponse().cookie({
|
|
158
|
-
key: "sst_auth_token",
|
|
159
|
-
value: token,
|
|
160
|
-
maxAge: 10 * 365 * 24 * 60 * 60,
|
|
161
|
-
secure: true,
|
|
162
|
-
sameSite: "None",
|
|
163
|
-
httpOnly: true,
|
|
164
|
-
});
|
|
165
|
-
const { client_id, response_type, redirect_uri, state } = {
|
|
166
|
-
...useCookies(),
|
|
167
|
-
...useQueryParams(),
|
|
168
|
-
};
|
|
169
|
-
if (response_type === "token") {
|
|
170
|
-
const location = new URL(redirect_uri);
|
|
171
|
-
location.hash = `access_token=${token}&state=${state || ""}`;
|
|
172
|
-
return {
|
|
173
|
-
statusCode: 302,
|
|
174
|
-
headers: {
|
|
175
|
-
Location: location.href,
|
|
176
|
-
},
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
if (response_type === "code") {
|
|
180
|
-
// This allows the code to be reused within a 30 second window
|
|
181
|
-
// The code should be single use but we're making this tradeoff to remain stateless
|
|
182
|
-
// In the future can store this in a dynamo table to ensure single use
|
|
183
|
-
const code = createSigner({
|
|
184
|
-
expiresIn: 1000 * 60 * 5,
|
|
184
|
+
}, onSuccessResponse);
|
|
185
|
+
console.log("onSuccess", onSuccess);
|
|
186
|
+
if (onSuccess.type === "session") {
|
|
187
|
+
const { type, properties, ...rest } = onSuccess.properties;
|
|
188
|
+
// @ts-expect-error
|
|
189
|
+
const priv = Config[process.env.AUTH_ID + "PrivateKey"];
|
|
190
|
+
const signer = createSigner({
|
|
191
|
+
...rest,
|
|
185
192
|
key: priv,
|
|
186
193
|
algorithm: "RS512",
|
|
187
|
-
})({
|
|
188
|
-
client_id,
|
|
189
|
-
redirect_uri,
|
|
190
|
-
token: token,
|
|
191
194
|
});
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
+
const token = signer({
|
|
196
|
+
type,
|
|
197
|
+
properties,
|
|
198
|
+
});
|
|
199
|
+
useResponse().cookie({
|
|
200
|
+
key: "sst_auth_token",
|
|
201
|
+
value: token,
|
|
202
|
+
maxAge: 10 * 365 * 24 * 60 * 60,
|
|
203
|
+
secure: true,
|
|
204
|
+
sameSite: "None",
|
|
205
|
+
httpOnly: true,
|
|
206
|
+
});
|
|
207
|
+
const { client_id, response_type, redirect_uri, state } = {
|
|
208
|
+
...useCookies(),
|
|
209
|
+
...useQueryParams(),
|
|
210
|
+
};
|
|
211
|
+
if (response_type === "token") {
|
|
212
|
+
const location = new URL(redirect_uri);
|
|
213
|
+
location.hash = `access_token=${token}&state=${state || ""}`;
|
|
214
|
+
return {
|
|
215
|
+
statusCode: 302,
|
|
216
|
+
headers: {
|
|
217
|
+
Location: location.href,
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
if (response_type === "code") {
|
|
222
|
+
// This allows the code to be reused within a 30 second window
|
|
223
|
+
// The code should be single use but we're making this tradeoff to remain stateless
|
|
224
|
+
// In the future can store this in a dynamo table to ensure single use
|
|
225
|
+
const code = createSigner({
|
|
226
|
+
expiresIn: 1000 * 60 * 5,
|
|
227
|
+
key: priv,
|
|
228
|
+
algorithm: "RS512",
|
|
229
|
+
})({
|
|
230
|
+
client_id,
|
|
231
|
+
redirect_uri,
|
|
232
|
+
token: token,
|
|
233
|
+
});
|
|
234
|
+
const location = new URL(redirect_uri);
|
|
235
|
+
location.searchParams.set("code", code);
|
|
236
|
+
location.searchParams.set("state", state || "");
|
|
237
|
+
return {
|
|
238
|
+
statusCode: 302,
|
|
239
|
+
headers: {
|
|
240
|
+
Location: location.href,
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
195
244
|
return {
|
|
196
|
-
statusCode:
|
|
197
|
-
|
|
198
|
-
Location: location.href,
|
|
199
|
-
},
|
|
245
|
+
statusCode: 400,
|
|
246
|
+
body: `Unsupported response_type: ${response_type}`,
|
|
200
247
|
};
|
|
201
248
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
};
|
|
249
|
+
if (onSuccess.type === "http") {
|
|
250
|
+
return onSuccess.properties;
|
|
251
|
+
}
|
|
206
252
|
}
|
|
207
253
|
if (result.type === "error") {
|
|
208
254
|
return input.onError();
|
package/package.json
CHANGED
package/project.d.ts
CHANGED
|
@@ -24,6 +24,11 @@ export interface ConfigOptions {
|
|
|
24
24
|
fileAssetsBucketName?: string;
|
|
25
25
|
customPermissionsBoundary?: string;
|
|
26
26
|
publicAccessBlockConfiguration?: boolean;
|
|
27
|
+
deployRoleArn?: string;
|
|
28
|
+
fileAssetPublishingRoleArn?: string;
|
|
29
|
+
imageAssetPublishingRoleArn?: string;
|
|
30
|
+
cloudFormationExecutionRole?: string;
|
|
31
|
+
lookupRoleArn?: string;
|
|
27
32
|
};
|
|
28
33
|
}
|
|
29
34
|
declare const DEFAULTS: {
|
package/sst.mjs
CHANGED
|
@@ -284,6 +284,7 @@ async function load(input, shallow) {
|
|
|
284
284
|
let contents = await fs3.readFile(args.path).then((x) => x.toString());
|
|
285
285
|
const ast = babel.parse(contents, {
|
|
286
286
|
sourceType: "module",
|
|
287
|
+
filename: "sst.config.ts",
|
|
287
288
|
plugins: [ts]
|
|
288
289
|
});
|
|
289
290
|
babel.traverse(ast, {
|
|
@@ -5310,7 +5311,12 @@ async function bootstrapSST() {
|
|
|
5310
5311
|
},
|
|
5311
5312
|
synthesizer: new DefaultStackSynthesizer({
|
|
5312
5313
|
qualifier: cdk?.qualifier,
|
|
5313
|
-
fileAssetsBucketName: cdk?.fileAssetsBucketName
|
|
5314
|
+
fileAssetsBucketName: cdk?.fileAssetsBucketName,
|
|
5315
|
+
deployRoleArn: cdk?.deployRoleArn,
|
|
5316
|
+
fileAssetPublishingRoleArn: cdk?.fileAssetPublishingRoleArn,
|
|
5317
|
+
imageAssetPublishingRoleArn: cdk?.imageAssetPublishingRoleArn,
|
|
5318
|
+
cloudFormationExecutionRole: cdk?.cloudFormationExecutionRole,
|
|
5319
|
+
lookupRoleArn: cdk?.lookupRoleArn
|
|
5314
5320
|
})
|
|
5315
5321
|
});
|
|
5316
5322
|
for (const [key, value] of Object.entries(bootstrap2?.tags || {})) {
|