@scalekit-sdk/node 2.1.3 → 2.1.5
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/buf.gen.yaml +2 -0
- package/lib/core.js +1 -1
- package/lib/pkg/grpc/scalekit/v1/auditlogs/auditlogs_connect.d.ts +19 -0
- package/lib/pkg/grpc/scalekit/v1/auditlogs/auditlogs_connect.js +27 -0
- package/lib/pkg/grpc/scalekit/v1/auditlogs/auditlogs_connect.js.map +1 -0
- package/lib/pkg/grpc/scalekit/v1/auditlogs/auditlogs_pb.d.ts +154 -0
- package/lib/pkg/grpc/scalekit/v1/auditlogs/auditlogs_pb.js +226 -0
- package/lib/pkg/grpc/scalekit/v1/auditlogs/auditlogs_pb.js.map +1 -0
- package/lib/pkg/grpc/scalekit/v1/sessions/sessions_connect.d.ts +46 -0
- package/lib/pkg/grpc/scalekit/v1/sessions/sessions_connect.js +54 -0
- package/lib/pkg/grpc/scalekit/v1/sessions/sessions_connect.js.map +1 -0
- package/lib/pkg/grpc/scalekit/v1/sessions/sessions_pb.d.ts +377 -0
- package/lib/pkg/grpc/scalekit/v1/sessions/sessions_pb.js +513 -0
- package/lib/pkg/grpc/scalekit/v1/sessions/sessions_pb.js.map +1 -0
- package/lib/scalekit.d.ts +22 -0
- package/lib/scalekit.js +35 -6
- package/lib/scalekit.js.map +1 -1
- package/lib/session.d.ts +48 -0
- package/lib/session.js +101 -0
- package/lib/session.js.map +1 -0
- package/package.json +1 -1
- package/src/core.ts +1 -1
- package/src/pkg/grpc/scalekit/v1/auditlogs/auditlogs_connect.ts +26 -0
- package/src/pkg/grpc/scalekit/v1/auditlogs/auditlogs_pb.ts +282 -0
- package/src/pkg/grpc/scalekit/v1/sessions/sessions_connect.ts +53 -0
- package/src/pkg/grpc/scalekit/v1/sessions/sessions_pb.ts +697 -0
- package/src/scalekit.ts +42 -6
- package/src/session.ts +134 -0
package/src/scalekit.ts
CHANGED
|
@@ -10,6 +10,7 @@ import DomainClient from './domain';
|
|
|
10
10
|
import OrganizationClient from './organization';
|
|
11
11
|
import PasswordlessClient from './passwordless';
|
|
12
12
|
import UserClient from './user';
|
|
13
|
+
import SessionClient from './session';
|
|
13
14
|
import RoleClient from './role';
|
|
14
15
|
import PermissionClient from './permission';
|
|
15
16
|
import { IdpInitiatedLoginClaims, IdTokenClaim, User } from './types/auth';
|
|
@@ -39,6 +40,7 @@ export default class ScalekitClient {
|
|
|
39
40
|
readonly directory: DirectoryClient;
|
|
40
41
|
readonly passwordless: PasswordlessClient;
|
|
41
42
|
readonly user: UserClient;
|
|
43
|
+
readonly session: SessionClient;
|
|
42
44
|
readonly role: RoleClient;
|
|
43
45
|
readonly permission: PermissionClient;
|
|
44
46
|
constructor(
|
|
@@ -79,6 +81,10 @@ export default class ScalekitClient {
|
|
|
79
81
|
this.grpcConnect,
|
|
80
82
|
this.coreClient
|
|
81
83
|
);
|
|
84
|
+
this.session = new SessionClient(
|
|
85
|
+
this.grpcConnect,
|
|
86
|
+
this.coreClient
|
|
87
|
+
);
|
|
82
88
|
this.role = new RoleClient(
|
|
83
89
|
this.grpcConnect,
|
|
84
90
|
this.coreClient
|
|
@@ -251,7 +257,37 @@ export default class ScalekitClient {
|
|
|
251
257
|
const webhookTimestamp = headers['webhook-timestamp'];
|
|
252
258
|
const webhookSignature = headers['webhook-signature'];
|
|
253
259
|
|
|
254
|
-
|
|
260
|
+
return this.verifyPayloadSignature(secret, webhookId, webhookTimestamp, webhookSignature, payload);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Verify interceptor payload
|
|
265
|
+
*
|
|
266
|
+
* @param {string} secret The secret
|
|
267
|
+
* @param {Record<string, string>} headers The headers
|
|
268
|
+
* @param {string} payload The payload
|
|
269
|
+
* @return {boolean} Returns true if the payload is valid.
|
|
270
|
+
*/
|
|
271
|
+
verifyInterceptorPayload(secret: string, headers: Record<string, string>, payload: string): boolean {
|
|
272
|
+
const interceptorId = headers['interceptor-id'];
|
|
273
|
+
const interceptorTimestamp = headers['interceptor-timestamp'];
|
|
274
|
+
const interceptorSignature = headers['interceptor-signature'];
|
|
275
|
+
|
|
276
|
+
return this.verifyPayloadSignature(secret, interceptorId, interceptorTimestamp, interceptorSignature, payload);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Common payload signature verification logic
|
|
281
|
+
*
|
|
282
|
+
* @param {string} secret The secret
|
|
283
|
+
* @param {string} id The webhook/interceptor id
|
|
284
|
+
* @param {string} timestamp The timestamp
|
|
285
|
+
* @param {string} signature The signature
|
|
286
|
+
* @param {string} payload The payload
|
|
287
|
+
* @return {boolean} Returns true if the payload signature is valid.
|
|
288
|
+
*/
|
|
289
|
+
private verifyPayloadSignature(secret: string, id: string, timestamp: string, signature: string, payload: string): boolean {
|
|
290
|
+
if (!id || !timestamp || !signature) {
|
|
255
291
|
throw new WebhookVerificationError("Missing required headers");
|
|
256
292
|
}
|
|
257
293
|
|
|
@@ -261,18 +297,18 @@ export default class ScalekitClient {
|
|
|
261
297
|
}
|
|
262
298
|
|
|
263
299
|
try {
|
|
264
|
-
const
|
|
265
|
-
const data = `${
|
|
300
|
+
const timestampDate = this.verifyTimestamp(timestamp);
|
|
301
|
+
const data = `${id}.${Math.floor(timestampDate.getTime() / 1000)}.${payload}`;
|
|
266
302
|
const secretBytes = Buffer.from(secretParts[1], 'base64');
|
|
267
303
|
const computedSignature = this.computeSignature(secretBytes, data);
|
|
268
|
-
const receivedSignatures =
|
|
304
|
+
const receivedSignatures = signature.split(" ");
|
|
269
305
|
|
|
270
306
|
for (const versionedSignature of receivedSignatures) {
|
|
271
|
-
const [version,
|
|
307
|
+
const [version, receivedSignature] = versionedSignature.split(",");
|
|
272
308
|
if (version !== WEBHOOK_SIGNATURE_VERSION) {
|
|
273
309
|
continue;
|
|
274
310
|
}
|
|
275
|
-
if (crypto.timingSafeEqual(Buffer.from(
|
|
311
|
+
if (crypto.timingSafeEqual(Buffer.from(receivedSignature, 'base64'), Buffer.from(computedSignature, 'base64'))) {
|
|
276
312
|
return true;
|
|
277
313
|
}
|
|
278
314
|
}
|
package/src/session.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { PartialMessage } from '@bufbuild/protobuf';
|
|
2
|
+
import { PromiseClient } from '@connectrpc/connect';
|
|
3
|
+
import GrpcConnect from './connect';
|
|
4
|
+
import CoreClient from './core';
|
|
5
|
+
import { SessionService } from './pkg/grpc/scalekit/v1/sessions/sessions_connect';
|
|
6
|
+
import {
|
|
7
|
+
SessionDetailsRequest,
|
|
8
|
+
SessionDetails,
|
|
9
|
+
UserSessionDetailsRequest,
|
|
10
|
+
UserSessionDetails,
|
|
11
|
+
UserSessionFilter,
|
|
12
|
+
RevokeSessionRequest,
|
|
13
|
+
RevokeSessionResponse,
|
|
14
|
+
RevokeAllUserSessionsRequest,
|
|
15
|
+
RevokeAllUserSessionsResponse
|
|
16
|
+
} from './pkg/grpc/scalekit/v1/sessions/sessions_pb';
|
|
17
|
+
import { Timestamp } from '@bufbuild/protobuf';
|
|
18
|
+
|
|
19
|
+
export default class SessionClient {
|
|
20
|
+
private client: PromiseClient<typeof SessionService>;
|
|
21
|
+
|
|
22
|
+
constructor(
|
|
23
|
+
private readonly grpcConnect: GrpcConnect,
|
|
24
|
+
private readonly coreClient: CoreClient
|
|
25
|
+
) {
|
|
26
|
+
this.client = this.grpcConnect.createClient(SessionService);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get details for a specific session
|
|
31
|
+
* @param {string} sessionId The session id
|
|
32
|
+
* @returns {Promise<SessionDetails>} The session details
|
|
33
|
+
*/
|
|
34
|
+
async getSession(sessionId: string): Promise<SessionDetails> {
|
|
35
|
+
return this.coreClient.connectExec(
|
|
36
|
+
this.client.getSession,
|
|
37
|
+
{
|
|
38
|
+
sessionId
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get all session details for a user with pagination and filtering
|
|
45
|
+
* @param {string} userId The user id
|
|
46
|
+
* @param {object} options The pagination and filtering options
|
|
47
|
+
* @param {number} options.pageSize The page size
|
|
48
|
+
* @param {string} options.pageToken The page token
|
|
49
|
+
* @param {object} options.filter The session filter options
|
|
50
|
+
* @param {string[]} options.filter.status The session statuses to filter by
|
|
51
|
+
* @param {Date} options.filter.startTime The start time for filtering sessions
|
|
52
|
+
* @param {Date} options.filter.endTime The end time for filtering sessions
|
|
53
|
+
* @returns {Promise<UserSessionDetails>} The user session details
|
|
54
|
+
*/
|
|
55
|
+
async getUserSessions(
|
|
56
|
+
userId: string,
|
|
57
|
+
options?: {
|
|
58
|
+
pageSize?: number,
|
|
59
|
+
pageToken?: string,
|
|
60
|
+
filter?: {
|
|
61
|
+
status?: string[],
|
|
62
|
+
startTime?: Date,
|
|
63
|
+
endTime?: Date
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
): Promise<UserSessionDetails> {
|
|
67
|
+
const request: PartialMessage<UserSessionDetailsRequest> = {
|
|
68
|
+
userId
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
if (options?.pageSize !== undefined) {
|
|
72
|
+
request.pageSize = options.pageSize;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (options?.pageToken) {
|
|
76
|
+
request.pageToken = options.pageToken;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (options?.filter) {
|
|
80
|
+
const filter = new UserSessionFilter();
|
|
81
|
+
|
|
82
|
+
if (options.filter.status) {
|
|
83
|
+
filter.status = options.filter.status;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (options.filter.startTime) {
|
|
87
|
+
filter.startTime = Timestamp.fromDate(options.filter.startTime);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (options.filter.endTime) {
|
|
91
|
+
filter.endTime = Timestamp.fromDate(options.filter.endTime);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
request.filter = filter;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return this.coreClient.connectExec(
|
|
98
|
+
this.client.getUserSessions,
|
|
99
|
+
request
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Revoke a session for a user
|
|
105
|
+
* @param {string} sessionId The session id to revoke
|
|
106
|
+
* @returns {Promise<RevokeSessionResponse>} The response with revoked session details
|
|
107
|
+
*/
|
|
108
|
+
async revokeSession(sessionId: string): Promise<RevokeSessionResponse> {
|
|
109
|
+
return this.coreClient.connectExec(
|
|
110
|
+
this.client.revokeSession,
|
|
111
|
+
{
|
|
112
|
+
sessionId
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Revoke all sessions for a user
|
|
119
|
+
* @param {string} userId The user id whose sessions should be revoked
|
|
120
|
+
* @returns {Promise<RevokeAllUserSessionsResponse>} The response with all revoked session details
|
|
121
|
+
*/
|
|
122
|
+
async revokeAllUserSessions(userId: string): Promise<RevokeAllUserSessionsResponse> {
|
|
123
|
+
if (!userId) {
|
|
124
|
+
throw new Error('userId is required');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return this.coreClient.connectExec(
|
|
128
|
+
this.client.revokeAllUserSessions,
|
|
129
|
+
{
|
|
130
|
+
userId
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|