@or-sdk/authorizer 0.24.17 → 0.24.18
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 +9 -0
- package/README.md +12 -32
- package/dist/cjs/Basic/BasicCollection.js +260 -27
- package/dist/cjs/Basic/BasicCollection.js.map +1 -1
- package/dist/cjs/Basic/index.js +21 -0
- package/dist/cjs/Basic/index.js.map +1 -0
- package/dist/cjs/Basic/utils/createAuthKey.js +5 -1
- package/dist/cjs/Basic/utils/createAuthKey.js.map +1 -1
- package/dist/cjs/OAuth/OAuth.js +114 -131
- package/dist/cjs/OAuth/OAuth.js.map +1 -1
- package/dist/cjs/OAuth/index.js +21 -0
- package/dist/cjs/OAuth/index.js.map +1 -0
- package/dist/cjs/OAuth/types.js.map +1 -1
- package/dist/cjs/OAuth/utils/createAuthKey.js +5 -1
- 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/OAuthCollection/OAuthCollection.js +312 -0
- 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 +237 -26
- package/dist/cjs/Token/TokenCollection.js.map +1 -1
- package/dist/cjs/Token/index.js +21 -0
- package/dist/cjs/Token/index.js.map +1 -0
- package/dist/cjs/Token/utils/createAuthKey.js +5 -1
- package/dist/cjs/Token/utils/createAuthKey.js.map +1 -1
- package/dist/cjs/constants.js +2 -1
- package/dist/cjs/constants.js.map +1 -1
- package/dist/cjs/index.js +9 -13
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/Basic/BasicCollection.js +183 -23
- package/dist/esm/Basic/BasicCollection.js.map +1 -1
- package/dist/esm/Basic/index.js +3 -0
- package/dist/esm/Basic/index.js.map +1 -0
- 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 +73 -107
- package/dist/esm/OAuth/OAuth.js.map +1 -1
- package/dist/esm/OAuth/index.js +3 -0
- package/dist/esm/OAuth/index.js.map +1 -0
- package/dist/esm/OAuth/types.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/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 +161 -23
- package/dist/esm/Token/TokenCollection.js.map +1 -1
- package/dist/esm/Token/index.js +3 -0
- package/dist/esm/Token/index.js.map +1 -0
- 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 +4 -6
- package/dist/esm/index.js.map +1 -1
- package/dist/types/Basic/BasicCollection.d.ts +20 -8
- package/dist/types/Basic/BasicCollection.d.ts.map +1 -1
- package/dist/types/Basic/index.d.ts +3 -0
- package/dist/types/Basic/index.d.ts.map +1 -0
- package/dist/types/Basic/types.d.ts +19 -8
- 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 +9 -6
- package/dist/types/OAuth/OAuth.d.ts.map +1 -1
- package/dist/types/OAuth/index.d.ts +3 -0
- package/dist/types/OAuth/index.d.ts.map +1 -0
- package/dist/types/OAuth/types.d.ts +93 -9
- 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 +12 -8
- package/dist/types/Token/TokenCollection.d.ts.map +1 -1
- package/dist/types/Token/index.d.ts +3 -0
- package/dist/types/Token/index.d.ts.map +1 -0
- package/dist/types/Token/types.d.ts +16 -0
- 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 +4 -6
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +39 -2
- package/src/Basic/BasicCollection.ts +295 -32
- package/src/Basic/index.ts +3 -0
- package/src/Basic/types.ts +20 -15
- package/src/Basic/utils/createAuthKey.ts +4 -0
- package/src/OAuth/OAuth.ts +148 -174
- package/src/OAuth/index.ts +3 -0
- package/src/OAuth/types.ts +198 -13
- 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 +258 -31
- package/src/Token/index.ts +3 -0
- package/src/Token/types.ts +17 -0
- package/src/Token/utils/createAuthKey.ts +4 -0
- package/src/constants.ts +1 -0
- package/src/index.ts +4 -8
- package/dist/cjs/Basic/BasicAuth.js +0 -162
- package/dist/cjs/Basic/BasicAuth.js.map +0 -1
- package/dist/cjs/OAuth/OAuthCollection.js +0 -138
- package/dist/cjs/OAuth/OAuthCollection.js.map +0 -1
- package/dist/cjs/Token/TokenAuth.js +0 -140
- package/dist/cjs/Token/TokenAuth.js.map +0 -1
- package/dist/esm/Basic/BasicAuth.js +0 -88
- package/dist/esm/Basic/BasicAuth.js.map +0 -1
- package/dist/esm/OAuth/OAuthCollection.js +0 -69
- package/dist/esm/OAuth/OAuthCollection.js.map +0 -1
- package/dist/esm/Token/TokenAuth.js +0 -66
- package/dist/esm/Token/TokenAuth.js.map +0 -1
- package/dist/types/Basic/BasicAuth.d.ts +0 -20
- package/dist/types/Basic/BasicAuth.d.ts.map +0 -1
- package/dist/types/OAuth/OAuthCollection.d.ts +0 -15
- package/dist/types/OAuth/OAuthCollection.d.ts.map +0 -1
- package/dist/types/Token/TokenAuth.d.ts +0 -12
- package/dist/types/Token/TokenAuth.d.ts.map +0 -1
- package/src/Basic/BasicAuth.ts +0 -129
- package/src/OAuth/OAuthCollection.ts +0 -118
- package/src/Token/TokenAuth.ts +0 -102
|
@@ -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,78 +1,305 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { makeList, List } from '@or-sdk/base';
|
|
2
|
+
import { Providers } from '@or-sdk/providers';
|
|
2
3
|
import { KeyValueStorage } from '@or-sdk/key-value-storage';
|
|
3
|
-
import {
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
+
import { createAuthKey, createDynamicKey } from './utils/createAuthKey';
|
|
4
6
|
|
|
5
7
|
import {
|
|
6
8
|
TokenCollectionConfig,
|
|
7
9
|
CreateTokenAuthInCollectionConfig,
|
|
10
|
+
TokenAuthData,
|
|
11
|
+
TokenDynamicCollection,
|
|
8
12
|
} from './types';
|
|
9
13
|
|
|
10
14
|
export class TokenCollection {
|
|
11
|
-
private
|
|
15
|
+
private serviceName: string;
|
|
12
16
|
private readonly keyValueStorage: KeyValueStorage;
|
|
13
|
-
private readonly
|
|
14
|
-
private readonly localDiscoveryUrl: string;
|
|
17
|
+
private readonly providers: Providers;
|
|
15
18
|
|
|
16
19
|
constructor(params: TokenCollectionConfig) {
|
|
17
|
-
const { token, discoveryUrl, serviceName } = params;
|
|
20
|
+
const { token, discoveryUrl, serviceName, accountId } = params;
|
|
18
21
|
|
|
19
|
-
this.
|
|
20
|
-
this.localDiscoveryUrl = discoveryUrl;
|
|
21
|
-
this.serviceName = serviceName;
|
|
22
|
+
this.serviceName = serviceName || '';
|
|
22
23
|
this.keyValueStorage = new KeyValueStorage({
|
|
23
24
|
token,
|
|
24
25
|
discoveryUrl,
|
|
26
|
+
accountId,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
this.providers = new Providers({
|
|
30
|
+
token,
|
|
31
|
+
discoveryUrl,
|
|
25
32
|
});
|
|
26
33
|
}
|
|
27
34
|
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Allows to explicitly (re-)set authorization service name
|
|
38
|
+
*/
|
|
39
|
+
public init(serviceName: string) {
|
|
40
|
+
if (!serviceName) throw new Error('Servide name is required.');
|
|
41
|
+
|
|
42
|
+
this.serviceName = serviceName;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
28
46
|
/**
|
|
29
47
|
* Returns array of auth keys from this collection
|
|
30
48
|
*/
|
|
31
|
-
public async listAuthorizations(): Promise<string
|
|
32
|
-
const { items: records } = await this.keyValueStorage.listKeys(this.serviceName);
|
|
49
|
+
public async listAuthorizations(dynamicCollectionName?: string): Promise<List<string>> {
|
|
50
|
+
const { items: records } = await this.keyValueStorage.listKeys(this.serviceName, '', false);
|
|
51
|
+
|
|
52
|
+
const pattern = dynamicCollectionName ? `::token-collection::${dynamicCollectionName}` : '::token::';
|
|
33
53
|
|
|
34
|
-
return records.map((record) => record.key);
|
|
54
|
+
return makeList<string>(records.map((record) => record.key).filter(key => key.includes(pattern)));
|
|
35
55
|
}
|
|
36
56
|
|
|
37
57
|
/**
|
|
38
58
|
* Returns TokenAuth instance for given key
|
|
39
59
|
*/
|
|
40
|
-
public async getAuthorization(key: string): Promise<
|
|
41
|
-
|
|
60
|
+
public async getAuthorization(key: string, dynamicCollectionName: string): Promise<TokenAuthData> {
|
|
61
|
+
if (!this.serviceName) throw new Error('Service name is not defined.');
|
|
62
|
+
|
|
63
|
+
if (dynamicCollectionName) {
|
|
64
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
65
|
+
'__authorizer_dynamic_collections',
|
|
66
|
+
dynamicCollectionName
|
|
67
|
+
);
|
|
68
|
+
const collection = value as TokenDynamicCollection;
|
|
69
|
+
if (!collection) throw new Error('Dynamic collection name is invalid');
|
|
70
|
+
|
|
71
|
+
key = collection.authorizations[key];
|
|
72
|
+
}
|
|
73
|
+
if (!key.includes('::token')) throw new Error('The Token authorization key should contain "token" type specifier.');
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
const record = await this.keyValueStorage.getValueByKey(this.serviceName, encodeURIComponent(key));
|
|
42
77
|
if (!record.value) {
|
|
43
78
|
throw new Error('Authorization does not exist');
|
|
44
79
|
}
|
|
45
80
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
81
|
+
const authData = record.value as Omit<TokenAuthData, 'key'>;
|
|
82
|
+
|
|
83
|
+
if (!(authData.auth_name || authData._auth_name) || !(authData.date_created || authData._date_created)) {
|
|
84
|
+
throw new Error('Authorization is invalid.');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
...authData,
|
|
89
|
+
key,
|
|
90
|
+
} as TokenAuthData;
|
|
52
91
|
}
|
|
53
92
|
|
|
93
|
+
|
|
54
94
|
/**
|
|
55
95
|
* Creates a new auth record in current collection with the given config.
|
|
56
|
-
* @returns
|
|
96
|
+
* @returns TokenAuthData object
|
|
57
97
|
*
|
|
58
98
|
* ```typescript
|
|
59
|
-
* const
|
|
99
|
+
* const tokenAuthData = await tokenCollectionInstance.createAuthorization({
|
|
60
100
|
* authName: 'my-auth-name',
|
|
61
101
|
* credentials: {
|
|
62
102
|
* token: 'secrettoken'
|
|
63
|
-
* }
|
|
103
|
+
* },
|
|
104
|
+
* dynamicCollection: 'my-dynamic-collection' // Optional
|
|
64
105
|
* });
|
|
65
106
|
* ```
|
|
66
107
|
*/
|
|
67
108
|
public async createAuthorization(
|
|
68
109
|
params: CreateTokenAuthInCollectionConfig
|
|
69
|
-
): Promise<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
110
|
+
): Promise<TokenAuthData> {
|
|
111
|
+
const { authName, credentials, dynamicCollection, destinationAccount = 'CURRENT', customAccountId } = params;
|
|
112
|
+
|
|
113
|
+
if (!this.serviceName) throw new Error('Service name is not defined.');
|
|
114
|
+
if (!authName || !credentials) throw new Error('Invalid authorization parameters passed.');
|
|
115
|
+
|
|
116
|
+
const id = uuidv4();
|
|
117
|
+
const authKey = dynamicCollection ? createDynamicKey(id, dynamicCollection) : createAuthKey(id, authName);
|
|
118
|
+
|
|
119
|
+
const authData = {
|
|
120
|
+
...credentials,
|
|
121
|
+
auth_name: authName,
|
|
122
|
+
_date_created: new Date().toISOString(),
|
|
123
|
+
} as Omit<TokenAuthData, 'key'>;
|
|
124
|
+
|
|
125
|
+
if (dynamicCollection) {
|
|
126
|
+
const { value } = await this.keyValueStorage.getValueByKey('__authorizer_dynamic_collections', dynamicCollection);
|
|
127
|
+
|
|
128
|
+
const collection = (value || {
|
|
129
|
+
name: dynamicCollection,
|
|
130
|
+
type: 'token',
|
|
131
|
+
service: this.serviceName,
|
|
132
|
+
serviceConfigName: this.serviceName,
|
|
133
|
+
authorizations: {},
|
|
134
|
+
}) as TokenDynamicCollection;
|
|
135
|
+
|
|
136
|
+
if (collection.type !== 'token' || collection.service !== this.serviceName) {
|
|
137
|
+
throw new Error('Dynamic collection\'s type or service is invalid');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
collection.authorizations[authName] = authKey;
|
|
141
|
+
await this.keyValueStorage.setValueByKey('__authorizer_dynamic_collections', dynamicCollection, collection);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Accounts handling
|
|
145
|
+
if (destinationAccount === 'CURRENT') {
|
|
146
|
+
await this.keyValueStorage.setValueByKey(this.serviceName, encodeURIComponent(authKey), authData);
|
|
147
|
+
} else {
|
|
148
|
+
const localRecord = {
|
|
149
|
+
auth_name: authData.auth_name,
|
|
150
|
+
isRemote: true,
|
|
151
|
+
id,
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
if (destinationAccount === 'CUSTOM' && !customAccountId) {
|
|
155
|
+
throw new Error('Custom Account ID is required if destinationAccount === "CUSTOM"');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
await this.providers.makeRequest({
|
|
159
|
+
route: 'authorizer/redirect',
|
|
160
|
+
params: {
|
|
161
|
+
method: 'PUT',
|
|
162
|
+
data: {
|
|
163
|
+
authData,
|
|
164
|
+
id,
|
|
165
|
+
storeAccount: destinationAccount,
|
|
166
|
+
storeCustomAccountId: destinationAccount === 'CUSTOM' ? customAccountId : undefined,
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
}).catch(() => { throw new Error('Could not save token to the specified account');});
|
|
170
|
+
|
|
171
|
+
await this.keyValueStorage.setValueByKey(this.serviceName, encodeURIComponent(authKey), localRecord);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
...authData,
|
|
176
|
+
key: authKey,
|
|
177
|
+
} as TokenAuthData;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Updates credentials
|
|
183
|
+
*/
|
|
184
|
+
public async updateAuthorization(
|
|
185
|
+
tokenAuth: TokenAuthData,
|
|
186
|
+
newCredentials: Record<string, unknown>
|
|
187
|
+
): Promise<TokenAuthData> {
|
|
188
|
+
if (!this.serviceName) throw new Error('Service name is not defined.');
|
|
189
|
+
if (!newCredentials) throw new Error('New credentials are empty or invalid');
|
|
190
|
+
if (!tokenAuth || !tokenAuth.auth_name || !(tokenAuth.date_created || tokenAuth._date_created)) {
|
|
191
|
+
throw new Error('Token authorization data is invalid');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const updatedData = {
|
|
195
|
+
...tokenAuth,
|
|
196
|
+
...newCredentials,
|
|
197
|
+
auth_name: tokenAuth.auth_name,
|
|
198
|
+
_date_created: tokenAuth._date_created,
|
|
199
|
+
key: undefined,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const response = await this.keyValueStorage.setValueByKey(
|
|
203
|
+
this.serviceName,
|
|
204
|
+
encodeURIComponent(tokenAuth.key),
|
|
205
|
+
updatedData
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const updatedRecord = response.value as Omit<TokenAuthData, 'key'>;
|
|
209
|
+
return {
|
|
210
|
+
...updatedRecord,
|
|
211
|
+
key: tokenAuth.key,
|
|
212
|
+
} as TokenAuthData;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Deletes authorization from collection
|
|
218
|
+
*/
|
|
219
|
+
public async deleteAuthorization(key: string): Promise<void> {
|
|
220
|
+
if (!this.serviceName) throw new Error('Service name is not defined.');
|
|
221
|
+
if (!key) throw new Error('Key is missing or invalid');
|
|
222
|
+
|
|
223
|
+
if (key.includes('::token-collection::')) {
|
|
224
|
+
const dynamicCollectionName = key.split('::')[2].split(' ')[0];
|
|
225
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
226
|
+
'__authorizer_dynamic_collections',
|
|
227
|
+
dynamicCollectionName
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
const collection = value as TokenDynamicCollection;
|
|
231
|
+
if (collection) {
|
|
232
|
+
const authName = Object.keys(collection.authorizations)
|
|
233
|
+
.find(name => collection.authorizations[name] === key);
|
|
234
|
+
|
|
235
|
+
if (authName) {
|
|
236
|
+
delete collection.authorizations[authName];
|
|
237
|
+
await this.keyValueStorage.setValueByKey(
|
|
238
|
+
'__authorizer_dynamic_collections',
|
|
239
|
+
dynamicCollectionName,
|
|
240
|
+
collection
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
await this.keyValueStorage.deleteKey(this.serviceName, encodeURIComponent(key));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Creates a Dynamic Token collection
|
|
251
|
+
*/
|
|
252
|
+
public async createDynamicCollection(dynamicCollectionName: string): Promise<void> {
|
|
253
|
+
if (!dynamicCollectionName) throw new Error('Dynamic collection name is empty or invalid');
|
|
254
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
255
|
+
'__authorizer_dynamic_collections',
|
|
256
|
+
dynamicCollectionName
|
|
257
|
+
);
|
|
258
|
+
const collection = value as TokenDynamicCollection;
|
|
259
|
+
|
|
260
|
+
if (!value) {
|
|
261
|
+
await this.keyValueStorage.setValueByKey(
|
|
262
|
+
'__authorizer_dynamic_collections',
|
|
263
|
+
dynamicCollectionName,
|
|
264
|
+
{
|
|
265
|
+
name: dynamicCollectionName,
|
|
266
|
+
type: 'token',
|
|
267
|
+
service: this.serviceName,
|
|
268
|
+
serviceConfigName: this.serviceName,
|
|
269
|
+
authorizations: {},
|
|
270
|
+
});
|
|
271
|
+
} else if (collection.type === 'oauth' && collection.service === this.serviceName) {
|
|
272
|
+
throw new Error('Same collection already exists');
|
|
273
|
+
} else {
|
|
274
|
+
throw new Error('Different collection exists with this name');
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Deletes a Dynamic collection
|
|
281
|
+
*/
|
|
282
|
+
public async deleteDynamicCollection(dynamicCollectionName: string): Promise<void> {
|
|
283
|
+
if (!dynamicCollectionName) throw new Error('Dynamic collection name is empty or invalid');
|
|
284
|
+
const { value } = await this.keyValueStorage.getValueByKey(
|
|
285
|
+
'__authorizer_dynamic_collections',
|
|
286
|
+
dynamicCollectionName
|
|
287
|
+
);
|
|
288
|
+
const collection = value as TokenDynamicCollection;
|
|
289
|
+
|
|
290
|
+
await Promise.all(
|
|
291
|
+
Object.keys(collection.authorizations)
|
|
292
|
+
.map(authName => {
|
|
293
|
+
return this.keyValueStorage.deleteKey(
|
|
294
|
+
collection.service,
|
|
295
|
+
encodeURIComponent(collection.authorizations[authName])
|
|
296
|
+
);
|
|
297
|
+
})
|
|
298
|
+
).catch(() => {});
|
|
299
|
+
|
|
300
|
+
await this.keyValueStorage.deleteKey(
|
|
301
|
+
'__authorizer_dynamic_collections',
|
|
302
|
+
dynamicCollectionName
|
|
303
|
+
);
|
|
77
304
|
}
|
|
78
305
|
}
|