2 aclTable
: L
.cbi
.AbstractValue
.extend({
3 strGlob: function(pattern
, match
) {
4 var re
= new RegExp('^' + (pattern
5 .replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1')
6 .replace(/\\\*/g, '.*?')) + '$');
11 aclMatch: function(list
, group
) {
12 for (var i
= 0; i
< list
.length
; i
++)
14 var x
= list
[i
].replace(/^\s*!\s*/, '');
18 if (this.strGlob(x
, group
))
22 for (var i
= 0; i
< list
.length
; i
++)
24 var x
= list
[i
].replace(/^\s*!\s*/, '');
28 if (this.strGlob(x
, group
))
35 aclTest: function(list
, group
) {
36 for (var i
= 0; i
< list
.length
; i
++)
43 aclEqual: function(list1
, list2
) {
44 if (list1
.length
!= list2
.length
)
47 for (var i
= 0; i
< list1
.length
; i
++)
48 if (list1
[i
] != list2
[i
])
54 aclFromUCI: function(value
) {
56 if (typeof(value
) == 'string')
57 list
= value
.split(/\s+/);
58 else if ($.isArray(value
))
65 for (var i
= 0; i
< this.choices
.length
; i
++)
66 if (this.aclMatch(list
, this.choices
[i
][0]))
67 rv
.push(this.choices
[i
][0]);
72 aclToUCI: function(list
) {
73 if (list
.length
< (this.choices
.length
/ 2))
77 for (var i
= 0; i
< list
.length
; i
++)
81 for (var i
= 0; i
< this.choices
.length
; i
++)
82 if (!set[this.choices
[i
][0]])
83 rv
.push('!' + this.choices
[i
][0]);
88 setAll: function(ev
) {
89 $(this).parents('table')
90 .find('input[value=%d]'.format(ev
.data
.level
))
91 .prop('checked', true);
96 var t
= $('<table />')
97 .attr('id', this.id(sid
))
100 .text(L
.tr('ACL Group')))
102 .text(L
.trc('No access', 'N'))
103 .attr('title', L
.tr('Set all to no access'))
104 .css('cursor', 'pointer')
105 .click({ level
: 0 }, this.setAll
))
107 .text(L
.trc('Read only access', 'R'))
108 .attr('title', L
.tr('Set all to read only access'))
109 .css('cursor', 'pointer')
110 .click({ level
: 1 }, this.setAll
))
112 .text(L
.trc('Full access', 'F'))
113 .attr('title', L
.tr('Set all to full access'))
114 .css('cursor', 'pointer')
115 .click({ level
: 2 }, this.setAll
)));
117 var acl_r
= this.aclFromUCI(this.map
.get('rpcd', sid
, 'read'));
118 var acl_w
= this.aclFromUCI(this.map
.get('rpcd', sid
, 'write'));
121 for (var i
= 0; i
< this.choices
.length
; i
++)
123 var r
= t
.get(0).insertRow(-1);
124 var is_r
= this.aclTest(acl_r
, this.choices
[i
][0]);
125 var is_w
= this.aclTest(acl_w
, this.choices
[i
][0]);
128 .text(this.choices
[i
][1]);
130 for (var j
= 0; j
< 3; j
++)
133 .append($('<input />')
134 .attr('type', 'radio')
135 .attr('name', '%s_%s'.format(this.id(sid
), this.choices
[i
][0]))
137 .prop('checked', (j
== 0 && !is_r
&& !is_w
) ||
138 (j
== 1 && is_r
&& !is_w
) ||
146 textvalue: function(sid
)
148 var acl_r
= this.aclFromUCI(this.map
.get('rpcd', sid
, 'read'));
149 var acl_w
= this.aclFromUCI(this.map
.get('rpcd', sid
, 'write'));
151 var htmlid
= this.id(sid
);
152 var radios
= $('#' + htmlid
+ ' input');
156 for (var i
= 0; i
< this.choices
.length
; i
++)
158 switch (radios
.filter('[name=%s_%s]:checked'.format(htmlid
, this.choices
[i
][0])).val())
161 acls
.push('%s: %s'.format(this.choices
[i
][0], L
.trc('Full access', 'F')));
165 acls
.push('%s: %s'.format(this.choices
[i
][0], L
.trc('Read only access', 'R')));
169 acls
.push('%s: %s'.format(this.choices
[i
][0], L
.trc('No access', 'N')));
174 return acls
.join(', ');
177 value: function(k
, v
)
182 this.choices
.push([k
, v
|| k
]);
188 var acl_r
= this.aclFromUCI(this.map
.get('rpcd', sid
, 'read'));
189 var acl_w
= this.aclFromUCI(this.map
.get('rpcd', sid
, 'write'));
194 var htmlid
= this.id(sid
);
195 var radios
= $('#' + htmlid
+ ' input');
197 for (var i
= 0; i
< this.choices
.length
; i
++)
199 switch (radios
.filter('[name=%s_%s]:checked'.format(htmlid
, this.choices
[i
][0])).val())
202 acl_r_new
.push(this.choices
[i
][0]);
203 acl_w_new
.push(this.choices
[i
][0]);
207 acl_r_new
.push(this.choices
[i
][0]);
212 if (!this.aclEqual(acl_r
, acl_r_new
))
213 this.map
.set('rpcd', sid
, 'read', this.aclToUCI(acl_r_new
));
215 if (!this.aclEqual(acl_w
, acl_w_new
))
216 this.map
.set('rpcd', sid
, 'write', this.aclToUCI(acl_w_new
));
220 execute: function() {
222 L
.ui
.listAvailableACLs().then(function(acls
) {
223 var m
= new L
.cbi
.Map('rpcd', {
224 caption
: L
.tr('Guest Logins'),
225 description
: L
.tr('Manage user accounts and permissions for accessing the LuCI ui.'),
229 var s
= m
.section(L
.cbi
.TypedSection
, 'login', {
230 caption: function(sid
) {
231 var u
= sid
? this.fields
.username
.textvalue(sid
) : undefined;
232 return u
? L
.tr('Login "%s"').format(u
) : L
.tr('New login');
235 add_caption
: L
.tr('Add new user …'),
236 teasers
: [ '__shadow', '__acls' ]
239 s
.option(L
.cbi
.InputValue
, 'username', {
240 caption
: L
.tr('Username'),
241 description
: L
.tr('Specifies the login name for the guest account'),
246 var shadow
= s
.option(L
.cbi
.CheckboxValue
, '__shadow', {
247 caption
: L
.tr('Use system account'),
248 description
: L
.tr('Use password from the Linux user database')
251 shadow
.ucivalue = function(sid
) {
252 var pw
= this.map
.get('rpcd', sid
, 'password');
253 return (pw
&& pw
.indexOf('$p$') == 0);
257 var password
= s
.option(L
.cbi
.PasswordValue
, 'password', {
258 caption
: L
.tr('Password'),
259 description
: L
.tr('Specifies the password for the guest account. If you enter a plaintext password here, it will get replaced with a crypted password hash on save.'),
263 password
.depends('__shadow', false);
265 password
.toggle = function(sid
) {
266 var id
= '#' + this.id(sid
);
267 var pw
= this.map
.get('rpcd', sid
, 'password');
268 var sh
= this.section
.fields
.__shadow
.formvalue(sid
);
270 if (!sh
&& pw
&& pw
.indexOf('$p$') == 0)
273 this.callSuper('toggle', sid
);
276 shadow
.save
= password
.save = function(sid
) {
277 var sh
= this.section
.fields
.__shadow
.formvalue(sid
);
278 var pw
= this.section
.fields
.password
.formvalue(sid
);
281 pw
= '$p$' + this.section
.fields
.username
.formvalue(sid
);
283 if (pw
.match(/^\$[0-9p][a-z]?\$/))
285 if (pw
!= this.map
.get('rpcd', sid
, 'password'))
286 this.map
.set('rpcd', sid
, 'password', pw
);
291 return L
.ui
.cryptPassword(pw
).then(function(crypt
) {
292 map
.set('rpcd', sid
, 'password', crypt
);
297 var o
= s
.option(self
.aclTable
, '__acls', {
298 caption
: L
.tr('User ACLs'),
299 description
: L
.tr('Specifies the access levels of this account. The "-" column means no access, "R" stands for read only access and "F" for full access.')
303 for (var group_name
in acls
)
304 groups
.push(group_name
);
308 for (var i
= 0; i
< groups
.length
; i
++)
309 o
.value(groups
[i
], acls
[groups
[i
]].description
);
311 return m
.insertInto('#map');