@takaro/auth 0.0.1 → 0.0.4
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/dist/config.d.ts +6 -31
- package/dist/config.js +5 -25
- package/dist/config.js.map +1 -1
- package/dist/lib/ory.d.ts +3 -25
- package/dist/lib/ory.js +31 -146
- package/dist/lib/ory.js.map +1 -1
- package/dist/lib/permissions.d.ts +3 -1
- package/dist/lib/permissions.js +12 -0
- package/dist/lib/permissions.js.map +1 -1
- package/dist/main.d.ts +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/package.json +2 -3
- package/src/config.ts +6 -31
- package/src/lib/__tests__/ory.integration.test.ts +5 -5
- package/src/lib/ory.ts +38 -152
- package/src/lib/oryAxiosClient.ts +2 -2
- package/src/lib/permissions.ts +12 -0
- package/src/main.ts +1 -1
- package/dist/lib/paginationHelpers.d.ts +0 -2
- package/dist/lib/paginationHelpers.js +0 -38
- package/dist/lib/paginationHelpers.js.map +0 -1
- package/src/lib/paginationHelpers.ts +0 -46
package/dist/config.d.ts
CHANGED
|
@@ -4,12 +4,7 @@ export interface IAuthConfig extends IBaseConfig {
|
|
|
4
4
|
publicUrl: string;
|
|
5
5
|
adminUrl: string;
|
|
6
6
|
};
|
|
7
|
-
|
|
8
|
-
publicUrl: string;
|
|
9
|
-
adminUrl: string;
|
|
10
|
-
adminClientId: string;
|
|
11
|
-
adminClientSecret: string;
|
|
12
|
-
};
|
|
7
|
+
adminClientSecret: string;
|
|
13
8
|
takaro: {
|
|
14
9
|
url: string;
|
|
15
10
|
};
|
|
@@ -29,31 +24,11 @@ export declare const configSchema: {
|
|
|
29
24
|
env: string;
|
|
30
25
|
};
|
|
31
26
|
};
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
env: string;
|
|
38
|
-
};
|
|
39
|
-
adminUrl: {
|
|
40
|
-
doc: string;
|
|
41
|
-
format: StringConstructor;
|
|
42
|
-
default: string;
|
|
43
|
-
env: string;
|
|
44
|
-
};
|
|
45
|
-
adminClientId: {
|
|
46
|
-
doc: string;
|
|
47
|
-
format: StringConstructor;
|
|
48
|
-
default: null;
|
|
49
|
-
env: string;
|
|
50
|
-
};
|
|
51
|
-
adminClientSecret: {
|
|
52
|
-
doc: string;
|
|
53
|
-
format: StringConstructor;
|
|
54
|
-
default: null;
|
|
55
|
-
env: string;
|
|
56
|
-
};
|
|
27
|
+
adminClientSecret: {
|
|
28
|
+
doc: string;
|
|
29
|
+
format: StringConstructor;
|
|
30
|
+
default: null;
|
|
31
|
+
env: string;
|
|
57
32
|
};
|
|
58
33
|
takaro: {
|
|
59
34
|
url: {
|
package/dist/config.js
CHANGED
|
@@ -14,31 +14,11 @@ export const configSchema = {
|
|
|
14
14
|
env: 'KRATOS_ADMIN_URL',
|
|
15
15
|
},
|
|
16
16
|
},
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
env: 'TAKARO_OAUTH_HOST',
|
|
23
|
-
},
|
|
24
|
-
adminUrl: {
|
|
25
|
-
doc: 'The URL of the Takaro OAuth admin server',
|
|
26
|
-
format: String,
|
|
27
|
-
default: 'http://hydra:4445',
|
|
28
|
-
env: 'TAKARO_OAUTH_ADMIN_HOST',
|
|
29
|
-
},
|
|
30
|
-
adminClientId: {
|
|
31
|
-
doc: 'The client ID to use when authenticating with the Takaro server',
|
|
32
|
-
format: String,
|
|
33
|
-
default: null,
|
|
34
|
-
env: 'ADMIN_CLIENT_ID',
|
|
35
|
-
},
|
|
36
|
-
adminClientSecret: {
|
|
37
|
-
doc: 'The client secret to use when authenticating with the Takaro server',
|
|
38
|
-
format: String,
|
|
39
|
-
default: null,
|
|
40
|
-
env: 'ADMIN_CLIENT_SECRET',
|
|
41
|
-
},
|
|
17
|
+
adminClientSecret: {
|
|
18
|
+
doc: 'The client secret to use when authenticating with the Takaro server',
|
|
19
|
+
format: String,
|
|
20
|
+
default: null,
|
|
21
|
+
env: 'ADMIN_CLIENT_SECRET',
|
|
42
22
|
},
|
|
43
23
|
takaro: {
|
|
44
24
|
url: {
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAe,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAe,MAAM,gBAAgB,CAAC;AAarD,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,MAAM,EAAE;QACN,SAAS,EAAE;YACT,GAAG,EAAE,kCAAkC;YACvC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,oBAAoB;YAC7B,GAAG,EAAE,YAAY;SAClB;QACD,QAAQ,EAAE;YACR,GAAG,EAAE,iCAAiC;YACtC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,oBAAoB;YAC7B,GAAG,EAAE,kBAAkB;SACxB;KACF;IACD,iBAAiB,EAAE;QACjB,GAAG,EAAE,qEAAqE;QAC1E,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,IAAI;QACb,GAAG,EAAE,qBAAqB;KAC3B;IACD,MAAM,EAAE;QACN,GAAG,EAAE;YACH,GAAG,EAAE,8BAA8B;YACnC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,uBAAuB;YAChC,GAAG,EAAE,aAAa;SACnB;KACF;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAc,CAAC,YAAY,CAAC,CAAC,CAAC"}
|
package/dist/lib/ory.d.ts
CHANGED
|
@@ -1,42 +1,20 @@
|
|
|
1
|
-
import { TakaroDTO } from '@takaro/util';
|
|
2
1
|
import { Request } from 'express';
|
|
3
|
-
export declare enum AUDIENCES {
|
|
4
|
-
TAKARO_API_ADMIN = "t:api:admin"
|
|
5
|
-
}
|
|
6
2
|
export interface ITakaroIdentity {
|
|
7
3
|
id: string;
|
|
8
4
|
email: string;
|
|
9
|
-
domainId: string;
|
|
10
|
-
}
|
|
11
|
-
export declare class TakaroTokenDTO extends TakaroDTO<TakaroTokenDTO> {
|
|
12
|
-
active: boolean;
|
|
13
|
-
clientId: string;
|
|
14
|
-
exp: number;
|
|
15
|
-
iat: number;
|
|
16
|
-
iss: string;
|
|
17
|
-
sub: string;
|
|
18
|
-
aud: string[];
|
|
19
5
|
}
|
|
20
6
|
declare class Ory {
|
|
21
|
-
private authToken;
|
|
22
7
|
private log;
|
|
23
|
-
private adminClient;
|
|
24
8
|
private identityClient;
|
|
25
9
|
private frontendClient;
|
|
26
10
|
constructor();
|
|
27
|
-
get OAuth2URL(): string;
|
|
28
|
-
deleteIdentitiesForDomain(domainId: string): Promise<void>;
|
|
29
11
|
getIdentity(id: string): Promise<ITakaroIdentity>;
|
|
30
|
-
|
|
12
|
+
getIdentityByEmail(email: string): Promise<ITakaroIdentity | null>;
|
|
13
|
+
createIdentity(email: string, password?: string): Promise<ITakaroIdentity>;
|
|
31
14
|
deleteIdentity(id: string): Promise<void>;
|
|
32
|
-
getIdentityFromReq(req: Request): Promise<ITakaroIdentity>;
|
|
15
|
+
getIdentityFromReq(req: Request): Promise<ITakaroIdentity | null>;
|
|
33
16
|
submitApiLogin(username: string, password: string): Promise<import("axios").AxiosResponse<import("@ory/client").SuccessfulNativeLogin, any>>;
|
|
34
17
|
apiLogout(req: Request): Promise<true | import("axios").AxiosResponse<void, any>>;
|
|
35
|
-
introspectToken(token: string): Promise<TakaroTokenDTO>;
|
|
36
|
-
createOIDCClient(): Promise<{
|
|
37
|
-
clientId: string;
|
|
38
|
-
clientSecret: string;
|
|
39
|
-
}>;
|
|
40
18
|
getRecoveryFlow(id: string): Promise<import("@ory/client").RecoveryLinkForIdentity>;
|
|
41
19
|
}
|
|
42
20
|
export declare const ory: Ory;
|
package/dist/lib/ory.js
CHANGED
|
@@ -1,63 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
};
|
|
7
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
-
};
|
|
10
|
-
import { Configuration, FrontendApi, IdentityApi, OAuth2Api } from '@ory/client';
|
|
1
|
+
import { Configuration, FrontendApi, IdentityApi } from '@ory/client';
|
|
11
2
|
import { config } from '../config.js';
|
|
12
|
-
import {
|
|
3
|
+
import { logger } from '@takaro/util';
|
|
13
4
|
import { createAxiosClient } from './oryAxiosClient.js';
|
|
14
|
-
import { paginateIdentities } from './paginationHelpers.js';
|
|
15
|
-
import { IsBoolean, IsNumber, IsString } from 'class-validator';
|
|
16
5
|
var IDENTITY_SCHEMA;
|
|
17
6
|
(function (IDENTITY_SCHEMA) {
|
|
18
7
|
IDENTITY_SCHEMA["USER"] = "user_v0";
|
|
19
8
|
})(IDENTITY_SCHEMA || (IDENTITY_SCHEMA = {}));
|
|
20
|
-
export var AUDIENCES;
|
|
21
|
-
(function (AUDIENCES) {
|
|
22
|
-
// Used for various sysadmin tasks in the Takaro API
|
|
23
|
-
AUDIENCES["TAKARO_API_ADMIN"] = "t:api:admin";
|
|
24
|
-
})(AUDIENCES || (AUDIENCES = {}));
|
|
25
|
-
export class TakaroTokenDTO extends TakaroDTO {
|
|
26
|
-
}
|
|
27
|
-
__decorate([
|
|
28
|
-
IsBoolean(),
|
|
29
|
-
__metadata("design:type", Boolean)
|
|
30
|
-
], TakaroTokenDTO.prototype, "active", void 0);
|
|
31
|
-
__decorate([
|
|
32
|
-
IsString(),
|
|
33
|
-
__metadata("design:type", String)
|
|
34
|
-
], TakaroTokenDTO.prototype, "clientId", void 0);
|
|
35
|
-
__decorate([
|
|
36
|
-
IsNumber(),
|
|
37
|
-
__metadata("design:type", Number)
|
|
38
|
-
], TakaroTokenDTO.prototype, "exp", void 0);
|
|
39
|
-
__decorate([
|
|
40
|
-
IsNumber(),
|
|
41
|
-
__metadata("design:type", Number)
|
|
42
|
-
], TakaroTokenDTO.prototype, "iat", void 0);
|
|
43
|
-
__decorate([
|
|
44
|
-
IsString(),
|
|
45
|
-
__metadata("design:type", String)
|
|
46
|
-
], TakaroTokenDTO.prototype, "iss", void 0);
|
|
47
|
-
__decorate([
|
|
48
|
-
IsString(),
|
|
49
|
-
__metadata("design:type", String)
|
|
50
|
-
], TakaroTokenDTO.prototype, "sub", void 0);
|
|
51
|
-
__decorate([
|
|
52
|
-
IsString({ each: true }),
|
|
53
|
-
__metadata("design:type", Array)
|
|
54
|
-
], TakaroTokenDTO.prototype, "aud", void 0);
|
|
55
|
-
function metadataTypeguard(metadata) {
|
|
56
|
-
return typeof metadata === 'object' && metadata !== null && 'domainId' in metadata;
|
|
57
|
-
}
|
|
58
9
|
class Ory {
|
|
59
10
|
constructor() {
|
|
60
|
-
this.authToken = null;
|
|
61
11
|
this.log = logger('ory');
|
|
62
12
|
this.identityClient = new IdentityApi(new Configuration({
|
|
63
13
|
basePath: config.get('kratos.adminUrl'),
|
|
@@ -65,53 +15,39 @@ class Ory {
|
|
|
65
15
|
this.frontendClient = new FrontendApi(new Configuration({
|
|
66
16
|
basePath: config.get('kratos.publicUrl'),
|
|
67
17
|
}), undefined, createAxiosClient(config.get('kratos.publicUrl')));
|
|
68
|
-
this.adminClient = new OAuth2Api(new Configuration({
|
|
69
|
-
basePath: config.get('hydra.adminUrl'),
|
|
70
|
-
}), undefined, createAxiosClient(config.get('hydra.adminUrl')));
|
|
71
|
-
}
|
|
72
|
-
get OAuth2URL() {
|
|
73
|
-
return config.get('hydra.publicUrl');
|
|
74
|
-
}
|
|
75
|
-
async deleteIdentitiesForDomain(domainId) {
|
|
76
|
-
for await (const identities of paginateIdentities(this.identityClient)) {
|
|
77
|
-
for (const identity of identities) {
|
|
78
|
-
if (identity.metadata_public &&
|
|
79
|
-
metadataTypeguard(identity.metadata_public) &&
|
|
80
|
-
identity.metadata_public.domainId === domainId) {
|
|
81
|
-
await this.deleteIdentity(identity.id);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
18
|
}
|
|
86
19
|
async getIdentity(id) {
|
|
87
20
|
const res = await this.identityClient.getIdentity({
|
|
88
21
|
id,
|
|
89
22
|
});
|
|
90
|
-
if (!res.data.metadata_public) {
|
|
91
|
-
this.log.warn('Identity has no metadata_public', {
|
|
92
|
-
identity: res.data.id,
|
|
93
|
-
});
|
|
94
|
-
throw new errors.ForbiddenError();
|
|
95
|
-
}
|
|
96
|
-
if (!metadataTypeguard(res.data.metadata_public)) {
|
|
97
|
-
this.log.warn('Identity metadata_public is not of type {domainId: string}', { identity: res.data.id });
|
|
98
|
-
throw new errors.ForbiddenError();
|
|
99
|
-
}
|
|
100
23
|
return {
|
|
101
24
|
id: res.data.id,
|
|
102
25
|
email: res.data.traits.email,
|
|
103
|
-
domainId: res.data.metadata_public.domainId,
|
|
104
26
|
};
|
|
105
27
|
}
|
|
106
|
-
async
|
|
28
|
+
async getIdentityByEmail(email) {
|
|
29
|
+
const identity = await this.identityClient.listIdentities({ credentialsIdentifier: email });
|
|
30
|
+
if (!identity.data.length)
|
|
31
|
+
return null;
|
|
32
|
+
return {
|
|
33
|
+
id: identity.data[0].id,
|
|
34
|
+
email: identity.data[0].traits.email,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async createIdentity(email, password) {
|
|
38
|
+
const existing = await this.identityClient.listIdentities({ credentialsIdentifier: email });
|
|
39
|
+
if (existing.data.length) {
|
|
40
|
+
this.log.warn('Identity already exists, returning existing one.', { email });
|
|
41
|
+
return {
|
|
42
|
+
id: existing.data[0].id,
|
|
43
|
+
email: existing.data[0].traits.email,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
107
46
|
const body = {
|
|
108
47
|
schema_id: IDENTITY_SCHEMA.USER,
|
|
109
48
|
traits: {
|
|
110
49
|
email,
|
|
111
50
|
},
|
|
112
|
-
metadata_public: {
|
|
113
|
-
domainId,
|
|
114
|
-
},
|
|
115
51
|
};
|
|
116
52
|
if (password) {
|
|
117
53
|
body.credentials = {
|
|
@@ -128,7 +64,6 @@ class Ory {
|
|
|
128
64
|
return {
|
|
129
65
|
id: res.data.id,
|
|
130
66
|
email: res.data.traits.email,
|
|
131
|
-
domainId,
|
|
132
67
|
};
|
|
133
68
|
}
|
|
134
69
|
async deleteIdentity(id) {
|
|
@@ -138,27 +73,20 @@ class Ory {
|
|
|
138
73
|
}
|
|
139
74
|
async getIdentityFromReq(req) {
|
|
140
75
|
const tokenFromAuthHeader = req.headers['authorization']?.replace('Bearer ', '');
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (!sessionRes.data.identity.metadata_public) {
|
|
146
|
-
this.log.warn('Identity has no metadata_public', {
|
|
147
|
-
identity: sessionRes.data.identity.id,
|
|
76
|
+
try {
|
|
77
|
+
const sessionRes = await this.frontendClient.toSession({
|
|
78
|
+
cookie: req.headers.cookie,
|
|
79
|
+
xSessionToken: tokenFromAuthHeader,
|
|
148
80
|
});
|
|
149
|
-
|
|
81
|
+
return {
|
|
82
|
+
id: sessionRes.data.identity.id,
|
|
83
|
+
email: sessionRes.data.identity.traits.email,
|
|
84
|
+
};
|
|
150
85
|
}
|
|
151
|
-
|
|
152
|
-
this.log.warn('
|
|
153
|
-
|
|
154
|
-
});
|
|
155
|
-
throw new errors.ForbiddenError();
|
|
86
|
+
catch (error) {
|
|
87
|
+
this.log.warn('Could not get identity from request', { error });
|
|
88
|
+
return null;
|
|
156
89
|
}
|
|
157
|
-
return {
|
|
158
|
-
id: sessionRes.data.identity.id,
|
|
159
|
-
email: sessionRes.data.identity.traits.email,
|
|
160
|
-
domainId: sessionRes.data.identity.metadata_public.domainId,
|
|
161
|
-
};
|
|
162
90
|
}
|
|
163
91
|
async submitApiLogin(username, password) {
|
|
164
92
|
const flow = await this.frontendClient.createNativeLoginFlow({
|
|
@@ -183,49 +111,6 @@ class Ory {
|
|
|
183
111
|
},
|
|
184
112
|
});
|
|
185
113
|
}
|
|
186
|
-
async introspectToken(token) {
|
|
187
|
-
const introspectRes = await this.adminClient.introspectOAuth2Token({
|
|
188
|
-
token,
|
|
189
|
-
});
|
|
190
|
-
const data = new TakaroTokenDTO({
|
|
191
|
-
active: introspectRes.data.active,
|
|
192
|
-
clientId: introspectRes.data.client_id,
|
|
193
|
-
aud: introspectRes.data.aud,
|
|
194
|
-
exp: introspectRes.data.exp,
|
|
195
|
-
iat: introspectRes.data.iat,
|
|
196
|
-
iss: introspectRes.data.iss,
|
|
197
|
-
sub: introspectRes.data.sub,
|
|
198
|
-
});
|
|
199
|
-
try {
|
|
200
|
-
// Check for correctness of the data
|
|
201
|
-
// DOES NOT CHECK FOR EXPIRATION
|
|
202
|
-
await data.validate();
|
|
203
|
-
}
|
|
204
|
-
catch (error) {
|
|
205
|
-
this.log.warn('Introspected token has invalid shape', { error });
|
|
206
|
-
throw new errors.ForbiddenError();
|
|
207
|
-
}
|
|
208
|
-
return data;
|
|
209
|
-
}
|
|
210
|
-
// Currently, this is only used for creating the admin-auth client.
|
|
211
|
-
// ...In the future we should make this more generic and allow for
|
|
212
|
-
// creating any API client perhaps?
|
|
213
|
-
async createOIDCClient() {
|
|
214
|
-
const client = await this.adminClient.createOAuth2Client({
|
|
215
|
-
oAuth2Client: {
|
|
216
|
-
grant_types: ['client_credentials'],
|
|
217
|
-
audience: [AUDIENCES.TAKARO_API_ADMIN],
|
|
218
|
-
},
|
|
219
|
-
});
|
|
220
|
-
if (!client.data.client_id || !client.data.client_secret) {
|
|
221
|
-
this.log.error('Could not create OIDC client', { client });
|
|
222
|
-
throw new errors.InternalServerError();
|
|
223
|
-
}
|
|
224
|
-
return {
|
|
225
|
-
clientId: client.data.client_id,
|
|
226
|
-
clientSecret: client.data.client_secret,
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
114
|
async getRecoveryFlow(id) {
|
|
230
115
|
const recoveryRes = await this.identityClient.createRecoveryLinkForIdentity({
|
|
231
116
|
createRecoveryLinkForIdentityBody: {
|
package/dist/lib/ory.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ory.js","sourceRoot":"","sources":["../../src/lib/ory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ory.js","sourceRoot":"","sources":["../../src/lib/ory.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,9 @@ export declare enum PERMISSIONS {
|
|
|
17
17
|
'READ_EVENTS' = "READ_EVENTS",
|
|
18
18
|
'MANAGE_EVENTS' = "MANAGE_EVENTS",
|
|
19
19
|
'READ_ITEMS' = "READ_ITEMS",
|
|
20
|
-
'MANAGE_ITEMS' = "MANAGE_ITEMS"
|
|
20
|
+
'MANAGE_ITEMS' = "MANAGE_ITEMS",
|
|
21
|
+
'MANAGE_SHOP_LISTINGS' = "MANAGE_SHOP_LISTINGS",
|
|
22
|
+
'MANAGE_SHOP_ORDERS' = "MANAGE_SHOP_ORDERS"
|
|
21
23
|
}
|
|
22
24
|
export interface IPermissionDetails {
|
|
23
25
|
permission: string;
|
package/dist/lib/permissions.js
CHANGED
|
@@ -19,6 +19,8 @@ export var PERMISSIONS;
|
|
|
19
19
|
PERMISSIONS["MANAGE_EVENTS"] = "MANAGE_EVENTS";
|
|
20
20
|
PERMISSIONS["READ_ITEMS"] = "READ_ITEMS";
|
|
21
21
|
PERMISSIONS["MANAGE_ITEMS"] = "MANAGE_ITEMS";
|
|
22
|
+
PERMISSIONS["MANAGE_SHOP_LISTINGS"] = "MANAGE_SHOP_LISTINGS";
|
|
23
|
+
PERMISSIONS["MANAGE_SHOP_ORDERS"] = "MANAGE_SHOP_ORDERS";
|
|
22
24
|
})(PERMISSIONS || (PERMISSIONS = {}));
|
|
23
25
|
export const PERMISSION_DETAILS = {
|
|
24
26
|
[PERMISSIONS.ROOT]: {
|
|
@@ -116,5 +118,15 @@ export const PERMISSION_DETAILS = {
|
|
|
116
118
|
friendlyName: 'Manage Items',
|
|
117
119
|
description: 'Can create, update, and delete items',
|
|
118
120
|
},
|
|
121
|
+
[PERMISSIONS.MANAGE_SHOP_LISTINGS]: {
|
|
122
|
+
permission: PERMISSIONS.MANAGE_SHOP_LISTINGS,
|
|
123
|
+
friendlyName: 'Manage Shop Listings',
|
|
124
|
+
description: 'Can create, update, and delete shop listings',
|
|
125
|
+
},
|
|
126
|
+
[PERMISSIONS.MANAGE_SHOP_ORDERS]: {
|
|
127
|
+
permission: PERMISSIONS.MANAGE_SHOP_ORDERS,
|
|
128
|
+
friendlyName: 'Manage Shop Orders',
|
|
129
|
+
description: 'Can view orders not belonging to the themself and perform administrative actions on them',
|
|
130
|
+
},
|
|
119
131
|
};
|
|
120
132
|
//# sourceMappingURL=permissions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/lib/permissions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/lib/permissions.ts"],"names":[],"mappings":"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"}
|
package/dist/main.d.ts
CHANGED
package/dist/main.js
CHANGED
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,IAAI,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,EAAE,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,IAAI,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,cAAc,sBAAsB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@takaro/auth",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "An opinionated auth handler",
|
|
5
5
|
"main": "dist/main.js",
|
|
6
6
|
"types": "dist/main.d.ts",
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
"convict": "^6.2.3"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@takaro/test": "0.0.1",
|
|
23
22
|
"@types/convict": "^6.1.1"
|
|
24
23
|
}
|
|
25
|
-
}
|
|
24
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -5,12 +5,7 @@ export interface IAuthConfig extends IBaseConfig {
|
|
|
5
5
|
publicUrl: string;
|
|
6
6
|
adminUrl: string;
|
|
7
7
|
};
|
|
8
|
-
|
|
9
|
-
publicUrl: string;
|
|
10
|
-
adminUrl: string;
|
|
11
|
-
adminClientId: string;
|
|
12
|
-
adminClientSecret: string;
|
|
13
|
-
};
|
|
8
|
+
adminClientSecret: string;
|
|
14
9
|
takaro: {
|
|
15
10
|
url: string;
|
|
16
11
|
};
|
|
@@ -31,31 +26,11 @@ export const configSchema = {
|
|
|
31
26
|
env: 'KRATOS_ADMIN_URL',
|
|
32
27
|
},
|
|
33
28
|
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
env: 'TAKARO_OAUTH_HOST',
|
|
40
|
-
},
|
|
41
|
-
adminUrl: {
|
|
42
|
-
doc: 'The URL of the Takaro OAuth admin server',
|
|
43
|
-
format: String,
|
|
44
|
-
default: 'http://hydra:4445',
|
|
45
|
-
env: 'TAKARO_OAUTH_ADMIN_HOST',
|
|
46
|
-
},
|
|
47
|
-
adminClientId: {
|
|
48
|
-
doc: 'The client ID to use when authenticating with the Takaro server',
|
|
49
|
-
format: String,
|
|
50
|
-
default: null,
|
|
51
|
-
env: 'ADMIN_CLIENT_ID',
|
|
52
|
-
},
|
|
53
|
-
adminClientSecret: {
|
|
54
|
-
doc: 'The client secret to use when authenticating with the Takaro server',
|
|
55
|
-
format: String,
|
|
56
|
-
default: null,
|
|
57
|
-
env: 'ADMIN_CLIENT_SECRET',
|
|
58
|
-
},
|
|
29
|
+
adminClientSecret: {
|
|
30
|
+
doc: 'The client secret to use when authenticating with the Takaro server',
|
|
31
|
+
format: String,
|
|
32
|
+
default: null,
|
|
33
|
+
env: 'ADMIN_CLIENT_SECRET',
|
|
59
34
|
},
|
|
60
35
|
takaro: {
|
|
61
36
|
url: {
|
|
@@ -7,9 +7,7 @@ describe('Ory', () => {
|
|
|
7
7
|
// First, create a bunch of identities
|
|
8
8
|
const totalIdentities = 150;
|
|
9
9
|
const identities = await Promise.all(
|
|
10
|
-
Array.from({ length: totalIdentities }).map(() =>
|
|
11
|
-
ory.createIdentity(faker.internet.email(), 'password', 'domainId')
|
|
12
|
-
)
|
|
10
|
+
Array.from({ length: totalIdentities }).map(() => ory.createIdentity(faker.internet.email(), 'password')),
|
|
13
11
|
);
|
|
14
12
|
|
|
15
13
|
// Fetch the first one by ID
|
|
@@ -18,9 +16,11 @@ describe('Ory', () => {
|
|
|
18
16
|
expect(firstIdentity.email).to.be.eq(identities[0].email);
|
|
19
17
|
|
|
20
18
|
// Delete them all
|
|
21
|
-
await ory.
|
|
19
|
+
await Promise.all(identities.map((i) => ory.deleteIdentity(i.id)));
|
|
22
20
|
|
|
23
21
|
// Make sure they're gone
|
|
24
|
-
expect(ory.getIdentity(identities[0].id)).to.eventually.be.rejectedWith(
|
|
22
|
+
await expect(ory.getIdentity(identities[0].id)).to.eventually.be.rejectedWith(
|
|
23
|
+
'Request failed with status code 404',
|
|
24
|
+
);
|
|
25
25
|
});
|
|
26
26
|
});
|
package/src/lib/ory.ts
CHANGED
|
@@ -1,52 +1,21 @@
|
|
|
1
|
-
import { Configuration, CreateIdentityBody, FrontendApi, IdentityApi
|
|
1
|
+
import { Configuration, CreateIdentityBody, FrontendApi, IdentityApi } from '@ory/client';
|
|
2
2
|
import { config } from '../config.js';
|
|
3
|
-
import {
|
|
3
|
+
import { logger } from '@takaro/util';
|
|
4
4
|
import { createAxiosClient } from './oryAxiosClient.js';
|
|
5
|
-
import { paginateIdentities } from './paginationHelpers.js';
|
|
6
5
|
import { Request } from 'express';
|
|
7
|
-
import { IsBoolean, IsNumber, IsString } from 'class-validator';
|
|
8
6
|
|
|
9
7
|
enum IDENTITY_SCHEMA {
|
|
10
8
|
USER = 'user_v0',
|
|
11
9
|
}
|
|
12
10
|
|
|
13
|
-
export enum AUDIENCES {
|
|
14
|
-
// Used for various sysadmin tasks in the Takaro API
|
|
15
|
-
TAKARO_API_ADMIN = 't:api:admin',
|
|
16
|
-
}
|
|
17
|
-
|
|
18
11
|
export interface ITakaroIdentity {
|
|
19
12
|
id: string;
|
|
20
13
|
email: string;
|
|
21
|
-
domainId: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class TakaroTokenDTO extends TakaroDTO<TakaroTokenDTO> {
|
|
25
|
-
@IsBoolean()
|
|
26
|
-
active: boolean;
|
|
27
|
-
@IsString()
|
|
28
|
-
clientId: string;
|
|
29
|
-
@IsNumber()
|
|
30
|
-
exp: number;
|
|
31
|
-
@IsNumber()
|
|
32
|
-
iat: number;
|
|
33
|
-
@IsString()
|
|
34
|
-
iss: string;
|
|
35
|
-
@IsString()
|
|
36
|
-
sub: string;
|
|
37
|
-
@IsString({ each: true })
|
|
38
|
-
aud: string[];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function metadataTypeguard(metadata: unknown): metadata is { domainId: string } {
|
|
42
|
-
return typeof metadata === 'object' && metadata !== null && 'domainId' in metadata;
|
|
43
14
|
}
|
|
44
15
|
|
|
45
16
|
class Ory {
|
|
46
|
-
private authToken: string | null = null;
|
|
47
17
|
private log = logger('ory');
|
|
48
18
|
|
|
49
|
-
private adminClient: OAuth2Api;
|
|
50
19
|
private identityClient: IdentityApi;
|
|
51
20
|
private frontendClient: FrontendApi;
|
|
52
21
|
|
|
@@ -56,7 +25,7 @@ class Ory {
|
|
|
56
25
|
basePath: config.get('kratos.adminUrl'),
|
|
57
26
|
}),
|
|
58
27
|
undefined,
|
|
59
|
-
createAxiosClient(config.get('kratos.adminUrl'))
|
|
28
|
+
createAxiosClient(config.get('kratos.adminUrl')),
|
|
60
29
|
);
|
|
61
30
|
|
|
62
31
|
this.frontendClient = new FrontendApi(
|
|
@@ -64,33 +33,8 @@ class Ory {
|
|
|
64
33
|
basePath: config.get('kratos.publicUrl'),
|
|
65
34
|
}),
|
|
66
35
|
undefined,
|
|
67
|
-
createAxiosClient(config.get('kratos.publicUrl'))
|
|
36
|
+
createAxiosClient(config.get('kratos.publicUrl')),
|
|
68
37
|
);
|
|
69
|
-
this.adminClient = new OAuth2Api(
|
|
70
|
-
new Configuration({
|
|
71
|
-
basePath: config.get('hydra.adminUrl'),
|
|
72
|
-
}),
|
|
73
|
-
undefined,
|
|
74
|
-
createAxiosClient(config.get('hydra.adminUrl'))
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
get OAuth2URL() {
|
|
79
|
-
return config.get('hydra.publicUrl');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async deleteIdentitiesForDomain(domainId: string) {
|
|
83
|
-
for await (const identities of paginateIdentities(this.identityClient)) {
|
|
84
|
-
for (const identity of identities) {
|
|
85
|
-
if (
|
|
86
|
-
identity.metadata_public &&
|
|
87
|
-
metadataTypeguard(identity.metadata_public) &&
|
|
88
|
-
identity.metadata_public.domainId === domainId
|
|
89
|
-
) {
|
|
90
|
-
await this.deleteIdentity(identity.id);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
38
|
}
|
|
95
39
|
|
|
96
40
|
async getIdentity(id: string): Promise<ITakaroIdentity> {
|
|
@@ -98,34 +42,39 @@ class Ory {
|
|
|
98
42
|
id,
|
|
99
43
|
});
|
|
100
44
|
|
|
101
|
-
if (!res.data.metadata_public) {
|
|
102
|
-
this.log.warn('Identity has no metadata_public', {
|
|
103
|
-
identity: res.data.id,
|
|
104
|
-
});
|
|
105
|
-
throw new errors.ForbiddenError();
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (!metadataTypeguard(res.data.metadata_public)) {
|
|
109
|
-
this.log.warn('Identity metadata_public is not of type {domainId: string}', { identity: res.data.id });
|
|
110
|
-
throw new errors.ForbiddenError();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
45
|
return {
|
|
114
46
|
id: res.data.id,
|
|
115
47
|
email: res.data.traits.email,
|
|
116
|
-
domainId: res.data.metadata_public.domainId,
|
|
117
48
|
};
|
|
118
49
|
}
|
|
119
50
|
|
|
120
|
-
async
|
|
51
|
+
async getIdentityByEmail(email: string): Promise<ITakaroIdentity | null> {
|
|
52
|
+
const identity = await this.identityClient.listIdentities({ credentialsIdentifier: email });
|
|
53
|
+
|
|
54
|
+
if (!identity.data.length) return null;
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
id: identity.data[0].id,
|
|
58
|
+
email: identity.data[0].traits.email,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async createIdentity(email: string, password?: string): Promise<ITakaroIdentity> {
|
|
63
|
+
const existing = await this.identityClient.listIdentities({ credentialsIdentifier: email });
|
|
64
|
+
|
|
65
|
+
if (existing.data.length) {
|
|
66
|
+
this.log.warn('Identity already exists, returning existing one.', { email });
|
|
67
|
+
return {
|
|
68
|
+
id: existing.data[0].id,
|
|
69
|
+
email: existing.data[0].traits.email,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
121
73
|
const body: CreateIdentityBody = {
|
|
122
74
|
schema_id: IDENTITY_SCHEMA.USER,
|
|
123
75
|
traits: {
|
|
124
76
|
email,
|
|
125
77
|
},
|
|
126
|
-
metadata_public: {
|
|
127
|
-
domainId,
|
|
128
|
-
},
|
|
129
78
|
};
|
|
130
79
|
|
|
131
80
|
if (password) {
|
|
@@ -145,7 +94,6 @@ class Ory {
|
|
|
145
94
|
return {
|
|
146
95
|
id: res.data.id,
|
|
147
96
|
email: res.data.traits.email,
|
|
148
|
-
domainId,
|
|
149
97
|
};
|
|
150
98
|
}
|
|
151
99
|
|
|
@@ -155,33 +103,23 @@ class Ory {
|
|
|
155
103
|
});
|
|
156
104
|
}
|
|
157
105
|
|
|
158
|
-
async getIdentityFromReq(req: Request): Promise<ITakaroIdentity> {
|
|
106
|
+
async getIdentityFromReq(req: Request): Promise<ITakaroIdentity | null> {
|
|
159
107
|
const tokenFromAuthHeader = req.headers['authorization']?.replace('Bearer ', '');
|
|
160
108
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (!sessionRes.data.identity!.metadata_public) {
|
|
167
|
-
this.log.warn('Identity has no metadata_public', {
|
|
168
|
-
identity: sessionRes.data.identity!.id,
|
|
109
|
+
try {
|
|
110
|
+
const sessionRes = await this.frontendClient.toSession({
|
|
111
|
+
cookie: req.headers.cookie,
|
|
112
|
+
xSessionToken: tokenFromAuthHeader,
|
|
169
113
|
});
|
|
170
|
-
throw new errors.ForbiddenError();
|
|
171
|
-
}
|
|
172
114
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
115
|
+
return {
|
|
116
|
+
id: sessionRes.data.identity!.id,
|
|
117
|
+
email: sessionRes.data.identity!.traits.email,
|
|
118
|
+
};
|
|
119
|
+
} catch (error) {
|
|
120
|
+
this.log.warn('Could not get identity from request', { error });
|
|
121
|
+
return null;
|
|
178
122
|
}
|
|
179
|
-
|
|
180
|
-
return {
|
|
181
|
-
id: sessionRes.data.identity!.id,
|
|
182
|
-
email: sessionRes.data.identity!.traits.email,
|
|
183
|
-
domainId: sessionRes.data.identity!.metadata_public.domainId,
|
|
184
|
-
};
|
|
185
123
|
}
|
|
186
124
|
|
|
187
125
|
async submitApiLogin(username: string, password: string) {
|
|
@@ -210,58 +148,6 @@ class Ory {
|
|
|
210
148
|
});
|
|
211
149
|
}
|
|
212
150
|
|
|
213
|
-
async introspectToken(token: string): Promise<TakaroTokenDTO> {
|
|
214
|
-
const introspectRes = await this.adminClient.introspectOAuth2Token({
|
|
215
|
-
token,
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
const data = new TakaroTokenDTO({
|
|
219
|
-
active: introspectRes.data.active,
|
|
220
|
-
clientId: introspectRes.data.client_id,
|
|
221
|
-
aud: introspectRes.data.aud,
|
|
222
|
-
exp: introspectRes.data.exp,
|
|
223
|
-
iat: introspectRes.data.iat,
|
|
224
|
-
iss: introspectRes.data.iss,
|
|
225
|
-
sub: introspectRes.data.sub,
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
try {
|
|
229
|
-
// Check for correctness of the data
|
|
230
|
-
// DOES NOT CHECK FOR EXPIRATION
|
|
231
|
-
await data.validate();
|
|
232
|
-
} catch (error) {
|
|
233
|
-
this.log.warn('Introspected token has invalid shape', { error });
|
|
234
|
-
throw new errors.ForbiddenError();
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return data;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Currently, this is only used for creating the admin-auth client.
|
|
241
|
-
// ...In the future we should make this more generic and allow for
|
|
242
|
-
// creating any API client perhaps?
|
|
243
|
-
async createOIDCClient(): Promise<{
|
|
244
|
-
clientId: string;
|
|
245
|
-
clientSecret: string;
|
|
246
|
-
}> {
|
|
247
|
-
const client = await this.adminClient.createOAuth2Client({
|
|
248
|
-
oAuth2Client: {
|
|
249
|
-
grant_types: ['client_credentials'],
|
|
250
|
-
audience: [AUDIENCES.TAKARO_API_ADMIN],
|
|
251
|
-
},
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
if (!client.data.client_id || !client.data.client_secret) {
|
|
255
|
-
this.log.error('Could not create OIDC client', { client });
|
|
256
|
-
throw new errors.InternalServerError();
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return {
|
|
260
|
-
clientId: client.data.client_id,
|
|
261
|
-
clientSecret: client.data.client_secret,
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
151
|
async getRecoveryFlow(id: string) {
|
|
266
152
|
const recoveryRes = await this.identityClient.createRecoveryLinkForIdentity({
|
|
267
153
|
createRecoveryLinkForIdentityBody: {
|
|
@@ -35,7 +35,7 @@ export function createAxiosClient(baseURL: string) {
|
|
|
35
35
|
status: response.status,
|
|
36
36
|
method: response.request.method,
|
|
37
37
|
url: response.request.url,
|
|
38
|
-
}
|
|
38
|
+
},
|
|
39
39
|
);
|
|
40
40
|
|
|
41
41
|
return response;
|
|
@@ -61,7 +61,7 @@ export function createAxiosClient(baseURL: string) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
return Promise.reject(error);
|
|
64
|
-
}
|
|
64
|
+
},
|
|
65
65
|
);
|
|
66
66
|
|
|
67
67
|
return client;
|
package/src/lib/permissions.ts
CHANGED
|
@@ -18,6 +18,8 @@ export enum PERMISSIONS {
|
|
|
18
18
|
'MANAGE_EVENTS' = 'MANAGE_EVENTS',
|
|
19
19
|
'READ_ITEMS' = 'READ_ITEMS',
|
|
20
20
|
'MANAGE_ITEMS' = 'MANAGE_ITEMS',
|
|
21
|
+
'MANAGE_SHOP_LISTINGS' = 'MANAGE_SHOP_LISTINGS',
|
|
22
|
+
'MANAGE_SHOP_ORDERS' = 'MANAGE_SHOP_ORDERS',
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
export interface IPermissionDetails {
|
|
@@ -122,4 +124,14 @@ export const PERMISSION_DETAILS: Record<PERMISSIONS, IPermissionDetails> = {
|
|
|
122
124
|
friendlyName: 'Manage Items',
|
|
123
125
|
description: 'Can create, update, and delete items',
|
|
124
126
|
},
|
|
127
|
+
[PERMISSIONS.MANAGE_SHOP_LISTINGS]: {
|
|
128
|
+
permission: PERMISSIONS.MANAGE_SHOP_LISTINGS,
|
|
129
|
+
friendlyName: 'Manage Shop Listings',
|
|
130
|
+
description: 'Can create, update, and delete shop listings',
|
|
131
|
+
},
|
|
132
|
+
[PERMISSIONS.MANAGE_SHOP_ORDERS]: {
|
|
133
|
+
permission: PERMISSIONS.MANAGE_SHOP_ORDERS,
|
|
134
|
+
friendlyName: 'Manage Shop Orders',
|
|
135
|
+
description: 'Can view orders not belonging to the themself and perform administrative actions on them',
|
|
136
|
+
},
|
|
125
137
|
};
|
package/src/main.ts
CHANGED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { parse, URLSearchParams } from 'url';
|
|
2
|
-
export async function* paginateIdentities(adminClient, page = undefined, perPage = 100) {
|
|
3
|
-
let nextPage = page;
|
|
4
|
-
while (true) {
|
|
5
|
-
const response = await adminClient.listIdentities({
|
|
6
|
-
page: nextPage,
|
|
7
|
-
perPage,
|
|
8
|
-
});
|
|
9
|
-
if (response.data.length === 0) {
|
|
10
|
-
// Stop the iteration if there are no more items
|
|
11
|
-
break;
|
|
12
|
-
}
|
|
13
|
-
yield response.data;
|
|
14
|
-
// Parse Link header
|
|
15
|
-
const linkHeader = response.headers.link;
|
|
16
|
-
const links = linkHeader.split(',');
|
|
17
|
-
const nextLink = links.find((link) => link.includes('rel="next"'));
|
|
18
|
-
if (!nextLink) {
|
|
19
|
-
break;
|
|
20
|
-
}
|
|
21
|
-
// Extract the 'next' page URL
|
|
22
|
-
const match = nextLink.match(/<(.*)>/);
|
|
23
|
-
const url = match ? match[1] : undefined;
|
|
24
|
-
if (!url) {
|
|
25
|
-
break;
|
|
26
|
-
}
|
|
27
|
-
const parsedUrl = parse(url);
|
|
28
|
-
const params = new URLSearchParams(parsedUrl.query || '');
|
|
29
|
-
const nextPageToken = params.get('page');
|
|
30
|
-
if (nextPageToken) {
|
|
31
|
-
nextPage = parseInt(nextPageToken, 10);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
break; // stop if there is no next page
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=paginationHelpers.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"paginationHelpers.js","sourceRoot":"","sources":["../../src/lib/paginationHelpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,KAAK,CAAC;AAE7C,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,kBAAkB,CAAC,WAAwB,EAAE,IAAI,GAAG,SAAS,EAAE,OAAO,GAAG,GAAG;IACjG,IAAI,QAAQ,GAAuB,IAAI,CAAC;IAExC,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,cAAc,CAAC;YAChD,IAAI,EAAE,QAAQ;YACd,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,gDAAgD;YAChD,MAAM;QACR,CAAC;QAED,MAAM,QAAQ,CAAC,IAAI,CAAC;QAEpB,oBAAoB;QACpB,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;QAE3E,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM;QACR,CAAC;QAED,8BAA8B;QAC9B,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEzC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM;QACR,CAAC;QAED,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QAC1D,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,aAAa,EAAE,CAAC;YAClB,QAAQ,GAAG,QAAQ,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,gCAAgC;QACzC,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { IdentityApi } from '@ory/client';
|
|
2
|
-
import { parse, URLSearchParams } from 'url';
|
|
3
|
-
|
|
4
|
-
export async function* paginateIdentities(adminClient: IdentityApi, page = undefined, perPage = 100) {
|
|
5
|
-
let nextPage: number | undefined = page;
|
|
6
|
-
|
|
7
|
-
while (true) {
|
|
8
|
-
const response = await adminClient.listIdentities({
|
|
9
|
-
page: nextPage,
|
|
10
|
-
perPage,
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
if (response.data.length === 0) {
|
|
14
|
-
// Stop the iteration if there are no more items
|
|
15
|
-
break;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
yield response.data;
|
|
19
|
-
|
|
20
|
-
// Parse Link header
|
|
21
|
-
const linkHeader = response.headers.link;
|
|
22
|
-
const links = linkHeader.split(',');
|
|
23
|
-
const nextLink = links.find((link: string) => link.includes('rel="next"'));
|
|
24
|
-
|
|
25
|
-
if (!nextLink) {
|
|
26
|
-
break;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Extract the 'next' page URL
|
|
30
|
-
const match = nextLink.match(/<(.*)>/);
|
|
31
|
-
const url = match ? match[1] : undefined;
|
|
32
|
-
|
|
33
|
-
if (!url) {
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const parsedUrl = parse(url);
|
|
38
|
-
const params = new URLSearchParams(parsedUrl.query || '');
|
|
39
|
-
const nextPageToken = params.get('page');
|
|
40
|
-
if (nextPageToken) {
|
|
41
|
-
nextPage = parseInt(nextPageToken, 10);
|
|
42
|
-
} else {
|
|
43
|
-
break; // stop if there is no next page
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|