@n42/cli 0.1.42 → 0.1.67
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 +2 -2
- package/docs/DB_USAGE.md +223 -0
- package/package.json +4 -3
- package/src/auth.js +77 -7
- package/src/browser.js +1 -0
- package/src/cli.js +140 -21
- package/src/completion/bash.sh +19 -0
- package/src/config.js +5 -22
- package/src/db.js +157 -0
- package/src/discover.js +26 -9
- package/src/user.js +18 -55
- package/src/utils.js +70 -38
- package/test/auth.test.js +98 -0
- package/test/db.test.js +142 -0
- package/test/utils.test.js +20 -18
- package/src/signin.js +0 -58
package/src/db.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
const config = require("./config");
|
|
5
|
+
let DATABASE_FILE = config.DATABASE_FILE;
|
|
6
|
+
let artefactIndex = null;
|
|
7
|
+
|
|
8
|
+
function setSource(p) {
|
|
9
|
+
DATABASE_FILE = p;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function load() {
|
|
13
|
+
if (!fs.existsSync(DATABASE_FILE)) return {
|
|
14
|
+
user: [],
|
|
15
|
+
artefacts: [],
|
|
16
|
+
usage: [],
|
|
17
|
+
};
|
|
18
|
+
return JSON.parse(fs.readFileSync(DATABASE_FILE, "utf8"));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function save(database) {
|
|
22
|
+
invalidateArtefactIndex();
|
|
23
|
+
|
|
24
|
+
const dir = path.dirname(DATABASE_FILE);
|
|
25
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
26
|
+
|
|
27
|
+
const tmp = DATABASE_FILE + ".tmp";
|
|
28
|
+
|
|
29
|
+
// always write tmp
|
|
30
|
+
fs.writeFileSync(tmp, JSON.stringify(database, null, 2), "utf8");
|
|
31
|
+
|
|
32
|
+
try { fs.renameSync(tmp, DATABASE_FILE); }
|
|
33
|
+
catch (e) {
|
|
34
|
+
if (e.code === "ENOENT") {
|
|
35
|
+
// fallback for first write
|
|
36
|
+
fs.writeFileSync(DATABASE_FILE, JSON.stringify(database, null, 2), "utf8");
|
|
37
|
+
} else {
|
|
38
|
+
throw e;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function insert(collection, item) {
|
|
44
|
+
const db = load();
|
|
45
|
+
db[collection] ??= [];
|
|
46
|
+
db[collection].push(item);
|
|
47
|
+
save(db);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function update(collection, item, key = "id") {
|
|
51
|
+
const db = load();
|
|
52
|
+
const idx = db[collection]?.findIndex(x => x[key] === item[key]);
|
|
53
|
+
|
|
54
|
+
if (idx < 0) return false;
|
|
55
|
+
|
|
56
|
+
db[collection][idx] = { ...db[collection][idx], ...item };
|
|
57
|
+
save(db);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function upsert(collection, item, key = "id") {
|
|
62
|
+
const db = load();
|
|
63
|
+
db[collection] ??= [];
|
|
64
|
+
|
|
65
|
+
const idx = db[collection].findIndex(x => x[key] === item[key]);
|
|
66
|
+
if (idx >= 0) {
|
|
67
|
+
db[collection][idx] = { ...db[collection][idx], ...item, updatedAt: Date.now() };
|
|
68
|
+
} else {
|
|
69
|
+
db[collection].push({ ...item, createdAt: Date.now() });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
save(db);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function replace(collection, value) {
|
|
76
|
+
const db = load();
|
|
77
|
+
db[collection] = value;
|
|
78
|
+
save(db);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function set(collection, key, value) {
|
|
82
|
+
const db = load();
|
|
83
|
+
db[collection] ??= {};
|
|
84
|
+
db[collection][key] = value;
|
|
85
|
+
save(db);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function remove(collection, keyValue, key = "id") {
|
|
89
|
+
const db = load();
|
|
90
|
+
db[collection] = (db[collection] ?? []).filter(x => x[key] !== keyValue);
|
|
91
|
+
save(db);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function get(collection) {
|
|
95
|
+
const db = load();
|
|
96
|
+
return db[collection] ?? [];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function find(collection, predicate) {
|
|
100
|
+
const db = load();
|
|
101
|
+
return (db[collection] ?? []).filter(predicate);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function indexBy(list, key) {
|
|
105
|
+
const map = Object.create(null);
|
|
106
|
+
|
|
107
|
+
for (const item of list) {
|
|
108
|
+
const k = item?.[key];
|
|
109
|
+
if (k == null) continue; // skip null/undefined
|
|
110
|
+
(map[k] ??= []).push(item);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return map;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function indexByFn(list, keyFn) {
|
|
117
|
+
const map = Object.create(null);
|
|
118
|
+
|
|
119
|
+
for (const item of list) {
|
|
120
|
+
const k = keyFn(item);
|
|
121
|
+
if (k == null) continue;
|
|
122
|
+
(map[k] ??= []).push(item);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return map;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function indexByMap(list, key) {
|
|
129
|
+
const map = new Map();
|
|
130
|
+
for (const item of list) {
|
|
131
|
+
const k = item?.[key];
|
|
132
|
+
if (k == null) continue;
|
|
133
|
+
const arr = map.get(k) ?? [];
|
|
134
|
+
arr.push(item);
|
|
135
|
+
map.set(k, arr);
|
|
136
|
+
}
|
|
137
|
+
return map;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function getArtefactIndex() {
|
|
141
|
+
if (!artefactIndex) {
|
|
142
|
+
const list = get("artefacts");
|
|
143
|
+
artefactIndex = indexBy(list, "participantId");
|
|
144
|
+
}
|
|
145
|
+
return artefactIndex;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function invalidateArtefactIndex() {
|
|
149
|
+
artefactIndex = null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function artefactsByParticipant(pid) {
|
|
153
|
+
const idx = getArtefactIndex();
|
|
154
|
+
return idx[pid] ?? [];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
module.exports = { setSource, load, save, insert, update, upsert, replace, set, remove, get, find, indexBy, indexByFn, indexByMap, artefactsByParticipant };
|
package/src/discover.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const pkg = require("../package.json");
|
|
4
|
+
const db = require("./db");
|
|
4
5
|
|
|
5
6
|
const { fetchWithAuth } = require("./auth");
|
|
6
7
|
const { API_URL, EP_DISCOVER, DEFAULT_OUTPUT, DEFAULT_FORMAT, ARTEFACTS_DIR } = require("./config");
|
|
7
|
-
const { getUserUsage
|
|
8
|
+
const { getUserUsage } = require("./user");
|
|
8
9
|
const { clearScreen, startSpinner, buildDocLabel, promptForDocument } = require("./utils");
|
|
9
10
|
const { handleError } = require("./errors");
|
|
10
11
|
|
|
@@ -33,7 +34,7 @@ const DEFAULT_DISCOVERY_INPUT = {
|
|
|
33
34
|
const discoveryInput = DEFAULT_DISCOVERY_INPUT;
|
|
34
35
|
let docSelected = false;
|
|
35
36
|
|
|
36
|
-
async function processSupportedDocuments(encodedDocs,
|
|
37
|
+
async function processSupportedDocuments(encodedDocs, onDone) {
|
|
37
38
|
if (encodedDocs && !docSelected) {
|
|
38
39
|
const docs = JSON.parse(Buffer.from(encodedDocs, "base64").toString("utf8"))
|
|
39
40
|
.map(d => ({ ...d, label: buildDocLabel(d) }));
|
|
@@ -52,13 +53,16 @@ async function processSupportedDocuments(encodedDocs, environment, participantId
|
|
|
52
53
|
discoveryInput.document.value = docSelected.value;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
if (typeof onDone === "function") {
|
|
57
|
+
await onDone(); // no args
|
|
58
|
+
}
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
}
|
|
59
62
|
|
|
60
|
-
async function runDiscovery(
|
|
63
|
+
async function runDiscovery(participantId, options) {
|
|
61
64
|
const {
|
|
65
|
+
env,
|
|
62
66
|
output = DEFAULT_OUTPUT,
|
|
63
67
|
format = DEFAULT_FORMAT,
|
|
64
68
|
forceHttps,
|
|
@@ -72,7 +76,7 @@ async function runDiscovery(environment, participantId, options) {
|
|
|
72
76
|
|
|
73
77
|
const payload = {
|
|
74
78
|
...discoveryInput,
|
|
75
|
-
env
|
|
79
|
+
env,
|
|
76
80
|
options: {
|
|
77
81
|
output,
|
|
78
82
|
format,
|
|
@@ -116,7 +120,14 @@ async function runDiscovery(environment, participantId, options) {
|
|
|
116
120
|
const currentMonth = new Date().toISOString().slice(0, 7);
|
|
117
121
|
userUsage.serviceUsage.discovery[currentMonth] = serviceUsage;
|
|
118
122
|
|
|
119
|
-
|
|
123
|
+
db.replace("serviceUsage", userUsage);
|
|
124
|
+
|
|
125
|
+
db.insert("artefacts", {
|
|
126
|
+
id: refId,
|
|
127
|
+
participantId,
|
|
128
|
+
options,
|
|
129
|
+
createdAt: Date.now()
|
|
130
|
+
});
|
|
120
131
|
|
|
121
132
|
if (output === "plantuml" && format === "svg") {
|
|
122
133
|
const svg = await res.text();
|
|
@@ -127,7 +138,9 @@ async function runDiscovery(environment, participantId, options) {
|
|
|
127
138
|
process.exit(1);
|
|
128
139
|
}
|
|
129
140
|
|
|
130
|
-
await processSupportedDocuments(encodedDocs,
|
|
141
|
+
await processSupportedDocuments(encodedDocs, async () => {
|
|
142
|
+
await runDiscovery(participantId, options);
|
|
143
|
+
});
|
|
131
144
|
|
|
132
145
|
const file = path.join(ARTEFACTS_DIR, `${refId}.svg`);
|
|
133
146
|
fs.writeFileSync(file, svg);
|
|
@@ -142,7 +155,9 @@ async function runDiscovery(environment, participantId, options) {
|
|
|
142
155
|
const text = await res.text();
|
|
143
156
|
stopSpinner();
|
|
144
157
|
|
|
145
|
-
await processSupportedDocuments(encodedDocs,
|
|
158
|
+
await processSupportedDocuments(encodedDocs, async () => {
|
|
159
|
+
await runDiscovery(participantId, options);
|
|
160
|
+
});
|
|
146
161
|
|
|
147
162
|
const file = path.join(ARTEFACTS_DIR, `${refId}.puml`);
|
|
148
163
|
fs.writeFileSync(file, text);
|
|
@@ -157,7 +172,9 @@ async function runDiscovery(environment, participantId, options) {
|
|
|
157
172
|
const json = await res.json();
|
|
158
173
|
stopSpinner();
|
|
159
174
|
|
|
160
|
-
await processSupportedDocuments(encodedDocs,
|
|
175
|
+
await processSupportedDocuments(encodedDocs, async () => {
|
|
176
|
+
await runDiscovery(participantId, options);
|
|
177
|
+
});
|
|
161
178
|
|
|
162
179
|
const file = path.join(ARTEFACTS_DIR, `${refId}.json`);
|
|
163
180
|
fs.writeFileSync(file, JSON.stringify(json, null, 2));
|
package/src/user.js
CHANGED
|
@@ -1,64 +1,27 @@
|
|
|
1
|
-
const
|
|
2
|
-
const { NODE42_DIR, USER_FILE, USAGE_FILE } = require("./config");
|
|
1
|
+
const db = require("./db");
|
|
3
2
|
|
|
4
|
-
function
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function getUserInfo() {
|
|
14
|
-
try {
|
|
15
|
-
if (!fs.existsSync(USER_FILE)) {
|
|
16
|
-
return {
|
|
17
|
-
userName: "n/a",
|
|
18
|
-
userMail: "n/a",
|
|
19
|
-
role: "n/a"
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
return JSON.parse(fs.readFileSync(USER_FILE, "utf8"));
|
|
23
|
-
} catch {
|
|
24
|
-
return {
|
|
25
|
-
userName: "n/a",
|
|
26
|
-
userMail: "n/a",
|
|
27
|
-
role: "n/a"
|
|
3
|
+
function getUser() {
|
|
4
|
+
const users = db.get("user");
|
|
5
|
+
return users.length ? users[0] : {
|
|
6
|
+
"id": "n/a",
|
|
7
|
+
"userName": "n/a",
|
|
8
|
+
"userMail": "n/a",
|
|
9
|
+
"role": "n/a"
|
|
28
10
|
};
|
|
29
|
-
}
|
|
30
11
|
}
|
|
31
12
|
|
|
32
|
-
function
|
|
33
|
-
|
|
13
|
+
function getUserUsage() {
|
|
14
|
+
const usage = db.get("serviceUsage");
|
|
34
15
|
|
|
35
|
-
|
|
36
|
-
USAGE_FILE,
|
|
37
|
-
JSON.stringify(usage, null, 2)
|
|
38
|
-
);
|
|
39
|
-
}
|
|
16
|
+
if (usage && usage.serviceUsage) return usage;
|
|
40
17
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
discovery: {},
|
|
47
|
-
validation: {},
|
|
48
|
-
transactions: {}
|
|
49
|
-
}
|
|
50
|
-
};
|
|
18
|
+
return {
|
|
19
|
+
serviceUsage: {
|
|
20
|
+
discovery: {},
|
|
21
|
+
validation: {},
|
|
22
|
+
transactions: {}
|
|
51
23
|
}
|
|
52
|
-
|
|
53
|
-
} catch {
|
|
54
|
-
return {
|
|
55
|
-
serviceUsage: {
|
|
56
|
-
discovery: {},
|
|
57
|
-
validation: {},
|
|
58
|
-
transactions: {}
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
}
|
|
24
|
+
};
|
|
62
25
|
}
|
|
63
26
|
|
|
64
|
-
module.exports = {
|
|
27
|
+
module.exports = { getUser, getUserUsage };
|
package/src/utils.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
1
2
|
const inquirer = require("inquirer");
|
|
2
3
|
const readline = require("readline");
|
|
4
|
+
const config = require("./config");
|
|
5
|
+
|
|
3
6
|
|
|
4
7
|
function clearScreen(text) {
|
|
5
8
|
process.stdout.write("\x1Bc");
|
|
@@ -8,7 +11,7 @@ function clearScreen(text) {
|
|
|
8
11
|
}
|
|
9
12
|
}
|
|
10
13
|
|
|
11
|
-
function ask(question, hidden=false) {
|
|
14
|
+
function ask(question, def, hidden=false) {
|
|
12
15
|
return new Promise(resolve => {
|
|
13
16
|
const rl = readline.createInterface({
|
|
14
17
|
input: process.stdin,
|
|
@@ -16,6 +19,8 @@ function ask(question, hidden=false) {
|
|
|
16
19
|
terminal: true
|
|
17
20
|
});
|
|
18
21
|
|
|
22
|
+
const q = def ? `${question} (${def}): ` : `${question}: `;
|
|
23
|
+
|
|
19
24
|
process.stdin.on("data", char => {
|
|
20
25
|
char = char + "";
|
|
21
26
|
switch (char) {
|
|
@@ -28,16 +33,16 @@ function ask(question, hidden=false) {
|
|
|
28
33
|
if (hidden) {
|
|
29
34
|
process.stdout.clearLine(0);
|
|
30
35
|
process.stdout.cursorTo(0);
|
|
31
|
-
process.stdout.write(
|
|
36
|
+
process.stdout.write(q + "*".repeat(rl.line.length));
|
|
32
37
|
}
|
|
33
38
|
break;
|
|
34
39
|
}
|
|
35
40
|
});
|
|
36
41
|
|
|
37
|
-
rl.question(
|
|
42
|
+
rl.question(q, answer => {
|
|
38
43
|
rl.history = rl.history.slice(1);
|
|
39
44
|
rl.close();
|
|
40
|
-
resolve(answer);
|
|
45
|
+
resolve(answer || def);
|
|
41
46
|
});
|
|
42
47
|
});
|
|
43
48
|
}
|
|
@@ -56,6 +61,59 @@ function startSpinner(text = "Working") {
|
|
|
56
61
|
};
|
|
57
62
|
}
|
|
58
63
|
|
|
64
|
+
async function promptForDocument(docs) {
|
|
65
|
+
const { document } = await inquirer.prompt([
|
|
66
|
+
{
|
|
67
|
+
type: "list",
|
|
68
|
+
name: "document",
|
|
69
|
+
message: "Select document type:",
|
|
70
|
+
choices: docs.map(d => ({
|
|
71
|
+
name: d.label,
|
|
72
|
+
value: d
|
|
73
|
+
}))
|
|
74
|
+
}
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
return document;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function validateEnv(env) {
|
|
81
|
+
const allowedEnvs = ["TEST", "PROD"];
|
|
82
|
+
if (!allowedEnvs.includes(env.toUpperCase())) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Invalid environment: ${env}\nAllowed values: ${allowedEnvs.join(", ")}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function validateId(type, id) {
|
|
90
|
+
const value = id.replace(/\s+/g, "");
|
|
91
|
+
|
|
92
|
+
// ISO 6523–safe; participant id like 0000:12345 or 9915:abcde
|
|
93
|
+
if (!/^[0-9]{4}:[a-zA-Z0-9\-\._~]{1,135}$/.test(value)) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Invalid ${type}Id: ${id}\nExpected format: 0007:123456789 or 0007:abcd`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function createAppDirs(force=false) {
|
|
101
|
+
fs.mkdirSync(config.NODE42_DIR, { recursive: true });
|
|
102
|
+
fs.mkdirSync(config.ARTEFACTS_DIR, { recursive: true });
|
|
103
|
+
fs.mkdirSync(config.TRANSACTIONS_DIR, { recursive: true });
|
|
104
|
+
fs.mkdirSync(config.VALIDATION_DIR, { recursive: true });
|
|
105
|
+
|
|
106
|
+
if (!fs.existsSync(config.CONFIG_FILE) || force) {
|
|
107
|
+
fs.writeFileSync(
|
|
108
|
+
config.CONFIG_FILE,
|
|
109
|
+
JSON.stringify({
|
|
110
|
+
DEFAULT_OUTPUT: config.DEFAULT_OUTPUT,
|
|
111
|
+
DEFAULT_FORMAT: config.DEFAULT_FORMAT
|
|
112
|
+
}, null, 2)
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
59
117
|
function buildDocLabel({ scheme, value }) {
|
|
60
118
|
// 1. Document name (after :: before ##)
|
|
61
119
|
const docMatch = value.match(/::([^#]+)##/);
|
|
@@ -95,40 +153,14 @@ function buildDocLabel({ scheme, value }) {
|
|
|
95
153
|
return docName;
|
|
96
154
|
}
|
|
97
155
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
name: d.label,
|
|
106
|
-
value: d
|
|
107
|
-
}))
|
|
108
|
-
}
|
|
109
|
-
]);
|
|
110
|
-
|
|
111
|
-
return document;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function validateEnv(env) {
|
|
115
|
-
const allowedEnvs = ["TEST", "PROD"];
|
|
116
|
-
if (!allowedEnvs.includes(env.toUpperCase())) {
|
|
117
|
-
throw new Error(
|
|
118
|
-
`Invalid environment: ${env}\nAllowed values: ${allowedEnvs.join(", ")}`
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function validateId(type, id) {
|
|
124
|
-
const value = id.replace(/\s+/g, "");
|
|
125
|
-
|
|
126
|
-
// ISO 6523–safe; participant id like 0000:12345 or 9915:abcde
|
|
127
|
-
if (!/^[0-9]{4}:[a-zA-Z0-9\-\._~]{1,135}$/.test(value)) {
|
|
128
|
-
throw new Error(
|
|
129
|
-
`Invalid ${type}Id: ${id}\nExpected format: 0007:123456789 or 0007:abcd`
|
|
130
|
-
);
|
|
156
|
+
function getArtefactExt(output, format) {
|
|
157
|
+
if (output === "plantuml" && format === "svg") {
|
|
158
|
+
return "svg";
|
|
159
|
+
} else if (output === "plantuml" && format === "text") {
|
|
160
|
+
return "puml"
|
|
161
|
+
} else {
|
|
162
|
+
return "json";
|
|
131
163
|
}
|
|
132
164
|
}
|
|
133
165
|
|
|
134
|
-
module.exports = { clearScreen, startSpinner, ask, buildDocLabel, promptForDocument, validateEnv, validateId };
|
|
166
|
+
module.exports = { clearScreen, startSpinner, ask, buildDocLabel, promptForDocument, validateEnv, validateId, createAppDirs, getArtefactExt };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const { expect } = require("chai");
|
|
2
|
+
const sinon = require("sinon");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const os = require("os");
|
|
6
|
+
const db = require("../src/db");
|
|
7
|
+
|
|
8
|
+
const TEST_DB = path.join(os.tmpdir(), "test-db.json");
|
|
9
|
+
|
|
10
|
+
describe("auth", () => {
|
|
11
|
+
describe("login()", () => {
|
|
12
|
+
let login;
|
|
13
|
+
let utils;
|
|
14
|
+
let auth;
|
|
15
|
+
let user;
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
sinon.restore();
|
|
19
|
+
|
|
20
|
+
db.setSource(TEST_DB);
|
|
21
|
+
if (fs.existsSync(TEST_DB)) fs.unlinkSync(TEST_DB);
|
|
22
|
+
|
|
23
|
+
// fresh require each test
|
|
24
|
+
delete require.cache[require.resolve("../src/utils")];
|
|
25
|
+
delete require.cache[require.resolve("../src/user")];
|
|
26
|
+
delete require.cache[require.resolve("../src/auth")];
|
|
27
|
+
|
|
28
|
+
utils = require("../src/utils");
|
|
29
|
+
user = require("../src/user");
|
|
30
|
+
|
|
31
|
+
sinon.stub(utils, "clearScreen");
|
|
32
|
+
sinon.stub(utils, "ask")
|
|
33
|
+
.onFirstCall().resolves("user")
|
|
34
|
+
.onSecondCall().resolves("secret");
|
|
35
|
+
|
|
36
|
+
sinon.stub(utils, "startSpinner").callsFake(() => () => {});
|
|
37
|
+
sinon.stub(user, "getUser").returns({
|
|
38
|
+
userName: "User",
|
|
39
|
+
userMail: "user@test.com",
|
|
40
|
+
role: "user"
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
sinon.stub(fs, "mkdirSync");
|
|
44
|
+
sinon.stub(fs, "writeFileSync");
|
|
45
|
+
|
|
46
|
+
sinon.stub(console, "log");
|
|
47
|
+
sinon.stub(console, "error");
|
|
48
|
+
sinon.stub(process, "exit").callsFake(() => {
|
|
49
|
+
throw new Error("process.exit");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
auth = require("../src/auth");
|
|
53
|
+
login = auth.login;
|
|
54
|
+
|
|
55
|
+
sinon.stub(auth, "checkAuth").returns(true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
sinon.restore();
|
|
60
|
+
delete global.fetch;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("logs in successfully and writes tokens", async () => {
|
|
64
|
+
// mock fetch
|
|
65
|
+
global.fetch = sinon.stub().resolves({
|
|
66
|
+
ok: true,
|
|
67
|
+
json: async () => ({
|
|
68
|
+
accessToken: "a",
|
|
69
|
+
refreshToken: "r",
|
|
70
|
+
idToken: "i"
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
await login();
|
|
75
|
+
|
|
76
|
+
expect(fs.writeFileSync.called).to.be.true;
|
|
77
|
+
expect(console.log.calledWithMatch("Authenticated as")).to.be.true;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("exits on http error", async () => {
|
|
81
|
+
global.fetch = sinon.stub().resolves({
|
|
82
|
+
ok: false,
|
|
83
|
+
status: 401,
|
|
84
|
+
json: async () => ({})
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
await login();
|
|
89
|
+
} catch (e) {
|
|
90
|
+
// expected
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
expect(console.error.calledWithMatch("Login failed")).to.be.true;
|
|
94
|
+
expect(process.exit.calledWith(1)).to.be.true;
|
|
95
|
+
expect(fs.writeFileSync.called).to.be.false;
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|