@or-sdk/authorizer 0.25.0-beta.990.0 → 0.25.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/CHANGELOG.md +317 -0
- package/README.md +12 -32
- package/dist/cjs/Basic/BasicCollection.js +166 -26
- package/dist/cjs/Basic/BasicCollection.js.map +1 -1
- package/dist/cjs/Basic/utils/createAuthKey.js +4 -0
- package/dist/cjs/Basic/utils/createAuthKey.js.map +1 -1
- package/dist/cjs/OAuth/OAuth.js +92 -138
- package/dist/cjs/OAuth/OAuth.js.map +1 -1
- package/dist/cjs/OAuth/index.js +1 -3
- package/dist/cjs/OAuth/index.js.map +1 -1
- package/dist/cjs/OAuth/types.js +1 -1
- package/dist/cjs/OAuth/types.js.map +1 -1
- package/dist/cjs/OAuth/utils/ServiceDefinition.js.map +1 -1
- package/dist/cjs/OAuth/utils/createAuthKey.js +4 -0
- package/dist/cjs/OAuth/utils/createAuthKey.js.map +1 -1
- package/dist/cjs/OAuth/utils/createOAuthHelper.js +379 -0
- package/dist/cjs/OAuth/utils/createOAuthHelper.js.map +1 -0
- package/dist/cjs/OAuth/utils/formatScope.js.map +1 -1
- package/dist/cjs/{OAuth → OAuthCollection}/OAuthCollection.js +132 -28
- package/dist/cjs/OAuthCollection/OAuthCollection.js.map +1 -0
- package/dist/cjs/OAuthCollection/index.js +21 -0
- package/dist/cjs/OAuthCollection/index.js.map +1 -0
- package/dist/cjs/Token/TokenCollection.js +166 -21
- package/dist/cjs/Token/TokenCollection.js.map +1 -1
- package/dist/cjs/Token/utils/createAuthKey.js +4 -0
- package/dist/cjs/Token/utils/createAuthKey.js.map +1 -1
- package/dist/cjs/constants.js +3 -2
- package/dist/cjs/constants.js.map +1 -1
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/Basic/BasicCollection.js +115 -17
- package/dist/esm/Basic/BasicCollection.js.map +1 -1
- package/dist/esm/Basic/utils/createAuthKey.js +3 -0
- package/dist/esm/Basic/utils/createAuthKey.js.map +1 -1
- package/dist/esm/OAuth/OAuth.js +56 -115
- package/dist/esm/OAuth/OAuth.js.map +1 -1
- package/dist/esm/OAuth/index.js +0 -1
- package/dist/esm/OAuth/index.js.map +1 -1
- package/dist/esm/OAuth/types.js.map +1 -1
- package/dist/esm/OAuth/utils/ServiceDefinition.js.map +1 -1
- package/dist/esm/OAuth/utils/createAuthKey.js +3 -0
- package/dist/esm/OAuth/utils/createAuthKey.js.map +1 -1
- package/dist/esm/OAuth/utils/createOAuthHelper.js +262 -0
- package/dist/esm/OAuth/utils/createOAuthHelper.js.map +1 -0
- package/dist/esm/OAuth/utils/formatScope.js.map +1 -1
- package/dist/esm/OAuthCollection/OAuthCollection.js +190 -0
- package/dist/esm/OAuthCollection/OAuthCollection.js.map +1 -0
- package/dist/esm/OAuthCollection/index.js +3 -0
- package/dist/esm/OAuthCollection/index.js.map +1 -0
- package/dist/esm/Token/TokenCollection.js +115 -12
- package/dist/esm/Token/TokenCollection.js.map +1 -1
- package/dist/esm/Token/utils/createAuthKey.js +3 -0
- package/dist/esm/Token/utils/createAuthKey.js.map +1 -1
- package/dist/esm/constants.js +1 -0
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/types/Basic/BasicCollection.d.ts +6 -4
- package/dist/types/Basic/BasicCollection.d.ts.map +1 -1
- package/dist/types/Basic/types.d.ts +20 -11
- package/dist/types/Basic/types.d.ts.map +1 -1
- package/dist/types/Basic/utils/createAuthKey.d.ts +1 -0
- package/dist/types/Basic/utils/createAuthKey.d.ts.map +1 -1
- package/dist/types/OAuth/OAuth.d.ts +8 -5
- package/dist/types/OAuth/OAuth.d.ts.map +1 -1
- package/dist/types/OAuth/index.d.ts +0 -1
- package/dist/types/OAuth/index.d.ts.map +1 -1
- package/dist/types/OAuth/types.d.ts +95 -19
- package/dist/types/OAuth/types.d.ts.map +1 -1
- package/dist/types/OAuth/utils/createAuthKey.d.ts +1 -0
- package/dist/types/OAuth/utils/createAuthKey.d.ts.map +1 -1
- package/dist/types/OAuth/utils/createOAuthHelper.d.ts +33 -0
- package/dist/types/OAuth/utils/createOAuthHelper.d.ts.map +1 -0
- package/dist/types/OAuthCollection/OAuthCollection.d.ts +27 -0
- package/dist/types/OAuthCollection/OAuthCollection.d.ts.map +1 -0
- package/dist/types/OAuthCollection/index.d.ts +3 -0
- package/dist/types/OAuthCollection/index.d.ts.map +1 -0
- package/dist/types/Token/TokenCollection.d.ts +5 -2
- package/dist/types/Token/TokenCollection.d.ts.map +1 -1
- package/dist/types/Token/types.d.ts +19 -5
- package/dist/types/Token/types.d.ts.map +1 -1
- package/dist/types/Token/utils/createAuthKey.d.ts +1 -0
- package/dist/types/Token/utils/createAuthKey.d.ts.map +1 -1
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +32 -26
- package/src/Basic/BasicCollection.ts +170 -18
- package/src/Basic/types.ts +17 -14
- package/src/Basic/utils/createAuthKey.ts +4 -0
- package/src/OAuth/OAuth.ts +111 -195
- package/src/OAuth/index.ts +0 -1
- package/src/OAuth/types.ts +171 -15
- package/src/OAuth/utils/createAuthKey.ts +8 -0
- package/src/OAuth/utils/createOAuthHelper.ts +374 -0
- package/src/OAuthCollection/OAuthCollection.ts +348 -0
- package/src/OAuthCollection/index.ts +3 -0
- package/src/Token/TokenCollection.ts +174 -16
- package/src/Token/types.ts +15 -0
- package/src/Token/utils/createAuthKey.ts +4 -0
- package/src/constants.ts +1 -0
- package/src/index.ts +2 -1
- package/dist/cjs/OAuth/OAuthCollection.js.map +0 -1
- package/dist/esm/OAuth/OAuthCollection.js +0 -120
- package/dist/esm/OAuth/OAuthCollection.js.map +0 -1
- package/dist/types/OAuth/OAuthCollection.d.ts +0 -21
- package/dist/types/OAuth/OAuthCollection.d.ts.map +0 -1
- package/src/OAuth/OAuthCollection.ts +0 -206
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { Token, List, makeList } from '@or-sdk/base';
|
|
2
|
+
import { KeyValueStorage } from '@or-sdk/key-value-storage';
|
|
3
|
+
import { Providers } from '@or-sdk/providers';
|
|
4
|
+
import { OAuth } from '../OAuth/OAuth';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
CreateOAuthInCollectionConfig,
|
|
8
|
+
CreateOAuthResult,
|
|
9
|
+
OAuthCollectionConfig,
|
|
10
|
+
OAuthApp,
|
|
11
|
+
OAuthCollectionInitConfig,
|
|
12
|
+
OAuthDynamicCollection,
|
|
13
|
+
OAuthService,
|
|
14
|
+
} from '../OAuth/types';
|
|
15
|
+
|
|
16
|
+
export class OAuthCollection {
|
|
17
|
+
private readonly token: Token;
|
|
18
|
+
private readonly providers: Providers;
|
|
19
|
+
private readonly discoveryUrl: string;
|
|
20
|
+
private readonly accountId: string | undefined;
|
|
21
|
+
private readonly sdkUrl: string | undefined;
|
|
22
|
+
private readonly eventManagerUrl: string | undefined;
|
|
23
|
+
private readonly providersAccountId: string | undefined;
|
|
24
|
+
private readonly crossAccount: boolean;
|
|
25
|
+
private keyValueCollection: string;
|
|
26
|
+
private keyValueStorage: KeyValueStorage;
|
|
27
|
+
private serviceName: string;
|
|
28
|
+
|
|
29
|
+
constructor(params: OAuthCollectionConfig) {
|
|
30
|
+
const {
|
|
31
|
+
token,
|
|
32
|
+
discoveryUrl,
|
|
33
|
+
accountId,
|
|
34
|
+
serviceName,
|
|
35
|
+
keyValueCollection,
|
|
36
|
+
eventManagerUrl,
|
|
37
|
+
providersAccountId,
|
|
38
|
+
sdkUrl,
|
|
39
|
+
crossAccount = true,
|
|
40
|
+
} = params;
|
|
41
|
+
|
|
42
|
+
this.token = token;
|
|
43
|
+
this.sdkUrl = sdkUrl;
|
|
44
|
+
this.accountId = accountId;
|
|
45
|
+
this.crossAccount = crossAccount;
|
|
46
|
+
this.discoveryUrl = discoveryUrl;
|
|
47
|
+
this.serviceName = serviceName || '';
|
|
48
|
+
this.eventManagerUrl = eventManagerUrl;
|
|
49
|
+
this.providersAccountId = providersAccountId;
|
|
50
|
+
this.keyValueCollection = keyValueCollection || serviceName || '';
|
|
51
|
+
|
|
52
|
+
this.keyValueStorage = new KeyValueStorage({
|
|
53
|
+
token,
|
|
54
|
+
discoveryUrl,
|
|
55
|
+
accountId: crossAccount ? accountId : undefined,
|
|
56
|
+
sdkUrl,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
this.providers = new Providers({
|
|
60
|
+
token,
|
|
61
|
+
discoveryUrl,
|
|
62
|
+
eventManagerUrl,
|
|
63
|
+
providersAccountId,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Allows to explicitly (re)initialize collection parameters
|
|
70
|
+
*/
|
|
71
|
+
public init(params: OAuthCollectionInitConfig): void {
|
|
72
|
+
const { serviceName, keyValueCollection } = params;
|
|
73
|
+
|
|
74
|
+
this.serviceName = serviceName || this.serviceName;
|
|
75
|
+
this.keyValueCollection = keyValueCollection || this.keyValueCollection || this.serviceName;
|
|
76
|
+
|
|
77
|
+
if (!this.serviceName) {
|
|
78
|
+
throw new Error('No service name provided.');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Returns array of auth keys from this collection
|
|
85
|
+
*/
|
|
86
|
+
public async listAuthorizations(dynamicCollection?: string): Promise<List<string>> {
|
|
87
|
+
const { items: records } = await this.keyValueStorage.listKeys(
|
|
88
|
+
this.keyValueCollection
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const pattern = dynamicCollection ? `::oauth-collection::${dynamicCollection}` : '::oauth::';
|
|
92
|
+
|
|
93
|
+
return makeList<string>(records.map((record) => record.key)
|
|
94
|
+
.filter(key => key.includes(pattern)));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Returns array of OAuth applications for this service
|
|
99
|
+
*/
|
|
100
|
+
public async listOAuthApps(): Promise<List<OAuthApp>> {
|
|
101
|
+
const appsStorageRecord = await this.keyValueStorage.getValueByKey(
|
|
102
|
+
this.keyValueCollection,
|
|
103
|
+
'__authorizer_apps'
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
if (!appsStorageRecord.value) {
|
|
107
|
+
return makeList<OAuthApp>([]);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const appsRecords = appsStorageRecord.value as Array<{
|
|
111
|
+
label: string;
|
|
112
|
+
value: Omit<OAuthApp, 'name'>;
|
|
113
|
+
}>;
|
|
114
|
+
|
|
115
|
+
return makeList<OAuthApp>(appsRecords.map((record) => ({
|
|
116
|
+
name: record.label,
|
|
117
|
+
...record.value,
|
|
118
|
+
})));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Returns OAuth instance for given key
|
|
124
|
+
*/
|
|
125
|
+
public async getAuthorization(key: string, dynamicCollection?: string): Promise<OAuth> {
|
|
126
|
+
if (!this.serviceName) throw new Error('No service name provided.');
|
|
127
|
+
let authName = undefined;
|
|
128
|
+
|
|
129
|
+
if (dynamicCollection) {
|
|
130
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
131
|
+
'__authorizer_dynamic_collections',
|
|
132
|
+
dynamicCollection
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (!value) {
|
|
136
|
+
throw new Error('Cynamic collection name is invalid');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const collection = value as OAuthDynamicCollection;
|
|
140
|
+
if (collection.service !== this.serviceName) {
|
|
141
|
+
throw new Error('Dynamic Collection and is related to other service than SDK Service Name');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
authName = key;
|
|
145
|
+
key = collection.authorizations[key];
|
|
146
|
+
|
|
147
|
+
} else {
|
|
148
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
149
|
+
this.keyValueCollection,
|
|
150
|
+
encodeURIComponent(key)
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
if (!value) {
|
|
154
|
+
throw new Error('This authorization does not exist');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!key.includes('::oauth')) throw new Error('The OAuth authorization key should contain "oauth" type specifier.');
|
|
159
|
+
|
|
160
|
+
return new OAuth({
|
|
161
|
+
authName,
|
|
162
|
+
authKey: key,
|
|
163
|
+
dynamicCollection,
|
|
164
|
+
discoveryUrl: this.discoveryUrl,
|
|
165
|
+
eventManagerUrl: this.eventManagerUrl,
|
|
166
|
+
keyValueCollection: this.keyValueCollection,
|
|
167
|
+
providersAccountId: this.providersAccountId,
|
|
168
|
+
sdkUrl: this.sdkUrl,
|
|
169
|
+
serviceName: this.serviceName,
|
|
170
|
+
token: this.token,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Creates a new auth record in current collection with the given config.
|
|
177
|
+
* @returns Object with OAuth instance connected to created auth and authorizerUrl
|
|
178
|
+
* to redirect the user to for completing authorization
|
|
179
|
+
*
|
|
180
|
+
* ```typescript
|
|
181
|
+
* const {
|
|
182
|
+
* authorizeUrl, // redirect user to this url for completing authorization
|
|
183
|
+
* instance // new instance
|
|
184
|
+
* } = await oAuthCollectionInstance.createAuthorization({
|
|
185
|
+
* authName: 'my-auth-name',
|
|
186
|
+
* appId: 'my-app-id',
|
|
187
|
+
*
|
|
188
|
+
* // Optional params
|
|
189
|
+
* sdkUrl: 'sdkapi.staging.api.onereach.ai' // SDK API url. If passed, won't be fetched from discovery.
|
|
190
|
+
* eventManagerUrl: 'em.staging.api.onereach.ai' // Event Manager url. If passed, won't be fetched from discovery.
|
|
191
|
+
* providersAccountId: 'providers-account-id-v4' // Account ID of provider account. If passed, won't be fetched from discovery.
|
|
192
|
+
* keyValueCollection: 'custom_collection_name' // Pass this if you using custom name for key-value collection
|
|
193
|
+
* // that differs from serviceName.
|
|
194
|
+
* destinationAccount: 'CUSTOM' or 'PROVIDER' // Allows to save authorization data to custom account.
|
|
195
|
+
* customAccountId: 'custom-account-uuid-v4' // Account ID for destinationAccount == "CUSTOM".
|
|
196
|
+
* useNextProvider: boolean (default: false) // Use authorizer-next redirect endpoint.
|
|
197
|
+
* userScope: 'user:read' // Scopes for Slack service.
|
|
198
|
+
* useNonce: true // Allows to use Nonce to avoid repetition attacks.
|
|
199
|
+
* });
|
|
200
|
+
*
|
|
201
|
+
* // if you want to use returned instance, you must call a method
|
|
202
|
+
* that returns a promise that will be resolved when the user completes authorization process
|
|
203
|
+
* // if not, you can omit this step
|
|
204
|
+
* try {
|
|
205
|
+
* await instance.waitForCompletion()
|
|
206
|
+
* } catch (e) {
|
|
207
|
+
* // will be called if the user does not complete authorization within 5 minutes
|
|
208
|
+
* }
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
public async createAuthorization(
|
|
212
|
+
params: CreateOAuthInCollectionConfig,
|
|
213
|
+
): Promise<CreateOAuthResult> {
|
|
214
|
+
if (!this.serviceName) throw new Error('No service name provided.');
|
|
215
|
+
return await OAuth.create({
|
|
216
|
+
...params,
|
|
217
|
+
accountId: this.accountId,
|
|
218
|
+
crossAccount: this.crossAccount,
|
|
219
|
+
discoveryUrl: this.discoveryUrl,
|
|
220
|
+
eventManagerUrl: this.eventManagerUrl,
|
|
221
|
+
keyValueCollection: this.keyValueCollection,
|
|
222
|
+
providersAccountId: this.providersAccountId,
|
|
223
|
+
sdkUrl: this.sdkUrl,
|
|
224
|
+
serviceName: this.serviceName,
|
|
225
|
+
token: this.token,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Returns a list of predefined OAuth Services
|
|
232
|
+
*/
|
|
233
|
+
public async listPredefinedServices(): Promise<Record<string, unknown>[]> {
|
|
234
|
+
|
|
235
|
+
const globalServices = await this.providers.makeRequest({
|
|
236
|
+
method: 'GET',
|
|
237
|
+
route: 'authorizer/services/list',
|
|
238
|
+
params: {
|
|
239
|
+
type: 'list',
|
|
240
|
+
},
|
|
241
|
+
}) as Record<string, unknown>;
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
const globalServicesList = Object.keys(globalServices).map(record => {
|
|
245
|
+
const label = record.split('__authorization_service_')[1]
|
|
246
|
+
.replace(/_/g, ' ');
|
|
247
|
+
|
|
248
|
+
const value = globalServices[record];
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
label,
|
|
252
|
+
value,
|
|
253
|
+
};
|
|
254
|
+
}) as Record<string, unknown>[];
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
const localServices = await this.keyValueStorage.listKeys(
|
|
258
|
+
'__authorization_service_predefined_services_local',
|
|
259
|
+
undefined,
|
|
260
|
+
true
|
|
261
|
+
) as unknown as Record<string, Record<string, string>[]>;
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
const localServicesList = localServices.items.map(el => {
|
|
265
|
+
const label = el.key
|
|
266
|
+
.split('__authorization_service_')[1]
|
|
267
|
+
.replace(/_/g, ' ') + ' (local)';
|
|
268
|
+
|
|
269
|
+
const value = el.value;
|
|
270
|
+
return {
|
|
271
|
+
label,
|
|
272
|
+
value,
|
|
273
|
+
};
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
return [...globalServicesList, ...localServicesList];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Defines a Local service
|
|
282
|
+
*/
|
|
283
|
+
public async defineService(params: Omit<OAuthService, 'serviceName'>): Promise<void> {
|
|
284
|
+
if (!this.serviceName) throw new Error('No service name provided.');
|
|
285
|
+
const newService = {
|
|
286
|
+
...params,
|
|
287
|
+
serviceName: this.serviceName,
|
|
288
|
+
} as OAuthService;
|
|
289
|
+
|
|
290
|
+
this.keyValueStorage.setValueByKey(
|
|
291
|
+
'__authorization_service_predefined_services_local',
|
|
292
|
+
this.serviceName,
|
|
293
|
+
newService
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Creates a Dynamic OAuth collection
|
|
300
|
+
*/
|
|
301
|
+
public async createDynamicCollection(dynamicCollectionName: string): Promise<void> {
|
|
302
|
+
if (!this.serviceName) throw new Error('No service name provided.');
|
|
303
|
+
if (!dynamicCollectionName) throw new Error('Dynamic collection name is empty or invalid');
|
|
304
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
305
|
+
'__authorizer_dynamic_collections',
|
|
306
|
+
dynamicCollectionName
|
|
307
|
+
);
|
|
308
|
+
const collection = value as OAuthDynamicCollection;
|
|
309
|
+
|
|
310
|
+
if (!value) {
|
|
311
|
+
await this.keyValueStorage.setValueByKey('__authorizer_dynamic_collections', dynamicCollectionName, {
|
|
312
|
+
name: dynamicCollectionName,
|
|
313
|
+
type: 'oauth',
|
|
314
|
+
service: this.keyValueCollection,
|
|
315
|
+
serviceConfigName: this.serviceName,
|
|
316
|
+
authorizations: {},
|
|
317
|
+
});
|
|
318
|
+
} else if (collection.type === 'oauth' && collection.service === this.serviceName) {
|
|
319
|
+
throw new Error('Same collection already exists');
|
|
320
|
+
} else {
|
|
321
|
+
throw new Error('Different collection exists with this name');
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Deletes a Dynamic OAuth collection
|
|
327
|
+
*/
|
|
328
|
+
public async deleteDynamicCollection(dynamicCollectionName: string): Promise<void> {
|
|
329
|
+
if (!dynamicCollectionName) throw new Error('Dynamic collection name is empty or invalid');
|
|
330
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
331
|
+
'__authorizer_dynamic_collections',
|
|
332
|
+
dynamicCollectionName
|
|
333
|
+
);
|
|
334
|
+
const collection = value as OAuthDynamicCollection;
|
|
335
|
+
|
|
336
|
+
await Promise.all(
|
|
337
|
+
Object.keys(collection.authorizations)
|
|
338
|
+
.map(authName => {
|
|
339
|
+
return this.keyValueStorage.deleteKey(
|
|
340
|
+
collection.service,
|
|
341
|
+
encodeURIComponent(collection.authorizations[authName])
|
|
342
|
+
);
|
|
343
|
+
})
|
|
344
|
+
).catch(() => {});
|
|
345
|
+
|
|
346
|
+
await this.keyValueStorage.deleteKey('__authorizer_dynamic_collections', dynamicCollectionName);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { makeList, List } from '@or-sdk/base';
|
|
2
2
|
import { KeyValueStorage } from '@or-sdk/key-value-storage';
|
|
3
|
+
import { Providers } from '@or-sdk/providers';
|
|
3
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
-
import { createAuthKey } from './utils/createAuthKey';
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
TokenCollectionConfig,
|
|
8
8
|
CreateTokenAuthInCollectionConfig,
|
|
9
9
|
TokenAuthData,
|
|
10
|
+
TokenDynamicCollection,
|
|
10
11
|
} from './types';
|
|
12
|
+
import { createAuthKey, createDynamicKey } from './utils/createAuthKey';
|
|
13
|
+
|
|
11
14
|
|
|
12
15
|
export class TokenCollection {
|
|
13
16
|
private serviceName: string;
|
|
14
17
|
private readonly keyValueStorage: KeyValueStorage;
|
|
18
|
+
private readonly providers: Providers;
|
|
15
19
|
|
|
16
20
|
constructor(params: TokenCollectionConfig) {
|
|
17
21
|
const { token, discoveryUrl, serviceName, accountId } = params;
|
|
@@ -22,6 +26,11 @@ export class TokenCollection {
|
|
|
22
26
|
discoveryUrl,
|
|
23
27
|
accountId,
|
|
24
28
|
});
|
|
29
|
+
|
|
30
|
+
this.providers = new Providers({
|
|
31
|
+
token,
|
|
32
|
+
discoveryUrl,
|
|
33
|
+
});
|
|
25
34
|
}
|
|
26
35
|
|
|
27
36
|
|
|
@@ -38,17 +47,30 @@ export class TokenCollection {
|
|
|
38
47
|
/**
|
|
39
48
|
* Returns array of auth keys from this collection
|
|
40
49
|
*/
|
|
41
|
-
public async listAuthorizations(): Promise<List<string>> {
|
|
42
|
-
const { items: records } = await this.keyValueStorage.listKeys(this.serviceName);
|
|
50
|
+
public async listAuthorizations(dynamicCollectionName?: string): Promise<List<string>> {
|
|
51
|
+
const { items: records } = await this.keyValueStorage.listKeys(this.serviceName, '', false);
|
|
43
52
|
|
|
44
|
-
|
|
53
|
+
const pattern = dynamicCollectionName ? `::token-collection::${dynamicCollectionName}` : '::token::';
|
|
54
|
+
|
|
55
|
+
return makeList<string>(records.map((record) => record.key).filter(key => key.includes(pattern)));
|
|
45
56
|
}
|
|
46
57
|
|
|
47
58
|
/**
|
|
48
59
|
* Returns TokenAuth instance for given key
|
|
49
60
|
*/
|
|
50
|
-
public async getAuthorization(key: string): Promise<TokenAuthData> {
|
|
61
|
+
public async getAuthorization(key: string, dynamicCollectionName: string): Promise<TokenAuthData> {
|
|
51
62
|
if (!this.serviceName) throw new Error('Service name is not defined.');
|
|
63
|
+
|
|
64
|
+
if (dynamicCollectionName) {
|
|
65
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
66
|
+
'__authorizer_dynamic_collections',
|
|
67
|
+
dynamicCollectionName
|
|
68
|
+
);
|
|
69
|
+
const collection = value as TokenDynamicCollection;
|
|
70
|
+
if (!collection) throw new Error('Dynamic collection name is invalid');
|
|
71
|
+
|
|
72
|
+
key = collection.authorizations[key];
|
|
73
|
+
}
|
|
52
74
|
if (!key.includes('::token')) throw new Error('The Token authorization key should contain "token" type specifier.');
|
|
53
75
|
|
|
54
76
|
|
|
@@ -59,7 +81,7 @@ export class TokenCollection {
|
|
|
59
81
|
|
|
60
82
|
const authData = record.value as Omit<TokenAuthData, 'key'>;
|
|
61
83
|
|
|
62
|
-
if (!authData.auth_name || !authData.date_created) {
|
|
84
|
+
if (!(authData.auth_name || authData._auth_name) || !(authData.date_created || authData._date_created)) {
|
|
63
85
|
throw new Error('Authorization is invalid.');
|
|
64
86
|
}
|
|
65
87
|
|
|
@@ -72,35 +94,83 @@ export class TokenCollection {
|
|
|
72
94
|
|
|
73
95
|
/**
|
|
74
96
|
* Creates a new auth record in current collection with the given config.
|
|
75
|
-
* @returns
|
|
97
|
+
* @returns TokenAuthData object
|
|
76
98
|
*
|
|
77
99
|
* ```typescript
|
|
78
|
-
* const
|
|
100
|
+
* const tokenAuthData = await tokenCollectionInstance.createAuthorization({
|
|
79
101
|
* authName: 'my-auth-name',
|
|
80
102
|
* credentials: {
|
|
81
103
|
* token: 'secrettoken'
|
|
82
|
-
* }
|
|
104
|
+
* },
|
|
105
|
+
* dynamicCollection: 'my-dynamic-collection' // Optional
|
|
83
106
|
* });
|
|
84
107
|
* ```
|
|
85
108
|
*/
|
|
86
109
|
public async createAuthorization(
|
|
87
110
|
params: CreateTokenAuthInCollectionConfig
|
|
88
111
|
): Promise<TokenAuthData> {
|
|
89
|
-
const { authName, credentials } = params;
|
|
112
|
+
const { authName, credentials, dynamicCollection, destinationAccount = 'CURRENT', customAccountId } = params;
|
|
90
113
|
|
|
91
114
|
if (!this.serviceName) throw new Error('Service name is not defined.');
|
|
92
115
|
if (!authName || !credentials) throw new Error('Invalid authorization parameters passed.');
|
|
93
116
|
|
|
94
117
|
const id = uuidv4();
|
|
95
|
-
const authKey = createAuthKey(id, authName);
|
|
118
|
+
const authKey = dynamicCollection ? createDynamicKey(id, dynamicCollection) : createAuthKey(id, authName);
|
|
96
119
|
|
|
97
120
|
const authData = {
|
|
98
121
|
...credentials,
|
|
99
122
|
auth_name: authName,
|
|
100
|
-
|
|
123
|
+
_date_created: new Date().toISOString(),
|
|
101
124
|
} as Omit<TokenAuthData, 'key'>;
|
|
102
125
|
|
|
103
|
-
|
|
126
|
+
if (dynamicCollection) {
|
|
127
|
+
const { value } = await this.keyValueStorage.getValueByKey('__authorizer_dynamic_collections', dynamicCollection);
|
|
128
|
+
|
|
129
|
+
const collection = (value || {
|
|
130
|
+
name: dynamicCollection,
|
|
131
|
+
type: 'token',
|
|
132
|
+
service: this.serviceName,
|
|
133
|
+
serviceConfigName: this.serviceName,
|
|
134
|
+
authorizations: {},
|
|
135
|
+
}) as TokenDynamicCollection;
|
|
136
|
+
|
|
137
|
+
if (collection.type !== 'token' || collection.service !== this.serviceName) {
|
|
138
|
+
throw new Error('Dynamic collection\'s type or service is invalid');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
collection.authorizations[authName] = authKey;
|
|
142
|
+
await this.keyValueStorage.setValueByKey('__authorizer_dynamic_collections', dynamicCollection, collection);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Accounts handling
|
|
146
|
+
if (destinationAccount === 'CURRENT') {
|
|
147
|
+
await this.keyValueStorage.setValueByKey(this.serviceName, encodeURIComponent(authKey), authData);
|
|
148
|
+
} else {
|
|
149
|
+
const localRecord = {
|
|
150
|
+
auth_name: authData.auth_name,
|
|
151
|
+
isRemote: true,
|
|
152
|
+
id,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
if (destinationAccount === 'CUSTOM' && !customAccountId) {
|
|
156
|
+
throw new Error('Custom Account ID is required if destinationAccount === "CUSTOM"');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
await this.providers.makeRequest({
|
|
160
|
+
route: 'authorizer/redirect',
|
|
161
|
+
params: {
|
|
162
|
+
method: 'PUT',
|
|
163
|
+
data: {
|
|
164
|
+
authData,
|
|
165
|
+
id,
|
|
166
|
+
storeAccount: destinationAccount,
|
|
167
|
+
storeCustomAccountId: destinationAccount === 'CUSTOM' ? customAccountId : undefined,
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
}).catch(() => { throw new Error('Could not save token to the specified account');});
|
|
171
|
+
|
|
172
|
+
await this.keyValueStorage.setValueByKey(this.serviceName, encodeURIComponent(authKey), localRecord);
|
|
173
|
+
}
|
|
104
174
|
|
|
105
175
|
return {
|
|
106
176
|
...authData,
|
|
@@ -118,18 +188,25 @@ export class TokenCollection {
|
|
|
118
188
|
): Promise<TokenAuthData> {
|
|
119
189
|
if (!this.serviceName) throw new Error('Service name is not defined.');
|
|
120
190
|
if (!newCredentials) throw new Error('New credentials are empty or invalid');
|
|
121
|
-
if (!tokenAuth || !tokenAuth.auth_name || !tokenAuth.date_created)
|
|
191
|
+
if (!tokenAuth || !tokenAuth.auth_name || !(tokenAuth.date_created || tokenAuth._date_created)) {
|
|
122
192
|
throw new Error('Token authorization data is invalid');
|
|
193
|
+
}
|
|
123
194
|
|
|
124
195
|
const updatedData = {
|
|
125
196
|
...tokenAuth,
|
|
126
197
|
...newCredentials,
|
|
198
|
+
auth_name: tokenAuth.auth_name,
|
|
199
|
+
_date_created: tokenAuth._date_created,
|
|
127
200
|
key: undefined,
|
|
128
201
|
};
|
|
129
202
|
|
|
130
|
-
const response = await this.keyValueStorage.setValueByKey(
|
|
203
|
+
const response = await this.keyValueStorage.setValueByKey(
|
|
204
|
+
this.serviceName,
|
|
205
|
+
encodeURIComponent(tokenAuth.key),
|
|
206
|
+
updatedData
|
|
207
|
+
);
|
|
131
208
|
|
|
132
|
-
const updatedRecord = response.value
|
|
209
|
+
const updatedRecord = response.value;
|
|
133
210
|
return {
|
|
134
211
|
...updatedRecord,
|
|
135
212
|
key: tokenAuth.key,
|
|
@@ -143,6 +220,87 @@ export class TokenCollection {
|
|
|
143
220
|
public async deleteAuthorization(key: string): Promise<void> {
|
|
144
221
|
if (!this.serviceName) throw new Error('Service name is not defined.');
|
|
145
222
|
if (!key) throw new Error('Key is missing or invalid');
|
|
223
|
+
|
|
224
|
+
if (key.includes('::token-collection::')) {
|
|
225
|
+
const dynamicCollectionName = key.split('::')[2].split(' ')[0];
|
|
226
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
227
|
+
'__authorizer_dynamic_collections',
|
|
228
|
+
dynamicCollectionName
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const collection = value as TokenDynamicCollection;
|
|
232
|
+
if (collection) {
|
|
233
|
+
const authName = Object.keys(collection.authorizations)
|
|
234
|
+
.find(name => collection.authorizations[name] === key);
|
|
235
|
+
|
|
236
|
+
if (authName) {
|
|
237
|
+
delete collection.authorizations[authName];
|
|
238
|
+
await this.keyValueStorage.setValueByKey(
|
|
239
|
+
'__authorizer_dynamic_collections',
|
|
240
|
+
dynamicCollectionName,
|
|
241
|
+
collection
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
146
246
|
await this.keyValueStorage.deleteKey(this.serviceName, encodeURIComponent(key));
|
|
147
247
|
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Creates a Dynamic Token collection
|
|
252
|
+
*/
|
|
253
|
+
public async createDynamicCollection(dynamicCollectionName: string): Promise<void> {
|
|
254
|
+
if (!dynamicCollectionName) throw new Error('Dynamic collection name is empty or invalid');
|
|
255
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
256
|
+
'__authorizer_dynamic_collections',
|
|
257
|
+
dynamicCollectionName
|
|
258
|
+
);
|
|
259
|
+
const collection = value as TokenDynamicCollection;
|
|
260
|
+
|
|
261
|
+
if (!value) {
|
|
262
|
+
await this.keyValueStorage.setValueByKey(
|
|
263
|
+
'__authorizer_dynamic_collections',
|
|
264
|
+
dynamicCollectionName,
|
|
265
|
+
{
|
|
266
|
+
name: dynamicCollectionName,
|
|
267
|
+
type: 'token',
|
|
268
|
+
service: this.serviceName,
|
|
269
|
+
serviceConfigName: this.serviceName,
|
|
270
|
+
authorizations: {},
|
|
271
|
+
});
|
|
272
|
+
} else if (collection.type === 'oauth' && collection.service === this.serviceName) {
|
|
273
|
+
throw new Error('Same collection already exists');
|
|
274
|
+
} else {
|
|
275
|
+
throw new Error('Different collection exists with this name');
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Deletes a Dynamic collection
|
|
282
|
+
*/
|
|
283
|
+
public async deleteDynamicCollection(dynamicCollectionName: string): Promise<void> {
|
|
284
|
+
if (!dynamicCollectionName) throw new Error('Dynamic collection name is empty or invalid');
|
|
285
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
286
|
+
'__authorizer_dynamic_collections',
|
|
287
|
+
dynamicCollectionName
|
|
288
|
+
);
|
|
289
|
+
const collection = value as TokenDynamicCollection;
|
|
290
|
+
|
|
291
|
+
await Promise.all(
|
|
292
|
+
Object.keys(collection.authorizations)
|
|
293
|
+
.map(authName => {
|
|
294
|
+
return this.keyValueStorage.deleteKey(
|
|
295
|
+
collection.service,
|
|
296
|
+
encodeURIComponent(collection.authorizations[authName])
|
|
297
|
+
);
|
|
298
|
+
})
|
|
299
|
+
).catch(() => {});
|
|
300
|
+
|
|
301
|
+
await this.keyValueStorage.deleteKey(
|
|
302
|
+
'__authorizer_dynamic_collections',
|
|
303
|
+
dynamicCollectionName
|
|
304
|
+
);
|
|
305
|
+
}
|
|
148
306
|
}
|
package/src/Token/types.ts
CHANGED
|
@@ -38,6 +38,9 @@ export type CreateTokenAuthConfig = {
|
|
|
38
38
|
*/
|
|
39
39
|
token: Token;
|
|
40
40
|
discoveryUrl: string;
|
|
41
|
+
dynamicCollection?: string;
|
|
42
|
+
destinationAccount: 'CURRENT' | 'PROVIDER' | 'CUSTOM';
|
|
43
|
+
customAccountId?: string;
|
|
41
44
|
};
|
|
42
45
|
|
|
43
46
|
export type CreateTokenAuthInCollectionConfig = Omit<CreateTokenAuthConfig, 'serviceName' | 'discoveryUrl' | 'token'>;
|
|
@@ -51,3 +54,15 @@ export type TokenCollectionConfig = {
|
|
|
51
54
|
serviceName: string;
|
|
52
55
|
accountId?: string;
|
|
53
56
|
};
|
|
57
|
+
|
|
58
|
+
export type TokenDynamicCollection = {
|
|
59
|
+
name: string;
|
|
60
|
+
type: string;
|
|
61
|
+
service: string;
|
|
62
|
+
serviceConfigName: string;
|
|
63
|
+
authorizations: {
|
|
64
|
+
[key: string]: string;
|
|
65
|
+
};
|
|
66
|
+
appId?: string;
|
|
67
|
+
scope?: string;
|
|
68
|
+
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
export const createAuthKey = (id: string, authName: string): string => {
|
|
2
2
|
return `${id}::token::${authName}`;
|
|
3
3
|
};
|
|
4
|
+
|
|
5
|
+
export function createDynamicKey(id: string, dynamicCollection: string): string {
|
|
6
|
+
return `${id}::token-collection::${dynamicCollection} collection auth`;
|
|
7
|
+
}
|
package/src/constants.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { BasicCollection } from './Basic/index';
|
|
2
2
|
export { TokenCollection } from './Token/index';
|
|
3
|
-
export { OAuth
|
|
3
|
+
export { OAuth } from './OAuth/index';
|
|
4
|
+
export { OAuthCollection } from './OAuthCollection/index';
|
|
4
5
|
|
|
5
6
|
export * from './types';
|