dcp-client 5.1.11 → 5.3.0
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/bin/dcp-bank +269 -0
- package/build/bundle +1 -1
- package/dist/dcp-client-bundle.js +1 -1
- package/dist/dcp-client-bundle.js.map +1 -1
- package/index.js +6 -5
- package/lib/getopt.js +94 -0
- package/package.json +6 -4
- package/windows-registry.js +154 -156
package/index.js
CHANGED
|
@@ -1305,16 +1305,15 @@ exports.createConfigFragments = async function dcpClient$$createConfigFragments(
|
|
|
1305
1305
|
addConfigFile(localConfig, resourceDir, 'dcp-config');
|
|
1306
1306
|
await addConfigRKey(localConfig, 'HKCU', 'dcp/dcp-config');
|
|
1307
1307
|
addConfigFile(localConfig, resourceDir, `${programName}/dcp-config`);
|
|
1308
|
-
await addConfigRKey(localConfig, 'HKCU',
|
|
1308
|
+
await addConfigRKey(localConfig, 'HKCU', `${programName}/dcp-config`);
|
|
1309
1309
|
addConfig (localConfig, initConfig);
|
|
1310
1310
|
addConfigEnv (localConfig, 'DCP_CONFIG_');
|
|
1311
1311
|
addConfig (localConfig, mkEnvConfig());
|
|
1312
1312
|
addConfig (localConfig, mkCliConfig(options));
|
|
1313
1313
|
addConfigFile(localConfig, etc, `dcp/${programName}/dcp-config`);
|
|
1314
|
-
await addConfigRKey(localConfig, 'HKLM',
|
|
1314
|
+
await addConfigRKey(localConfig, 'HKLM', `${programName}/dcp-config`);
|
|
1315
1315
|
addConfigFile(localConfig, etc, 'dcp/override-dcp-config');
|
|
1316
1316
|
await addConfigRKey(localConfig, 'HKLM', 'dcp/override-dcp-config');
|
|
1317
|
-
await addConfigRKey(localConfig, 'HKLM', 'dcp-client/dcp-config'); /* legacy - used by screen saver, /wg sep'22 */
|
|
1318
1317
|
|
|
1319
1318
|
/* 5. Use the aggregate of the default and local configs to figure out where the scheduler is. Use
|
|
1320
1319
|
* this to figure where the web config is and where an auto-update bundle would be if auto-update
|
|
@@ -1351,8 +1350,10 @@ exports.createConfigFragments = async function dcpClient$$createConfigFragments(
|
|
|
1351
1350
|
{
|
|
1352
1351
|
if (reportErrors !== false)
|
|
1353
1352
|
{
|
|
1354
|
-
|
|
1355
|
-
console.
|
|
1353
|
+
const code = error.code ? ` (${error.code})` : '';
|
|
1354
|
+
console.error('Error: dcp-client::init could not fetch scheduler configuration at ' + aggrConfig.scheduler.configLocation + code);
|
|
1355
|
+
if (error.code !== 'EHTTP_STATUS_ECONNREFUSED')
|
|
1356
|
+
console.debug(require('dcp/utils').justFetchPrettyError(error));
|
|
1356
1357
|
process.exit(1);
|
|
1357
1358
|
}
|
|
1358
1359
|
throw error;
|
package/lib/getopt.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file getopt.js - utility functions for parsing command-line options for DCP programs.
|
|
3
|
+
* Depends on posix-getopt npm library.
|
|
4
|
+
* @author Wes Garland, wes@distributive.network
|
|
5
|
+
* @date Nov 2025
|
|
6
|
+
*/
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
exports.parse = parse;
|
|
10
|
+
exports.uniq = uniq;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A posix getopt parser with a nice UX and API.
|
|
14
|
+
* - accepts optionsDefn string like posix-getopt module, but understands that the character * means
|
|
15
|
+
* long option only, and the -- option means to stop processing.
|
|
16
|
+
* - is a generator that yields for each option
|
|
17
|
+
* - option: character or long option when character is *.
|
|
18
|
+
* Magic option -- means that argvSegment is remainder of argv.
|
|
19
|
+
* - optarg: argument to option
|
|
20
|
+
* - optind: position of option character in argv
|
|
21
|
+
* - argvSegment: elements of argv used to make up option and optarg
|
|
22
|
+
*
|
|
23
|
+
* @note this generator intercepts process.stderr for the duration of iteration
|
|
24
|
+
* @note option characters above \u1000 are not supported
|
|
25
|
+
*
|
|
26
|
+
* @example parse(process.argv.slice(2), 'vh(help)*:(earnings-account)p:(port)')
|
|
27
|
+
* -v
|
|
28
|
+
* -h, --help
|
|
29
|
+
* --earnings-account=0xc0ffee
|
|
30
|
+
* -p123, --port=123
|
|
31
|
+
*
|
|
32
|
+
* @param {Array} argv array of options to parse
|
|
33
|
+
* @param {string} optionsDefn
|
|
34
|
+
* @throws {Error} when the options string is invalid
|
|
35
|
+
*/
|
|
36
|
+
function *parse(argv, optionsDefn)
|
|
37
|
+
{
|
|
38
|
+
const { BasicParser } = require('posix-getopt');
|
|
39
|
+
var longOptCount = 0;
|
|
40
|
+
|
|
41
|
+
optionsDefn = optionsDefn /* patchup long opt * to > \u1000 chars */
|
|
42
|
+
.match(/[A-Za-z*]:?(\([^)]*\))?/g)
|
|
43
|
+
.map(s => s[0] === '*' ? String.fromCharCode(++longOptCount + 0x1000) + s.slice(1) : s).join('');
|
|
44
|
+
const optionChars = optionsDefn.match(/[A-Za-z\u1000-\u1100/](:?\([^)]*\))?/g).map(s=>s[0]);
|
|
45
|
+
const uniqueOptionChars = uniq(optionChars);
|
|
46
|
+
if (optionChars.length !== uniqueOptionChars.length)
|
|
47
|
+
{
|
|
48
|
+
uniqueOptionChars.forEach(ch => {
|
|
49
|
+
if (optionChars.lastIndexOf(ch) !== optionChars.indexOf(ch))
|
|
50
|
+
throw new Error(`getopt - option character '${ch}' used more than once`);
|
|
51
|
+
});
|
|
52
|
+
throw new Error('unreachable code');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
argv = process.argv.slice(0,2).concat(argv);
|
|
56
|
+
const parser = new BasicParser(optionsDefn, argv);
|
|
57
|
+
const psw = process.stderr.write;
|
|
58
|
+
process.stderr.write = function patchupGetoptErrorOutput(s, ...args) {
|
|
59
|
+
/* posix-getopt library has useless chr for long opts when stderr.write('option requires an argument -- ' + chr + '\n'); */
|
|
60
|
+
if (s.startsWith('option requires an argument -- '))
|
|
61
|
+
s = `option ${argv[parser.optind() - 1]} requires an argument\n`;
|
|
62
|
+
psw.call(process.stderr, s, ...args);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
for (let opthnd, lastOpt=2; (opthnd = parser.getopt()); lastOpt = parser.optind())
|
|
66
|
+
{
|
|
67
|
+
let option;
|
|
68
|
+
|
|
69
|
+
/* To fake long-only-opts, we use short opts >= \u1000), and present only the long opt below */
|
|
70
|
+
if (opthnd.option < '\u1000')
|
|
71
|
+
option = opthnd.option;
|
|
72
|
+
else
|
|
73
|
+
option = (Object.entries(parser.gop_aliases).filter(longShort => longShort[1] === opthnd.option)[0] || ['?'])[0];
|
|
74
|
+
|
|
75
|
+
yield { option, optarg: opthnd.optarg, optind: parser.optind() - 2, argvSegment: argv.slice(lastOpt, parser.optind()) };
|
|
76
|
+
if (opthnd.error)
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (argv.length !== parser.optind())
|
|
81
|
+
yield { option: '--', optind: parser.optind(), argvSegment: argv.slice(parser.optind()) };
|
|
82
|
+
|
|
83
|
+
process.stderr.write = psw; // eslint-disable-line require-atomic-updates
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Return a new array composed only of unique elements of arr
|
|
88
|
+
* @param {Array} arr
|
|
89
|
+
* @returns {Array}
|
|
90
|
+
*/
|
|
91
|
+
function uniq(array)
|
|
92
|
+
{
|
|
93
|
+
return array.filter((val, idx, arr) => arr.indexOf(val) === idx);
|
|
94
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dcp-client",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"dcp": {
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "3eaced9015812e24ed08f2a0432c53b493483c37",
|
|
6
6
|
"repository": "git@gitlab.com:Distributed-Compute-Protocol/dcp.git"
|
|
7
7
|
},
|
|
8
8
|
"description": "Core libraries for accessing DCP network",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"author": "Distributive",
|
|
22
22
|
"main": "index",
|
|
23
23
|
"bin": {
|
|
24
|
-
"dcp-config-value": "bin/dcp-config-value"
|
|
24
|
+
"dcp-config-value": "bin/dcp-config-value",
|
|
25
|
+
"dcp-bank": "bin/dcp-bank"
|
|
25
26
|
},
|
|
26
27
|
"directories": {
|
|
27
28
|
"example": "examples"
|
|
@@ -45,11 +46,12 @@
|
|
|
45
46
|
"http-proxy-agent": "^4.0.1",
|
|
46
47
|
"https-agent": "^1.0.0",
|
|
47
48
|
"https-proxy-agent": "^5.0.0",
|
|
48
|
-
"kvin": "^
|
|
49
|
+
"kvin": "^9.0.0",
|
|
49
50
|
"memfs": "4.17.2",
|
|
50
51
|
"nanoid": "3.3.11",
|
|
51
52
|
"physical-cpu-count": "^2.0.0",
|
|
52
53
|
"polyfill-crypto.getrandomvalues": "^1.0.0",
|
|
54
|
+
"posix-getopt": "1.2.1",
|
|
53
55
|
"regedit": "^3.0.3",
|
|
54
56
|
"semver": "^7.3.5",
|
|
55
57
|
"socket.io-client": "4.8.0",
|
package/windows-registry.js
CHANGED
|
@@ -1,156 +1,154 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file windows-registry.js
|
|
3
|
-
* Windows registry configuration/integration utility for DCP. All exported functions
|
|
4
|
-
* return false on non-Windows platforms.
|
|
5
|
-
*
|
|
6
|
-
* Basic idea: summarize registry into an objects which can be used as the
|
|
7
|
-
* initializer object for DCP Client and wallet cache. Multiple hives are read
|
|
8
|
-
* to support higher-priviledged overrides for Administrators writing Group
|
|
9
|
-
* Policy files in Enterprise installs.
|
|
10
|
-
*
|
|
11
|
-
* Note: In registry-speak, keys are like directories and values are like files -- i.e. a key can
|
|
12
|
-
* contain keys and/or values, but values cannot contain keys; only strings and numbers and stuff.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* future - we will need a better way to return registry values, current proposal is to use
|
|
16
|
-
* REG_BINARY to encode richer types thus:
|
|
17
|
-
* 0x00 - null
|
|
18
|
-
* 0x20 - next 8 bytes are a little-endian float64
|
|
19
|
-
* 0x40 - next byte is start of Uint8Array
|
|
20
|
-
* 0x80 - false
|
|
21
|
-
* 0x81 - true
|
|
22
|
-
* 0x82 - undefined
|
|
23
|
-
* future - we should probably expand our understanding of types as follows
|
|
24
|
-
* REG_DWORD - integer
|
|
25
|
-
* REG_QWORD - bigint
|
|
26
|
-
* REG_NONE - treat as missing
|
|
27
|
-
*
|
|
28
|
-
* @author Wes Garland, wes@kingsds.network
|
|
29
|
-
* @date Jul 2020
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const regedit = require('regedit');
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
tree =
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* @file windows-registry.js
|
|
3
|
+
* Windows registry configuration/integration utility for DCP. All exported functions
|
|
4
|
+
* return false on non-Windows platforms.
|
|
5
|
+
*
|
|
6
|
+
* Basic idea: summarize registry into an objects which can be used as the
|
|
7
|
+
* initializer object for DCP Client and wallet cache. Multiple hives are read
|
|
8
|
+
* to support higher-priviledged overrides for Administrators writing Group
|
|
9
|
+
* Policy files in Enterprise installs.
|
|
10
|
+
*
|
|
11
|
+
* Note: In registry-speak, keys are like directories and values are like files -- i.e. a key can
|
|
12
|
+
* contain keys and/or values, but values cannot contain keys; only strings and numbers and stuff.
|
|
13
|
+
*
|
|
14
|
+
*
|
|
15
|
+
* future - we will need a better way to return registry values, current proposal is to use
|
|
16
|
+
* REG_BINARY to encode richer types thus:
|
|
17
|
+
* 0x00 - null
|
|
18
|
+
* 0x20 - next 8 bytes are a little-endian float64
|
|
19
|
+
* 0x40 - next byte is start of Uint8Array
|
|
20
|
+
* 0x80 - false
|
|
21
|
+
* 0x81 - true
|
|
22
|
+
* 0x82 - undefined
|
|
23
|
+
* future - we should probably expand our understanding of types as follows
|
|
24
|
+
* REG_DWORD - integer
|
|
25
|
+
* REG_QWORD - bigint
|
|
26
|
+
* REG_NONE - treat as missing
|
|
27
|
+
*
|
|
28
|
+
* @author Wes Garland, wes@kingsds.network
|
|
29
|
+
* @date Jul 2020
|
|
30
|
+
*/
|
|
31
|
+
'use strict';
|
|
32
|
+
|
|
33
|
+
const regedit = require('regedit');
|
|
34
|
+
exports.baseKey = process.env.DCP_REGISTRY_BASEKEY || 'Software\\Distributive';
|
|
35
|
+
|
|
36
|
+
/** Get all of the entries for a given key. Keys are returned in a property
|
|
37
|
+
* named keys. Values are returned in a property named values.
|
|
38
|
+
*/
|
|
39
|
+
async function getEntries(key) {
|
|
40
|
+
var entries = {};
|
|
41
|
+
|
|
42
|
+
return new Promise(function (resolve, reject) {
|
|
43
|
+
try {
|
|
44
|
+
let stream = regedit.list([key]);
|
|
45
|
+
|
|
46
|
+
stream.on('data', function(entry) {
|
|
47
|
+
entries[entry.key] = entry.data;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
stream.on('finish', function () {
|
|
51
|
+
resolve(entries);
|
|
52
|
+
})
|
|
53
|
+
} catch(e) {
|
|
54
|
+
reject(e);
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Get all of the keys for a given key */
|
|
60
|
+
async function getKeys(key) {
|
|
61
|
+
let entries = await getEntries(key);
|
|
62
|
+
return entries[key].keys || [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Get all of the values for a given key */
|
|
66
|
+
async function getValues(key) {
|
|
67
|
+
let entries = await getEntries(key);
|
|
68
|
+
return entries[key].values || {};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Returns true if a given key exists in the registry. Strange algorithm works
|
|
72
|
+
* around bugs in the npm regedit package.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} key The key to check, eg HKLM\\Software\\Kings Distributed Systems
|
|
75
|
+
* @returns Promise which resolves to boolean
|
|
76
|
+
*/
|
|
77
|
+
async function keyExists(key) {
|
|
78
|
+
var lhs, rhs;
|
|
79
|
+
|
|
80
|
+
for (rhs = key.split('\\'), lhs = rhs.splice(0,2).join('\\');
|
|
81
|
+
rhs.length;
|
|
82
|
+
lhs += '\\' + rhs.shift()) {
|
|
83
|
+
let subKeys = await getKeys(lhs);
|
|
84
|
+
if ((subKeys.map((a) => a.toUpperCase()).filter((a) => a === rhs[0].toUpperCase())).length === 0)
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Return the registry tree, including both keys and values, from the rootPath on down.
|
|
92
|
+
* keys are represented as JS objects, values are represented as JS values. For example,
|
|
93
|
+
* a registry with \\HKCU\KDS\dcp-client\scheduler\location = 'https://scheduler.kds.net'
|
|
94
|
+
* would become { 'dcp-client': scheduler: { location: 'https://scheduler.kds.net' } } if
|
|
95
|
+
* the rootPath were \\HKCU\KDS.
|
|
96
|
+
*
|
|
97
|
+
* @param {string} rootPath The registry key to traverse
|
|
98
|
+
* @param {object} tree [optional] the JS object to decorate with the registry tree
|
|
99
|
+
* @returns tree or a newly-created object
|
|
100
|
+
*/
|
|
101
|
+
async function regTree(rootPath, tree) {
|
|
102
|
+
var values;
|
|
103
|
+
|
|
104
|
+
if (arguments.length !== 2)
|
|
105
|
+
tree = {};
|
|
106
|
+
|
|
107
|
+
for (let path of await getKeys(rootPath)) {
|
|
108
|
+
tree[path] = {};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
for (let path in tree) {
|
|
112
|
+
await regTree(rootPath + '\\' + path, tree[path]);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
values = await getValues(rootPath);
|
|
116
|
+
for (let prop in values) {
|
|
117
|
+
tree[prop] = values[prop].value;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return tree;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get an object from the registry. This is can be a key or a tree. The object is identified
|
|
125
|
+
* by the hive, exports.baseKey, and the keyTail.
|
|
126
|
+
*
|
|
127
|
+
* @param {string} hive the hive to search (eg HKLM)
|
|
128
|
+
* @param {string} keyTail the end of the key
|
|
129
|
+
*
|
|
130
|
+
* @returns {Promise} that resolves to false (lookup miss), a registry tree, or a registry object from
|
|
131
|
+
* regTree().
|
|
132
|
+
*/
|
|
133
|
+
exports.getObject = async function dcpClient$$windowsRegistry$getObject(hive, keyTail) {
|
|
134
|
+
var tree = {};
|
|
135
|
+
|
|
136
|
+
keyTail = keyTail.replace(/\//g, '\\');
|
|
137
|
+
const key = `${hive}\\${exports.baseKey}\\${keyTail}`;
|
|
138
|
+
|
|
139
|
+
if (await keyExists(key))
|
|
140
|
+
await regTree(key, tree);
|
|
141
|
+
else
|
|
142
|
+
return false;
|
|
143
|
+
|
|
144
|
+
return tree;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Make all exported functions fast-path false return on non-windows */
|
|
148
|
+
if (require('os').platform() !== 'win32') {
|
|
149
|
+
for (let exp in exports) {
|
|
150
|
+
if (typeof exports[exp] === 'function') {
|
|
151
|
+
exports[exp] = function() { return false };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|