@boxyhq/saml-jackson 0.2.3-beta.231 → 0.2.3-beta.235

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.
Files changed (50) hide show
  1. package/README.md +1 -2
  2. package/package.json +12 -4
  3. package/ nodemon.json +0 -12
  4. package/.dockerignore +0 -2
  5. package/.eslintrc.js +0 -18
  6. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -27
  7. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  8. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -43
  9. package/.github/pull_request_template.md +0 -31
  10. package/.github/workflows/codesee-arch-diagram.yml +0 -81
  11. package/.github/workflows/main.yml +0 -123
  12. package/_dev/docker-compose.yml +0 -37
  13. package/map.js +0 -1
  14. package/prettier.config.js +0 -4
  15. package/src/controller/api.ts +0 -225
  16. package/src/controller/error.ts +0 -13
  17. package/src/controller/oauth/allowed.ts +0 -22
  18. package/src/controller/oauth/code-verifier.ts +0 -11
  19. package/src/controller/oauth/redirect.ts +0 -12
  20. package/src/controller/oauth.ts +0 -334
  21. package/src/controller/utils.ts +0 -17
  22. package/src/db/db.ts +0 -100
  23. package/src/db/encrypter.ts +0 -38
  24. package/src/db/mem.ts +0 -128
  25. package/src/db/mongo.ts +0 -110
  26. package/src/db/redis.ts +0 -103
  27. package/src/db/sql/entity/JacksonIndex.ts +0 -43
  28. package/src/db/sql/entity/JacksonStore.ts +0 -43
  29. package/src/db/sql/entity/JacksonTTL.ts +0 -17
  30. package/src/db/sql/model/JacksonIndex.ts +0 -3
  31. package/src/db/sql/model/JacksonStore.ts +0 -8
  32. package/src/db/sql/sql.ts +0 -181
  33. package/src/db/store.ts +0 -49
  34. package/src/db/utils.ts +0 -26
  35. package/src/env.ts +0 -42
  36. package/src/index.ts +0 -84
  37. package/src/jackson.ts +0 -173
  38. package/src/read-config.ts +0 -29
  39. package/src/saml/claims.ts +0 -41
  40. package/src/saml/saml.ts +0 -233
  41. package/src/saml/x509.ts +0 -51
  42. package/src/test/api.test.ts +0 -270
  43. package/src/test/data/metadata/boxyhq.js +0 -6
  44. package/src/test/data/metadata/boxyhq.xml +0 -30
  45. package/src/test/data/saml_response +0 -1
  46. package/src/test/db.test.ts +0 -313
  47. package/src/test/oauth.test.ts +0 -362
  48. package/src/typings.ts +0 -167
  49. package/tsconfig.build.json +0 -6
  50. package/tsconfig.json +0 -26
@@ -1,270 +0,0 @@
1
- import * as path from 'path';
2
- import { DatabaseOption, IdPConfig } from 'saml-jackson';
3
- import sinon from 'sinon';
4
- import tap from 'tap';
5
- import * as dbutils from '../db/utils';
6
- import controllers from '../index';
7
- import readConfig from '../read-config';
8
-
9
- // TODO: Add the type
10
- let apiController;
11
-
12
- const CLIENT_ID = '75edb050796a0eb1cf2cfb0da7245f85bc50baa7';
13
- const PROVIDER = 'accounts.google.com';
14
- const OPTIONS = {
15
- externalUrl: 'https://my-cool-app.com',
16
- samlAudience: 'https://saml.boxyhq.com',
17
- samlPath: '/sso/oauth/saml',
18
- db: {
19
- engine: 'mem',
20
- } as DatabaseOption,
21
- };
22
-
23
- tap.before(async () => {
24
- const controller = await controllers(OPTIONS);
25
-
26
- apiController = controller.apiController;
27
- });
28
-
29
- tap.teardown(async () => {
30
- process.exit(0);
31
- });
32
-
33
- tap.test('controller/api', async (t) => {
34
- const metadataPath = path.join(__dirname, '/data/metadata');
35
- const config = await readConfig(metadataPath);
36
-
37
- t.afterEach(async () => {
38
- await apiController.deleteConfig({
39
- tenant: config[0].tenant,
40
- product: config[0].product,
41
- });
42
- });
43
-
44
- t.test('Create the config', async (t) => {
45
- t.test('when required fields are missing or invalid', async (t) => {
46
- t.test('when `rawMetadata` is empty', async (t) => {
47
- const body: Partial<IdPConfig> = Object.assign({}, config[0]);
48
- delete body['rawMetadata'];
49
-
50
- try {
51
- await apiController.config(body);
52
- t.fail('Expecting JacksonError.');
53
- } catch (err: any) {
54
- t.equal(err.message, 'Please provide rawMetadata');
55
- t.equal(err.statusCode, 400);
56
- }
57
-
58
- t.end();
59
- });
60
-
61
- t.test('when `defaultRedirectUrl` is empty', async (t) => {
62
- const body: Partial<IdPConfig> = Object.assign({}, config[0]);
63
- delete body['defaultRedirectUrl'];
64
-
65
- try {
66
- await apiController.config(body);
67
- t.fail('Expecting JacksonError.');
68
- } catch (err: any) {
69
- t.equal(err.message, 'Please provide a defaultRedirectUrl');
70
- t.equal(err.statusCode, 400);
71
- }
72
-
73
- t.end();
74
- });
75
-
76
- t.test('when `redirectUrl` is empty', async (t) => {
77
- const body: Partial<IdPConfig> = Object.assign({}, config[0]);
78
- delete body['redirectUrl'];
79
-
80
- try {
81
- await apiController.config(body);
82
- t.fail('Expecting JacksonError.');
83
- } catch (err: any) {
84
- t.equal(err.message, 'Please provide redirectUrl');
85
- t.equal(err.statusCode, 400);
86
- }
87
-
88
- t.end();
89
- });
90
-
91
- t.test('when `tenant` is empty', async (t) => {
92
- const body: Partial<IdPConfig> = Object.assign({}, config[0]);
93
- delete body['tenant'];
94
-
95
- try {
96
- await apiController.config(body);
97
- t.fail('Expecting JacksonError.');
98
- } catch (err: any) {
99
- t.equal(err.message, 'Please provide tenant');
100
- t.equal(err.statusCode, 400);
101
- }
102
-
103
- t.end();
104
- });
105
-
106
- t.test('when `product` is empty', async (t) => {
107
- const body: Partial<IdPConfig> = Object.assign({}, config[0]);
108
- delete body['product'];
109
-
110
- try {
111
- await apiController.config(body);
112
- t.fail('Expecting JacksonError.');
113
- } catch (err: any) {
114
- t.equal(err.message, 'Please provide product');
115
- t.equal(err.statusCode, 400);
116
- }
117
-
118
- t.end();
119
- });
120
-
121
- t.test('when `rawMetadata` is not a valid XML', async (t) => {
122
- const body = Object.assign({}, config[0]);
123
- body['rawMetadata'] = 'not a valid XML';
124
-
125
- try {
126
- await apiController.config(body);
127
- t.fail('Expecting Error.');
128
- } catch (err: any) {
129
- t.match(err.message, /Non-whitespace before first tag./);
130
- }
131
-
132
- t.end();
133
- });
134
- });
135
-
136
- t.test('when the request is good', async (t) => {
137
- const body = Object.assign({}, config[0]);
138
-
139
- const kdStub = sinon.stub(dbutils, 'keyDigest').returns(CLIENT_ID);
140
-
141
- const response = await apiController.config(body);
142
-
143
- t.ok(kdStub.called);
144
- t.equal(response.client_id, CLIENT_ID);
145
- t.equal(response.provider, PROVIDER);
146
-
147
- const savedConf = await apiController.getConfig({
148
- clientID: CLIENT_ID,
149
- });
150
-
151
- t.equal(savedConf.provider, PROVIDER);
152
-
153
- kdStub.restore();
154
-
155
- t.end();
156
- });
157
-
158
- t.end();
159
- });
160
-
161
- t.test('Get the config', async (t) => {
162
- t.test('when valid request', async (t) => {
163
- const body: Partial<IdPConfig> = Object.assign({}, config[0]);
164
-
165
- await apiController.config(body);
166
-
167
- const { provider } = await apiController.getConfig(body);
168
-
169
- t.equal(provider, PROVIDER);
170
-
171
- t.end();
172
- });
173
-
174
- t.test('when invalid request', async (t) => {
175
- let response;
176
-
177
- const body: Partial<IdPConfig> = Object.assign({}, config[0]);
178
-
179
- await apiController.config(body);
180
-
181
- // Empty body
182
- try {
183
- await apiController.getConfig({});
184
- t.fail('Expecting Error.');
185
- } catch (err: any) {
186
- t.match(
187
- err.message,
188
- 'Please provide `clientID` or `tenant` and `product`.'
189
- );
190
- }
191
-
192
- // Invalid clientID
193
- response = await apiController.getConfig({
194
- clientID: 'an invalid clientID',
195
- });
196
-
197
- t.match(response, {});
198
-
199
- // Invalid tenant and product combination
200
- response = await apiController.getConfig({
201
- tenant: 'demo.com',
202
- product: 'desk',
203
- });
204
-
205
- t.match(response, {});
206
-
207
- t.end();
208
- });
209
-
210
- t.end();
211
- });
212
-
213
- t.test('Delete the config', async (t) => {
214
- t.test('when valid request', async (t) => {
215
- const body: Partial<IdPConfig> = Object.assign({}, config[0]);
216
-
217
- const client = await apiController.config(body);
218
-
219
- await apiController.deleteConfig({
220
- clientID: client.client_id,
221
- clientSecret: client.client_secret,
222
- });
223
-
224
- const response = await apiController.getConfig({
225
- clientID: client.client_id,
226
- });
227
-
228
- t.match(response, {});
229
-
230
- t.end();
231
- });
232
-
233
- t.test('when invalid request', async (t) => {
234
- let response;
235
-
236
- const body: Partial<IdPConfig> = Object.assign({}, config[0]);
237
-
238
- const client = await apiController.config(body);
239
-
240
- // Empty body
241
- try {
242
- await apiController.deleteConfig({});
243
- t.fail('Expecting Error.');
244
- } catch (err: any) {
245
- t.match(
246
- err.message,
247
- 'Please provide `clientID` and `clientSecret` or `tenant` and `product`.'
248
- );
249
- }
250
-
251
- // Invalid clientID or clientSecret
252
- try {
253
- await apiController.deleteConfig({
254
- clientID: client.client_id,
255
- clientSecret: 'invalid client secret',
256
- });
257
-
258
- t.fail('Expecting Error.');
259
- } catch (err: any) {
260
- t.match(err.message, 'clientSecret mismatch.');
261
- }
262
-
263
- t.end();
264
- });
265
-
266
- t.end();
267
- });
268
-
269
- t.end();
270
- });
@@ -1,6 +0,0 @@
1
- module.exports = {
2
- defaultRedirectUrl: 'http://localhost:3000/sso/oauth/completed',
3
- redirectUrl: '["http://localhost:3000"]',
4
- tenant: 'boxyhq.com',
5
- product: 'crm',
6
- };
@@ -1,30 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
- <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://accounts.google.com/o/saml2" validUntil="2026-06-22T18:39:53.000Z">
3
- <md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
4
- <md:KeyDescriptor use="signing">
5
- <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
6
- <ds:X509Data>
7
- <ds:X509Certificate>MIIDdDCCAlygAwIBAgIGAXo6K+u/MA0GCSqGSIb3DQEBCwUAMHsxFDASBgNVBAoTC0dvb2dsZSBJ
8
- bmMuMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MQ8wDQYDVQQDEwZHb29nbGUxGDAWBgNVBAsTD0dv
9
- b2dsZSBGb3IgV29yazELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEwHhcNMjEwNjIz
10
- MTgzOTUzWhcNMjYwNjIyMTgzOTUzWjB7MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEWMBQGA1UEBxMN
11
- TW91bnRhaW4gVmlldzEPMA0GA1UEAxMGR29vZ2xlMRgwFgYDVQQLEw9Hb29nbGUgRm9yIFdvcmsx
12
- CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
13
- MIIBCgKCAQEA4qZcxwPiVka9GzGdQ9LVlgVkn3A7O3HtxR6RIm5AMaL4YZziEHt2HgxLdJZyXYJw
14
- yfT1KB2IHt+XDQBkgEpQVXuuwSPI8vhI8Jr+nr8zia3MMoy9vJF8ZG7HuWeakaKEh7tJqjYu1Cl9
15
- a81rkYdXAFUA+gl2q+stvK26xylAUwptCJSQo0NanWzCq+k5zvX0uLmh58+W5Yv11hDTtAoW+1dH
16
- LWUTHXPfoZINPRy5NGKJ2Onq5/D5XJRimNnUa2iYi0Yv9txp1RRq4dpB9MaVttt3iKyDo4/+8fg/
17
- bL8BLhguiOeqcP4DEIzMuExi3bZAOu2NC7k7Qf28nA81LzP9DQIDAQABMA0GCSqGSIb3DQEBCwUA
18
- A4IBAQARBNB3+MfmKr5WXNXXE9YwUzUGmpfbqUPXh2y2dOAkj6TzoekAsOLWB0p8oyJ5d1bFlTsx
19
- i1OY9RuFl0tc35Jbo+ae5GfUvJmbnYGi9z8sBL55HY6x3KQNmM/ehof7ttZwvB6nwuRxAiGYG497
20
- 3tSzrqMQzEskcgX1mlCW0vks/ztCaayprDXcCUxWdP9FaiSZDEXV6PHhFZgGlRNvERsgaMDJgOsq
21
- v6hLX10Q9CtOWzqu18PI4DcfoZ7exWcC29yWvwZzDTfHGaSG1DtUFLwiQmhVUbfd7/fmLV+/iOxV
22
- zI0b5xSYZOJ7Kena7gd5zGVrc2ygKAFKiffiI5GLmLkv</ds:X509Certificate>
23
- </ds:X509Data>
24
- </ds:KeyInfo>
25
- </md:KeyDescriptor>
26
- <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
27
- <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://accounts.google.com/o/saml2"/>
28
- <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://accounts.google.com/o/saml2"/>
29
- </md:IDPSSODescriptor>
30
- </md:EntityDescriptor>
@@ -1 +0,0 @@
1
- PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzYW1sMnA6UmVzcG9uc2UgeG1sbnM6c2FtbDJwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIERlc3RpbmF0aW9uPSJodHRwczovLzdlYTItMTAzLTE1My0xMDQtMTYxLm5ncm9rLmlvL3Nzby9vYXV0aC9zYW1sIiBJRD0iXzRkZmM5MjYwZDFjZTVlMDRhZTQ4ZTg4ZWJkNGNlOTY3IiBJblJlc3BvbnNlVG89Il9kYWNkMTRhZGVmMmNiMDc1NGM5NiIgSXNzdWVJbnN0YW50PSIyMDIxLTEyLTA2VDE1OjIzOjA3LjM2MFoiIFZlcnNpb249IjIuMCI+DQogICA8c2FtbDI6SXNzdWVyIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIj5odHRwczovL2FjY291bnRzLmdvb2dsZS5jb20vby9zYW1sMjwvc2FtbDI6SXNzdWVyPg0KICAgPGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+DQogICAgICA8ZHM6U2lnbmVkSW5mbz4NCiAgICAgICAgIDxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIiAvPg0KICAgICAgICAgPGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiIC8+DQogICAgICAgICA8ZHM6UmVmZXJlbmNlIFVSST0iI180ZGZjOTI2MGQxY2U1ZTA0YWU0OGU4OGViZDRjZTk2NyI+DQogICAgICAgICAgICA8ZHM6VHJhbnNmb3Jtcz4NCiAgICAgICAgICAgICAgIDxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIgLz4NCiAgICAgICAgICAgICAgIDxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiIC8+DQogICAgICAgICAgICA8L2RzOlRyYW5zZm9ybXM+DQogICAgICAgICAgICA8ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2IiAvPg0KICAgICAgICAgICAgPGRzOkRpZ2VzdFZhbHVlPjI3Vy9EZTVKTlZIWkk1VTVKZGIvUi9mUXIya0pmd1VPbk0vVlRmQ1ZwQU09PC9kczpEaWdlc3RWYWx1ZT4NCiAgICAgICAgIDwvZHM6UmVmZXJlbmNlPg0KICAgICAgPC9kczpTaWduZWRJbmZvPg0KICAgICAgPGRzOlNpZ25hdHVyZVZhbHVlPm4vWCsvb0ZzK3JNU2gxMlg4dnowWlNkNlFpcU50eTY3RnFVbVNwdGllRmNoM0NScGQzZ2dpSHNwTTlMcm9MWjZVZGlsbThtdFZqTkgNCi9ob21yWDNvVEQ4UStxdzNiSllOTEptNEQvRWNmZmRDNmpSb0RJZzRYeFYxYlBVaWhQTnI4dlBFZEF2eEdwNTNiZ2MyREJsWkJpT3gNCnh4RlBSbEtnajJDWjh5SWk1R05FMUVTYms2SEtjY3g4R2dxWmtSYkVRbWtnbVMxZG1xcGl5bUpQM3orMHlaaXQyZ3dwQW5WVjNCMDUNCnZOcy8rSTFzRlZLaHNWcTc4QzZNWlZzV1pUSi80RFhadWhVSnpLNElTSU11b1RqUWFacEZMeEpBKzlhZzIvcm9OMjkwcitpcTZ5MVQNCjNHSlF1TlBPU0JVS1NpWlZVNmdwTldRRDBxckFxSWFQUFpOZnp3PT08L2RzOlNpZ25hdHVyZVZhbHVlPg0KICAgICAgPGRzOktleUluZm8+DQogICAgICAgICA8ZHM6WDUwOURhdGE+DQogICAgICAgICAgICA8ZHM6WDUwOVN1YmplY3ROYW1lPlNUPUNhbGlmb3JuaWEsQz1VUyxPVT1Hb29nbGUgRm9yIFdvcmssQ049R29vZ2xlLEw9TW91bnRhaW4gVmlldyxPPUdvb2dsZSBJbmMuPC9kczpYNTA5U3ViamVjdE5hbWU+DQogICAgICAgICAgICA8ZHM6WDUwOUNlcnRpZmljYXRlPk1JSURkRENDQWx5Z0F3SUJBZ0lHQVhvNksrdS9NQTBHQ1NxR1NJYjNEUUVCQ3dVQU1Ic3hGREFTQmdOVkJBb1RDMGR2YjJkc1pTQkoNCmJtTXVNUll3RkFZRFZRUUhFdzFOYjNWdWRHRnBiaUJXYVdWM01ROHdEUVlEVlFRREV3WkhiMjluYkdVeEdEQVdCZ05WQkFzVEQwZHYNCmIyZHNaU0JHYjNJZ1YyOXlhekVMTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR2xtYjNKdWFXRXdIaGNOTWpFd05qSXoNCk1UZ3pPVFV6V2hjTk1qWXdOakl5TVRnek9UVXpXakI3TVJRd0VnWURWUVFLRXd0SGIyOW5iR1VnU1c1akxqRVdNQlFHQTFVRUJ4TU4NClRXOTFiblJoYVc0Z1ZtbGxkekVQTUEwR0ExVUVBeE1HUjI5dloyeGxNUmd3RmdZRFZRUUxFdzlIYjI5bmJHVWdSbTl5SUZkdmNtc3gNCkN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUlFd3BEWVd4cFptOXlibWxoTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEENCk1JSUJDZ0tDQVFFQTRxWmN4d1BpVmthOUd6R2RROUxWbGdWa24zQTdPM0h0eFI2UkltNUFNYUw0WVp6aUVIdDJIZ3hMZEpaeVhZSncNCnlmVDFLQjJJSHQrWERRQmtnRXBRVlh1dXdTUEk4dmhJOEpyK25yOHppYTNNTW95OXZKRjhaRzdIdVdlYWthS0VoN3RKcWpZdTFDbDkNCmE4MXJrWWRYQUZVQStnbDJxK3N0dksyNnh5bEFVd3B0Q0pTUW8wTmFuV3pDcStrNXp2WDB1TG1oNTgrVzVZdjExaERUdEFvVysxZEgNCkxXVVRIWFBmb1pJTlBSeTVOR0tKMk9ucTUvRDVYSlJpbU5uVWEyaVlpMFl2OXR4cDFSUnE0ZHBCOU1hVnR0dDNpS3lEbzQvKzhmZy8NCmJMOEJMaGd1aU9lcWNQNERFSXpNdUV4aTNiWkFPdTJOQzdrN1FmMjhuQTgxTHpQOURRSURBUUFCTUEwR0NTcUdTSWIzRFFFQkN3VUENCkE0SUJBUUFSQk5CMytNZm1LcjVXWE5YWEU5WXdVelVHbXBmYnFVUFhoMnkyZE9Ba2o2VHpvZWtBc09MV0IwcDhveUo1ZDFiRmxUc3gNCmkxT1k5UnVGbDB0YzM1SmJvK2FlNUdmVXZKbWJuWUdpOXo4c0JMNTVIWTZ4M0tRTm1NL2Vob2Y3dHRad3ZCNm53dVJ4QWlHWUc0OTcNCjN0U3pycU1RekVza2NnWDFtbENXMHZrcy96dENhYXlwckRYY0NVeFdkUDlGYWlTWkRFWFY2UEhoRlpnR2xSTnZFUnNnYU1ESmdPc3ENCnY2aExYMTBROUN0T1d6cXUxOFBJNERjZm9aN2V4V2NDMjl5V3Z3WnpEVGZIR2FTRzFEdFVGTHdpUW1oVlViZmQ3L2ZtTFYrL2lPeFYNCnpJMGI1eFNZWk9KN0tlbmE3Z2Q1ekdWcmMyeWdLQUZLaWZmaUk1R0xtTGt2PC9kczpYNTA5Q2VydGlmaWNhdGU+DQogICAgICAgICA8L2RzOlg1MDlEYXRhPg0KICAgICAgPC9kczpLZXlJbmZvPg0KICAgPC9kczpTaWduYXR1cmU+DQogICA8c2FtbDJwOlN0YXR1cz4NCiAgICAgIDxzYW1sMnA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIiAvPg0KICAgPC9zYW1sMnA6U3RhdHVzPg0KICAgPHNhbWwyOkFzc2VydGlvbiB4bWxuczpzYW1sMj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgSUQ9Il8xMWZkN2U5MDdjZmNiMTEwODM3NjI5OGM1Nzc0ZjgyNyIgSXNzdWVJbnN0YW50PSIyMDIxLTEyLTA2VDE1OjIzOjA3LjM2MFoiIFZlcnNpb249IjIuMCI+DQogICAgICA8c2FtbDI6SXNzdWVyPmh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL3NhbWwyPC9zYW1sMjpJc3N1ZXI+DQogICAgICA8c2FtbDI6U3ViamVjdD4NCiAgICAgICAgIDxzYW1sMjpOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjE6bmFtZWlkLWZvcm1hdDplbWFpbEFkZHJlc3MiPmtpcmFuQGRlbW8uY29tPC9zYW1sMjpOYW1lSUQ+DQogICAgICAgICA8c2FtbDI6U3ViamVjdENvbmZpcm1hdGlvbiBNZXRob2Q9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjbTpiZWFyZXIiPg0KICAgICAgICAgICAgPHNhbWwyOlN1YmplY3RDb25maXJtYXRpb25EYXRhIEluUmVzcG9uc2VUbz0iX2RhY2QxNGFkZWYyY2IwNzU0Yzk2IiBOb3RPbk9yQWZ0ZXI9IjIwMjEtMTItMDZUMTU6Mjg6MDcuMzYwWiIgUmVjaXBpZW50PSJodHRwczovLzdlYTItMTAzLTE1My0xMDQtMTYxLm5ncm9rLmlvL3Nzby9vYXV0aC9zYW1sIiAvPg0KICAgICAgICAgPC9zYW1sMjpTdWJqZWN0Q29uZmlybWF0aW9uPg0KICAgICAgPC9zYW1sMjpTdWJqZWN0Pg0KICAgICAgPHNhbWwyOkNvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDIxLTEyLTA2VDE1OjE4OjA3LjM2MFoiIE5vdE9uT3JBZnRlcj0iMjAyMS0xMi0wNlQxNToyODowNy4zNjBaIj4NCiAgICAgICAgIDxzYW1sMjpBdWRpZW5jZVJlc3RyaWN0aW9uPg0KICAgICAgICAgICAgPHNhbWwyOkF1ZGllbmNlPmh0dHBzOi8vc2FtbC5ib3h5aHEuY29tPC9zYW1sMjpBdWRpZW5jZT4NCiAgICAgICAgIDwvc2FtbDI6QXVkaWVuY2VSZXN0cmljdGlvbj4NCiAgICAgIDwvc2FtbDI6Q29uZGl0aW9ucz4NCiAgICAgIDxzYW1sMjpBdHRyaWJ1dGVTdGF0ZW1lbnQ+DQogICAgICAgICA8c2FtbDI6QXR0cmlidXRlIE5hbWU9InVzZXIuZW1haWwiPg0KICAgICAgICAgICAgPHNhbWwyOkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOmFueVR5cGUiPmtpcmFuQGRlbW8uY29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT4NCiAgICAgICAgIDwvc2FtbDI6QXR0cmlidXRlPg0KICAgICAgICAgPHNhbWwyOkF0dHJpYnV0ZSBOYW1lPSJ1c2VyLmZpcnN0TmFtZSI+DQogICAgICAgICAgICA8c2FtbDI6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6YW55VHlwZSI+S2lyYW48L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPg0KICAgICAgICAgPC9zYW1sMjpBdHRyaWJ1dGU+DQogICAgICAgICA8c2FtbDI6QXR0cmlidXRlIE5hbWU9InVzZXIuaWQiIC8+DQogICAgICAgICA8c2FtbDI6QXR0cmlidXRlIE5hbWU9InVzZXIubGFzdE5hbWUiPg0KICAgICAgICAgICAgPHNhbWwyOkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOmFueVR5cGUiPks8L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPg0KICAgICAgICAgPC9zYW1sMjpBdHRyaWJ1dGU+DQogICAgICAgICA8c2FtbDI6QXR0cmlidXRlIE5hbWU9Im1lbWJlci1vZiIgLz4NCiAgICAgIDwvc2FtbDI6QXR0cmlidXRlU3RhdGVtZW50Pg0KICAgICAgPHNhbWwyOkF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAyMS0xMi0wNlQxNToxNzowNS4wMDBaIiBTZXNzaW9uSW5kZXg9Il8xMWZkN2U5MDdjZmNiMTEwODM3NjI5OGM1Nzc0ZjgyNyI+DQogICAgICAgICA8c2FtbDI6QXV0aG5Db250ZXh0Pg0KICAgICAgICAgICAgPHNhbWwyOkF1dGhuQ29udGV4dENsYXNzUmVmPnVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphYzpjbGFzc2VzOnVuc3BlY2lmaWVkPC9zYW1sMjpBdXRobkNvbnRleHRDbGFzc1JlZj4NCiAgICAgICAgIDwvc2FtbDI6QXV0aG5Db250ZXh0Pg0KICAgICAgPC9zYW1sMjpBdXRoblN0YXRlbWVudD4NCiAgIDwvc2FtbDI6QXNzZXJ0aW9uPg0KPC9zYW1sMnA6UmVzcG9uc2U+
@@ -1,313 +0,0 @@
1
- import {
2
- DatabaseEngine,
3
- DatabaseOption,
4
- EncryptionKey,
5
- Storable,
6
- } from 'saml-jackson';
7
- import tap from 'tap';
8
- import DB from '../db/db';
9
-
10
- const encryptionKey: EncryptionKey = '3yGrTcnKPBqqHoH3zZMAU6nt4bmIYb2q';
11
-
12
- let configStores: Storable[] = [];
13
- let ttlStores: Storable[] = [];
14
- const ttl = 3;
15
-
16
- const record1 = {
17
- id: '1',
18
- name: 'Deepak',
19
- city: 'London',
20
- };
21
-
22
- const record2 = {
23
- id: '2',
24
- name: 'Sama',
25
- city: 'London',
26
- };
27
-
28
- const memDbConfig = <DatabaseOption>{
29
- engine: 'mem',
30
- ttl: 1,
31
- };
32
-
33
- const redisDbConfig = <DatabaseOption>{
34
- engine: 'redis',
35
- url: 'redis://localhost:6379',
36
- };
37
-
38
- const postgresDbConfig = <DatabaseOption>{
39
- engine: 'sql',
40
- url: 'postgresql://postgres:postgres@localhost:5432/postgres',
41
- type: 'postgres',
42
- ttl: 1,
43
- cleanupLimit: 1,
44
- };
45
-
46
- const mongoDbConfig = <DatabaseOption>{
47
- engine: 'mongo',
48
- url: 'mongodb://localhost:27017/jackson',
49
- };
50
-
51
- const mysqlDbConfig = <DatabaseOption>{
52
- engine: 'sql',
53
- url: 'mysql://root:mysql@localhost:3307/mysql',
54
- type: 'mysql',
55
- ttl: 1,
56
- cleanupLimit: 1,
57
- };
58
-
59
- const mariadbDbConfig = <DatabaseOption>{
60
- engine: 'sql',
61
- url: 'mariadb://root@localhost:3306/mysql',
62
- type: 'mariadb',
63
- ttl: 1,
64
- cleanupLimit: 1,
65
- };
66
-
67
- const dbs = [
68
- {
69
- ...memDbConfig,
70
- },
71
- {
72
- ...memDbConfig,
73
- encryptionKey,
74
- },
75
- {
76
- ...redisDbConfig,
77
- },
78
- {
79
- ...redisDbConfig,
80
- encryptionKey,
81
- },
82
- {
83
- ...postgresDbConfig,
84
- },
85
- {
86
- ...postgresDbConfig,
87
- encryptionKey,
88
- },
89
- {
90
- ...mongoDbConfig,
91
- },
92
- {
93
- ...mongoDbConfig,
94
- encryptionKey,
95
- },
96
- {
97
- ...mysqlDbConfig,
98
- },
99
- {
100
- ...mysqlDbConfig,
101
- encryptionKey,
102
- },
103
- {
104
- ...mariadbDbConfig,
105
- },
106
- {
107
- ...mariadbDbConfig,
108
- encryptionKey,
109
- },
110
- ];
111
-
112
- tap.before(async () => {
113
- for (const idx in dbs) {
114
- const opts = dbs[idx];
115
- const db = await DB.new(opts);
116
-
117
- configStores.push(db.store('saml:config'));
118
- ttlStores.push(db.store('oauth:session', ttl));
119
- }
120
- });
121
-
122
- tap.teardown(async () => {
123
- process.exit(0);
124
- });
125
-
126
- tap.test('dbs', ({ end }) => {
127
- for (const idx in configStores) {
128
- const configStore = configStores[idx];
129
- const ttlStore = ttlStores[idx];
130
- let dbEngine = dbs[idx].engine;
131
-
132
- if (dbs[idx].type) {
133
- dbEngine += ': ' + dbs[idx].type;
134
- }
135
-
136
- tap.test('put(): ' + dbEngine, async (t) => {
137
- await configStore.put(
138
- record1.id,
139
- record1,
140
- {
141
- // secondary index on city
142
- name: 'city',
143
- value: record1.city,
144
- },
145
- {
146
- // secondary index on name
147
- name: 'name',
148
- value: record1.name,
149
- }
150
- );
151
-
152
- await configStore.put(
153
- record2.id,
154
- record2,
155
- {
156
- // secondary index on city
157
- name: 'city',
158
- value: record2.city,
159
- },
160
- {
161
- // secondary index on name
162
- name: 'name',
163
- value: record2.name,
164
- }
165
- );
166
-
167
- t.end();
168
- });
169
-
170
- tap.test('get(): ' + dbEngine, async (t) => {
171
- const ret1 = await configStore.get(record1.id);
172
- const ret2 = await configStore.get(record2.id);
173
-
174
- t.same(ret1, record1, 'unable to get record1');
175
- t.same(ret2, record2, 'unable to get record2');
176
-
177
- t.end();
178
- });
179
-
180
- tap.test('getByIndex(): ' + dbEngine, async (t) => {
181
- const ret1 = await configStore.getByIndex({
182
- name: 'name',
183
- value: record1.name,
184
- });
185
-
186
- const ret2 = await configStore.getByIndex({
187
- name: 'city',
188
- value: record1.city,
189
- });
190
-
191
- t.same(ret1, [record1], 'unable to get index "name"');
192
- t.same(
193
- ret2.sort((a, b) => a.id.localeCompare(b.id)),
194
- [record1, record2].sort((a, b) => a.id.localeCompare(b.id)),
195
- 'unable to get index "city"'
196
- );
197
-
198
- t.end();
199
- });
200
-
201
- tap.test('delete(): ' + dbEngine, async (t) => {
202
- await configStore.delete(record1.id);
203
-
204
- const ret0 = await configStore.getByIndex({
205
- name: 'city',
206
- value: record1.city,
207
- });
208
-
209
- t.same(ret0, [record2], 'unable to get index "city" after delete');
210
-
211
- await configStore.delete(record2.id);
212
-
213
- const ret1 = await configStore.get(record1.id);
214
- const ret2 = await configStore.get(record2.id);
215
-
216
- const ret3 = await configStore.getByIndex({
217
- name: 'name',
218
- value: record1.name,
219
- });
220
- const ret4 = await configStore.getByIndex({
221
- name: 'city',
222
- value: record1.city,
223
- });
224
-
225
- t.same(ret1, null, 'delete for record1 failed');
226
- t.same(ret2, null, 'delete for record2 failed');
227
-
228
- t.same(ret3, [], 'delete for record1 failed');
229
- t.same(ret4, [], 'delete for record2 failed');
230
-
231
- t.end();
232
- });
233
-
234
- tap.test('ttl indexes: ' + dbEngine, async (t) => {
235
- try {
236
- await ttlStore.put(
237
- record1.id,
238
- record1,
239
- {
240
- // secondary index on city
241
- name: 'city',
242
- value: record1.city,
243
- },
244
- {
245
- // secondary index on name
246
- name: 'name',
247
- value: record1.name,
248
- }
249
- );
250
-
251
- t.fail('expecting a secondary indexes not allow on a store with ttl');
252
- } catch (err) {
253
- t.ok(err, 'got expected error');
254
- }
255
-
256
- t.end();
257
- });
258
-
259
- tap.test('ttl put(): ' + dbEngine, async (t) => {
260
- await ttlStore.put(record1.id, record1);
261
-
262
- await ttlStore.put(record2.id, record2);
263
-
264
- t.end();
265
- });
266
-
267
- tap.test('ttl get(): ' + dbEngine, async (t) => {
268
- const ret1 = await ttlStore.get(record1.id);
269
- const ret2 = await ttlStore.get(record2.id);
270
-
271
- t.same(ret1, record1, 'unable to get record1');
272
- t.same(ret2, record2, 'unable to get record2');
273
-
274
- t.end();
275
- });
276
-
277
- tap.test('ttl expiry: ' + dbEngine, async (t) => {
278
- // mongo runs ttl task every 60 seconds
279
- if (dbEngine.startsWith('mongo')) {
280
- t.end();
281
- return;
282
- }
283
-
284
- await new Promise((resolve) =>
285
- setTimeout(resolve, (2 * ttl + 0.5) * 1000)
286
- );
287
-
288
- const ret1 = await ttlStore.get(record1.id);
289
- const ret2 = await ttlStore.get(record2.id);
290
-
291
- t.same(ret1, null, 'ttl for record1 failed');
292
- t.same(ret2, null, 'ttl for record2 failed');
293
-
294
- t.end();
295
- });
296
- }
297
-
298
- tap.test('db.new() error', async (t) => {
299
- try {
300
- await DB.new(<DatabaseOption>{
301
- engine: <DatabaseEngine>'somedb',
302
- });
303
-
304
- t.fail('expecting an unsupported db error');
305
- } catch (err) {
306
- t.ok(err, 'got expected error');
307
- }
308
-
309
- t.end();
310
- });
311
-
312
- end();
313
- });