@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.
- package/README.md +1 -2
- package/package.json +12 -4
- package/ nodemon.json +0 -12
- package/.dockerignore +0 -2
- package/.eslintrc.js +0 -18
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -27
- package/.github/ISSUE_TEMPLATE/config.yml +0 -5
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -43
- package/.github/pull_request_template.md +0 -31
- package/.github/workflows/codesee-arch-diagram.yml +0 -81
- package/.github/workflows/main.yml +0 -123
- package/_dev/docker-compose.yml +0 -37
- package/map.js +0 -1
- package/prettier.config.js +0 -4
- package/src/controller/api.ts +0 -225
- package/src/controller/error.ts +0 -13
- package/src/controller/oauth/allowed.ts +0 -22
- package/src/controller/oauth/code-verifier.ts +0 -11
- package/src/controller/oauth/redirect.ts +0 -12
- package/src/controller/oauth.ts +0 -334
- package/src/controller/utils.ts +0 -17
- package/src/db/db.ts +0 -100
- package/src/db/encrypter.ts +0 -38
- package/src/db/mem.ts +0 -128
- package/src/db/mongo.ts +0 -110
- package/src/db/redis.ts +0 -103
- package/src/db/sql/entity/JacksonIndex.ts +0 -43
- package/src/db/sql/entity/JacksonStore.ts +0 -43
- package/src/db/sql/entity/JacksonTTL.ts +0 -17
- package/src/db/sql/model/JacksonIndex.ts +0 -3
- package/src/db/sql/model/JacksonStore.ts +0 -8
- package/src/db/sql/sql.ts +0 -181
- package/src/db/store.ts +0 -49
- package/src/db/utils.ts +0 -26
- package/src/env.ts +0 -42
- package/src/index.ts +0 -84
- package/src/jackson.ts +0 -173
- package/src/read-config.ts +0 -29
- package/src/saml/claims.ts +0 -41
- package/src/saml/saml.ts +0 -233
- package/src/saml/x509.ts +0 -51
- package/src/test/api.test.ts +0 -270
- package/src/test/data/metadata/boxyhq.js +0 -6
- package/src/test/data/metadata/boxyhq.xml +0 -30
- package/src/test/data/saml_response +0 -1
- package/src/test/db.test.ts +0 -313
- package/src/test/oauth.test.ts +0 -362
- package/src/typings.ts +0 -167
- package/tsconfig.build.json +0 -6
- package/tsconfig.json +0 -26
package/src/test/api.test.ts
DELETED
@@ -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,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+
|
package/src/test/db.test.ts
DELETED
@@ -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
|
-
});
|