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.
- package/index.js +1 -1
- package/package.json +4 -3
- package/skills/roster-server/SKILL.md +6 -9
- package/vendor/greenlock-express/.prettierrc +7 -0
- package/vendor/greenlock-express/LICENSE +375 -0
- package/vendor/greenlock-express/README.md +536 -0
- package/vendor/greenlock-express/WALKTHROUGH.md +256 -0
- package/vendor/greenlock-express/config.js +20 -0
- package/vendor/greenlock-express/demo.js +35 -0
- package/vendor/greenlock-express/examples/cluster/package.json +12 -0
- package/vendor/greenlock-express/examples/express/my-express-app.js +17 -0
- package/vendor/greenlock-express/examples/express/package.json +12 -0
- package/vendor/greenlock-express/examples/http/package.json +12 -0
- package/vendor/greenlock-express/examples/http-proxy/package.json +12 -0
- package/vendor/greenlock-express/examples/http2/package.json +12 -0
- package/vendor/greenlock-express/examples/https/package.json +12 -0
- package/vendor/greenlock-express/examples/quickstart/README.md +22 -0
- package/vendor/greenlock-express/examples/quickstart/package.json +12 -0
- package/vendor/greenlock-express/examples/socket.io/package.json +12 -0
- package/vendor/greenlock-express/examples/websockets/package.json +12 -0
- package/vendor/greenlock-express/greenlock-express.js +48 -0
- package/vendor/greenlock-express/greenlock-shim.js +72 -0
- package/vendor/greenlock-express/http-middleware.js +154 -0
- package/vendor/greenlock-express/https-middleware.js +139 -0
- package/vendor/greenlock-express/install.sh +14 -0
- package/vendor/greenlock-express/lib/compat.js +37 -0
- package/vendor/greenlock-express/main.js +32 -0
- package/vendor/greenlock-express/master.js +164 -0
- package/vendor/greenlock-express/package-lock.json +149 -0
- package/vendor/greenlock-express/package.json +51 -0
- package/vendor/greenlock-express/scripts/postinstall +77 -0
- package/vendor/greenlock-express/servers.js +171 -0
- package/vendor/greenlock-express/single.js +36 -0
- package/vendor/greenlock-express/sni.js +215 -0
- 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
|
+
}
|