Skip to content

Commit 733664e

Browse files
luci-app-2fa: Add priority option and QR code display
Signed-off-by: tokisaki galaxy <moebest@outlook.jp>
1 parent f91d3eb commit 733664e

4 files changed

Lines changed: 59 additions & 35 deletions

File tree

applications/luci-app-2fa/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ PKG_MAINTAINER:=tokisaki galaxy <moebest@outlook.jp>
1414
PKG_DESCRIPTION:=LuCI 2-Factor Authentication Plugin
1515

1616
LUCI_TITLE:=LuCI 2-Factor Authentication
17-
LUCI_DEPENDS:=+luci-base +ucode-mod-struct +ucode-mod-digest
17+
LUCI_DEPENDS:=+luci-base +luci-lib-uqr +ucode-mod-struct +ucode-mod-digest
1818
LUCI_PKGARCH:=all
1919
LUCI_URL:=https://github.com/tokisaki-galaxy/luci-app-2fa
2020

applications/luci-app-2fa/htdocs/luci-static/resources/uqr.js

Lines changed: 0 additions & 33 deletions
This file was deleted.

applications/luci-app-2fa/root/usr/share/ucode/luci/plugins/auth/login/bb4ea47fcffb44ec9bb3d3673c9b4ed2.uc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ const DEFAULT_MIN_VALID_TIME = 1767225600;
2525
// Rate limit state file
2626
const RATE_LIMIT_FILE = '/tmp/2fa_rate_limit.json';
2727
const RATE_LIMIT_LOCK_FILE = '/tmp/2fa_rate_limit.lock';
28+
const DEFAULT_PRIORITY = 15;
29+
30+
function get_priority() {
31+
let ctx = cursor();
32+
let value = ctx.get('luci_plugins', PLUGIN_UUID, 'priority');
33+
34+
if (!value || !match(value, /^-?[0-9]+$/))
35+
return DEFAULT_PRIORITY;
36+
37+
return int(value);
38+
}
2839

2940
// Check if system time is calibrated (not earlier than minimum valid time)
3041
function check_time_calibration() {
@@ -509,7 +520,7 @@ function get_client_ip(http) {
509520
}
510521

511522
return {
512-
priority: 10,
523+
priority: get_priority(),
513524

514525
check: function(http, user) {
515526
let client_ip = get_client_ip(http);

applications/luci-app-2fa/root/www/luci-static/resources/view/plugins/bb4ea47fcffb44ec9bb3d3673c9b4ed2.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,42 @@
33
'require form';
44
'require uci';
55
'require rpc';
6+
'require uqr';
7+
8+
var CBIQRCode = form.DummyValue.extend({
9+
renderWidget(section_id) {
10+
var key = uci.get('luci_plugins', section_id, 'key_root') || '';
11+
var type = uci.get('luci_plugins', section_id, 'type_root') || 'totp';
12+
13+
if (!key)
14+
return E('em', {}, _('Set and save the secret key first to display a QR code.'));
15+
16+
var issuer = 'OpenWrt';
17+
var label = 'root';
18+
var option;
19+
20+
if (type == 'hotp') {
21+
var counter = uci.get('luci_plugins', section_id, 'counter_root') || '0';
22+
option = 'counter=' + counter;
23+
}
24+
else {
25+
var step = uci.get('luci_plugins', section_id, 'step_root') || '30';
26+
option = 'period=' + step;
27+
}
28+
29+
var otpAuth = 'otpauth://' + type + '/' + encodeURIComponent(issuer) + ':' + encodeURIComponent(label) +
30+
'?secret=' + key + '&issuer=' + encodeURIComponent(issuer) + '&' + option;
31+
var svg = uqr.renderSVG(otpAuth, { pixelSize: 4 });
32+
33+
return E('div', {}, [
34+
E('div', { 'style': 'max-width:260px' }, [ E(svg) ]),
35+
E('br'),
36+
E('em', {}, _('Scan this QR code with your authenticator app.')),
37+
E('br'),
38+
E('code', { 'style': 'word-break:break-all;font-size:10px;' }, otpAuth)
39+
]);
40+
}
41+
});
642

743
return baseclass.extend({
844
class: 'auth',
@@ -27,6 +63,13 @@ return baseclass.extend({
2763
o.default = o.disabled;
2864
o.rmempty = false;
2965

66+
o = s.taboption('basic', form.Value, 'priority', _('Priority'),
67+
_('Execution order for this plugin. Lower values run earlier.'));
68+
o.depends('enabled', '1');
69+
o.datatype = 'integer';
70+
o.placeholder = '15';
71+
o.rmempty = true;
72+
3073
// User configuration section
3174
o = s.taboption('basic', form.SectionValue, '_users', form.TableSection, 'luci_plugins', _('User Configuration'),
3275
_('Configure 2FA keys for individual users. The key must be a Base32-encoded secret.'));
@@ -66,6 +109,9 @@ return baseclass.extend({
66109
o.datatype = 'uinteger';
67110
o.rmempty = true;
68111

112+
o = s.taboption('basic', CBIQRCode, '_qrcode', _('Authenticator QR Code'));
113+
o.depends('enabled', '1');
114+
69115
// Tab: Security
70116
s.tab('security', _('Security'));
71117

0 commit comments

Comments
 (0)