roster-server 2.2.10 → 2.2.12
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/package.json +12 -3
- package/tasks/lessons.md +1 -0
- package/vendor/greenlock/.prettierrc +8 -0
- package/vendor/greenlock/LICENSE +312 -0
- package/vendor/greenlock/MIGRATION_GUIDE.md +403 -0
- package/vendor/greenlock/README.md +667 -0
- package/vendor/greenlock/accounts.js +218 -0
- package/vendor/greenlock/bin/add.js +72 -0
- package/vendor/greenlock/bin/certonly.js +368 -0
- package/vendor/greenlock/bin/config.js +77 -0
- package/vendor/greenlock/bin/defaults.js +58 -0
- package/vendor/greenlock/bin/greenlock.js +26 -0
- package/vendor/greenlock/bin/init.js +159 -0
- package/vendor/greenlock/bin/lib/cli.js +230 -0
- package/vendor/greenlock/bin/lib/flags.js +385 -0
- package/vendor/greenlock/bin/remove.js +46 -0
- package/vendor/greenlock/bin/tmpl/app.tmpl.js +9 -0
- package/vendor/greenlock/bin/tmpl/cluster.tmpl.js +30 -0
- package/vendor/greenlock/bin/tmpl/greenlock.tmpl.js +13 -0
- package/vendor/greenlock/bin/tmpl/server.tmpl.js +20 -0
- package/vendor/greenlock/bin/update.js +62 -0
- package/vendor/greenlock/certificates.js +324 -0
- package/vendor/greenlock/errors.js +58 -0
- package/vendor/greenlock/greenlock.js +621 -0
- package/vendor/greenlock/greenlockrc.js +169 -0
- package/vendor/greenlock/lib/challenges-wrapper.js +88 -0
- package/vendor/greenlock/lib/directory-url.js +44 -0
- package/vendor/greenlock/lib/init.js +191 -0
- package/vendor/greenlock/lib/manager-wrapper.js +625 -0
- package/vendor/greenlock/lib/rc.js +70 -0
- package/vendor/greenlock/logo/beaker-browser-301x112.png +0 -0
- package/vendor/greenlock/logo/from-not-secure-to-secure-url-bar.png +0 -0
- package/vendor/greenlock/logo/greenlock-1063x250.png +0 -0
- package/vendor/greenlock/logo/greenlock-850x200.png +0 -0
- package/vendor/greenlock/logo/ibm-301x112.png +0 -0
- package/vendor/greenlock/logo/telebit-301x112.png +0 -0
- package/vendor/greenlock/order.js +63 -0
- package/vendor/greenlock/package-lock.json +140 -0
- package/vendor/greenlock/package.json +56 -0
- package/vendor/greenlock/plugins.js +270 -0
- package/vendor/greenlock/tests/cli.sh +31 -0
- package/vendor/greenlock/tests/index.js +53 -0
- package/vendor/greenlock/user-events.js +7 -0
- package/vendor/greenlock/utils.js +281 -0
- package/vendor/greenlock-express/greenlock-shim.js +3 -1
- package/vendor/greenlock-express/package.json +0 -1
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var A = module.exports;
|
|
4
|
+
var log = require('lemonlog')('greenlock-accounts');
|
|
5
|
+
var U = require('./utils.js');
|
|
6
|
+
var E = require('./errors.js');
|
|
7
|
+
|
|
8
|
+
var pending = {};
|
|
9
|
+
|
|
10
|
+
A._getOrCreate = function(gnlck, mconf, db, acme, args) {
|
|
11
|
+
var email = args.subscriberEmail || mconf.subscriberEmail;
|
|
12
|
+
|
|
13
|
+
if (!email) {
|
|
14
|
+
throw E.NO_SUBSCRIBER('get account', args.subject);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// TODO send welcome message with benefit info
|
|
18
|
+
return U._validMx(email)
|
|
19
|
+
.catch(function() {
|
|
20
|
+
throw E.NO_SUBSCRIBER('get account', args.subcriberEmail);
|
|
21
|
+
})
|
|
22
|
+
.then(function() {
|
|
23
|
+
if (pending[email]) {
|
|
24
|
+
return pending[email];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pending[email] = A._rawGetOrCreate(
|
|
28
|
+
gnlck,
|
|
29
|
+
mconf,
|
|
30
|
+
db,
|
|
31
|
+
acme,
|
|
32
|
+
args,
|
|
33
|
+
email
|
|
34
|
+
)
|
|
35
|
+
.catch(function(e) {
|
|
36
|
+
delete pending[email];
|
|
37
|
+
throw e;
|
|
38
|
+
})
|
|
39
|
+
.then(function(result) {
|
|
40
|
+
delete pending[email];
|
|
41
|
+
return result;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return pending[email];
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// What we really need out of this is the private key and the ACME "key" id
|
|
49
|
+
A._rawGetOrCreate = function(gnlck, mconf, db, acme, args, email) {
|
|
50
|
+
var p;
|
|
51
|
+
if (db.check) {
|
|
52
|
+
p = A._checkStore(gnlck, mconf, db, acme, args, email);
|
|
53
|
+
} else {
|
|
54
|
+
p = Promise.resolve(null);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return p.then(function(fullAccount) {
|
|
58
|
+
if (!fullAccount) {
|
|
59
|
+
return A._newAccount(gnlck, mconf, db, acme, args, email, null);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (fullAccount.keypair && fullAccount.key && fullAccount.key.kid) {
|
|
63
|
+
return fullAccount;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return A._newAccount(gnlck, mconf, db, acme, args, email, fullAccount);
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
A._newAccount = function(gnlck, mconf, db, acme, args, email, fullAccount) {
|
|
71
|
+
var keyType = args.accountKeyType || mconf.accountKeyType;
|
|
72
|
+
var query = {
|
|
73
|
+
subject: args.subject,
|
|
74
|
+
email: email,
|
|
75
|
+
subscriberEmail: email,
|
|
76
|
+
customerEmail: args.customerEmail,
|
|
77
|
+
account: fullAccount || {},
|
|
78
|
+
directoryUrl:
|
|
79
|
+
args.directoryUrl ||
|
|
80
|
+
mconf.directoryUrl ||
|
|
81
|
+
gnlck._defaults.directoryUrl
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return U._getOrCreateKeypair(db, args.subject, query, keyType).then(
|
|
85
|
+
function(kresult) {
|
|
86
|
+
var keypair = kresult.keypair;
|
|
87
|
+
var accReg = {
|
|
88
|
+
subscriberEmail: email,
|
|
89
|
+
agreeToTerms:
|
|
90
|
+
args.agreeToTerms ||
|
|
91
|
+
mconf.agreeToTerms ||
|
|
92
|
+
gnlck._defaults.agreeToTerms,
|
|
93
|
+
accountKey: keypair.privateKeyJwk || keypair.private,
|
|
94
|
+
debug: args.debug
|
|
95
|
+
};
|
|
96
|
+
return acme.accounts.create(accReg).then(function(receipt) {
|
|
97
|
+
var reg = {
|
|
98
|
+
keypair: keypair,
|
|
99
|
+
receipt: receipt,
|
|
100
|
+
// shudder... not actually a KeyID... but so it is called anyway...
|
|
101
|
+
kid:
|
|
102
|
+
receipt &&
|
|
103
|
+
receipt.key &&
|
|
104
|
+
(receipt.key.kid || receipt.kid),
|
|
105
|
+
email: args.email,
|
|
106
|
+
subscriberEmail: email,
|
|
107
|
+
customerEmail: args.customerEmail
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
var keyP;
|
|
111
|
+
if (kresult.exists) {
|
|
112
|
+
keyP = Promise.resolve();
|
|
113
|
+
} else {
|
|
114
|
+
query.keypair = keypair;
|
|
115
|
+
query.receipt = receipt;
|
|
116
|
+
/*
|
|
117
|
+
query.server = gnlck._defaults.directoryUrl.replace(
|
|
118
|
+
/^https?:\/\//i,
|
|
119
|
+
''
|
|
120
|
+
);
|
|
121
|
+
*/
|
|
122
|
+
keyP = db.setKeypair(query, keypair);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return keyP
|
|
126
|
+
.then(function() {
|
|
127
|
+
if (!db.set) {
|
|
128
|
+
return Promise.resolve({
|
|
129
|
+
keypair: keypair
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return db.set(
|
|
133
|
+
{
|
|
134
|
+
// id to be set by Store
|
|
135
|
+
email: email,
|
|
136
|
+
subscriberEmail: email,
|
|
137
|
+
customerEmail: args.customerEmail,
|
|
138
|
+
agreeTos: true,
|
|
139
|
+
agreeToTerms: true,
|
|
140
|
+
directoryUrl:
|
|
141
|
+
args.directoryUrl ||
|
|
142
|
+
mconf.directoryUrl ||
|
|
143
|
+
gnlck._defaults.directoryUrl
|
|
144
|
+
/*
|
|
145
|
+
server: gnlck._defaults.directoryUrl.replace(
|
|
146
|
+
/^https?:\/\//i,
|
|
147
|
+
''
|
|
148
|
+
)
|
|
149
|
+
*/
|
|
150
|
+
},
|
|
151
|
+
reg
|
|
152
|
+
);
|
|
153
|
+
})
|
|
154
|
+
.then(function(fullAccount) {
|
|
155
|
+
if (fullAccount && 'object' !== typeof fullAccount) {
|
|
156
|
+
throw new Error(
|
|
157
|
+
"accounts.set should either return 'null' or an object with an 'id' string"
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!fullAccount) {
|
|
162
|
+
fullAccount = {};
|
|
163
|
+
}
|
|
164
|
+
fullAccount.keypair = keypair;
|
|
165
|
+
if (!fullAccount.key) {
|
|
166
|
+
fullAccount.key = {};
|
|
167
|
+
}
|
|
168
|
+
fullAccount.key.kid = reg.kid;
|
|
169
|
+
|
|
170
|
+
return fullAccount;
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
A._checkStore = function(gnlck, mconf, db, acme, args, email) {
|
|
178
|
+
if ((args.domain || args.domains) && !args.subject) {
|
|
179
|
+
log.warn("Use 'subject' instead of 'domain'");
|
|
180
|
+
args.subject = args.domain;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
var account = args.account;
|
|
184
|
+
if (!account) {
|
|
185
|
+
account = {};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (args.accountKey) {
|
|
189
|
+
log.warn('Prefer storing accountKey in your account key store instead of passing it');
|
|
190
|
+
// TODO we probably don't need this
|
|
191
|
+
return U._importKeypair(args.accountKey);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (!db.check) {
|
|
195
|
+
return Promise.resolve(null);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return db
|
|
199
|
+
.check({
|
|
200
|
+
//keypair: undefined,
|
|
201
|
+
//receipt: undefined,
|
|
202
|
+
email: email,
|
|
203
|
+
subscriberEmail: email,
|
|
204
|
+
customerEmail: args.customerEmail || mconf.customerEmail,
|
|
205
|
+
account: account,
|
|
206
|
+
directoryUrl:
|
|
207
|
+
args.directoryUrl ||
|
|
208
|
+
mconf.directoryUrl ||
|
|
209
|
+
gnlck._defaults.directoryUrl
|
|
210
|
+
})
|
|
211
|
+
.then(function(fullAccount) {
|
|
212
|
+
if (!fullAccount) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return fullAccount;
|
|
217
|
+
});
|
|
218
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var log = require('lemonlog')('greenlock-add');
|
|
4
|
+
var args = process.argv.slice(3);
|
|
5
|
+
var cli = require('./lib/cli.js');
|
|
6
|
+
//var path = require('path');
|
|
7
|
+
//var pkgpath = path.join(__dirname, '..', 'package.json');
|
|
8
|
+
//var pkgpath = path.join(process.cwd(), 'package.json');
|
|
9
|
+
|
|
10
|
+
var Flags = require('./lib/flags.js');
|
|
11
|
+
|
|
12
|
+
Flags.init().then(function({ flagOptions, greenlock, mconf }) {
|
|
13
|
+
var myFlags = {};
|
|
14
|
+
[
|
|
15
|
+
'subject',
|
|
16
|
+
'altnames',
|
|
17
|
+
'renew-offset',
|
|
18
|
+
'subscriber-email',
|
|
19
|
+
'customer-email',
|
|
20
|
+
'server-key-type',
|
|
21
|
+
'challenge-http-01',
|
|
22
|
+
'challenge-http-01-xxxx',
|
|
23
|
+
'challenge-dns-01',
|
|
24
|
+
'challenge-dns-01-xxxx',
|
|
25
|
+
'challenge-tls-alpn-01',
|
|
26
|
+
'challenge-tls-alpn-01-xxxx',
|
|
27
|
+
'challenge',
|
|
28
|
+
'challenge-xxxx',
|
|
29
|
+
'challenge-json',
|
|
30
|
+
'force-save'
|
|
31
|
+
].forEach(function(k) {
|
|
32
|
+
myFlags[k] = flagOptions[k];
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
cli.parse(myFlags);
|
|
36
|
+
cli.main(function(argList, flags) {
|
|
37
|
+
Flags.mangleFlags(flags, mconf);
|
|
38
|
+
main(argList, flags, greenlock);
|
|
39
|
+
}, args);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
async function main(_, flags, greenlock) {
|
|
43
|
+
if (!flags.subject || !flags.altnames) {
|
|
44
|
+
log.error('Provide --subject and --altnames (valid domains)');
|
|
45
|
+
process.exit(1);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
greenlock
|
|
50
|
+
.add(flags)
|
|
51
|
+
.catch(function(err) {
|
|
52
|
+
log.error('Add failed:', err.message);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
})
|
|
55
|
+
.then(function() {
|
|
56
|
+
return greenlock
|
|
57
|
+
._config({
|
|
58
|
+
servername:
|
|
59
|
+
flags.altnames[
|
|
60
|
+
Math.floor(Math.random() * flags.altnames.length)
|
|
61
|
+
]
|
|
62
|
+
})
|
|
63
|
+
.then(function(site) {
|
|
64
|
+
if (!site) {
|
|
65
|
+
log.error('No config found after add (internal mismatch)');
|
|
66
|
+
process.exit(1);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
log.info('Site config:', site);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var log = require('lemonlog')('greenlock-certonly');
|
|
4
|
+
var mkdirp = require('@root/mkdirp');
|
|
5
|
+
var cli = require('./cli.js');
|
|
6
|
+
|
|
7
|
+
cli.parse({
|
|
8
|
+
'directory-url': [
|
|
9
|
+
false,
|
|
10
|
+
' ACME Directory Resource URL',
|
|
11
|
+
'string',
|
|
12
|
+
'https://acme-v02.api.letsencrypt.org/directory',
|
|
13
|
+
'server,acme-url'
|
|
14
|
+
],
|
|
15
|
+
email: [
|
|
16
|
+
false,
|
|
17
|
+
' Email used for registration and recovery contact. (default: null)',
|
|
18
|
+
'email'
|
|
19
|
+
],
|
|
20
|
+
'agree-tos': [
|
|
21
|
+
false,
|
|
22
|
+
" Agree to the Greenlock and Let's Encrypt Subscriber Agreements",
|
|
23
|
+
'boolean',
|
|
24
|
+
false
|
|
25
|
+
],
|
|
26
|
+
'community-member': [
|
|
27
|
+
false,
|
|
28
|
+
' Submit stats to and get updates from Greenlock',
|
|
29
|
+
'boolean',
|
|
30
|
+
false
|
|
31
|
+
],
|
|
32
|
+
domains: [
|
|
33
|
+
false,
|
|
34
|
+
' Domain names to apply. For multiple domains you can enter a comma separated list of domains as a parameter. (default: [])',
|
|
35
|
+
'string'
|
|
36
|
+
],
|
|
37
|
+
'renew-offset': [
|
|
38
|
+
false,
|
|
39
|
+
' Positive (time after issue) or negative (time before expiry) offset, such as 30d or -45d',
|
|
40
|
+
'string',
|
|
41
|
+
'45d'
|
|
42
|
+
],
|
|
43
|
+
'renew-within': [
|
|
44
|
+
false,
|
|
45
|
+
' (ignored) use renew-offset instead',
|
|
46
|
+
'ignore',
|
|
47
|
+
undefined
|
|
48
|
+
],
|
|
49
|
+
'cert-path': [
|
|
50
|
+
false,
|
|
51
|
+
' Path to where new cert.pem is saved',
|
|
52
|
+
'string',
|
|
53
|
+
':configDir/live/:hostname/cert.pem'
|
|
54
|
+
],
|
|
55
|
+
'fullchain-path': [
|
|
56
|
+
false,
|
|
57
|
+
' Path to where new fullchain.pem (cert + chain) is saved',
|
|
58
|
+
'string',
|
|
59
|
+
':configDir/live/:hostname/fullchain.pem'
|
|
60
|
+
],
|
|
61
|
+
'bundle-path': [
|
|
62
|
+
false,
|
|
63
|
+
' Path to where new bundle.pem (fullchain + privkey) is saved',
|
|
64
|
+
'string',
|
|
65
|
+
':configDir/live/:hostname/bundle.pem'
|
|
66
|
+
],
|
|
67
|
+
'chain-path': [
|
|
68
|
+
false,
|
|
69
|
+
' Path to where new chain.pem is saved',
|
|
70
|
+
'string',
|
|
71
|
+
':configDir/live/:hostname/chain.pem'
|
|
72
|
+
],
|
|
73
|
+
'privkey-path': [
|
|
74
|
+
false,
|
|
75
|
+
' Path to where privkey.pem is saved',
|
|
76
|
+
'string',
|
|
77
|
+
':configDir/live/:hostname/privkey.pem'
|
|
78
|
+
],
|
|
79
|
+
'config-dir': [
|
|
80
|
+
false,
|
|
81
|
+
' Configuration directory.',
|
|
82
|
+
'string',
|
|
83
|
+
'~/letsencrypt/etc/'
|
|
84
|
+
],
|
|
85
|
+
store: [
|
|
86
|
+
false,
|
|
87
|
+
' The name of the storage module to use',
|
|
88
|
+
'string',
|
|
89
|
+
'greenlock-store-fs'
|
|
90
|
+
],
|
|
91
|
+
'store-xxxx': [
|
|
92
|
+
false,
|
|
93
|
+
' An option for the chosen storage module, such as --store-apikey or --store-bucket',
|
|
94
|
+
'bag'
|
|
95
|
+
],
|
|
96
|
+
'store-json': [
|
|
97
|
+
false,
|
|
98
|
+
' A JSON string containing all option for the chosen store module (instead of --store-xxxx)',
|
|
99
|
+
'json',
|
|
100
|
+
'{}'
|
|
101
|
+
],
|
|
102
|
+
challenge: [
|
|
103
|
+
false,
|
|
104
|
+
' The name of the HTTP-01, DNS-01, or TLS-ALPN-01 challenge module to use',
|
|
105
|
+
'string',
|
|
106
|
+
'@greenlock/acme-http-01-fs'
|
|
107
|
+
],
|
|
108
|
+
'challenge-xxxx': [
|
|
109
|
+
false,
|
|
110
|
+
' An option for the chosen challenge module, such as --challenge-apikey or --challenge-bucket',
|
|
111
|
+
'bag'
|
|
112
|
+
],
|
|
113
|
+
'challenge-json': [
|
|
114
|
+
false,
|
|
115
|
+
' A JSON string containing all option for the chosen challenge module (instead of --challenge-xxxx)',
|
|
116
|
+
'json',
|
|
117
|
+
'{}'
|
|
118
|
+
],
|
|
119
|
+
'skip-dry-run': [
|
|
120
|
+
false,
|
|
121
|
+
' Use with caution (and test with the staging url first). Creates an Order on the ACME server without a self-test.',
|
|
122
|
+
'boolean'
|
|
123
|
+
],
|
|
124
|
+
'skip-challenge-tests': [
|
|
125
|
+
false,
|
|
126
|
+
' Use with caution (and with the staging url first). Presents challenges to the ACME server without first testing locally.',
|
|
127
|
+
'boolean'
|
|
128
|
+
],
|
|
129
|
+
'http-01-port': [
|
|
130
|
+
false,
|
|
131
|
+
' Required to be 80 for live servers. Do not use. For special test environments only.',
|
|
132
|
+
'int'
|
|
133
|
+
],
|
|
134
|
+
'dns-01': [false, ' Use DNS-01 challange type', 'boolean', false],
|
|
135
|
+
standalone: [
|
|
136
|
+
false,
|
|
137
|
+
' Obtain certs using a "standalone" webserver.',
|
|
138
|
+
'boolean',
|
|
139
|
+
false
|
|
140
|
+
],
|
|
141
|
+
manual: [
|
|
142
|
+
false,
|
|
143
|
+
' Print the token and key to the screen and wait for you to hit enter, giving you time to copy it somewhere before continuing (uses acme-http-01-cli or acme-dns-01-cli)',
|
|
144
|
+
'boolean',
|
|
145
|
+
false
|
|
146
|
+
],
|
|
147
|
+
debug: [false, ' show traces and logs', 'boolean', false],
|
|
148
|
+
root: [
|
|
149
|
+
false,
|
|
150
|
+
' public_html / webroot path (may use the :hostname template such as /srv/www/:hostname)',
|
|
151
|
+
'string',
|
|
152
|
+
undefined,
|
|
153
|
+
'webroot-path'
|
|
154
|
+
],
|
|
155
|
+
|
|
156
|
+
//
|
|
157
|
+
// backwards compat
|
|
158
|
+
//
|
|
159
|
+
duplicate: [
|
|
160
|
+
false,
|
|
161
|
+
' Allow getting a certificate that duplicates an existing one/is an early renewal',
|
|
162
|
+
'boolean',
|
|
163
|
+
false
|
|
164
|
+
],
|
|
165
|
+
'rsa-key-size': [
|
|
166
|
+
false,
|
|
167
|
+
' (ignored) use server-key-type or account-key-type instead',
|
|
168
|
+
'ignore',
|
|
169
|
+
2048
|
|
170
|
+
],
|
|
171
|
+
'server-key-path': [
|
|
172
|
+
false,
|
|
173
|
+
' Path to privkey.pem to use for certificate (default: generate new)',
|
|
174
|
+
'string',
|
|
175
|
+
undefined,
|
|
176
|
+
'domain-key-path'
|
|
177
|
+
],
|
|
178
|
+
'server-key-type': [
|
|
179
|
+
false,
|
|
180
|
+
" One of 'RSA' (2048), 'RSA-3084', 'RSA-4096', 'ECDSA' (P-256), or 'P-384'. For best compatibility, security, and efficiency use the default (More bits != More security)",
|
|
181
|
+
'string',
|
|
182
|
+
'RSA'
|
|
183
|
+
],
|
|
184
|
+
'account-key-path': [
|
|
185
|
+
false,
|
|
186
|
+
' Path to privkey.pem to use for account (default: generate new)',
|
|
187
|
+
'string'
|
|
188
|
+
],
|
|
189
|
+
'account-key-type': [
|
|
190
|
+
false,
|
|
191
|
+
" One of 'ECDSA' (P-256), 'P-384', 'RSA', 'RSA-3084', or 'RSA-4096'. Stick with 'ECDSA' (P-256) unless you need 'RSA' (2048) for legacy compatibility. (More bits != More security)",
|
|
192
|
+
'string',
|
|
193
|
+
'P-256'
|
|
194
|
+
],
|
|
195
|
+
webroot: [false, ' (ignored) for certbot compatibility', 'ignore', false],
|
|
196
|
+
//, 'standalone-supported-challenges': [ false, " Supported challenges, order preferences are randomly chosen. (default: http-01,tls-alpn-01)", 'string', 'http-01']
|
|
197
|
+
'work-dir': [
|
|
198
|
+
false,
|
|
199
|
+
' for certbot compatibility (ignored)',
|
|
200
|
+
'string',
|
|
201
|
+
'~/letsencrypt/var/lib/'
|
|
202
|
+
],
|
|
203
|
+
'logs-dir': [
|
|
204
|
+
false,
|
|
205
|
+
' for certbot compatibility (ignored)',
|
|
206
|
+
'string',
|
|
207
|
+
'~/letsencrypt/var/log/'
|
|
208
|
+
],
|
|
209
|
+
'acme-version': [
|
|
210
|
+
false,
|
|
211
|
+
' (ignored) ACME is now RFC 8555 and prior drafts are no longer supported',
|
|
212
|
+
'ignore',
|
|
213
|
+
'rfc8555'
|
|
214
|
+
]
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// ignore certonly and extraneous arguments
|
|
218
|
+
cli.main(function(_, options) {
|
|
219
|
+
|
|
220
|
+
[
|
|
221
|
+
'configDir',
|
|
222
|
+
'privkeyPath',
|
|
223
|
+
'certPath',
|
|
224
|
+
'chainPath',
|
|
225
|
+
'fullchainPath',
|
|
226
|
+
'bundlePath'
|
|
227
|
+
].forEach(function(k) {
|
|
228
|
+
if (options[k]) {
|
|
229
|
+
options.storeOpts[k] = options[k];
|
|
230
|
+
}
|
|
231
|
+
delete options[k];
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
if (options.workDir) {
|
|
235
|
+
options.challengeOpts.workDir = options.workDir;
|
|
236
|
+
delete options.workDir;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (options.debug) log.debug('certonly options', options);
|
|
240
|
+
|
|
241
|
+
var args = {};
|
|
242
|
+
var homedir = require('os').homedir();
|
|
243
|
+
|
|
244
|
+
Object.keys(options).forEach(function(key) {
|
|
245
|
+
var val = options[key];
|
|
246
|
+
|
|
247
|
+
if ('string' === typeof val) {
|
|
248
|
+
val = val.replace(/^~/, homedir);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
key = key.replace(/\-([a-z0-9A-Z])/g, function(c) {
|
|
252
|
+
return c[1].toUpperCase();
|
|
253
|
+
});
|
|
254
|
+
args[key] = val;
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
Object.keys(args).forEach(function(key) {
|
|
258
|
+
var val = args[key];
|
|
259
|
+
|
|
260
|
+
if ('string' === typeof val) {
|
|
261
|
+
val = val.replace(/(\:configDir)|(\:config)/, args.configDir);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
args[key] = val;
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
if (args.domains) {
|
|
268
|
+
args.domains = args.domains.split(',');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (
|
|
272
|
+
!(Array.isArray(args.domains) && args.domains.length) ||
|
|
273
|
+
!args.email ||
|
|
274
|
+
!args.agreeTos ||
|
|
275
|
+
(!args.server && !args.directoryUrl)
|
|
276
|
+
) {
|
|
277
|
+
log.error(
|
|
278
|
+
'Usage: greenlock certonly --standalone --agree-tos --email user@example.com --domains example.com --config-dir ~/acme/etc (see greenlock --help)'
|
|
279
|
+
);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (args.http01Port) {
|
|
284
|
+
// [@agnat]: Coerce to string. cli returns a number although we request a string.
|
|
285
|
+
args.http01Port = '' + args.http01Port;
|
|
286
|
+
args.http01Port = args.http01Port.split(',').map(function(port) {
|
|
287
|
+
return parseInt(port, 10);
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function run() {
|
|
292
|
+
var challenges = {};
|
|
293
|
+
if (/http.?01/i.test(args.challenge)) {
|
|
294
|
+
challenges['http-01'] = args.challengeOpts;
|
|
295
|
+
}
|
|
296
|
+
if (/dns.?01/i.test(args.challenge)) {
|
|
297
|
+
challenges['dns-01'] = args.challengeOpts;
|
|
298
|
+
}
|
|
299
|
+
if (/alpn.?01/i.test(args.challenge)) {
|
|
300
|
+
challenges['tls-alpn-01'] = args.challengeOpts;
|
|
301
|
+
}
|
|
302
|
+
if (!Object.keys(challenges).length) {
|
|
303
|
+
throw new Error(
|
|
304
|
+
"Could not determine the challenge type for '" +
|
|
305
|
+
args.challengeOpts.module +
|
|
306
|
+
"'. Expected a name like @you/acme-xxxx-01-foo. Please name the module with http-01, dns-01, or tls-alpn-01."
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
args.challengeOpts.module = args.challenge;
|
|
310
|
+
args.storeOpts.module = args.store;
|
|
311
|
+
|
|
312
|
+
require(args.challenge);
|
|
313
|
+
require(args.store);
|
|
314
|
+
|
|
315
|
+
var greenlock = require('../').create({
|
|
316
|
+
maintainerEmail: args.maintainerEmail || 'coolaj86@gmail.com',
|
|
317
|
+
manager: './manager.js',
|
|
318
|
+
configFile: '~/.config/greenlock/certs.json',
|
|
319
|
+
challenges: challenges,
|
|
320
|
+
store: args.storeOpts,
|
|
321
|
+
renewOffset: args.renewOffset || '30d',
|
|
322
|
+
renewStagger: '1d'
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// for long-running processes
|
|
326
|
+
if (args.renewEvery) {
|
|
327
|
+
setInterval(function() {
|
|
328
|
+
greenlock.renew({
|
|
329
|
+
period: args.renewEvery
|
|
330
|
+
});
|
|
331
|
+
}, args.renewEvery);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// TODO should greenlock.add simply always include greenlock.renew?
|
|
335
|
+
// the concern is conflating error events
|
|
336
|
+
return greenlock
|
|
337
|
+
.add({
|
|
338
|
+
subject: args.subject,
|
|
339
|
+
altnames: args.altnames,
|
|
340
|
+
subscriberEmail: args.subscriberEmail || args.email
|
|
341
|
+
})
|
|
342
|
+
.then(function(changes) {
|
|
343
|
+
log.info('Certificate order result:', changes);
|
|
344
|
+
// renew should always
|
|
345
|
+
return greenlock
|
|
346
|
+
.renew({
|
|
347
|
+
subject: args.subject,
|
|
348
|
+
force: false
|
|
349
|
+
})
|
|
350
|
+
.then(function() {});
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if ('greenlock-store-fs' !== args.store) {
|
|
355
|
+
run();
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// TODO remove mkdirp and let greenlock-store-fs do this?
|
|
360
|
+
mkdirp(args.storeOpts.configDir, function(err) {
|
|
361
|
+
if (!err) {
|
|
362
|
+
run();
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
log.error("Could not create config dir '%s': %s. Try --config-dir '/tmp'", args.configDir, err.code);
|
|
366
|
+
return;
|
|
367
|
+
});
|
|
368
|
+
}, process.argv.slice(3));
|