roster-server 1.9.8 → 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 (35) hide show
  1. package/index.js +1 -1
  2. package/package.json +4 -3
  3. package/skills/roster-server/SKILL.md +6 -9
  4. package/vendor/greenlock-express/.prettierrc +7 -0
  5. package/vendor/greenlock-express/LICENSE +375 -0
  6. package/vendor/greenlock-express/README.md +536 -0
  7. package/vendor/greenlock-express/WALKTHROUGH.md +256 -0
  8. package/vendor/greenlock-express/config.js +20 -0
  9. package/vendor/greenlock-express/demo.js +35 -0
  10. package/vendor/greenlock-express/examples/cluster/package.json +12 -0
  11. package/vendor/greenlock-express/examples/express/my-express-app.js +17 -0
  12. package/vendor/greenlock-express/examples/express/package.json +12 -0
  13. package/vendor/greenlock-express/examples/http/package.json +12 -0
  14. package/vendor/greenlock-express/examples/http-proxy/package.json +12 -0
  15. package/vendor/greenlock-express/examples/http2/package.json +12 -0
  16. package/vendor/greenlock-express/examples/https/package.json +12 -0
  17. package/vendor/greenlock-express/examples/quickstart/README.md +22 -0
  18. package/vendor/greenlock-express/examples/quickstart/package.json +12 -0
  19. package/vendor/greenlock-express/examples/socket.io/package.json +12 -0
  20. package/vendor/greenlock-express/examples/websockets/package.json +12 -0
  21. package/vendor/greenlock-express/greenlock-express.js +48 -0
  22. package/vendor/greenlock-express/greenlock-shim.js +72 -0
  23. package/vendor/greenlock-express/http-middleware.js +154 -0
  24. package/vendor/greenlock-express/https-middleware.js +139 -0
  25. package/vendor/greenlock-express/install.sh +14 -0
  26. package/vendor/greenlock-express/lib/compat.js +37 -0
  27. package/vendor/greenlock-express/main.js +32 -0
  28. package/vendor/greenlock-express/master.js +164 -0
  29. package/vendor/greenlock-express/package-lock.json +149 -0
  30. package/vendor/greenlock-express/package.json +51 -0
  31. package/vendor/greenlock-express/scripts/postinstall +77 -0
  32. package/vendor/greenlock-express/servers.js +171 -0
  33. package/vendor/greenlock-express/single.js +36 -0
  34. package/vendor/greenlock-express/sni.js +215 -0
  35. package/vendor/greenlock-express/worker.js +73 -0
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+
3
+ var sni = module.exports;
4
+ var tls = require("tls");
5
+ var servernameRe = /^[a-z0-9\.\-]+$/i;
6
+
7
+ // a nice, round, irrational number - about every 6¼ hours
8
+ var refreshOffset = Math.round(Math.PI * 2 * (60 * 60 * 1000));
9
+ // and another, about 15 minutes
10
+ var refreshStagger = Math.round(Math.PI * 5 * (60 * 1000));
11
+ // and another, about 30 seconds
12
+ var smallStagger = Math.round(Math.PI * (30 * 1000));
13
+
14
+ //secureOpts.SNICallback = sni.create(greenlock, secureOpts);
15
+ sni.create = function(greenlock, secureOpts) {
16
+ var _cache = {};
17
+ var defaultServername = greenlock.servername || "";
18
+
19
+ if (secureOpts.cert) {
20
+ // Note: it's fine if greenlock.servername is undefined,
21
+ // but if the caller wants this to auto-renew, they should define it
22
+ _cache[defaultServername] = {
23
+ refreshAt: 0,
24
+ secureContext: tls.createSecureContext(secureOpts)
25
+ };
26
+ }
27
+
28
+ return getSecureContext;
29
+
30
+ function notify(ev, args) {
31
+ try {
32
+ // TODO _notify() or notify()?
33
+ (greenlock.notify || greenlock._notify)(ev, args);
34
+ } catch (e) {
35
+ console.error(e);
36
+ console.error(ev, args);
37
+ }
38
+ }
39
+
40
+ function getSecureContext(servername, cb) {
41
+ //console.log("debug sni", servername);
42
+ if ("string" !== typeof servername) {
43
+ // this will never happen... right? but stranger things have...
44
+ console.error("[sanity fail] non-string servername:", servername);
45
+ cb(new Error("invalid servername"), null);
46
+ return;
47
+ }
48
+
49
+ var secureContext = getCachedContext(servername);
50
+ if (secureContext) {
51
+ //console.log("debug sni got cached context", servername, getCachedMeta(servername));
52
+ cb(null, secureContext);
53
+ return;
54
+ }
55
+
56
+ getFreshContext(servername)
57
+ .then(function(secureContext) {
58
+ if (secureContext) {
59
+ //console.log("debug sni got fresh context", servername, getCachedMeta(servername));
60
+ cb(null, secureContext);
61
+ return;
62
+ }
63
+
64
+ // Note: this does not replace tlsSocket.setSecureContext()
65
+ // as it only works when SNI has been sent
66
+ //console.log("debug sni got default context", servername, getCachedMeta(servername));
67
+ if (!/PROD/.test(process.env.ENV) || /DEV|STAG/.test(process.env.ENV)) {
68
+ // Change this once
69
+ // A) the 'notify' message passing is verified fixed in cluster mode
70
+ // B) we have a good way to let people know their server isn't configured
71
+ console.debug("debug: ignoring servername " + JSON.stringify(servername));
72
+ console.debug(" (it's probably either missing from your config, or a bot)");
73
+ notify("servername_unknown", {
74
+ servername: servername
75
+ });
76
+ }
77
+ cb(null, getDefaultContext());
78
+ })
79
+ .catch(function(err) {
80
+ if (!err.context) {
81
+ err.context = "sni_callback";
82
+ }
83
+ notify("error", err);
84
+ //console.log("debug sni error", servername, err);
85
+ cb(err);
86
+ });
87
+ }
88
+
89
+ function getCachedMeta(servername) {
90
+ var meta = _cache[servername];
91
+ if (!meta) {
92
+ if (!_cache[wildname(servername)]) {
93
+ return null;
94
+ }
95
+ }
96
+ return meta;
97
+ }
98
+
99
+ function getCachedContext(servername) {
100
+ var meta = getCachedMeta(servername);
101
+ if (!meta) {
102
+ return null;
103
+ }
104
+
105
+ // always renew in background
106
+ if (!meta.refreshAt || Date.now() >= meta.refreshAt) {
107
+ getFreshContext(servername).catch(function(e) {
108
+ if (!e.context) {
109
+ e.context = "sni_background_refresh";
110
+ }
111
+ notify("error", e);
112
+ });
113
+ }
114
+
115
+ // under normal circumstances this would never be expired
116
+ // and, if it is expired, something is so wrong it's probably
117
+ // not worth wating for the renewal - it has probably failed
118
+ return meta.secureContext;
119
+ }
120
+
121
+ function getFreshContext(servername) {
122
+ var meta = getCachedMeta(servername);
123
+ if (!meta && !validServername(servername)) {
124
+ if ((servername && !/PROD/.test(process.env.ENV)) || /DEV|STAG/.test(process.env.ENV)) {
125
+ // Change this once
126
+ // A) the 'notify' message passing is verified fixed in cluster mode
127
+ // B) we have a good way to let people know their server isn't configured
128
+ console.debug("debug: invalid servername " + JSON.stringify(servername));
129
+ console.debug(" (it's probably just a bot trolling for vulnerable servers)");
130
+ notify("servername_invalid", {
131
+ servername: servername
132
+ });
133
+ }
134
+ return Promise.resolve(null);
135
+ }
136
+
137
+ if (meta) {
138
+ // prevent stampedes
139
+ meta.refreshAt = Date.now() + randomRefreshOffset();
140
+ }
141
+
142
+ // TODO don't get unknown certs at all, rely on auto-updates from greenlock
143
+ // Note: greenlock.get() will return an existing fresh cert or issue a new one
144
+ return greenlock.get({ servername: servername }).then(function(result) {
145
+ var meta = getCachedMeta(servername);
146
+ if (!meta) {
147
+ meta = _cache[servername] = { secureContext: { _valid: false } };
148
+ }
149
+ // prevent from being punked by bot trolls
150
+ meta.refreshAt = Date.now() + smallStagger;
151
+
152
+ // nothing to do
153
+ if (!result) {
154
+ return null;
155
+ }
156
+
157
+ // we only care about the first one
158
+ var pems = result.pems;
159
+ var site = result.site;
160
+ if (!pems || !pems.cert) {
161
+ // nothing to do
162
+ // (and the error should have been reported already)
163
+ return null;
164
+ }
165
+
166
+ meta = {
167
+ refreshAt: Date.now() + randomRefreshOffset(),
168
+ secureContext: tls.createSecureContext({
169
+ // TODO support passphrase-protected privkeys
170
+ key: pems.privkey,
171
+ cert: pems.cert + "\n" + pems.chain + "\n"
172
+ })
173
+ };
174
+ meta.secureContext._valid = true;
175
+
176
+ // copy this same object into every place
177
+ (result.altnames || site.altnames || [result.subject || site.subject]).forEach(function(altname) {
178
+ _cache[altname] = meta;
179
+ });
180
+
181
+ return meta.secureContext;
182
+ });
183
+ }
184
+
185
+ function getDefaultContext() {
186
+ return getCachedContext(defaultServername);
187
+ }
188
+ };
189
+
190
+ // whenever we need to know when to refresh next
191
+ function randomRefreshOffset() {
192
+ var stagger = Math.round(refreshStagger / 2) - Math.round(Math.random() * refreshStagger);
193
+ return refreshOffset + stagger;
194
+ }
195
+
196
+ function validServername(servername) {
197
+ // format and (lightly) sanitize sni so that users can be naive
198
+ // and not have to worry about SQL injection or fs discovery
199
+
200
+ servername = (servername || "").toLowerCase();
201
+ // hostname labels allow a-z, 0-9, -, and are separated by dots
202
+ // _ is sometimes allowed, but not as a "hostname", and not by Let's Encrypt ACME
203
+ // REGEX // https://www.codeproject.com/Questions/1063023/alphanumeric-validation-javascript-without-regex
204
+ return servernameRe.test(servername) && -1 === servername.indexOf("..");
205
+ }
206
+
207
+ function wildname(servername) {
208
+ return (
209
+ "*." +
210
+ servername
211
+ .split(".")
212
+ .slice(1)
213
+ .join(".")
214
+ );
215
+ }
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+
3
+ var Worker = module.exports;
4
+ // *very* generous, but well below the http norm of 120
5
+ var messageTimeout = 30 * 1000;
6
+ var msgPrefix = "greenlock:";
7
+
8
+ Worker.create = function() {
9
+ var greenlock = {};
10
+ ["getAcmeHttp01ChallengeResponse", "get", "notify", "_notify"].forEach(function(k) {
11
+ greenlock[k] = function(args) {
12
+ return rpc(k, args);
13
+ };
14
+ });
15
+
16
+ var worker = {
17
+ ready: function(fn) {
18
+ var servers = require("./servers.js").create(greenlock);
19
+ fn(servers);
20
+ return worker;
21
+ },
22
+ master: function() {
23
+ // ignore
24
+ return worker;
25
+ },
26
+ serve: function(fn) {
27
+ // keeping backwards compat
28
+ if (1 === fn.length) {
29
+ worker.ready(fn);
30
+ return;
31
+ }
32
+ // serving the express app, right away
33
+ worker.ready(function(glx) {
34
+ glx.serveApp(fn);
35
+ });
36
+ }
37
+ };
38
+ return worker;
39
+ };
40
+
41
+ function rpc(funcname, msg) {
42
+ return new Promise(function(resolve, reject) {
43
+ var rnd = Math.random()
44
+ .toString()
45
+ .slice(2)
46
+ .toString(16);
47
+ var id = msgPrefix + rnd;
48
+ var timeout;
49
+
50
+ function getResponse(msg) {
51
+ if (msg._id !== id) {
52
+ return;
53
+ }
54
+ process.removeListener("message", getResponse);
55
+ clearTimeout(timeout);
56
+ resolve(msg._result);
57
+ }
58
+
59
+ // TODO keep a single listener than just responds
60
+ // via a collection of callbacks? or leave as is?
61
+ process.on("message", getResponse);
62
+ process.send({
63
+ _id: id,
64
+ _funcname: funcname,
65
+ _input: msg
66
+ });
67
+
68
+ timeout = setTimeout(function() {
69
+ process.removeListener("message", getResponse);
70
+ reject(new Error("worker rpc request timeout"));
71
+ }, messageTimeout);
72
+ });
73
+ }