@boxyhq/saml-jackson 0.3.8-beta.763 → 0.3.8

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.
@@ -18,23 +18,10 @@ export declare class APIController implements IAPIController {
18
18
  * consumes:
19
19
  * - application/x-www-form-urlencoded
20
20
  * parameters:
21
- * - name: name
22
- * description: Name/identifier for the config
23
- * type: string
24
- * in: formData
25
- * example: cal-saml-config
26
- * - name: description
27
- * description: A short description for the config not more than 100 characters
28
- * type: string
29
- * in: formData
30
- * example: SAML login for cal.com app
31
21
  * - name: encodedRawMetadata
32
22
  * description: Base64 encoding of the XML metadata
33
23
  * in: formData
34
- * type: string
35
- * - name: rawMetadata
36
- * description: Raw XML metadata
37
- * in: formData
24
+ * required: true
38
25
  * type: string
39
26
  * - name: defaultRedirectUrl
40
27
  * description: The redirect URL to use in the IdP login flow
@@ -76,85 +63,10 @@ export declare class APIController implements IAPIController {
76
63
  * client_id: 8958e13053832b5af58fdf2ee83f35f5d013dc74
77
64
  * client_secret: 13f01f4df5b01770c616e682d14d3ba23f20948cfa89b1d7
78
65
  * type: accounts.google.com
79
- * 400:
80
- * description: Please provide rawMetadata or encodedRawMetadata | Please provide a defaultRedirectUrl | Please provide redirectUrl | Please provide tenant | Please provide product | Please provide a friendly name | Description should not exceed 100 characters
81
66
  * 401:
82
67
  * description: Unauthorized
83
68
  */
84
69
  config(body: IdPConfig): Promise<OAuth>;
85
- /**
86
- * @swagger
87
- *
88
- * /api/v1/saml/config:
89
- * patch:
90
- * summary: Update SAML configuration
91
- * operationId: update-saml-config
92
- * tags: [SAML Config]
93
- * consumes:
94
- * - application/json
95
- * - application/x-www-form-urlencoded
96
- * parameters:
97
- * - name: clientID
98
- * description: Client ID for the config
99
- * type: string
100
- * in: formData
101
- * required: true
102
- * - name: clientSecret
103
- * description: Client Secret for the config
104
- * type: string
105
- * in: formData
106
- * required: true
107
- * - name: name
108
- * description: Name/identifier for the config
109
- * type: string
110
- * in: formData
111
- * example: cal-saml-config
112
- * - name: description
113
- * description: A short description for the config not more than 100 characters
114
- * type: string
115
- * in: formData
116
- * example: SAML login for cal.com app
117
- * - name: encodedRawMetadata
118
- * description: Base64 encoding of the XML metadata
119
- * in: formData
120
- * type: string
121
- * - name: rawMetadata
122
- * description: Raw XML metadata
123
- * in: formData
124
- * type: string
125
- * - name: defaultRedirectUrl
126
- * description: The redirect URL to use in the IdP login flow
127
- * in: formData
128
- * required: true
129
- * type: string
130
- * example: http://localhost:3000/login/saml
131
- * - name: redirectUrl
132
- * description: JSON encoded array containing a list of allowed redirect URLs
133
- * in: formData
134
- * required: true
135
- * type: string
136
- * example: '["http://localhost:3000/*"]'
137
- * - name: tenant
138
- * description: Tenant
139
- * in: formData
140
- * required: true
141
- * type: string
142
- * example: boxyhq.com
143
- * - name: product
144
- * description: Product
145
- * in: formData
146
- * required: true
147
- * type: string
148
- * example: demo
149
- * responses:
150
- * 204:
151
- * description: Success
152
- * 400:
153
- * description: Please provide clientID | Please provide clientSecret | clientSecret mismatch | Tenant/Product config mismatch with IdP metadata | Description should not exceed 100 characters
154
- * 401:
155
- * description: Unauthorized
156
- */
157
- updateConfig(body: any): Promise<void>;
158
70
  /**
159
71
  * @swagger
160
72
  *
@@ -184,35 +96,11 @@ export declare class APIController implements IAPIController {
184
96
  * description: Success
185
97
  * schema:
186
98
  * type: object
99
+ * properties:
100
+ * provider:
101
+ * type: string
187
102
  * example:
188
- * {
189
- * "config": {
190
- * "idpMetadata": {
191
- * "sso": {
192
- * "postUrl": "https://dev-20901260.okta.com/app/dev-20901260_jacksonnext_1/xxxxxxxxxxxxx/sso/saml",
193
- * "redirectUrl": "https://dev-20901260.okta.com/app/dev-20901260_jacksonnext_1/xxxxxxxxxxxxx/sso/saml"
194
- * },
195
- * "entityID": "http://www.okta.com/xxxxxxxxxxxxx",
196
- * "thumbprint": "Eo+eUi3UM3XIMkFFtdVK3yJ5vO9f7YZdasdasdad",
197
- * "loginType": "idp",
198
- * "provider": "okta.com"
199
- * },
200
- * "defaultRedirectUrl": "https://hoppscotch.io/",
201
- * "redirectUrl": ["https://hoppscotch.io/"],
202
- * "tenant": "hoppscotch.io",
203
- * "product": "API Engine",
204
- * "name": "Hoppscotch-SP",
205
- * "description": "SP for hoppscotch.io",
206
- * "clientID": "Xq8AJt3yYAxmXizsCWmUBDRiVP1iTC8Y/otnvFIMitk",
207
- * "clientSecret": "00e3e11a3426f97d8000000738300009130cd45419c5943",
208
- * "certs": {
209
- * "publicKey": "-----BEGIN CERTIFICATE-----.......-----END CERTIFICATE-----",
210
- * "privateKey": "-----BEGIN PRIVATE KEY-----......-----END PRIVATE KEY-----"
211
- * }
212
- * }
213
- * }
214
- * '400':
215
- * description: Please provide `clientID` or `tenant` and `product`.
103
+ * type: accounts.google.com
216
104
  * '401':
217
105
  * description: Unauthorized
218
106
  */
@@ -220,7 +108,7 @@ export declare class APIController implements IAPIController {
220
108
  clientID: string;
221
109
  tenant: string;
222
110
  product: string;
223
- }): Promise<any>;
111
+ }): Promise<Partial<OAuth>>;
224
112
  /**
225
113
  * @swagger
226
114
  * /api/v1/saml/config:
@@ -255,8 +143,6 @@ export declare class APIController implements IAPIController {
255
143
  * responses:
256
144
  * '200':
257
145
  * description: Success
258
- * '400':
259
- * description: clientSecret mismatch | Please provide `clientID` and `clientSecret` or `tenant` and `product`.'
260
146
  * '401':
261
147
  * description: Unauthorized
262
148
  */
@@ -27,17 +27,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
27
27
  step((generator = generator.apply(thisArg, _arguments || [])).next());
28
28
  });
29
29
  };
30
- var __rest = (this && this.__rest) || function (s, e) {
31
- var t = {};
32
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
33
- t[p] = s[p];
34
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
35
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
36
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
37
- t[p[i]] = s[p[i]];
38
- }
39
- return t;
40
- };
41
30
  var __importDefault = (this && this.__importDefault) || function (mod) {
42
31
  return (mod && mod.__esModule) ? mod : { "default": mod };
43
32
  };
@@ -55,7 +44,7 @@ class APIController {
55
44
  this.configStore = configStore;
56
45
  }
57
46
  _validateIdPConfig(body) {
58
- const { encodedRawMetadata, rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product, description } = body;
47
+ const { encodedRawMetadata, rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product } = body;
59
48
  if (!rawMetadata && !encodedRawMetadata) {
60
49
  throw new error_1.JacksonError('Please provide rawMetadata or encodedRawMetadata', 400);
61
50
  }
@@ -71,9 +60,6 @@ class APIController {
71
60
  if (!product) {
72
61
  throw new error_1.JacksonError('Please provide product', 400);
73
62
  }
74
- if (description && description.length > 100) {
75
- throw new error_1.JacksonError('Description should not exceed 100 characters', 400);
76
- }
77
63
  }
78
64
  /**
79
65
  * @swagger
@@ -88,23 +74,10 @@ class APIController {
88
74
  * consumes:
89
75
  * - application/x-www-form-urlencoded
90
76
  * parameters:
91
- * - name: name
92
- * description: Name/identifier for the config
93
- * type: string
94
- * in: formData
95
- * example: cal-saml-config
96
- * - name: description
97
- * description: A short description for the config not more than 100 characters
98
- * type: string
99
- * in: formData
100
- * example: SAML login for cal.com app
101
77
  * - name: encodedRawMetadata
102
78
  * description: Base64 encoding of the XML metadata
103
79
  * in: formData
104
- * type: string
105
- * - name: rawMetadata
106
- * description: Raw XML metadata
107
- * in: formData
80
+ * required: true
108
81
  * type: string
109
82
  * - name: defaultRedirectUrl
110
83
  * description: The redirect URL to use in the IdP login flow
@@ -146,14 +119,12 @@ class APIController {
146
119
  * client_id: 8958e13053832b5af58fdf2ee83f35f5d013dc74
147
120
  * client_secret: 13f01f4df5b01770c616e682d14d3ba23f20948cfa89b1d7
148
121
  * type: accounts.google.com
149
- * 400:
150
- * description: Please provide rawMetadata or encodedRawMetadata | Please provide a defaultRedirectUrl | Please provide redirectUrl | Please provide tenant | Please provide product | Please provide a friendly name | Description should not exceed 100 characters
151
122
  * 401:
152
123
  * description: Unauthorized
153
124
  */
154
125
  config(body) {
155
126
  return __awaiter(this, void 0, void 0, function* () {
156
- const { encodedRawMetadata, rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product, name, description, } = body;
127
+ const { encodedRawMetadata, rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product } = body;
157
128
  metrics.increment('createConfig');
158
129
  this._validateIdPConfig(body);
159
130
  let metaData = rawMetadata;
@@ -186,8 +157,6 @@ class APIController {
186
157
  redirectUrl: JSON.parse(redirectUrl),
187
158
  tenant,
188
159
  product,
189
- name,
190
- description,
191
160
  clientID,
192
161
  clientSecret,
193
162
  certs,
@@ -207,129 +176,6 @@ class APIController {
207
176
  };
208
177
  });
209
178
  }
210
- /**
211
- * @swagger
212
- *
213
- * /api/v1/saml/config:
214
- * patch:
215
- * summary: Update SAML configuration
216
- * operationId: update-saml-config
217
- * tags: [SAML Config]
218
- * consumes:
219
- * - application/json
220
- * - application/x-www-form-urlencoded
221
- * parameters:
222
- * - name: clientID
223
- * description: Client ID for the config
224
- * type: string
225
- * in: formData
226
- * required: true
227
- * - name: clientSecret
228
- * description: Client Secret for the config
229
- * type: string
230
- * in: formData
231
- * required: true
232
- * - name: name
233
- * description: Name/identifier for the config
234
- * type: string
235
- * in: formData
236
- * example: cal-saml-config
237
- * - name: description
238
- * description: A short description for the config not more than 100 characters
239
- * type: string
240
- * in: formData
241
- * example: SAML login for cal.com app
242
- * - name: encodedRawMetadata
243
- * description: Base64 encoding of the XML metadata
244
- * in: formData
245
- * type: string
246
- * - name: rawMetadata
247
- * description: Raw XML metadata
248
- * in: formData
249
- * type: string
250
- * - name: defaultRedirectUrl
251
- * description: The redirect URL to use in the IdP login flow
252
- * in: formData
253
- * required: true
254
- * type: string
255
- * example: http://localhost:3000/login/saml
256
- * - name: redirectUrl
257
- * description: JSON encoded array containing a list of allowed redirect URLs
258
- * in: formData
259
- * required: true
260
- * type: string
261
- * example: '["http://localhost:3000/*"]'
262
- * - name: tenant
263
- * description: Tenant
264
- * in: formData
265
- * required: true
266
- * type: string
267
- * example: boxyhq.com
268
- * - name: product
269
- * description: Product
270
- * in: formData
271
- * required: true
272
- * type: string
273
- * example: demo
274
- * responses:
275
- * 204:
276
- * description: Success
277
- * 400:
278
- * description: Please provide clientID | Please provide clientSecret | clientSecret mismatch | Tenant/Product config mismatch with IdP metadata | Description should not exceed 100 characters
279
- * 401:
280
- * description: Unauthorized
281
- */
282
- updateConfig(body) {
283
- var _a;
284
- return __awaiter(this, void 0, void 0, function* () {
285
- const { encodedRawMetadata, // could be empty
286
- rawMetadata, // could be empty
287
- defaultRedirectUrl, redirectUrl, name, description } = body, clientInfo = __rest(body, ["encodedRawMetadata", "rawMetadata", "defaultRedirectUrl", "redirectUrl", "name", "description"]);
288
- if (!(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientID)) {
289
- throw new error_1.JacksonError('Please provide clientID', 400);
290
- }
291
- if (!(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientSecret)) {
292
- throw new error_1.JacksonError('Please provide clientSecret', 400);
293
- }
294
- if (description && description.length > 100) {
295
- throw new error_1.JacksonError('Description should not exceed 100 characters', 400);
296
- }
297
- const _currentConfig = (_a = (yield this.getConfig(clientInfo))) === null || _a === void 0 ? void 0 : _a.config;
298
- if (_currentConfig.clientSecret !== (clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientSecret)) {
299
- throw new error_1.JacksonError('clientSecret mismatch', 400);
300
- }
301
- let metaData = rawMetadata;
302
- if (encodedRawMetadata) {
303
- metaData = Buffer.from(encodedRawMetadata, 'base64').toString();
304
- }
305
- let newMetadata;
306
- if (metaData) {
307
- newMetadata = yield saml_1.default.parseMetadataAsync(metaData);
308
- // extract provider
309
- let providerName = extractHostName(newMetadata.entityID);
310
- if (!providerName) {
311
- providerName = extractHostName(newMetadata.sso.redirectUrl || newMetadata.sso.postUrl);
312
- }
313
- newMetadata.provider = providerName ? providerName : 'Unknown';
314
- }
315
- if (newMetadata) {
316
- // check if clientID matches with new metadata payload
317
- const clientID = dbutils.keyDigest(dbutils.keyFromParts(clientInfo.tenant, clientInfo.product, newMetadata.entityID));
318
- if (clientID !== (clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientID)) {
319
- throw new error_1.JacksonError('Tenant/Product config mismatch with IdP metadata', 400);
320
- }
321
- }
322
- yield this.configStore.put(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientID, Object.assign(Object.assign({}, _currentConfig), { name: name ? name : _currentConfig.name, description: description ? description : _currentConfig.description, idpMetadata: newMetadata ? newMetadata : _currentConfig.idpMetadata, defaultRedirectUrl: defaultRedirectUrl ? defaultRedirectUrl : _currentConfig.defaultRedirectUrl, redirectUrl: redirectUrl ? JSON.parse(redirectUrl) : _currentConfig.redirectUrl }), {
323
- // secondary index on entityID
324
- name: utils_1.IndexNames.EntityID,
325
- value: _currentConfig.idpMetadata.entityID,
326
- }, {
327
- // secondary index on tenant + product
328
- name: utils_1.IndexNames.TenantProduct,
329
- value: dbutils.keyFromParts(_currentConfig.tenant, _currentConfig.product),
330
- });
331
- });
332
- }
333
179
  /**
334
180
  * @swagger
335
181
  *
@@ -359,35 +205,11 @@ class APIController {
359
205
  * description: Success
360
206
  * schema:
361
207
  * type: object
208
+ * properties:
209
+ * provider:
210
+ * type: string
362
211
  * example:
363
- * {
364
- * "config": {
365
- * "idpMetadata": {
366
- * "sso": {
367
- * "postUrl": "https://dev-20901260.okta.com/app/dev-20901260_jacksonnext_1/xxxxxxxxxxxxx/sso/saml",
368
- * "redirectUrl": "https://dev-20901260.okta.com/app/dev-20901260_jacksonnext_1/xxxxxxxxxxxxx/sso/saml"
369
- * },
370
- * "entityID": "http://www.okta.com/xxxxxxxxxxxxx",
371
- * "thumbprint": "Eo+eUi3UM3XIMkFFtdVK3yJ5vO9f7YZdasdasdad",
372
- * "loginType": "idp",
373
- * "provider": "okta.com"
374
- * },
375
- * "defaultRedirectUrl": "https://hoppscotch.io/",
376
- * "redirectUrl": ["https://hoppscotch.io/"],
377
- * "tenant": "hoppscotch.io",
378
- * "product": "API Engine",
379
- * "name": "Hoppscotch-SP",
380
- * "description": "SP for hoppscotch.io",
381
- * "clientID": "Xq8AJt3yYAxmXizsCWmUBDRiVP1iTC8Y/otnvFIMitk",
382
- * "clientSecret": "00e3e11a3426f97d8000000738300009130cd45419c5943",
383
- * "certs": {
384
- * "publicKey": "-----BEGIN CERTIFICATE-----.......-----END CERTIFICATE-----",
385
- * "privateKey": "-----BEGIN PRIVATE KEY-----......-----END PRIVATE KEY-----"
386
- * }
387
- * }
388
- * }
389
- * '400':
390
- * description: Please provide `clientID` or `tenant` and `product`.
212
+ * type: accounts.google.com
391
213
  * '401':
392
214
  * description: Unauthorized
393
215
  */
@@ -397,7 +219,7 @@ class APIController {
397
219
  metrics.increment('getConfig');
398
220
  if (clientID) {
399
221
  const samlConfig = yield this.configStore.get(clientID);
400
- return samlConfig ? { config: samlConfig } : {};
222
+ return samlConfig ? { provider: samlConfig.idpMetadata.provider } : {};
401
223
  }
402
224
  if (tenant && product) {
403
225
  const samlConfigs = yield this.configStore.getByIndex({
@@ -407,7 +229,7 @@ class APIController {
407
229
  if (!samlConfigs || !samlConfigs.length) {
408
230
  return {};
409
231
  }
410
- return { config: samlConfigs[0] };
232
+ return { provider: samlConfigs[0].idpMetadata.provider };
411
233
  }
412
234
  throw new error_1.JacksonError('Please provide `clientID` or `tenant` and `product`.', 400);
413
235
  });
@@ -446,8 +268,6 @@ class APIController {
446
268
  * responses:
447
269
  * '200':
448
270
  * description: Success
449
- * '400':
450
- * description: clientSecret mismatch | Please provide `clientID` and `clientSecret` or `tenant` and `product`.'
451
271
  * '401':
452
272
  * description: Unauthorized
453
273
  */
@@ -464,7 +284,7 @@ class APIController {
464
284
  yield this.configStore.delete(clientID);
465
285
  }
466
286
  else {
467
- throw new error_1.JacksonError('clientSecret mismatch', 400);
287
+ throw new error_1.JacksonError('clientSecret mismatch.', 400);
468
288
  }
469
289
  return;
470
290
  }
@@ -138,6 +138,7 @@ class OAuthController {
138
138
  entityID: this.opts.samlAudience,
139
139
  callbackUrl: this.opts.externalUrl + this.opts.samlPath,
140
140
  signingKey: samlConfig.certs.privateKey,
141
+ publicKey: samlConfig.certs.publicKey,
141
142
  });
142
143
  const sessionId = crypto_1.default.randomBytes(16).toString('hex');
143
144
  yield this.sessionStore.put(sessionId, {
package/dist/db/db.d.ts CHANGED
@@ -4,7 +4,6 @@ declare class DB implements DatabaseDriver {
4
4
  private encryptionKey;
5
5
  constructor(db: DatabaseDriver, encryptionKey: EncryptionKey);
6
6
  get(namespace: string, key: string): Promise<unknown>;
7
- getAll(namespace: any): Promise<unknown[]>;
8
7
  getByIndex(namespace: string, idx: Index): Promise<unknown[]>;
9
8
  put(namespace: string, key: string, val: unknown, ttl?: number, ...indexes: Index[]): Promise<unknown>;
10
9
  delete(namespace: string, key: string): Promise<unknown>;
package/dist/db/db.js CHANGED
@@ -57,15 +57,6 @@ class DB {
57
57
  return decrypt(res, this.encryptionKey);
58
58
  });
59
59
  }
60
- getAll(namespace) {
61
- return __awaiter(this, void 0, void 0, function* () {
62
- const res = (yield this.db.getAll(namespace));
63
- const encryptionKey = this.encryptionKey;
64
- return res.map((r) => {
65
- return decrypt(r, encryptionKey);
66
- });
67
- });
68
- }
69
60
  getByIndex(namespace, idx) {
70
61
  return __awaiter(this, void 0, void 0, function* () {
71
62
  const res = yield this.db.getByIndex(namespace, idx);
package/dist/db/mem.d.ts CHANGED
@@ -10,7 +10,6 @@ declare class Mem implements DatabaseDriver {
10
10
  constructor(options: DatabaseOption);
11
11
  init(): Promise<Mem>;
12
12
  get(namespace: string, key: string): Promise<any>;
13
- getAll(namespace: string): Promise<unknown[]>;
14
13
  getByIndex(namespace: string, idx: Index): Promise<any>;
15
14
  put(namespace: string, key: string, val: Encrypted, ttl?: number, ...indexes: any[]): Promise<any>;
16
15
  delete(namespace: string, key: string): Promise<any>;
package/dist/db/mem.js CHANGED
@@ -66,21 +66,6 @@ class Mem {
66
66
  return null;
67
67
  });
68
68
  }
69
- getAll(namespace) {
70
- return __awaiter(this, void 0, void 0, function* () {
71
- const returnValue = [];
72
- if (namespace) {
73
- for (const key in this.store) {
74
- if (key.startsWith(namespace)) {
75
- returnValue.push(this.store[key]);
76
- }
77
- }
78
- }
79
- if (returnValue)
80
- return returnValue;
81
- return [];
82
- });
83
- }
84
69
  getByIndex(namespace, idx) {
85
70
  return __awaiter(this, void 0, void 0, function* () {
86
71
  const dbKeys = yield this.indexes[dbutils.keyForIndex(namespace, idx)];
@@ -95,10 +80,6 @@ class Mem {
95
80
  return __awaiter(this, void 0, void 0, function* () {
96
81
  const k = dbutils.key(namespace, key);
97
82
  this.store[k] = val;
98
- if (!Date.parse(this.store['createdAt']))
99
- this.store['createdAt'] = new Date().toISOString();
100
- this.store['modifiedAt'] = new Date().toISOString();
101
- // console.log(this.store)
102
83
  if (ttl) {
103
84
  this.ttlStore[k] = {
104
85
  namespace,
@@ -7,7 +7,6 @@ declare class Mongo implements DatabaseDriver {
7
7
  constructor(options: DatabaseOption);
8
8
  init(): Promise<Mongo>;
9
9
  get(namespace: string, key: string): Promise<any>;
10
- getAll(namespace: string): Promise<unknown[]>;
11
10
  getByIndex(namespace: string, idx: Index): Promise<any>;
12
11
  put(namespace: string, key: string, val: Encrypted, ttl?: number, ...indexes: any[]): Promise<void>;
13
12
  delete(namespace: string, key: string): Promise<any>;
package/dist/db/mongo.js CHANGED
@@ -36,16 +36,8 @@ class Mongo {
36
36
  }
37
37
  init() {
38
38
  return __awaiter(this, void 0, void 0, function* () {
39
- try {
40
- if (!this.options.url) {
41
- throw Error('Please specify a db url');
42
- }
43
- this.client = new mongodb_1.MongoClient(this.options.url);
44
- yield this.client.connect();
45
- }
46
- catch (err) {
47
- console.error(`error connecting to ${this.options.type} db: ${err}`);
48
- }
39
+ this.client = new mongodb_1.MongoClient(this.options.url);
40
+ yield this.client.connect();
49
41
  this.db = this.client.db();
50
42
  this.collection = this.db.collection('jacksonStore');
51
43
  yield this.collection.createIndex({ indexes: 1 });
@@ -64,15 +56,6 @@ class Mongo {
64
56
  return null;
65
57
  });
66
58
  }
67
- getAll(namespace) {
68
- return __awaiter(this, void 0, void 0, function* () {
69
- const _namespaceMatch = new RegExp(`^${namespace}:.*`);
70
- const docs = yield this.collection.find({ _id: _namespaceMatch }).toArray();
71
- if (docs)
72
- return docs.map(({ value }) => value);
73
- return [];
74
- });
75
- }
76
59
  getByIndex(namespace, idx) {
77
60
  return __awaiter(this, void 0, void 0, function* () {
78
61
  const docs = yield this.collection
@@ -103,12 +86,8 @@ class Mongo {
103
86
  }
104
87
  doc.indexes.push(idxKey);
105
88
  }
106
- doc.modifiedAt = new Date().toISOString();
107
89
  yield this.collection.updateOne({ _id: dbutils.key(namespace, key) }, {
108
90
  $set: doc,
109
- $setOnInsert: {
110
- createdAt: new Date().toISOString(),
111
- },
112
91
  }, { upsert: true });
113
92
  });
114
93
  }
@@ -5,7 +5,6 @@ declare class Redis implements DatabaseDriver {
5
5
  constructor(options: DatabaseOption);
6
6
  init(): Promise<Redis>;
7
7
  get(namespace: string, key: string): Promise<any>;
8
- getAll(namespace: string): Promise<unknown[]>;
9
8
  getByIndex(namespace: string, idx: Index): Promise<any>;
10
9
  put(namespace: string, key: string, val: Encrypted, ttl?: number, ...indexes: any[]): Promise<void>;
11
10
  delete(namespace: string, key: string): Promise<any>;
package/dist/db/redis.js CHANGED
@@ -57,26 +57,6 @@ class Redis {
57
57
  return null;
58
58
  });
59
59
  }
60
- getAll(namespace) {
61
- return __awaiter(this, void 0, void 0, function* () {
62
- const keys = yield this.client.sendCommand(['keys', namespace + ':*']);
63
- const returnValue = [];
64
- for (let i = 0; i < keys.length; i++) {
65
- try {
66
- if (this.client.get(keys[i])) {
67
- const value = yield this.client.get(keys[i]);
68
- returnValue.push(JSON.parse(value));
69
- }
70
- }
71
- catch (error) {
72
- console.error(error);
73
- }
74
- }
75
- if (returnValue)
76
- return returnValue;
77
- return [];
78
- });
79
- }
80
60
  getByIndex(namespace, idx) {
81
61
  return __awaiter(this, void 0, void 0, function* () {
82
62
  const dbKeys = yield this.client.sMembers(dbutils.keyForIndex(namespace, idx));
@@ -3,6 +3,4 @@ export declare class JacksonStore {
3
3
  value: string;
4
4
  iv?: string;
5
5
  tag?: string;
6
- createdAt?: Date;
7
- modifiedAt?: string;
8
6
  }
@@ -36,19 +36,6 @@ __decorate([
36
36
  nullable: true,
37
37
  })
38
38
  ], JacksonStore.prototype, "tag", void 0);
39
- __decorate([
40
- (0, typeorm_1.Column)({
41
- type: 'timestamp',
42
- default: () => 'CURRENT_TIMESTAMP',
43
- nullable: false,
44
- })
45
- ], JacksonStore.prototype, "createdAt", void 0);
46
- __decorate([
47
- (0, typeorm_1.Column)({
48
- type: 'timestamp',
49
- nullable: true,
50
- })
51
- ], JacksonStore.prototype, "modifiedAt", void 0);
52
39
  JacksonStore = __decorate([
53
40
  (0, typeorm_1.Entity)()
54
41
  ], JacksonStore);
@@ -10,7 +10,6 @@ declare class Sql implements DatabaseDriver {
10
10
  constructor(options: DatabaseOption);
11
11
  init(): Promise<Sql>;
12
12
  get(namespace: string, key: string): Promise<any>;
13
- getAll(namespace: string): Promise<unknown[]>;
14
13
  getByIndex(namespace: string, idx: Index): Promise<any>;
15
14
  put(namespace: string, key: string, val: Encrypted, ttl?: number, ...indexes: any[]): Promise<void>;
16
15
  delete(namespace: string, key: string): Promise<any>;
@@ -95,7 +95,7 @@ class Sql {
95
95
  }
96
96
  get(namespace, key) {
97
97
  return __awaiter(this, void 0, void 0, function* () {
98
- const res = yield this.storeRepository.findOne({
98
+ let res = yield this.storeRepository.findOne({
99
99
  key: dbutils.key(namespace, key),
100
100
  });
101
101
  if (res && res.value) {
@@ -108,22 +108,6 @@ class Sql {
108
108
  return null;
109
109
  });
110
110
  }
111
- getAll(namespace) {
112
- return __awaiter(this, void 0, void 0, function* () {
113
- const response = yield this.storeRepository.find({
114
- where: { key: (0, typeorm_1.Like)(`%${namespace}%`) },
115
- select: ['value', 'iv', 'tag'],
116
- order: {
117
- ['createdAt']: 'DESC',
118
- // ['createdAt']: 'ASC',
119
- },
120
- });
121
- const returnValue = JSON.parse(JSON.stringify(response));
122
- if (returnValue)
123
- return returnValue;
124
- return [];
125
- });
126
- }
127
111
  getByIndex(namespace, idx) {
128
112
  return __awaiter(this, void 0, void 0, function* () {
129
113
  const res = yield this.indexRepository.find({
@@ -151,7 +135,6 @@ class Sql {
151
135
  store.value = val.value;
152
136
  store.iv = val.iv;
153
137
  store.tag = val.tag;
154
- store.modifiedAt = new Date().toISOString();
155
138
  yield transactionalEntityManager.save(store);
156
139
  if (ttl) {
157
140
  const ttlRec = new JacksonTTL_1.JacksonTTL();
package/dist/db/store.js CHANGED
@@ -40,11 +40,6 @@ class Store {
40
40
  return yield this.db.get(this.namespace, dbutils.keyDigest(key));
41
41
  });
42
42
  }
43
- getAll() {
44
- return __awaiter(this, void 0, void 0, function* () {
45
- return yield this.db.getAll(this.namespace);
46
- });
47
- }
48
43
  getByIndex(idx) {
49
44
  return __awaiter(this, void 0, void 0, function* () {
50
45
  idx.value = dbutils.keyDigest(idx.value);
package/dist/index.d.ts CHANGED
@@ -1,11 +1,9 @@
1
1
  import { APIController } from './controller/api';
2
2
  import { OAuthController } from './controller/oauth';
3
- import { AdminController } from './controller/admin';
4
3
  import { JacksonOption } from './typings';
5
4
  export declare const controllers: (opts: JacksonOption) => Promise<{
6
5
  apiController: APIController;
7
6
  oauthController: OAuthController;
8
- adminController: AdminController;
9
7
  }>;
10
8
  export default controllers;
11
9
  export * from './typings';
package/dist/index.js CHANGED
@@ -25,7 +25,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.controllers = void 0;
26
26
  const api_1 = require("./controller/api");
27
27
  const oauth_1 = require("./controller/oauth");
28
- const admin_1 = require("./controller/admin");
29
28
  const db_1 = __importDefault(require("./db/db"));
30
29
  const read_config_1 = __importDefault(require("./read-config"));
31
30
  const defaultOpts = (opts) => {
@@ -56,7 +55,6 @@ const controllers = (opts) => __awaiter(void 0, void 0, void 0, function* () {
56
55
  const codeStore = db.store('oauth:code', opts.db.ttl);
57
56
  const tokenStore = db.store('oauth:token', opts.db.ttl);
58
57
  const apiController = new api_1.APIController({ configStore });
59
- const adminController = new admin_1.AdminController({ configStore });
60
58
  const oauthController = new oauth_1.OAuthController({
61
59
  configStore,
62
60
  sessionStore,
@@ -77,7 +75,6 @@ const controllers = (opts) => __awaiter(void 0, void 0, void 0, function* () {
77
75
  return {
78
76
  apiController,
79
77
  oauthController,
80
- adminController,
81
78
  };
82
79
  });
83
80
  exports.controllers = controllers;
@@ -1,6 +1,7 @@
1
1
  import { SAMLProfile, SAMLReq } from '../typings';
2
+ export declare const stripCertHeaderAndFooter: (cert: string) => string;
2
3
  declare const _default: {
3
- request: ({ ssoUrl, entityID, callbackUrl, isPassive, forceAuthn, identifierFormat, providerName, signingKey, }: SAMLReq) => {
4
+ request: ({ ssoUrl, entityID, callbackUrl, isPassive, forceAuthn, identifierFormat, providerName, signingKey, publicKey, }: SAMLReq) => {
4
5
  id: string;
5
6
  request: string;
6
7
  };
package/dist/saml/saml.js CHANGED
@@ -31,6 +31,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
31
31
  return (mod && mod.__esModule) ? mod : { "default": mod };
32
32
  };
33
33
  Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.stripCertHeaderAndFooter = void 0;
34
35
  const saml20_1 = __importDefault(require("@boxyhq/saml20"));
35
36
  const xml2js_1 = __importDefault(require("xml2js"));
36
37
  const thumbprint_1 = __importDefault(require("thumbprint"));
@@ -42,7 +43,32 @@ const claims_1 = __importDefault(require("./claims"));
42
43
  const idPrefix = '_';
43
44
  const authnXPath = '/*[local-name(.)="AuthnRequest" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:protocol"]';
44
45
  const issuerXPath = '/*[local-name(.)="Issuer" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:assertion"]';
45
- const signRequest = (xml, signingKey) => {
46
+ const stripCertHeaderAndFooter = (cert) => {
47
+ cert = cert.replace(/-+BEGIN CERTIFICATE-+\r?\n?/, '');
48
+ cert = cert.replace(/-+END CERTIFICATE-+\r?\n?/, '');
49
+ cert = cert.replace(/\r\n/g, '\n');
50
+ return cert;
51
+ };
52
+ exports.stripCertHeaderAndFooter = stripCertHeaderAndFooter;
53
+ function PubKeyInfo(pubKey) {
54
+ this.pubKey = (0, exports.stripCertHeaderAndFooter)(pubKey);
55
+ this.getKeyInfo = function (_key, prefix) {
56
+ prefix = prefix || '';
57
+ prefix = prefix ? prefix + ':' : prefix;
58
+ return ('<' +
59
+ prefix +
60
+ 'X509Data><' +
61
+ prefix +
62
+ 'X509Certificate>' +
63
+ this.pubKey +
64
+ '</' +
65
+ prefix +
66
+ 'X509Certificate></' +
67
+ prefix +
68
+ 'X509Data>');
69
+ };
70
+ }
71
+ const signRequest = (xml, signingKey, publicKey) => {
46
72
  if (!xml) {
47
73
  throw new Error('Please specify xml');
48
74
  }
@@ -51,6 +77,7 @@ const signRequest = (xml, signingKey) => {
51
77
  }
52
78
  const sig = new xml_crypto_1.default.SignedXml();
53
79
  sig.signatureAlgorithm = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
80
+ sig.keyInfoProvider = new PubKeyInfo(publicKey);
54
81
  sig.signingKey = signingKey;
55
82
  sig.addReference(authnXPath, ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#'], 'http://www.w3.org/2001/04/xmlenc#sha256');
56
83
  sig.computeSignature(xml, {
@@ -58,7 +85,7 @@ const signRequest = (xml, signingKey) => {
58
85
  });
59
86
  return sig.getSignedXml();
60
87
  };
61
- const request = ({ ssoUrl, entityID, callbackUrl, isPassive = false, forceAuthn = false, identifierFormat = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', providerName = 'BoxyHQ', signingKey, }) => {
88
+ const request = ({ ssoUrl, entityID, callbackUrl, isPassive = false, forceAuthn = false, identifierFormat = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', providerName = 'BoxyHQ', signingKey, publicKey, }) => {
62
89
  const id = idPrefix + crypto_1.default.randomBytes(10).toString('hex');
63
90
  const date = new Date().toISOString();
64
91
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -92,7 +119,7 @@ const request = ({ ssoUrl, entityID, callbackUrl, isPassive = false, forceAuthn
92
119
  }
93
120
  let xml = xmlbuilder_1.default.create(samlReq).end({});
94
121
  if (signingKey) {
95
- xml = signRequest(xml, signingKey);
122
+ xml = signRequest(xml, signingKey, publicKey);
96
123
  }
97
124
  return {
98
125
  id,
package/dist/typings.d.ts CHANGED
@@ -3,8 +3,6 @@ export declare type IdPConfig = {
3
3
  redirectUrl: string;
4
4
  tenant: string;
5
5
  product: string;
6
- name: string;
7
- description: string;
8
6
  rawMetadata?: string;
9
7
  encodedRawMetadata?: string;
10
8
  };
@@ -15,12 +13,11 @@ export interface OAuth {
15
13
  }
16
14
  export interface IAPIController {
17
15
  config(body: IdPConfig): Promise<OAuth>;
18
- updateConfig(body: any): Promise<void>;
19
16
  getConfig(body: {
20
17
  clientID?: string;
21
18
  tenant?: string;
22
19
  product?: string;
23
- }): Promise<any>;
20
+ }): Promise<Partial<OAuth>>;
24
21
  deleteConfig(body: {
25
22
  clientID?: string;
26
23
  clientSecret?: string;
@@ -39,9 +36,6 @@ export interface IOAuthController {
39
36
  token(body: OAuthTokenReq): Promise<OAuthTokenRes>;
40
37
  userInfo(token: string): Promise<Profile>;
41
38
  }
42
- export interface IAdminController {
43
- getAllConfig(): any;
44
- }
45
39
  export interface OAuthReqBody {
46
40
  response_type: 'code';
47
41
  client_id: string;
@@ -80,14 +74,12 @@ export interface Index {
80
74
  value: string;
81
75
  }
82
76
  export interface DatabaseDriver {
83
- getAll(namespace: string): Promise<unknown[]>;
84
77
  get(namespace: string, key: string): Promise<any>;
85
78
  put(namespace: string, key: string, val: any, ttl: number, ...indexes: Index[]): Promise<any>;
86
79
  delete(namespace: string, key: string): Promise<any>;
87
80
  getByIndex(namespace: string, idx: Index): Promise<any>;
88
81
  }
89
82
  export interface Storable {
90
- getAll(): Promise<unknown[]>;
91
83
  get(key: string): Promise<any>;
92
84
  put(key: string, val: any, ...indexes: Index[]): Promise<any>;
93
85
  delete(key: string): Promise<any>;
@@ -118,6 +110,7 @@ export interface SAMLReq {
118
110
  identifierFormat?: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress';
119
111
  providerName?: 'BoxyHQ';
120
112
  signingKey: string;
113
+ publicKey: string;
121
114
  }
122
115
  export interface SAMLProfile {
123
116
  audience: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boxyhq/saml-jackson",
3
- "version": "0.3.8-beta.763",
3
+ "version": "0.3.8",
4
4
  "description": "SAML 2.0 service",
5
5
  "keywords": [
6
6
  "SAML 2.0"
@@ -18,9 +18,9 @@
18
18
  ],
19
19
  "scripts": {
20
20
  "build": "tsc -p tsconfig.build.json",
21
- "db:migration:generate:postgres": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:generate --config ormconfig.js -n createdAt",
22
- "db:migration:generate:mysql": "cross-env DB_TYPE=mysql DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:generate --config ormconfig.js -n createdAt",
23
- "db:migration:generate:mariadb": "cross-env DB_TYPE=mariadb DB_URL=mariadb://root@localhost:3306/mysql ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:generate --config ormconfig.js -n createdAt",
21
+ "db:migration:generate:postgres": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:generate --config ormconfig.js -n Initial",
22
+ "db:migration:generate:mysql": "cross-env DB_TYPE=mysql DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:generate --config ormconfig.js -n Initial",
23
+ "db:migration:generate:mariadb": "cross-env DB_TYPE=mariadb DB_URL=mariadb://root@localhost:3306/mysql ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:generate --config ormconfig.js -n Initial",
24
24
  "db:migration:run:postgres": "ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run",
25
25
  "db:migration:run:mysql": "cross-env DB_TYPE=mysql DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run",
26
26
  "db:migration:run:mariadb": "cross-env DB_TYPE=mariadb DB_URL=mariadb://root@localhost:3306/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run",
@@ -1,8 +0,0 @@
1
- import { IAdminController, Storable, OAuth } from '../typings';
2
- export declare class AdminController implements IAdminController {
3
- configStore: Storable;
4
- constructor({ configStore }: {
5
- configStore: any;
6
- });
7
- getAllConfig(): Promise<Partial<OAuth>[]>;
8
- }
@@ -1,27 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.AdminController = void 0;
13
- class AdminController {
14
- constructor({ configStore }) {
15
- this.configStore = configStore;
16
- }
17
- getAllConfig() {
18
- return __awaiter(this, void 0, void 0, function* () {
19
- const configList = (yield this.configStore.getAll());
20
- if (!configList || !configList.length) {
21
- return [];
22
- }
23
- return configList;
24
- });
25
- }
26
- }
27
- exports.AdminController = AdminController;
@@ -1,16 +0,0 @@
1
- import {MigrationInterface, QueryRunner} from "typeorm";
2
-
3
- export class createdAt1644332636666 implements MigrationInterface {
4
- name = 'createdAt1644332636666'
5
-
6
- public async up(queryRunner: QueryRunner): Promise<void> {
7
- await queryRunner.query(`ALTER TABLE \`jackson_store\` ADD \`createdAt\` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP()`);
8
- await queryRunner.query(`ALTER TABLE \`jackson_store\` ADD \`modifiedAt\` timestamp NULL`);
9
- }
10
-
11
- public async down(queryRunner: QueryRunner): Promise<void> {
12
- await queryRunner.query(`ALTER TABLE \`jackson_store\` DROP COLUMN \`modifiedAt\``);
13
- await queryRunner.query(`ALTER TABLE \`jackson_store\` DROP COLUMN \`createdAt\``);
14
- }
15
-
16
- }
@@ -1,16 +0,0 @@
1
- import {MigrationInterface, QueryRunner} from "typeorm";
2
-
3
- export class createdAt1644332641078 implements MigrationInterface {
4
- name = 'createdAt1644332641078'
5
-
6
- public async up(queryRunner: QueryRunner): Promise<void> {
7
- await queryRunner.query(`ALTER TABLE \`jackson_store\` ADD \`createdAt\` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP`);
8
- await queryRunner.query(`ALTER TABLE \`jackson_store\` ADD \`modifiedAt\` timestamp NULL`);
9
- }
10
-
11
- public async down(queryRunner: QueryRunner): Promise<void> {
12
- await queryRunner.query(`ALTER TABLE \`jackson_store\` DROP COLUMN \`modifiedAt\``);
13
- await queryRunner.query(`ALTER TABLE \`jackson_store\` DROP COLUMN \`createdAt\``);
14
- }
15
-
16
- }
@@ -1,16 +0,0 @@
1
- import {MigrationInterface, QueryRunner} from "typeorm";
2
-
3
- export class createdAt1644332647279 implements MigrationInterface {
4
- name = 'createdAt1644332647279'
5
-
6
- public async up(queryRunner: QueryRunner): Promise<void> {
7
- await queryRunner.query(`ALTER TABLE "jackson_store" ADD "createdAt" TIMESTAMP NOT NULL DEFAULT now()`);
8
- await queryRunner.query(`ALTER TABLE "jackson_store" ADD "modifiedAt" TIMESTAMP`);
9
- }
10
-
11
- public async down(queryRunner: QueryRunner): Promise<void> {
12
- await queryRunner.query(`ALTER TABLE "jackson_store" DROP COLUMN "modifiedAt"`);
13
- await queryRunner.query(`ALTER TABLE "jackson_store" DROP COLUMN "createdAt"`);
14
- }
15
-
16
- }