UNPKG

4.62 kBJavaScriptView Raw
1'use strict'
2
3let co = require('co')
4let cli = require('heroku-cli-util')
5
6let openssl = require('../../lib/openssl.js')
7let endpoints = require('../../lib/endpoints.js').all
8
9function valEmpty (val) {
10 if (val) {
11 return val.length === 0
12 } else {
13 return true
14 }
15}
16
17function getSubject (context) {
18 let domain = context.args.domain
19
20 let owner = context.flags.owner
21 let country = context.flags.country
22 let area = context.flags.area
23 let city = context.flags.city
24
25 let subject = context.flags.subject
26
27 if (valEmpty(subject)) {
28 subject = ''
29 if (!valEmpty(country)) {
30 subject += `/C=${country}`
31 }
32
33 if (!valEmpty(area)) {
34 subject += `/ST=${area}`
35 }
36
37 if (!valEmpty(city)) {
38 subject += `/L=${city}`
39 }
40
41 if (!valEmpty(owner)) {
42 subject += `/O=${owner}`
43 }
44
45 subject += `/CN=${domain}`
46 }
47
48 return subject
49}
50
51function requiresPrompt (context) {
52 if (valEmpty(context.flags.subject)) {
53 let args = [context.flags.owner, context.flags.country, context.flags.area, context.flags.city]
54 if (!context.flags.now && args.every(function (v) { return valEmpty(v) })) {
55 return true
56 }
57 }
58 return false
59}
60
61function getCommand (certs, domain) {
62 if (certs.find(function (f) {
63 return f.ssl_cert.cert_domains.find(function (d) {
64 return d === domain
65 })
66 })) {
67 return 'update'
68 } else {
69 return 'add'
70 }
71}
72
73function * run (context, heroku) {
74 if (requiresPrompt(context)) {
75 context.flags.owner = yield cli.prompt('Owner of this certificate')
76 context.flags.country = yield cli.prompt('Country of owner (two-letter ISO code)')
77 context.flags.area = yield cli.prompt('State/province/etc. of owner')
78 context.flags.city = yield cli.prompt('City of owner')
79 }
80
81 let subject = getSubject(context)
82
83 let domain = context.args.domain
84 let keysize = context.flags.keysize || 2048
85 let keyfile = `${domain}.key`
86
87 let certs = yield endpoints(context.app, heroku)
88
89 var command = getCommand(certs, domain)
90
91 if (context.flags.selfsigned) {
92 let crtfile = `${domain}.crt`
93
94 yield openssl.spawn(['req', '-new', '-newkey', `rsa:${keysize}`, '-nodes', '-keyout', keyfile, '-out', crtfile, '-subj', subject, '-x509'])
95
96 cli.console.error('Your key and self-signed certificate have been generated.')
97 cli.console.error('Next, run:')
98 cli.console.error(`$ heroku certs:${command} ${crtfile} ${keyfile}`)
99 } else {
100 let csrfile = `${domain}.csr`
101
102 yield openssl.spawn(['req', '-new', '-newkey', `rsa:${keysize}`, '-nodes', '-keyout', keyfile, '-out', csrfile, '-subj', subject])
103
104 cli.console.error('Your key and certificate signing request have been generated.')
105 cli.console.error(`Submit the CSR in '${csrfile}' to your preferred certificate authority.`)
106 cli.console.error("When you've received your certificate, run:")
107 cli.console.error(`$ heroku certs:${command} CERTFILE ${keyfile}`)
108 }
109}
110
111module.exports = {
112 topic: 'certs',
113 command: 'generate',
114 args: [
115 {name: 'domain', optional: false}
116 ],
117 flags: [
118 {
119 name: 'selfsigned',
120 optional: true,
121 hasValue: false,
122 description: 'generate a self-signed certificate instead of a CSR'
123 }, {
124 name: 'keysize',
125 optional: true,
126 hasValue: true,
127 description: 'RSA key size in bits (default: 2048)'
128 }, {
129 name: 'owner',
130 optional: true,
131 hasValue: true,
132 description: 'name of organization certificate belongs to'
133 }, {
134 name: 'country',
135 optional: true,
136 hasValue: true,
137 description: 'country of owner, as a two-letter ISO country code'
138 }, {
139 name: 'area',
140 optional: true,
141 hasValue: true,
142 description: 'sub-country area (state, province, etc.) of owner'
143 }, {
144 name: 'city',
145 optional: true,
146 hasValue: true,
147 description: 'city of owner'
148 }, {
149 name: 'subject',
150 optional: true,
151 hasValue: true,
152 description: 'specify entire certificate subject'
153 }, {
154 name: 'now',
155 optional: true,
156 hasValue: false,
157 description: 'do not prompt for any owner information'
158 }
159 ],
160 description: 'generate a key and a CSR or self-signed certificate',
161 help: `Generate a key and certificate signing request (or self-signed certificate)\nfor an app. Prompts for information to put in the certificate unless --now\nis used, or at least one of the --subject, --owner, --country, --area, or\n--city options is specified.
162
163Example:
164
165 $ heroku certs:generate example.com
166`,
167 needsApp: true,
168 needsAuth: true,
169 run: cli.command(co.wrap(run))
170}