roster-server 1.9.6 → 2.0.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.
Files changed (36) hide show
  1. package/README.md +8 -0
  2. package/index.js +1 -1
  3. package/package.json +4 -3
  4. package/skills/roster-server/SKILL.md +257 -0
  5. package/vendor/greenlock-express/.prettierrc +7 -0
  6. package/vendor/greenlock-express/LICENSE +375 -0
  7. package/vendor/greenlock-express/README.md +536 -0
  8. package/vendor/greenlock-express/WALKTHROUGH.md +256 -0
  9. package/vendor/greenlock-express/config.js +20 -0
  10. package/vendor/greenlock-express/demo.js +35 -0
  11. package/vendor/greenlock-express/examples/cluster/package.json +12 -0
  12. package/vendor/greenlock-express/examples/express/my-express-app.js +17 -0
  13. package/vendor/greenlock-express/examples/express/package.json +12 -0
  14. package/vendor/greenlock-express/examples/http/package.json +12 -0
  15. package/vendor/greenlock-express/examples/http-proxy/package.json +12 -0
  16. package/vendor/greenlock-express/examples/http2/package.json +12 -0
  17. package/vendor/greenlock-express/examples/https/package.json +12 -0
  18. package/vendor/greenlock-express/examples/quickstart/README.md +22 -0
  19. package/vendor/greenlock-express/examples/quickstart/package.json +12 -0
  20. package/vendor/greenlock-express/examples/socket.io/package.json +12 -0
  21. package/vendor/greenlock-express/examples/websockets/package.json +12 -0
  22. package/vendor/greenlock-express/greenlock-express.js +48 -0
  23. package/vendor/greenlock-express/greenlock-shim.js +72 -0
  24. package/vendor/greenlock-express/http-middleware.js +154 -0
  25. package/vendor/greenlock-express/https-middleware.js +139 -0
  26. package/vendor/greenlock-express/install.sh +14 -0
  27. package/vendor/greenlock-express/lib/compat.js +37 -0
  28. package/vendor/greenlock-express/main.js +32 -0
  29. package/vendor/greenlock-express/master.js +164 -0
  30. package/vendor/greenlock-express/package-lock.json +149 -0
  31. package/vendor/greenlock-express/package.json +51 -0
  32. package/vendor/greenlock-express/scripts/postinstall +77 -0
  33. package/vendor/greenlock-express/servers.js +171 -0
  34. package/vendor/greenlock-express/single.js +36 -0
  35. package/vendor/greenlock-express/sni.js +215 -0
  36. package/vendor/greenlock-express/worker.js +73 -0
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+
3
+ var HttpMiddleware = module.exports;
4
+ var servernameRe = /^[a-z0-9\.\-]+$/i;
5
+ var challengePrefix = "/.well-known/acme-challenge/";
6
+
7
+ HttpMiddleware.create = function(gl, defaultApp) {
8
+ if (defaultApp && "function" !== typeof defaultApp) {
9
+ throw new Error("use greenlock.httpMiddleware() or greenlock.httpMiddleware(function (req, res) {})");
10
+ }
11
+
12
+ return function(req, res, next) {
13
+ var hostname = HttpMiddleware.sanitizeHostname(req);
14
+
15
+ req.on("error", function(err) {
16
+ explainError(gl, err, "http_01_middleware_socket", hostname);
17
+ });
18
+
19
+ // Skip unless the path begins with /.well-known/acme-challenge/
20
+ if (!hostname || 0 !== req.url.indexOf(challengePrefix)) {
21
+ skipChallenge(req, res, next, defaultApp);
22
+ return;
23
+ }
24
+
25
+ // HEADERS SENT DEBUG NOTE #2
26
+ // at this point, it's most likely Let's Encrypt server
27
+ // (or greenlock itself) performing the verification process
28
+ // Hmmm... perhaps we should change the greenlock prefix to test
29
+ // Anyway, we just got fast the first place where we could
30
+ // be sending headers.
31
+
32
+ var token = req.url.slice(challengePrefix.length);
33
+
34
+ var done = false;
35
+ var countA = 0;
36
+ var countB = 0;
37
+ gl.getAcmeHttp01ChallengeResponse({ type: "http-01", servername: hostname, token: token })
38
+ .catch(function(err) {
39
+ countA += 1;
40
+ // HEADERS SENT DEBUG NOTE #3
41
+ // This is the second possible time we could be sending headers
42
+ respondToError(gl, res, err, "http_01_middleware_challenge_response", hostname);
43
+ done = true;
44
+ return { __done: true };
45
+ })
46
+ .then(function(result) {
47
+ countB += 1;
48
+ if (result && result.__done) {
49
+ return;
50
+ }
51
+ if (done) {
52
+ console.error("Sanity check fail: `done` is in a quantum state of both true and false... huh?");
53
+ return;
54
+ }
55
+ // HEADERS SENT DEBUG NOTE #4b
56
+ // This is the third/fourth possible time send headers
57
+ return respondWithGrace(res, result, hostname, token);
58
+ })
59
+ .catch(function(err) {
60
+ // HEADERS SENT DEBUG NOTE #5
61
+ // I really don't see how this can be possible.
62
+ // Every case appears to be accounted for
63
+ console.error();
64
+ console.error("[warning] Developer Error:" + (err.code || err.context || ""), countA, countB);
65
+ console.error(err.stack);
66
+ console.error();
67
+ console.error(
68
+ "This is probably the error that happens routinely on http2 connections, but we're not sure why."
69
+ );
70
+ console.error("To track the status or help contribute,");
71
+ console.error("visit: https://git.rootprojects.org/root/greenlock-express.js/issues/9");
72
+ console.error();
73
+ try {
74
+ res.end("Internal Server Error [1003]: See logs for details.");
75
+ } catch (e) {
76
+ // ignore
77
+ }
78
+ });
79
+ };
80
+ };
81
+
82
+ function skipChallenge(req, res, next, defaultApp) {
83
+ if ("function" === typeof defaultApp) {
84
+ defaultApp(req, res, next);
85
+ } else if ("function" === typeof next) {
86
+ next();
87
+ } else {
88
+ res.statusCode = 500;
89
+ res.end("[500] Developer Error: app.use('/', greenlock.httpMiddleware()) or greenlock.httpMiddleware(app)");
90
+ }
91
+ }
92
+
93
+ function respondWithGrace(res, result, hostname, token) {
94
+ var keyAuth = result && result.keyAuthorization;
95
+
96
+ // HEADERS SENT DEBUG NOTE #4b
97
+ // This is (still) the third/fourth possible time we could be sending headers
98
+ if (keyAuth && "string" === typeof keyAuth) {
99
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
100
+ res.end(keyAuth);
101
+ return;
102
+ }
103
+
104
+ res.statusCode = 404;
105
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
106
+ res.end(JSON.stringify({ error: { message: "domain '" + hostname + "' has no token '" + token + "'." } }));
107
+ }
108
+
109
+ function explainError(gl, err, ctx, hostname) {
110
+ if (!err.servername) {
111
+ err.servername = hostname;
112
+ }
113
+ if (!err.context) {
114
+ err.context = ctx;
115
+ }
116
+ // leaving this in the build for now because it will help with existing error reports
117
+ console.error("[warning] network connection error:", (err.context || "") + " " + err.message);
118
+ (gl.notify || gl._notify)("error", err);
119
+ return err;
120
+ }
121
+
122
+ function respondToError(gl, res, err, ctx, hostname) {
123
+ // HEADERS SENT DEBUG NOTE #3b
124
+ // This is (still) the second possible time we could be sending headers
125
+ err = explainError(gl, err, ctx, hostname);
126
+ res.statusCode = 500;
127
+ res.end("Internal Server Error [1004]: See logs for details.");
128
+ }
129
+
130
+ HttpMiddleware.getHostname = function(req) {
131
+ return req.hostname || req.headers["x-forwarded-host"] || (req.headers.host || "");
132
+ };
133
+ HttpMiddleware.sanitizeHostname = function(req) {
134
+ // we can trust XFH because spoofing causes no ham in this limited use-case scenario
135
+ // (and only telebit would be legitimately setting XFH)
136
+ var servername = HttpMiddleware.getHostname(req)
137
+ .toLowerCase()
138
+ .replace(/:.*/, "");
139
+ try {
140
+ req.hostname = servername;
141
+ } catch (e) {
142
+ // read-only express property
143
+ }
144
+ if (req.headers["x-forwarded-host"]) {
145
+ req.headers["x-forwarded-host"] = servername;
146
+ }
147
+ try {
148
+ req.headers.host = servername;
149
+ } catch (e) {
150
+ // TODO is this a possible error?
151
+ }
152
+
153
+ return (servernameRe.test(servername) && -1 === servername.indexOf("..") && servername) || "";
154
+ };
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+
3
+ var SanitizeHost = module.exports;
4
+ var HttpMiddleware = require("./http-middleware.js");
5
+
6
+ SanitizeHost.create = function(gl, app) {
7
+ return function(req, res, next) {
8
+ function realNext() {
9
+ if ("function" === typeof app) {
10
+ app(req, res);
11
+ } else if ("function" === typeof next) {
12
+ next();
13
+ } else {
14
+ res.statusCode = 500;
15
+ res.end("Error: no middleware assigned");
16
+ }
17
+ }
18
+
19
+ var hostname = HttpMiddleware.getHostname(req);
20
+ // Replace the hostname, and get the safe version
21
+ var safehost = HttpMiddleware.sanitizeHostname(req);
22
+
23
+ // if no hostname, move along
24
+ if (!hostname) {
25
+ realNext();
26
+ return;
27
+ }
28
+
29
+ // if there were unallowed characters, complain
30
+ if (safehost.length !== hostname.length) {
31
+ res.statusCode = 400;
32
+ res.end("Malformed HTTP Header: 'Host: " + hostname + "'");
33
+ return;
34
+ }
35
+
36
+ // Note: This sanitize function is also called on plain sockets, which don't need Domain Fronting checks
37
+ if (req.socket.encrypted) {
38
+ if (req.socket && "string" === typeof req.socket.servername) {
39
+ // Workaround for https://github.com/nodejs/node/issues/22389
40
+ if (!SanitizeHost._checkServername(safehost, req.socket)) {
41
+ res.statusCode = 400;
42
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
43
+ res.end(
44
+ "<h1>Domain Fronting Error</h1>" +
45
+ "<p>This connection was secured using TLS/SSL for '" +
46
+ (req.socket.servername || "").toLowerCase() +
47
+ "'</p>" +
48
+ "<p>The HTTP request specified 'Host: " +
49
+ safehost +
50
+ "', which is (obviously) different.</p>" +
51
+ "<p>Because this looks like a domain fronting attack, the connection has been terminated.</p>"
52
+ );
53
+ return;
54
+ }
55
+ }
56
+ /*
57
+ else if (safehost && !gl._skip_fronting_check) {
58
+
59
+ // We used to print a log message here, but it turns out that it's
60
+ // really common for IoT devices to not use SNI (as well as many bots
61
+ // and such).
62
+ // It was common for the log message to pop up as the first request
63
+ // to the server, and that was confusing. So instead now we do nothing.
64
+
65
+ //console.warn("no string for req.socket.servername," + " skipping fronting check for '" + safehost + "'");
66
+ //gl._skip_fronting_check = true;
67
+ }
68
+ */
69
+ }
70
+
71
+ // carry on
72
+ realNext();
73
+ };
74
+ };
75
+
76
+ var warnDomainFronting = true;
77
+ var warnUnexpectedError = true;
78
+ SanitizeHost._checkServername = function(safeHost, tlsSocket) {
79
+ var servername = (tlsSocket.servername || "").toLowerCase();
80
+
81
+ // acceptable: older IoT devices may lack SNI support
82
+ if (!servername) {
83
+ return true;
84
+ }
85
+ // acceptable: odd... but acceptable
86
+ if (!safeHost) {
87
+ return true;
88
+ }
89
+ if (safeHost === servername) {
90
+ return true;
91
+ }
92
+
93
+ if ("function" !== typeof tlsSocket.getCertificate) {
94
+ // domain fronting attacks allowed
95
+ if (warnDomainFronting) {
96
+ // https://github.com/nodejs/node/issues/24095
97
+ console.warn(
98
+ "Warning: node " +
99
+ process.version +
100
+ " is vulnerable to domain fronting attacks. Please use node v11.2.0 or greater."
101
+ );
102
+ warnDomainFronting = false;
103
+ }
104
+ return true;
105
+ }
106
+
107
+ // connection established with servername and session is re-used for allowed name
108
+ // See https://github.com/nodejs/node/issues/24095
109
+ var cert = tlsSocket.getCertificate();
110
+ try {
111
+ // TODO optimize / cache?
112
+ // *should* always have a string, right?
113
+ // *should* always be lowercase already, right?
114
+ //console.log(safeHost, cert.subject.CN, cert.subjectaltname);
115
+ var isSubject = (cert.subject.CN || "").toLowerCase() === safeHost;
116
+ if (isSubject) {
117
+ return true;
118
+ }
119
+
120
+ var dnsnames = (cert.subjectaltname || "").split(/,\s+/);
121
+ var inSanList = dnsnames.some(function(name) {
122
+ // always prefixed with "DNS:"
123
+ return safeHost === name.slice(4).toLowerCase();
124
+ });
125
+
126
+ if (inSanList) {
127
+ return true;
128
+ }
129
+ } catch (e) {
130
+ // not sure what else to do in this situation...
131
+ if (warnUnexpectedError) {
132
+ console.warn("Warning: encoutered error while performing domain fronting check: " + e.message);
133
+ warnUnexpectedError = false;
134
+ }
135
+ return true;
136
+ }
137
+
138
+ return false;
139
+ };
@@ -0,0 +1,14 @@
1
+ # This is just an example (but it works)
2
+ export NODE_PATH=$NPM_CONFIG_PREFIX/lib/node_modules
3
+ export NPM_CONFIG_PREFIX=/opt/node
4
+ curl -fsSL https://bit.ly/node-installer | bash
5
+
6
+ /opt/node/bin/node /opt/node/bin/npm config set scripts-prepend-node-path true
7
+ /opt/node/bin/node /opt/node/bin/npm ci
8
+ sudo setcap 'cap_net_bind_service=+ep' /opt/node/bin/node
9
+ /opt/node/bin/node /opt/node/bin/npm start
10
+
11
+ sudo rsync -av dist/etc/systemd/system/greenlock-express.service /etc/systemd/system/
12
+ sudo systemctl daemon-reload
13
+
14
+ sudo systemctl restart greenlock-express
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ function requireBluebird() {
4
+ try {
5
+ return require("bluebird");
6
+ } catch (e) {
7
+ console.error("");
8
+ console.error("DON'T PANIC. You're running an old version of node with incomplete Promise support.");
9
+ console.error("EASY FIX: `npm install --save bluebird`");
10
+ console.error("");
11
+ throw e;
12
+ }
13
+ }
14
+
15
+ if ("undefined" === typeof Promise) {
16
+ global.Promise = requireBluebird();
17
+ }
18
+
19
+ if ("function" !== typeof require("util").promisify) {
20
+ require("util").promisify = requireBluebird().promisify;
21
+ }
22
+
23
+ if (!console.debug) {
24
+ console.debug = console.log;
25
+ }
26
+
27
+ var fs = require("fs");
28
+ var fsAsync = {};
29
+ Object.keys(fs).forEach(function(key) {
30
+ var fn = fs[key];
31
+ if ("function" !== typeof fn || !/[a-z]/.test(key[0])) {
32
+ return;
33
+ }
34
+ fsAsync[key] = require("util").promisify(fn);
35
+ });
36
+
37
+ exports.fsAsync = fsAsync;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ // this is the stuff that should run in the main foreground process,
4
+ // whether it's single or master
5
+
6
+ var major = parseInt(process.versions.node.split(".")[0], 10);
7
+ var minor = parseInt(process.versions.node.split(".")[1], 10) || 0;
8
+ var _hasSetSecureContext = false;
9
+ var shouldUpgrade = false;
10
+
11
+ // this applies to http2 as well (should exist in both or neither)
12
+ _hasSetSecureContext = major > 11 || (major === 11 && minor >= 2);
13
+
14
+ // TODO document in issues
15
+ if (!_hasSetSecureContext) {
16
+ // TODO this isn't necessary if greenlock options are set with options.cert
17
+ console.warn("Warning: node " + process.version + " is missing tlsSocket.setSecureContext().");
18
+ console.warn(" The default certificate may not be set.");
19
+ shouldUpgrade = true;
20
+ }
21
+
22
+ if (major < 11 || (11 === major && minor < 2)) {
23
+ // https://github.com/nodejs/node/issues/24095
24
+ console.warn("Warning: node " + process.version + " is missing tlsSocket.getCertificate().");
25
+ console.warn(" This is necessary to guard against domain fronting attacks.");
26
+ shouldUpgrade = true;
27
+ }
28
+
29
+ if (shouldUpgrade) {
30
+ console.warn("Warning: Please upgrade to node v11.2.0 or greater.");
31
+ console.warn();
32
+ }
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+
3
+ require("./main.js");
4
+
5
+ var Master = module.exports;
6
+
7
+ var cluster = require("cluster");
8
+ var os = require("os");
9
+ var msgPrefix = "greenlock:";
10
+
11
+ Master.create = function(opts) {
12
+ var resolveCb;
13
+ var _readyCb;
14
+ var _kicked = false;
15
+
16
+ var greenlock = require("./greenlock-shim.js").create(opts);
17
+
18
+ var ready = new Promise(function(resolve) {
19
+ resolveCb = resolve;
20
+ }).then(function(fn) {
21
+ _readyCb = fn;
22
+ return fn;
23
+ });
24
+
25
+ function kickoff() {
26
+ if (_kicked) {
27
+ return;
28
+ }
29
+ _kicked = true;
30
+
31
+ Master._spawnWorkers(opts, greenlock);
32
+
33
+ ready.then(function(fn) {
34
+ // not sure what this API should be yet
35
+ fn();
36
+ });
37
+ }
38
+
39
+ var master = {
40
+ ready: function() {
41
+ kickoff();
42
+ return master;
43
+ },
44
+ master: function(fn) {
45
+ if (_readyCb) {
46
+ throw new Error("can't call master twice");
47
+ }
48
+ kickoff();
49
+ resolveCb(fn);
50
+ return master;
51
+ },
52
+ serve: function(fn) {
53
+ // ignore
54
+ master.ready(fn);
55
+ }
56
+ };
57
+ return master;
58
+ };
59
+
60
+ function range(n) {
61
+ n = parseInt(n, 10);
62
+ if (!n) {
63
+ return [];
64
+ }
65
+ return new Array(n).join(",").split(",");
66
+ }
67
+
68
+ Master._spawnWorkers = function(opts, greenlock) {
69
+ var numCpus = parseInt(process.env.NUMBER_OF_PROCESSORS, 10) || os.cpus().length;
70
+
71
+ // process rpc messages
72
+ // start when dead
73
+ var numWorkers = parseInt(opts.workers || opts.numWorkers, 10);
74
+ if (!numWorkers) {
75
+ if (numCpus <= 2) {
76
+ numWorkers = 2;
77
+ } else {
78
+ numWorkers = numCpus - 1;
79
+ }
80
+ }
81
+
82
+ cluster.once("exit", function() {
83
+ setTimeout(function() {
84
+ process.exit(3);
85
+ }, 100);
86
+ });
87
+
88
+ var workers = range(numWorkers);
89
+ function next() {
90
+ if (!workers.length) {
91
+ return;
92
+ }
93
+ workers.pop();
94
+
95
+ // for a nice aesthetic
96
+ setTimeout(function() {
97
+ Master._spawnWorker(opts, greenlock);
98
+ next();
99
+ }, 250);
100
+ }
101
+
102
+ next();
103
+ };
104
+
105
+ Master._spawnWorker = function(opts, greenlock) {
106
+ var w = cluster.fork();
107
+ // automatically added to master's `cluster.workers`
108
+ w.once("exit", function(code, signal) {
109
+ // TODO handle failures
110
+ // Should test if the first starts successfully
111
+ // Should exit if failures happen too quickly
112
+
113
+ // For now just kill all when any die
114
+ if (signal) {
115
+ console.error("worker was killed by signal:", signal);
116
+ } else if (code !== 0) {
117
+ console.error("worker exited with error code:", code);
118
+ } else {
119
+ console.error("worker unexpectedly quit without exit code or signal");
120
+ }
121
+ process.exit(2);
122
+
123
+ //addWorker();
124
+ });
125
+
126
+ function handleMessage(msg) {
127
+ if (0 !== (msg._id || "").indexOf(msgPrefix)) {
128
+ return;
129
+ }
130
+ if ("string" !== typeof msg._funcname) {
131
+ // TODO developer error
132
+ return;
133
+ }
134
+
135
+ function rpc() {
136
+ return greenlock[msg._funcname](msg._input)
137
+ .then(function(result) {
138
+ w.send({
139
+ _id: msg._id,
140
+ _result: result
141
+ });
142
+ })
143
+ .catch(function(e) {
144
+ var error = new Error(e.message);
145
+ Object.getOwnPropertyNames(e).forEach(function(k) {
146
+ error[k] = e[k];
147
+ });
148
+ w.send({
149
+ _id: msg._id,
150
+ _error: error
151
+ });
152
+ });
153
+ }
154
+
155
+ try {
156
+ rpc();
157
+ } catch (e) {
158
+ console.error("Unexpected and uncaught greenlock." + msg._funcname + " error:");
159
+ console.error(e);
160
+ }
161
+ }
162
+
163
+ w.on("message", handleMessage);
164
+ };