@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
package/src/db/mongo.ts DELETED
@@ -1,110 +0,0 @@
1
- import { MongoClient } from 'mongodb';
2
- import { DatabaseDriver, DatabaseOption, Encrypted, Index } from 'saml-jackson';
3
- import * as dbutils from './utils';
4
-
5
- type Document = {
6
- value: Encrypted;
7
- expiresAt: Date;
8
- indexes: string[];
9
- };
10
-
11
- class Mongo implements DatabaseDriver {
12
- private options: DatabaseOption;
13
- private client!: MongoClient;
14
- private collection: any;
15
- private db: any;
16
-
17
- constructor(options: DatabaseOption) {
18
- this.options = options;
19
- }
20
-
21
- async init(): Promise<Mongo> {
22
- this.client = new MongoClient(this.options.url);
23
-
24
- await this.client.connect();
25
-
26
- this.db = this.client.db();
27
- this.collection = this.db.collection('jacksonStore');
28
-
29
- await this.collection.createIndex({ indexes: 1 });
30
- await this.collection.createIndex(
31
- { expiresAt: 1 },
32
- { expireAfterSeconds: 1 }
33
- );
34
-
35
- return this;
36
- }
37
-
38
- async get(namespace: string, key: string): Promise<any> {
39
- const res = await this.collection.findOne({
40
- _id: dbutils.key(namespace, key),
41
- });
42
- if (res && res.value) {
43
- return res.value;
44
- }
45
-
46
- return null;
47
- }
48
-
49
- async getByIndex(namespace: string, idx: Index): Promise<any> {
50
- const docs = await this.collection
51
- .find({
52
- indexes: dbutils.keyForIndex(namespace, idx),
53
- })
54
- .toArray();
55
-
56
- const ret: string[] = [];
57
- for (const doc of docs || []) {
58
- ret.push(doc.value);
59
- }
60
-
61
- return ret;
62
- }
63
-
64
- async put(
65
- namespace: string,
66
- key: string,
67
- val: Encrypted,
68
- ttl = 0,
69
- ...indexes: any[]
70
- ): Promise<void> {
71
- const doc = <Document>{
72
- value: val,
73
- };
74
-
75
- if (ttl) {
76
- doc.expiresAt = new Date(Date.now() + ttl * 1000);
77
- }
78
-
79
- // no ttl support for secondary indexes
80
- for (const idx of indexes || []) {
81
- const idxKey = dbutils.keyForIndex(namespace, idx);
82
-
83
- if (!doc.indexes) {
84
- doc.indexes = [];
85
- }
86
-
87
- doc.indexes.push(idxKey);
88
- }
89
-
90
- await this.collection.updateOne(
91
- { _id: dbutils.key(namespace, key) },
92
- {
93
- $set: doc,
94
- },
95
- { upsert: true }
96
- );
97
- }
98
-
99
- async delete(namespace: string, key: string): Promise<any> {
100
- return await this.collection.deleteOne({
101
- _id: dbutils.key(namespace, key),
102
- });
103
- }
104
- }
105
-
106
- export default {
107
- new: async (options: DatabaseOption): Promise<Mongo> => {
108
- return await new Mongo(options).init();
109
- },
110
- };
package/src/db/redis.ts DELETED
@@ -1,103 +0,0 @@
1
- import * as redis from 'redis';
2
- import { DatabaseDriver, DatabaseOption, Encrypted, Index } from 'saml-jackson';
3
- import * as dbutils from './utils';
4
-
5
- class Redis implements DatabaseDriver {
6
- private options: DatabaseOption;
7
- private client!: any;
8
-
9
- constructor(options: DatabaseOption) {
10
- this.options = options;
11
- }
12
-
13
- async init(): Promise<Redis> {
14
- const opts = {};
15
-
16
- if (this.options && this.options.url) {
17
- opts['socket'] = {
18
- url: this.options.url,
19
- };
20
- }
21
-
22
- this.client = redis.createClient(opts);
23
- this.client.on('error', (err: any) =>
24
- console.log('Redis Client Error', err)
25
- );
26
-
27
- await this.client.connect();
28
-
29
- return this;
30
- }
31
-
32
- async get(namespace: string, key: string): Promise<any> {
33
- const res = await this.client.get(dbutils.key(namespace, key));
34
- if (res) {
35
- return JSON.parse(res);
36
- }
37
-
38
- return null;
39
- }
40
-
41
- async getByIndex(namespace: string, idx: Index): Promise<any> {
42
- const dbKeys = await this.client.sMembers(
43
- dbutils.keyForIndex(namespace, idx)
44
- );
45
-
46
- const ret: string[] = [];
47
- for (const dbKey of dbKeys || []) {
48
- ret.push(await this.get(namespace, dbKey));
49
- }
50
-
51
- return ret;
52
- }
53
-
54
- async put(
55
- namespace: string,
56
- key: string,
57
- val: Encrypted,
58
- ttl = 0,
59
- ...indexes: any[]
60
- ): Promise<void> {
61
- let tx = this.client.multi();
62
- const k = dbutils.key(namespace, key);
63
-
64
- tx = tx.set(k, JSON.stringify(val));
65
-
66
- if (ttl) {
67
- tx = tx.expire(k, ttl);
68
- }
69
-
70
- // no ttl support for secondary indexes
71
- for (const idx of indexes || []) {
72
- const idxKey = dbutils.keyForIndex(namespace, idx);
73
- tx = tx.sAdd(idxKey, key);
74
- tx = tx.sAdd(dbutils.keyFromParts(dbutils.indexPrefix, k), idxKey);
75
- }
76
-
77
- await tx.exec();
78
- }
79
-
80
- async delete(namespace: string, key: string): Promise<any> {
81
- let tx = this.client.multi();
82
- const k = dbutils.key(namespace, key);
83
- tx = tx.del(k);
84
-
85
- const idxKey = dbutils.keyFromParts(dbutils.indexPrefix, k);
86
- // delete secondary indexes and then the mapping of the seconary indexes
87
- const dbKeys = await this.client.sMembers(idxKey);
88
-
89
- for (const dbKey of dbKeys || []) {
90
- tx.sRem(dbKey, key);
91
- }
92
-
93
- tx.del(idxKey);
94
-
95
- return await tx.exec();
96
- }
97
- }
98
-
99
- export default {
100
- new: async (options: DatabaseOption): Promise<Redis> => {
101
- return await new Redis(options).init();
102
- },
103
- };
@@ -1,43 +0,0 @@
1
- import { EntitySchema } from 'typeorm';
2
- import { JacksonIndex } from '../model/JacksonIndex';
3
- import { JacksonStore } from '../model/JacksonStore';
4
-
5
- export default 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
- // @ts-ignore
25
- store: {
26
- target: () => JacksonStore,
27
- type: 'many-to-one',
28
- inverseSide: 'indexes',
29
- eager: true,
30
- onDelete: 'CASCADE',
31
- },
32
- },
33
- indices: [
34
- {
35
- name: '_jackson_index_key',
36
- columns: ['key'],
37
- },
38
- {
39
- name: '_jackson_index_key_store',
40
- columns: ['key', 'storeKey'],
41
- },
42
- ],
43
- });
@@ -1,43 +0,0 @@
1
- import { DatabaseType } from 'saml-jackson';
2
- import { ColumnType, EntitySchema } from 'typeorm';
3
- import { JacksonStore } from '../model/JacksonStore';
4
-
5
- const valueType = (type: DatabaseType): ColumnType => {
6
- switch (type) {
7
- case 'postgres':
8
- case 'cockroachdb':
9
- return 'text';
10
- case 'mysql':
11
- case 'mariadb':
12
- return 'mediumtext';
13
- default:
14
- return 'varchar';
15
- }
16
- };
17
-
18
- export default (type: DatabaseType) => {
19
- return new EntitySchema({
20
- name: 'JacksonStore',
21
- target: JacksonStore,
22
- columns: {
23
- key: {
24
- primary: true,
25
- type: 'varchar',
26
- length: 1500,
27
- },
28
- value: {
29
- type: valueType(type),
30
- },
31
- iv: {
32
- type: 'varchar',
33
- length: 64,
34
- nullable: true,
35
- },
36
- tag: {
37
- type: 'varchar',
38
- length: 64,
39
- nullable: true,
40
- },
41
- },
42
- });
43
- };
@@ -1,17 +0,0 @@
1
- import { Entity, Column, Index } from 'typeorm';
2
-
3
- @Entity()
4
- export class JacksonTTL {
5
- @Column({
6
- primary: true,
7
- type: 'varchar',
8
- length: 1500,
9
- })
10
- key!: string;
11
-
12
- @Index('_jackson_ttl_expires_at')
13
- @Column({
14
- type: 'bigint',
15
- })
16
- expiresAt!: number;
17
- }
@@ -1,3 +0,0 @@
1
- export class JacksonIndex {
2
- constructor(public id: number, public key: string, public store: any) {}
3
- }
@@ -1,8 +0,0 @@
1
- export class JacksonStore {
2
- constructor(
3
- public key: string,
4
- public value: string,
5
- public iv?: string,
6
- public tag?: string
7
- ) {}
8
- }
package/src/db/sql/sql.ts DELETED
@@ -1,181 +0,0 @@
1
- /*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
2
-
3
- require('reflect-metadata');
4
-
5
- import { DatabaseDriver, DatabaseOption, Index, Encrypted } from 'saml-jackson';
6
- import { Connection, createConnection } from 'typeorm';
7
- import * as dbutils from '../utils';
8
- import JacksonIndexEntity from './entity/JacksonIndex';
9
- import JacksonStoreEntity from './entity/JacksonStore';
10
- import {
11
- JacksonTTL,
12
- JacksonTTL as JacksonTTLEntity,
13
- } from './entity/JacksonTTL';
14
- import { JacksonIndex } from './model/JacksonIndex';
15
- import { JacksonStore } from './model/JacksonStore';
16
-
17
- class Sql implements DatabaseDriver {
18
- private options: DatabaseOption;
19
- private connection!: Connection;
20
- private storeRepository;
21
- private indexRepository;
22
- private ttlRepository;
23
- private ttlCleanup;
24
- private timerId;
25
-
26
- constructor(options: DatabaseOption) {
27
- this.options = options;
28
- }
29
-
30
- async init(): Promise<Sql> {
31
- while (true) {
32
- try {
33
- this.connection = await createConnection({
34
- name: this.options.type + Math.floor(Math.random() * 100000),
35
- type: this.options.type,
36
- url: this.options.url,
37
- synchronize: true,
38
- migrationsTableName: '_jackson_migrations',
39
- logging: false,
40
- entities: [
41
- JacksonStoreEntity(this.options.type),
42
- JacksonIndexEntity,
43
- JacksonTTLEntity,
44
- ],
45
- });
46
-
47
- break;
48
- } catch (err) {
49
- console.error(`error connecting to ${this.options.type} db: ${err}`);
50
- await dbutils.sleep(1000);
51
- continue;
52
- }
53
- }
54
-
55
- this.storeRepository = this.connection.getRepository(JacksonStore);
56
- this.indexRepository = this.connection.getRepository(JacksonIndex);
57
- this.ttlRepository = this.connection.getRepository(JacksonTTL);
58
-
59
- if (this.options.ttl && this.options.cleanupLimit) {
60
- this.ttlCleanup = async () => {
61
- const now = Date.now();
62
-
63
- while (true) {
64
- const ids = await this.ttlRepository
65
- .createQueryBuilder('jackson_ttl')
66
- .limit(this.options.cleanupLimit)
67
- .where('jackson_ttl.expiresAt <= :expiresAt', {
68
- expiresAt: now,
69
- })
70
- .getMany();
71
-
72
- if (ids.length <= 0) {
73
- break;
74
- }
75
-
76
- const delIds = ids.map((id) => {
77
- return id.key;
78
- });
79
-
80
- await this.storeRepository.remove(ids);
81
- await this.ttlRepository.delete(delIds);
82
- }
83
-
84
- this.timerId = setTimeout(this.ttlCleanup, this.options.ttl * 1000);
85
- };
86
-
87
- this.timerId = setTimeout(this.ttlCleanup, this.options.ttl * 1000);
88
- } else {
89
- console.log(
90
- 'Warning: ttl cleanup not enabled, set both "ttl" and "cleanupLimit" options to enable it!'
91
- );
92
- }
93
-
94
- return this;
95
- }
96
-
97
- async get(namespace: string, key: string): Promise<any> {
98
- let res = await this.storeRepository.findOne({
99
- key: dbutils.key(namespace, key),
100
- });
101
-
102
- if (res && res.value) {
103
- return {
104
- value: res.value,
105
- iv: res.iv,
106
- tag: res.tag,
107
- };
108
- }
109
-
110
- return null;
111
- }
112
-
113
- async getByIndex(namespace: string, idx: Index): Promise<any> {
114
- const res = await this.indexRepository.find({
115
- key: dbutils.keyForIndex(namespace, idx),
116
- });
117
-
118
- const ret: Encrypted[] = [];
119
-
120
- if (res) {
121
- res.forEach((r) => {
122
- ret.push({
123
- value: r.store.value,
124
- iv: r.store.iv,
125
- tag: r.store.tag,
126
- });
127
- });
128
- }
129
-
130
- return ret;
131
- }
132
-
133
- async put(
134
- namespace: string,
135
- key: string,
136
- val: Encrypted,
137
- ttl: number = 0,
138
- ...indexes: any[]
139
- ): Promise<void> {
140
- await this.connection.transaction(async (transactionalEntityManager) => {
141
- const dbKey = dbutils.key(namespace, key);
142
-
143
- const store = new JacksonStore(dbKey, val.value, val.iv, val.tag);
144
-
145
- await transactionalEntityManager.save(store);
146
-
147
- if (ttl) {
148
- const ttlRec = new JacksonTTL();
149
- ttlRec.key = dbKey;
150
- ttlRec.expiresAt = Date.now() + ttl * 1000;
151
- await transactionalEntityManager.save(ttlRec);
152
- }
153
-
154
- // no ttl support for secondary indexes
155
- for (const idx of indexes || []) {
156
- const key = dbutils.keyForIndex(namespace, idx);
157
- const rec = await this.indexRepository.findOne({
158
- key,
159
- storeKey: store.key,
160
- });
161
- if (!rec) {
162
- await transactionalEntityManager.save(
163
- new JacksonIndex(0, key, store)
164
- );
165
- }
166
- }
167
- });
168
- }
169
-
170
- async delete(namespace: string, key: string): Promise<any> {
171
- return await this.storeRepository.remove({
172
- key: dbutils.key(namespace, key),
173
- });
174
- }
175
- }
176
-
177
- export default {
178
- new: async (options: DatabaseOption): Promise<Sql> => {
179
- return await new Sql(options).init();
180
- },
181
- };
package/src/db/store.ts DELETED
@@ -1,49 +0,0 @@
1
- import { Index, Storable } from 'saml-jackson';
2
- import * as dbutils from './utils';
3
-
4
- class Store implements Storable {
5
- private namespace: string;
6
- private db: any;
7
- private ttl: number;
8
-
9
- constructor(namespace: string, db: any, ttl = 0) {
10
- this.namespace = namespace;
11
- this.db = db;
12
- this.ttl = ttl;
13
- }
14
-
15
- async get(key: string): Promise<any> {
16
- return await this.db.get(this.namespace, dbutils.keyDigest(key));
17
- }
18
-
19
- async getByIndex(idx: Index): Promise<any> {
20
- idx.value = dbutils.keyDigest(idx.value);
21
-
22
- return await this.db.getByIndex(this.namespace, idx);
23
- }
24
-
25
- async put(key: string, val: any, ...indexes: Index[]): Promise<any> {
26
- indexes = (indexes || []).map((idx) => {
27
- idx.value = dbutils.keyDigest(idx.value);
28
- return idx;
29
- });
30
-
31
- return await this.db.put(
32
- this.namespace,
33
- dbutils.keyDigest(key),
34
- val,
35
- this.ttl,
36
- ...indexes
37
- );
38
- }
39
-
40
- async delete(key: string): Promise<any> {
41
- return await this.db.delete(this.namespace, dbutils.keyDigest(key));
42
- }
43
- }
44
-
45
- export default {
46
- new: (namespace: string, db: any, ttl = 0): Storable => {
47
- return new Store(namespace, db, ttl);
48
- },
49
- };
package/src/db/utils.ts DELETED
@@ -1,26 +0,0 @@
1
- import Ripemd160 from 'ripemd160';
2
- import { Index } from 'saml-jackson';
3
-
4
- export const key = (namespace: string, k: string): string => {
5
- return namespace + ':' + k;
6
- };
7
-
8
- export const keyForIndex = (namespace: string, idx: Index): string => {
9
- return key(key(namespace, idx.name), idx.value);
10
- };
11
-
12
- export const keyDigest = (k: string): string => {
13
- return new Ripemd160().update(k).digest('hex');
14
- };
15
-
16
- export const keyFromParts = (...parts: string[]): string => {
17
- // TODO: pick a better strategy, keys can collide now
18
-
19
- return parts.join(':');
20
- };
21
-
22
- export const sleep = (ms: number): Promise<void> => {
23
- return new Promise((resolve) => setTimeout(resolve, ms));
24
- };
25
-
26
- export const indexPrefix = '_index';
package/src/env.ts DELETED
@@ -1,42 +0,0 @@
1
- const hostUrl = process.env.HOST_URL || 'localhost';
2
- const hostPort = +(process.env.HOST_PORT || '5000');
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');
9
-
10
- const apiKeys = (process.env.JACKSON_API_KEYS || '').split(',');
11
-
12
- const samlAudience = process.env.SAML_AUDIENCE || 'https://saml.boxyhq.com';
13
- const preLoadedConfig = process.env.PRE_LOADED_CONFIG;
14
-
15
- const idpEnabled = process.env.IDP_ENABLED;
16
-
17
- const db = {
18
- engine: process.env.DB_ENGINE,
19
- url: process.env.DB_URL,
20
- type: process.env.DB_TYPE,
21
- ttl: process.env.DB_TTL,
22
- encryptionKey: process.env.DB_ENCRYPTION_KEY,
23
- };
24
-
25
- const env = {
26
- hostUrl,
27
- hostPort,
28
- externalUrl,
29
- samlPath,
30
- samlAudience,
31
- preLoadedConfig,
32
- internalHostUrl,
33
- internalHostPort,
34
- apiKeys,
35
- idpEnabled,
36
- db,
37
- useInternalServer: !(
38
- hostUrl === internalHostUrl && hostPort === internalHostPort
39
- ),
40
- };
41
-
42
- export default env;