6380fbe4b41118dc8ab752c7205272d9a91c6655
[project/luci.git] / applications / luci-app-acme / htdocs / luci-static / resources / view / acme.js
1 'use strict';
2 'require form';
3 'require fs';
4 'require uci';
5 'require view';
6
7 return view.extend({
8 load: function () {
9 return Promise.all([
10 L.resolveDefault(fs.stat('/usr/sbin/nginx'), {}),
11 L.resolveDefault(fs.stat('/usr/sbin/uhttpd'), {})
12 ]);
13 },
14
15 render: function (stats) {
16 var m, s, o;
17
18 m = new form.Map("acme", _("ACME certificates"),
19 _("This configures ACME (Letsencrypt) automatic certificate installation. " +
20 "Simply fill out this to have the router configured with Letsencrypt-issued " +
21 "certificates for the web interface. " +
22 "Note that the domain names in the certificate must already be configured to " +
23 "point at the router's public IP address. " +
24 "Once configured, issuing certificates can take a while. " +
25 "Check the logs for progress and any errors.") + '<br/>' +
26 _("Cert files are stored in") + ' <em>/etc/ssl/acme<em>'
27 );
28
29 s = m.section(form.TypedSection, "acme", _("ACME global config"));
30 s.anonymous = true;
31
32 o = s.option(form.Value, "account_email", _("Account email"),
33 _("Email address to associate with account key."))
34 o.rmempty = false;
35 o.datatype = "minlength(1)";
36
37 o = s.option(form.Flag, "debug", _("Enable debug logging"));
38 o.rmempty = false;
39
40 s = m.section(form.GridSection, "cert", _("Certificate config"))
41 s.anonymous = false;
42 s.addremove = true;
43 s.nodescriptions = true;
44
45 o = s.tab("general", _("General Settings"));
46 o = s.tab("challenge", _("Challenge Validation"));
47 o = s.tab("advanced", _('Advanced Settings'));
48
49 o = s.taboption('general', form.Flag, "enabled", _("Enabled"));
50 o.rmempty = false;
51
52 o = s.taboption('general', form.DynamicList, "domains", _("Domain names"),
53 _("Domain names to include in the certificate. " +
54 "The first name will be the subject name, subsequent names will be alt names. " +
55 "Note that all domain names must point at the router in the global DNS."));
56 o.datatype = "list(string)";
57
58 if (stats[1].type === 'file') {
59 o = s.taboption('general', form.Flag, "update_uhttpd", _("Use for uhttpd"),
60 _("Update the uhttpd config with this certificate once issued " +
61 "(only select this for one certificate). " +
62 "Is also available luci-app-uhttpd to configure uhttpd form the LuCI interface."));
63 o.rmempty = false;
64 o.modalonly = true;
65 }
66
67 if (stats[0].type === 'file') {
68 o = s.taboption('general', form.Flag, "update_nginx", _("Use for nginx"),
69 _("Update the nginx config with this certificate once issued " +
70 "(only select this for one certificate). " +
71 "Nginx must support ssl, if not it won't start as it needs to be " +
72 "compiled with ssl support to use cert options"));
73 o.rmempty = false;
74 o.modalonly = true;
75 }
76
77 o = s.taboption('challenge', form.ListValue, "validation_method", _("Validation method"),
78 _("Standalone mode will use the built-in webserver of acme.sh to issue a certificate. " +
79 "Webroot mode will use an existing webserver to issue a certificate. " +
80 "DNS mode will allow you to use the DNS API of your DNS provider to issue a certificate."));
81 o.value("standalone", _("Standalone"));
82 o.value("webroot", _("Webroot"));
83 o.value("dns", _("DNS"));
84 o.default = "standalone";
85
86 o = s.taboption('challenge', form.Value, "webroot", _("Webroot directory"),
87 _("Webserver root directory. Set this to the webserver " +
88 "document root to run Acme in webroot mode. The web " +
89 "server must be accessible from the internet on port 80."));
90 o.optional = true;
91 o.depends("validation_method", "webroot");
92 o.modalonly = true;
93
94 o = s.taboption('challenge', form.Value, "dns", _("DNS API"),
95 _("To use DNS mode to issue certificates, set this to the name of a DNS API supported by acme.sh. " +
96 "See https://github.com/acmesh-official/acme.sh/wiki/dnsapi for the list of available APIs. " +
97 "In DNS mode, the domain name does not have to resolve to the router IP. " +
98 "DNS mode is also the only mode that supports wildcard certificates. " +
99 "Using this mode requires the acme-dnsapi package to be installed."));
100 o.depends("validation_method", "dns");
101 o.modalonly = true;
102
103 o = s.taboption('challenge', form.DynamicList, "credentials", _("DNS API credentials"),
104 _("The credentials for the DNS API mode selected above. " +
105 "See https://github.com/acmesh-official/acme.sh/wiki/dnsapi for the format of credentials required by each API. " +
106 "Add multiple entries here in KEY=VAL shell variable format to supply multiple credential variables."))
107 o.datatype = "list(string)";
108 o.depends("validation_method", "dns");
109 o.modalonly = true;
110
111 o = s.taboption('challenge', form.Value, "calias", _("Challenge Alias"),
112 _("The challenge alias to use for ALL domains. " +
113 "See https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode for the details of this process. " +
114 "LUCI only supports one challenge alias per certificate."));
115 o.depends("validation_method", "dns");
116 o.modalonly = true;
117
118 o = s.taboption('challenge', form.Value, "dalias", _("Domain Alias"),
119 _("The domain alias to use for ALL domains. " +
120 "See https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode for the details of this process. " +
121 "LUCI only supports one challenge domain per certificate."));
122 o.depends("validation_method", "dns");
123 o.modalonly = true;
124
125
126 o = s.taboption('advanced', form.Flag, 'use_staging', _('Use staging server'),
127 _(
128 'Get certificate from the Letsencrypt staging server ' +
129 '(use for testing; the certificate won\'t be valid).'
130 )
131 );
132 o.rmempty = false;
133 o.modalonly = true;
134
135 o = s.taboption('advanced', form.ListValue, 'key_type', _('Key size'),
136 _('Key size (and type) for the generated certificate.')
137 );
138 o.value('rsa2048', _('RSA 2048 bits'));
139 o.value('rsa3072', _('RSA 3072 bits'));
140 o.value('rsa4096', _('RSA 4096 bits'));
141 o.value('ec256', _('ECC 256 bits'));
142 o.value('ec384', _('ECC 384 bits'));
143 o.rmempty = false;
144 o.optional = true;
145 o.modalonly = true;
146 o.cfgvalue = function(section_id, set_value) {
147 var keylength = uci.get('acme', section_id, 'keylength');
148 if (keylength) {
149 // migrate the old keylength to a new keytype
150 switch (keylength) {
151 case '2048': return 'rsa2048';
152 case '3072': return 'rsa3072';
153 case '4096': return 'rsa4096';
154 case 'ec-256': return 'ec256';
155 case 'ec-384': return 'ec384';
156 default: return ''; // bad value
157 }
158 }
159 return set_value;
160 };
161 o.write = function(section_id, value) {
162 // remove old keylength
163 uci.unset('acme', section_id, 'keylength');
164 uci.set('acme', section_id, 'key_type', value);
165 };
166
167 o = s.taboption('advanced', form.Flag, "use_acme_server",
168 _("Custom ACME CA"), _("Use a custom CA instead of Let's Encrypt."));
169 o.depends("use_staging", "0");
170 o.default = false;
171 o.modalonly = true;
172
173 o = s.taboption('advanced', form.Value, "acme_server", _("ACME server URL"),
174 _("Custom ACME server directory URL."));
175 o.depends("use_acme_server", "1");
176 o.placeholder = "https://api.buypass.com/acme/directory";
177 o.optional = true;
178 o.modalonly = true;
179
180 o = s.taboption('advanced', form.Value, 'days', _('Days until renewal'));
181 o.optional = true;
182 o.placeholder = 90;
183 o.datatype = 'uinteger';
184 o.modalonly = true;
185
186 return m.render()
187 }
188 })
189