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