@boxyhq/saml-jackson 0.2.4 → 0.3.0-beta.246
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/Dockerfile +9 -7
- package/README.md +1 -2
- package/dist/controller/api.d.ts +32 -0
- package/dist/controller/api.js +193 -0
- package/dist/controller/error.d.ts +5 -0
- package/dist/controller/error.js +12 -0
- package/dist/controller/oauth/allowed.d.ts +1 -0
- package/dist/controller/oauth/allowed.js +17 -0
- package/dist/controller/oauth/code-verifier.d.ts +2 -0
- package/dist/controller/oauth/code-verifier.js +15 -0
- package/dist/controller/oauth/redirect.d.ts +1 -0
- package/dist/controller/oauth/redirect.js +11 -0
- package/dist/controller/oauth.d.ts +23 -0
- package/dist/controller/oauth.js +263 -0
- package/dist/controller/utils.d.ts +6 -0
- package/dist/controller/utils.js +17 -0
- package/dist/db/db.d.ts +15 -0
- package/dist/db/db.js +107 -0
- package/dist/db/encrypter.d.ts +3 -0
- package/dist/db/encrypter.js +29 -0
- package/dist/db/mem.d.ts +20 -0
- package/dist/db/mem.js +128 -0
- package/dist/db/mongo.d.ts +17 -0
- package/dist/db/mongo.js +106 -0
- package/dist/db/redis.d.ts +15 -0
- package/dist/db/redis.js +107 -0
- package/dist/db/sql/entity/JacksonIndex.d.ts +7 -0
- package/dist/db/sql/entity/JacksonIndex.js +41 -0
- package/dist/db/sql/entity/JacksonStore.d.ts +6 -0
- package/dist/db/sql/entity/JacksonStore.js +42 -0
- package/dist/db/sql/entity/JacksonTTL.d.ts +4 -0
- package/dist/db/sql/entity/JacksonTTL.js +29 -0
- package/dist/db/sql/sql.d.ts +20 -0
- package/dist/db/sql/sql.js +174 -0
- package/dist/db/store.d.ts +5 -0
- package/dist/db/store.js +68 -0
- package/dist/db/utils.d.ts +7 -0
- package/dist/db/utils.js +29 -0
- package/dist/env.d.ts +22 -0
- package/dist/env.js +35 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +80 -0
- package/dist/jackson.d.ts +1 -0
- package/dist/jackson.js +153 -0
- package/dist/read-config.d.ts +3 -0
- package/dist/read-config.js +50 -0
- package/dist/saml/claims.d.ts +6 -0
- package/dist/saml/claims.js +35 -0
- package/dist/saml/saml.d.ts +11 -0
- package/dist/saml/saml.js +200 -0
- package/dist/saml/x509.d.ts +7 -0
- package/dist/saml/x509.js +69 -0
- package/dist/typings.d.ts +137 -0
- package/dist/typings.js +2 -0
- package/package.json +41 -21
- package/.dockerignore +0 -2
- package/.eslintrc.js +0 -13
- 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.js +0 -167
- package/src/controller/error.js +0 -12
- package/src/controller/oauth/allowed.js +0 -19
- package/src/controller/oauth/code-verifier.js +0 -16
- package/src/controller/oauth/redirect.js +0 -18
- package/src/controller/oauth.js +0 -321
- package/src/controller/utils.js +0 -19
- package/src/db/db.js +0 -81
- package/src/db/db.test.js +0 -302
- package/src/db/encrypter.js +0 -36
- package/src/db/mem.js +0 -111
- package/src/db/mongo.js +0 -89
- package/src/db/redis.js +0 -88
- package/src/db/sql/entity/JacksonIndex.js +0 -42
- package/src/db/sql/entity/JacksonStore.js +0 -42
- package/src/db/sql/entity/JacksonTTL.js +0 -23
- package/src/db/sql/model/JacksonIndex.js +0 -9
- package/src/db/sql/model/JacksonStore.js +0 -10
- package/src/db/sql/model/JacksonTTL.js +0 -8
- package/src/db/sql/sql.js +0 -153
- package/src/db/store.js +0 -42
- package/src/db/utils.js +0 -30
- package/src/env.js +0 -39
- package/src/index.js +0 -67
- package/src/jackson.js +0 -161
- package/src/read-config.js +0 -24
- package/src/saml/claims.js +0 -40
- package/src/saml/saml.js +0 -223
- package/src/saml/x509.js +0 -48
- package/src/test/api.test.js +0 -186
- 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/oauth.test.js +0 -342
package/src/db/encrypter.js
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
const crypto = require('crypto');
|
2
|
-
|
3
|
-
const ALGO = 'aes-256-gcm';
|
4
|
-
const BLOCK_SIZE = 16; // 128 bit
|
5
|
-
|
6
|
-
const encrypt = (text, key) => {
|
7
|
-
const iv = crypto.randomBytes(BLOCK_SIZE);
|
8
|
-
const cipher = crypto.createCipheriv(ALGO, key, iv);
|
9
|
-
|
10
|
-
let ciphertext = cipher.update(text, 'utf8', 'base64');
|
11
|
-
ciphertext += cipher.final('base64');
|
12
|
-
return {
|
13
|
-
iv: iv.toString('base64'),
|
14
|
-
tag: cipher.getAuthTag().toString('base64'),
|
15
|
-
value: ciphertext,
|
16
|
-
};
|
17
|
-
};
|
18
|
-
|
19
|
-
const decrypt = (ciphertext, iv, tag, key) => {
|
20
|
-
const decipher = crypto.createDecipheriv(
|
21
|
-
ALGO,
|
22
|
-
key,
|
23
|
-
Buffer.from(iv, 'base64')
|
24
|
-
);
|
25
|
-
decipher.setAuthTag(Buffer.from(tag, 'base64'));
|
26
|
-
|
27
|
-
let cleartext = decipher.update(ciphertext, 'base64', 'utf8');
|
28
|
-
cleartext += decipher.final('utf8');
|
29
|
-
|
30
|
-
return cleartext;
|
31
|
-
};
|
32
|
-
|
33
|
-
module.exports = {
|
34
|
-
encrypt,
|
35
|
-
decrypt,
|
36
|
-
};
|
package/src/db/mem.js
DELETED
@@ -1,111 +0,0 @@
|
|
1
|
-
// This is an in-memory implementation to be used with testing and prototyping only
|
2
|
-
const dbutils = require('./utils.js');
|
3
|
-
|
4
|
-
class Mem {
|
5
|
-
constructor(options) {
|
6
|
-
return (async () => {
|
7
|
-
this.store = {}; // map of key, value
|
8
|
-
this.indexes = {}; // map of key, Set
|
9
|
-
this.cleanup = {}; // map of indexes for cleanup when store key is deleted
|
10
|
-
this.ttlStore = {}; // map of key to ttl
|
11
|
-
|
12
|
-
if (options.ttl) {
|
13
|
-
this.ttlCleanup = async () => {
|
14
|
-
const now = Date.now();
|
15
|
-
for (const k in this.ttlStore) {
|
16
|
-
if (this.ttlStore[k].expiresAt < now) {
|
17
|
-
await this.delete(
|
18
|
-
this.ttlStore[k].namespace,
|
19
|
-
this.ttlStore[k].key
|
20
|
-
);
|
21
|
-
}
|
22
|
-
}
|
23
|
-
|
24
|
-
this.timerId = setTimeout(this.ttlCleanup, options.ttl * 1000);
|
25
|
-
};
|
26
|
-
|
27
|
-
this.timerId = setTimeout(this.ttlCleanup, options.ttl * 1000);
|
28
|
-
}
|
29
|
-
|
30
|
-
return this;
|
31
|
-
})();
|
32
|
-
}
|
33
|
-
|
34
|
-
async get(namespace, key) {
|
35
|
-
let res = this.store[dbutils.key(namespace, key)];
|
36
|
-
if (res) {
|
37
|
-
return res;
|
38
|
-
}
|
39
|
-
|
40
|
-
return null;
|
41
|
-
}
|
42
|
-
|
43
|
-
async getByIndex(namespace, idx) {
|
44
|
-
const dbKeys = await this.indexes[dbutils.keyForIndex(namespace, idx)];
|
45
|
-
|
46
|
-
const ret = [];
|
47
|
-
for (const dbKey of dbKeys || []) {
|
48
|
-
ret.push(await this.get(namespace, dbKey));
|
49
|
-
}
|
50
|
-
|
51
|
-
return ret;
|
52
|
-
}
|
53
|
-
|
54
|
-
async put(namespace, key, val, ttl = 0, ...indexes) {
|
55
|
-
const k = dbutils.key(namespace, key);
|
56
|
-
|
57
|
-
this.store[k] = val;
|
58
|
-
|
59
|
-
if (ttl) {
|
60
|
-
this.ttlStore[k] = {
|
61
|
-
namespace,
|
62
|
-
key,
|
63
|
-
expiresAt: Date.now() + ttl * 1000,
|
64
|
-
};
|
65
|
-
}
|
66
|
-
|
67
|
-
// no ttl support for secondary indexes
|
68
|
-
for (const idx of indexes || []) {
|
69
|
-
const idxKey = dbutils.keyForIndex(namespace, idx);
|
70
|
-
let set = this.indexes[idxKey];
|
71
|
-
if (!set) {
|
72
|
-
set = new Set();
|
73
|
-
this.indexes[idxKey] = set;
|
74
|
-
}
|
75
|
-
|
76
|
-
set.add(key);
|
77
|
-
|
78
|
-
const cleanupKey = dbutils.keyFromParts(dbutils.indexPrefix, k);
|
79
|
-
let cleanup = this.cleanup[cleanupKey];
|
80
|
-
if (!cleanup) {
|
81
|
-
cleanup = new Set();
|
82
|
-
this.cleanup[cleanupKey] = cleanup;
|
83
|
-
}
|
84
|
-
|
85
|
-
cleanup.add(idxKey);
|
86
|
-
}
|
87
|
-
}
|
88
|
-
|
89
|
-
async delete(namespace, key) {
|
90
|
-
const k = dbutils.key(namespace, key);
|
91
|
-
|
92
|
-
delete this.store[k];
|
93
|
-
|
94
|
-
const idxKey = dbutils.keyFromParts(dbutils.indexPrefix, k);
|
95
|
-
// delete secondary indexes and then the mapping of the seconary indexes
|
96
|
-
const dbKeys = this.cleanup[idxKey];
|
97
|
-
|
98
|
-
for (const dbKey of dbKeys || []) {
|
99
|
-
this.indexes[dbKey] && this.indexes[dbKey].delete(key);
|
100
|
-
}
|
101
|
-
|
102
|
-
delete this.cleanup[idxKey];
|
103
|
-
delete this.ttlStore[k];
|
104
|
-
}
|
105
|
-
}
|
106
|
-
|
107
|
-
module.exports = {
|
108
|
-
new: async (options) => {
|
109
|
-
return new Mem(options);
|
110
|
-
},
|
111
|
-
};
|
package/src/db/mongo.js
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
const { MongoClient } = require('mongodb');
|
2
|
-
const dbutils = require('./utils.js');
|
3
|
-
|
4
|
-
class Mongo {
|
5
|
-
constructor(options) {
|
6
|
-
return (async () => {
|
7
|
-
this.client = new MongoClient(options.url);
|
8
|
-
|
9
|
-
await this.client.connect();
|
10
|
-
this.db = this.client.db();
|
11
|
-
this.collection = this.db.collection('jacksonStore');
|
12
|
-
|
13
|
-
await this.collection.createIndex({ indexes: 1 });
|
14
|
-
await this.collection.createIndex(
|
15
|
-
{ expiresAt: 1 },
|
16
|
-
{ expireAfterSeconds: 1 }
|
17
|
-
);
|
18
|
-
|
19
|
-
return this;
|
20
|
-
})();
|
21
|
-
}
|
22
|
-
|
23
|
-
async get(namespace, key) {
|
24
|
-
let res = await this.collection.findOne({
|
25
|
-
_id: dbutils.key(namespace, key),
|
26
|
-
});
|
27
|
-
if (res && res.value) {
|
28
|
-
return res.value;
|
29
|
-
}
|
30
|
-
|
31
|
-
return null;
|
32
|
-
}
|
33
|
-
|
34
|
-
async getByIndex(namespace, idx) {
|
35
|
-
const docs = await this.collection
|
36
|
-
.find({
|
37
|
-
indexes: dbutils.keyForIndex(namespace, idx),
|
38
|
-
})
|
39
|
-
.toArray();
|
40
|
-
|
41
|
-
const ret = [];
|
42
|
-
for (const doc of docs || []) {
|
43
|
-
ret.push(doc.value);
|
44
|
-
}
|
45
|
-
|
46
|
-
return ret;
|
47
|
-
}
|
48
|
-
|
49
|
-
async put(namespace, key, val, ttl = 0, ...indexes) {
|
50
|
-
const doc = {
|
51
|
-
value: val,
|
52
|
-
};
|
53
|
-
|
54
|
-
if (ttl) {
|
55
|
-
doc.expiresAt = new Date(Date.now() + ttl * 1000);
|
56
|
-
}
|
57
|
-
|
58
|
-
// no ttl support for secondary indexes
|
59
|
-
for (const idx of indexes || []) {
|
60
|
-
const idxKey = dbutils.keyForIndex(namespace, idx);
|
61
|
-
|
62
|
-
if (!doc.indexes) {
|
63
|
-
doc.indexes = [];
|
64
|
-
}
|
65
|
-
|
66
|
-
doc.indexes.push(idxKey);
|
67
|
-
}
|
68
|
-
|
69
|
-
await this.collection.updateOne(
|
70
|
-
{ _id: dbutils.key(namespace, key) },
|
71
|
-
{
|
72
|
-
$set: doc,
|
73
|
-
},
|
74
|
-
{ upsert: true }
|
75
|
-
);
|
76
|
-
}
|
77
|
-
|
78
|
-
async delete(namespace, key) {
|
79
|
-
return await this.collection.deleteOne({
|
80
|
-
_id: dbutils.key(namespace, key),
|
81
|
-
});
|
82
|
-
}
|
83
|
-
}
|
84
|
-
|
85
|
-
module.exports = {
|
86
|
-
new: async (options) => {
|
87
|
-
return new Mongo(options);
|
88
|
-
},
|
89
|
-
};
|
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
|
-
});
|
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
|
-
};
|