@boxyhq/saml-jackson 0.2.3-beta.177 → 0.2.3-beta.206

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 (45) hide show
  1. package/ nodemon.json +12 -0
  2. package/.nyc_output/3fcecc4f-446a-412f-b692-364d37085e9c.json +1 -0
  3. package/.nyc_output/5ae45aaa-c2ec-465f-be5d-1eb335276bfd.json +1 -0
  4. package/.nyc_output/b5c9facc-f405-4aff-9bd6-619d3482da3d.json +1 -0
  5. package/.nyc_output/processinfo/3fcecc4f-446a-412f-b692-364d37085e9c.json +1 -0
  6. package/.nyc_output/processinfo/5ae45aaa-c2ec-465f-be5d-1eb335276bfd.json +1 -0
  7. package/.nyc_output/processinfo/b5c9facc-f405-4aff-9bd6-619d3482da3d.json +1 -0
  8. package/.nyc_output/processinfo/index.json +1 -0
  9. package/package.json +23 -15
  10. package/.eslintrc.js +0 -13
  11. package/prettier.config.js +0 -4
  12. package/src/controller/api.js +0 -167
  13. package/src/controller/error.js +0 -12
  14. package/src/controller/oauth/allowed.js +0 -19
  15. package/src/controller/oauth/code-verifier.js +0 -16
  16. package/src/controller/oauth/redirect.js +0 -18
  17. package/src/controller/oauth.js +0 -321
  18. package/src/controller/utils.js +0 -19
  19. package/src/db/db.js +0 -81
  20. package/src/db/db.test.js +0 -302
  21. package/src/db/encrypter.js +0 -36
  22. package/src/db/mem.js +0 -111
  23. package/src/db/mongo.js +0 -89
  24. package/src/db/redis.js +0 -88
  25. package/src/db/sql/entity/JacksonIndex.js +0 -42
  26. package/src/db/sql/entity/JacksonStore.js +0 -42
  27. package/src/db/sql/entity/JacksonTTL.js +0 -23
  28. package/src/db/sql/model/JacksonIndex.js +0 -9
  29. package/src/db/sql/model/JacksonStore.js +0 -10
  30. package/src/db/sql/model/JacksonTTL.js +0 -8
  31. package/src/db/sql/sql.js +0 -153
  32. package/src/db/store.js +0 -42
  33. package/src/db/utils.js +0 -30
  34. package/src/env.js +0 -39
  35. package/src/index.js +0 -67
  36. package/src/jackson.js +0 -161
  37. package/src/read-config.js +0 -24
  38. package/src/saml/claims.js +0 -40
  39. package/src/saml/saml.js +0 -223
  40. package/src/saml/x509.js +0 -48
  41. package/src/test/api.test.js +0 -186
  42. package/src/test/data/metadata/boxyhq.js +0 -6
  43. package/src/test/data/metadata/boxyhq.xml +0 -30
  44. package/src/test/data/saml_response +0 -1
  45. package/src/test/oauth.test.js +0 -342
package/src/db/redis.js DELETED
@@ -1,88 +0,0 @@
1
- const redis = require('redis');
2
- const dbutils = require('./utils.js');
3
-
4
- class Redis {
5
- constructor(options) {
6
- return (async () => {
7
- let opts = {};
8
- if (options && options.url) {
9
- opts.socket = {
10
- url: options.url,
11
- };
12
- }
13
- this.client = redis.createClient(opts);
14
-
15
- this.client.on('error', (err) => console.log('Redis Client Error', err));
16
-
17
- await this.client.connect();
18
-
19
- return this;
20
- })();
21
- }
22
-
23
- async get(namespace, key) {
24
- let res = await this.client.get(dbutils.key(namespace, key));
25
- if (res) {
26
- return JSON.parse(res);
27
- }
28
-
29
- return null;
30
- }
31
-
32
- async getByIndex(namespace, idx) {
33
- const dbKeys = await this.client.sMembers(
34
- dbutils.keyForIndex(namespace, idx)
35
- );
36
-
37
- const ret = [];
38
- for (const dbKey of dbKeys || []) {
39
- ret.push(await this.get(namespace, dbKey));
40
- }
41
-
42
- return ret;
43
- }
44
-
45
- async put(namespace, key, val, ttl = 0, ...indexes) {
46
- let tx = this.client.multi();
47
- const k = dbutils.key(namespace, key);
48
-
49
- tx = tx.set(k, JSON.stringify(val));
50
-
51
- if (ttl) {
52
- tx = tx.expire(k, ttl);
53
- }
54
-
55
- // no ttl support for secondary indexes
56
- for (const idx of indexes || []) {
57
- const idxKey = dbutils.keyForIndex(namespace, idx);
58
- tx = tx.sAdd(idxKey, key);
59
- tx = tx.sAdd(dbutils.keyFromParts(dbutils.indexPrefix, k), idxKey);
60
- }
61
-
62
- await tx.exec();
63
- }
64
-
65
- async delete(namespace, key) {
66
- let tx = this.client.multi();
67
- const k = dbutils.key(namespace, key);
68
- tx = tx.del(k);
69
-
70
- const idxKey = dbutils.keyFromParts(dbutils.indexPrefix, k);
71
- // delete secondary indexes and then the mapping of the seconary indexes
72
- const dbKeys = await this.client.sMembers(idxKey);
73
-
74
- for (const dbKey of dbKeys || []) {
75
- tx.sRem(dbKey, key);
76
- }
77
-
78
- tx.del(idxKey);
79
-
80
- return await tx.exec();
81
- }
82
- }
83
-
84
- module.exports = {
85
- new: async (options) => {
86
- return new Redis(options);
87
- },
88
- };
@@ -1,42 +0,0 @@
1
- const EntitySchema = require('typeorm').EntitySchema;
2
- const JacksonIndex = require('../model/JacksonIndex.js');
3
- const JacksonStore = require('../model/JacksonStore.js');
4
-
5
- module.exports = new EntitySchema({
6
- name: 'JacksonIndex',
7
- target: JacksonIndex,
8
- columns: {
9
- id: {
10
- primary: true,
11
- generated: true,
12
- type: 'int',
13
- },
14
- key: {
15
- type: 'varchar',
16
- length: 1500,
17
- },
18
- storeKey: {
19
- type: 'varchar',
20
- length: 1500,
21
- }
22
- },
23
- relations: {
24
- store: {
25
- target: () => JacksonStore,
26
- type: 'many-to-one',
27
- inverseSide: 'indexes',
28
- eager: true,
29
- onDelete: 'CASCADE',
30
- },
31
- },
32
- indices: [
33
- {
34
- name: '_jackson_index_key',
35
- columns: ['key'],
36
- },
37
- {
38
- name: '_jackson_index_key_store',
39
- columns: ['key', 'storeKey'],
40
- },
41
- ],
42
- });
@@ -1,42 +0,0 @@
1
- const EntitySchema = require('typeorm').EntitySchema;
2
- const JacksonStore = require('../model/JacksonStore.js');
3
-
4
- const valueType = (type) => {
5
- switch (type) {
6
- case 'postgres':
7
- case 'cockroachdb':
8
- return 'text';
9
- case 'mysql':
10
- case 'mariadb':
11
- return 'mediumtext';
12
- default:
13
- return 'varchar';
14
- }
15
- };
16
-
17
- module.exports = (type) => {
18
- return new EntitySchema({
19
- name: 'JacksonStore',
20
- target: JacksonStore,
21
- columns: {
22
- key: {
23
- primary: true,
24
- type: 'varchar',
25
- length: 1500,
26
- },
27
- value: {
28
- type: valueType(type),
29
- },
30
- iv: {
31
- type: 'varchar',
32
- length: 64,
33
- nullable: true,
34
- },
35
- tag: {
36
- type: 'varchar',
37
- length: 64,
38
- nullable: true,
39
- },
40
- },
41
- });
42
- };
@@ -1,23 +0,0 @@
1
- const EntitySchema = require('typeorm').EntitySchema;
2
- const JacksonTTL = require('../model/JacksonTTL.js');
3
-
4
- module.exports = new EntitySchema({
5
- name: 'JacksonTTL',
6
- target: JacksonTTL,
7
- columns: {
8
- key: {
9
- primary: true,
10
- type: 'varchar',
11
- length: 1500,
12
- },
13
- expiresAt: {
14
- type: 'bigint',
15
- },
16
- },
17
- indices: [
18
- {
19
- name: '_jackson_ttl_expires_at',
20
- columns: ['expiresAt'],
21
- },
22
- ],
23
- });
@@ -1,9 +0,0 @@
1
- /*export */ class JacksonIndex {
2
- constructor(id, key, store) {
3
- this.id = id;
4
- this.key = key;
5
- this.store = store;
6
- }
7
- }
8
-
9
- module.exports = JacksonIndex;
@@ -1,10 +0,0 @@
1
- /*export */ class JacksonStore {
2
- constructor(key, value, iv, tag) {
3
- this.key = key;
4
- this.value = value;
5
- this.iv = iv;
6
- this.tag = tag;
7
- }
8
- }
9
-
10
- module.exports = JacksonStore;
@@ -1,8 +0,0 @@
1
- /*export */ class JacksonTTL {
2
- constructor(key, expiresAt) {
3
- this.key = key;
4
- this.expiresAt = expiresAt;
5
- }
6
- }
7
-
8
- module.exports = JacksonTTL;
package/src/db/sql/sql.js DELETED
@@ -1,153 +0,0 @@
1
- /*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
2
-
3
- require('reflect-metadata');
4
- const typeorm = require('typeorm');
5
- const JacksonStore = require('./model/JacksonStore.js');
6
- const JacksonIndex = require('./model/JacksonIndex.js');
7
- const JacksonTTL = require('./model/JacksonTTL.js');
8
-
9
- const dbutils = require('../utils.js');
10
-
11
- class Sql {
12
- constructor(options) {
13
- return (async () => {
14
- while (true) {
15
- try {
16
- this.connection = await typeorm.createConnection({
17
- name: options.type + Math.floor(Math.random() * 100000),
18
- type: options.type,
19
- url: options.url,
20
- synchronize: true,
21
- migrationsTableName: '_jackson_migrations',
22
- logging: false,
23
- entities: [
24
- require('./entity/JacksonStore.js')(options.type),
25
- require('./entity/JacksonIndex.js'),
26
- require('./entity/JacksonTTL.js'),
27
- ],
28
- });
29
-
30
- break;
31
- } catch (err) {
32
- console.error(`error connecting to ${options.type} db: ${err}`);
33
- await dbutils.sleep(1000);
34
- continue;
35
- }
36
- }
37
-
38
- this.storeRepository = this.connection.getRepository(JacksonStore);
39
- this.indexRepository = this.connection.getRepository(JacksonIndex);
40
- this.ttlRepository = this.connection.getRepository(JacksonTTL);
41
-
42
- if (options.ttl && options.cleanupLimit) {
43
- this.ttlCleanup = async () => {
44
- const now = Date.now();
45
-
46
- while (true) {
47
- const ids = await this.ttlRepository
48
- .createQueryBuilder('jackson_ttl')
49
- .limit(options.cleanupLimit)
50
- .where('jackson_ttl.expiresAt <= :expiresAt', { expiresAt: now })
51
- .getMany();
52
-
53
- if (ids.length <= 0) {
54
- break;
55
- }
56
-
57
- const delIds = ids.map((id) => {
58
- return id.key;
59
- });
60
-
61
- await this.storeRepository.remove(ids);
62
- await this.ttlRepository.delete(delIds);
63
- }
64
-
65
- this.timerId = setTimeout(this.ttlCleanup, options.ttl * 1000);
66
- };
67
-
68
- this.timerId = setTimeout(this.ttlCleanup, options.ttl * 1000);
69
- } else {
70
- console.log(
71
- 'Warning: ttl cleanup not enabled, set both "ttl" and "cleanupLimit" options to enable it!'
72
- );
73
- }
74
-
75
- return this;
76
- })();
77
- }
78
-
79
- async get(namespace, key) {
80
- let res = await this.storeRepository.findOne({
81
- key: dbutils.key(namespace, key),
82
- });
83
-
84
- if (res && res.value) {
85
- return {
86
- value: res.value,
87
- iv: res.iv,
88
- tag: res.tag,
89
- };
90
- }
91
-
92
- return null;
93
- }
94
-
95
- async getByIndex(namespace, idx) {
96
- const res = await this.indexRepository.find({
97
- key: dbutils.keyForIndex(namespace, idx),
98
- });
99
-
100
- const ret = [];
101
-
102
- if (res) {
103
- res.forEach((r) => {
104
- ret.push({
105
- value: r.store.value,
106
- iv: r.store.iv,
107
- tag: r.store.tag,
108
- });
109
- });
110
- }
111
-
112
- return ret;
113
- }
114
-
115
- async put(namespace, key, val, ttl = 0, ...indexes) {
116
- await this.connection.transaction(async (transactionalEntityManager) => {
117
- const dbKey = dbutils.key(namespace, key);
118
- const store = new JacksonStore(dbKey, val.value, val.iv, val.tag);
119
- await transactionalEntityManager.save(store);
120
-
121
- if (ttl) {
122
- const ttlRec = new JacksonTTL(dbKey, Date.now() + ttl * 1000);
123
- await transactionalEntityManager.save(ttlRec);
124
- }
125
-
126
- // no ttl support for secondary indexes
127
- for (const idx of indexes || []) {
128
- const key = dbutils.keyForIndex(namespace, idx);
129
- const rec = await this.indexRepository.findOne({
130
- key,
131
- storeKey: store.key,
132
- });
133
- if (!rec) {
134
- await transactionalEntityManager.save(
135
- new JacksonIndex(0, key, store)
136
- );
137
- }
138
- }
139
- });
140
- }
141
-
142
- async delete(namespace, key) {
143
- return await this.storeRepository.remove({
144
- key: dbutils.key(namespace, key),
145
- });
146
- }
147
- }
148
-
149
- module.exports = {
150
- new: async (options) => {
151
- return new Sql(options);
152
- },
153
- };
package/src/db/store.js DELETED
@@ -1,42 +0,0 @@
1
- const dbutils = require('./utils.js');
2
-
3
- class Store {
4
- constructor(namespace, db, ttl = 0) {
5
- this.namespace = namespace;
6
- this.db = db;
7
- this.ttl = ttl;
8
- }
9
-
10
- async get(key) {
11
- return await this.db.get(this.namespace, dbutils.keyDigest(key));
12
- }
13
-
14
- async getByIndex(idx) {
15
- idx.value = dbutils.keyDigest(idx.value);
16
- return await this.db.getByIndex(this.namespace, idx);
17
- }
18
-
19
- async put(key, val, ...indexes) {
20
- indexes = (indexes || []).map((idx) => {
21
- idx.value = dbutils.keyDigest(idx.value);
22
- return idx;
23
- });
24
- return await this.db.put(
25
- this.namespace,
26
- dbutils.keyDigest(key),
27
- val,
28
- this.ttl,
29
- ...indexes
30
- );
31
- }
32
-
33
- async delete(key) {
34
- return await this.db.delete(this.namespace, dbutils.keyDigest(key));
35
- }
36
- }
37
-
38
- module.exports = {
39
- new: (namespace, db, ttl = 0) => {
40
- return new Store(namespace, db, ttl);
41
- },
42
- };
package/src/db/utils.js DELETED
@@ -1,30 +0,0 @@
1
- const Ripemd160 = require('ripemd160');
2
-
3
- const key = (namespace, k) => {
4
- return namespace + ':' + k;
5
- };
6
-
7
- const keyForIndex = (namespace, idx) => {
8
- return key(key(namespace, idx.name), idx.value);
9
- };
10
-
11
- const keyDigest = (k) => {
12
- return new Ripemd160().update(k).digest('hex');
13
- };
14
-
15
- const keyFromParts = (...parts) => {
16
- return parts.join(':'); // TODO: pick a better strategy, keys can collide now
17
- };
18
-
19
- const sleep = (ms) => {
20
- return new Promise((resolve) => setTimeout(resolve, ms));
21
- };
22
-
23
- module.exports = {
24
- key,
25
- keyForIndex,
26
- keyDigest,
27
- keyFromParts,
28
- sleep,
29
- indexPrefix: '_index',
30
- };
package/src/env.js DELETED
@@ -1,39 +0,0 @@
1
- const hostUrl = process.env.HOST_URL || 'localhost';
2
- const hostPort = (process.env.HOST_PORT || '5000') * 1;
3
- const externalUrl =
4
- process.env.EXTERNAL_URL || 'http://' + hostUrl + ':' + hostPort;
5
- const samlPath = process.env.SAML_PATH || '/oauth/saml';
6
-
7
- const internalHostUrl = process.env.INTERNAL_HOST_URL || 'localhost';
8
- const internalHostPort = (process.env.INTERNAL_HOST_PORT || '6000') * 1;
9
-
10
- const apiKeys = (process.env.JACKSON_API_KEYS || '').split(',');
11
-
12
- const samlAudience = process.env.SAML_AUDIENCE;
13
- const preLoadedConfig = process.env.PRE_LOADED_CONFIG;
14
-
15
- const idpEnabled = process.env.IDP_ENABLED;
16
- const db = {
17
- engine: process.env.DB_ENGINE,
18
- url: process.env.DB_URL,
19
- type: process.env.DB_TYPE,
20
- ttl: process.env.DB_TTL,
21
- encryptionKey: process.env.DB_ENCRYPTION_KEY,
22
- };
23
-
24
- module.exports = {
25
- hostUrl,
26
- hostPort,
27
- externalUrl,
28
- samlPath,
29
- samlAudience,
30
- preLoadedConfig,
31
- internalHostUrl,
32
- internalHostPort,
33
- apiKeys,
34
- idpEnabled,
35
- db,
36
- useInternalServer: !(
37
- hostUrl === internalHostUrl && hostPort === internalHostPort
38
- ),
39
- };
package/src/index.js DELETED
@@ -1,67 +0,0 @@
1
- const DB = require('./db/db.js');
2
- const readConfig = require('./read-config.js');
3
-
4
- const defaultOpts = (opts) => {
5
- const newOpts = {
6
- ...opts,
7
- };
8
-
9
- if (!newOpts.externalUrl) {
10
- throw new Error('externalUrl is required');
11
- }
12
- if (!newOpts.samlPath) {
13
- throw new Error('samlPath is required');
14
- }
15
-
16
- newOpts.samlAudience = newOpts.samlAudience || 'https://saml.boxyhq.com';
17
- newOpts.preLoadedConfig = newOpts.preLoadedConfig || ''; // path to folder containing static SAML config that will be preloaded. This is useful for self-hosted deployments that only have to support a single tenant (or small number of known tenants).
18
- newOpts.idpEnabled = newOpts.idpEnabled === true;
19
- newOpts.db = newOpts.db || {};
20
- newOpts.db.engine = newOpts.db.engine || 'sql'; // Supported values: redis, sql, mongo, mem. Keep comment in sync with db.js
21
- newOpts.db.url =
22
- newOpts.db.url || 'postgresql://postgres:postgres@localhost:5432/postgres';
23
- newOpts.db.type = newOpts.db.type || 'postgres'; // Only needed if DB_ENGINE is sql. Supported values: postgres, cockroachdb, mysql, mariadb
24
- newOpts.db.ttl = (newOpts.db.ttl || 300) * 1; // TTL for the code, session and token stores (in seconds)
25
- newOpts.db.cleanupLimit = (newOpts.db.cleanupLimit || 1000) * 1; // Limit cleanup of TTL entries to this many items at a time
26
-
27
- return newOpts;
28
- };
29
-
30
- module.exports = async function (opts) {
31
- opts = defaultOpts(opts);
32
-
33
- const db = await DB.new(opts.db);
34
- const configStore = db.store('saml:config');
35
- const sessionStore = db.store('oauth:session', opts.db.ttl);
36
- const codeStore = db.store('oauth:code', opts.db.ttl);
37
- const tokenStore = db.store('oauth:token', opts.db.ttl);
38
-
39
- const apiController = require('./controller/api.js')({ configStore });
40
- const oauthController = require('./controller/oauth.js')({
41
- configStore,
42
- sessionStore,
43
- codeStore,
44
- tokenStore,
45
- opts,
46
- });
47
- // write pre-loaded config if present
48
- if (opts.preLoadedConfig && opts.preLoadedConfig.length > 0) {
49
- const configs = await readConfig(opts.preLoadedConfig);
50
-
51
- for (const config of configs) {
52
- await apiController.config(config);
53
- console.log(
54
- `loaded config for tenant "${config.tenant}" and product "${config.product}"`
55
- );
56
- }
57
- }
58
-
59
- const type =
60
- opts.db.engine === 'sql' && opts.db.type ? ' Type: ' + opts.db.type : '';
61
- console.log(`Using engine: ${opts.db.engine}.${type}`);
62
-
63
- return {
64
- apiController,
65
- oauthController,
66
- };
67
- };