luci-app-opkg: add ipk upload feature

Signed-off-by: Richard Yu <yurichard3839@gmail.com>
[fix duplicate upload errors, remove temporary file, tweak style]
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
Richard Yu 2019-10-23 20:22:11 +08:00 committed by Jo-Philipp Wich
parent 33346dadf4
commit c360cdd1f0
3 changed files with 77 additions and 28 deletions

View file

@ -745,42 +745,83 @@ function handleRemove(ev)
function handleOpkg(ev) function handleOpkg(ev)
{ {
var cmd = ev.target.getAttribute('data-command'), return new Promise(function(resolveFn, rejectFn) {
pkg = ev.target.getAttribute('data-package'), var cmd = ev.target.getAttribute('data-command'),
rem = document.querySelector('input[name="autoremove"]'), pkg = ev.target.getAttribute('data-package'),
owr = document.querySelector('input[name="overwrite"]'), rem = document.querySelector('input[name="autoremove"]'),
url = 'admin/system/opkg/exec/' + encodeURIComponent(cmd); owr = document.querySelector('input[name="overwrite"]'),
url = 'admin/system/opkg/exec/' + encodeURIComponent(cmd);
var dlg = L.showModal(_('Executing package manager'), [ var dlg = L.showModal(_('Executing package manager'), [
E('p', { 'class': 'spinning' }, E('p', { 'class': 'spinning' },
_('Waiting for the <em>opkg %h</em> command to complete…').format(cmd)) _('Waiting for the <em>opkg %h</em> command to complete…').format(cmd))
]); ]);
L.post(url, { package: pkg, autoremove: rem ? rem.checked : false, overwrite: owr ? owr.checked : false }, function(xhr, res) { L.post(url, { package: pkg, autoremove: rem ? rem.checked : false, overwrite: owr ? owr.checked : false }, function(xhr, res) {
dlg.removeChild(dlg.lastChild); dlg.removeChild(dlg.lastChild);
if (res.stdout) if (res.stdout)
dlg.appendChild(E('pre', [ res.stdout ])); dlg.appendChild(E('pre', [ res.stdout ]));
if (res.stderr) { if (res.stderr) {
dlg.appendChild(E('h5', _('Errors'))); dlg.appendChild(E('h5', _('Errors')));
dlg.appendChild(E('pre', { 'class': 'errors' }, [ res.stderr ])); dlg.appendChild(E('pre', { 'class': 'errors' }, [ res.stderr ]));
} }
if (res.code !== 0) if (res.code !== 0)
dlg.appendChild(E('p', _('The <em>opkg %h</em> command failed with code <code>%d</code>.').format(cmd, (res.code & 0xff) || -1))); dlg.appendChild(E('p', _('The <em>opkg %h</em> command failed with code <code>%d</code>.').format(cmd, (res.code & 0xff) || -1)));
dlg.appendChild(E('div', { 'class': 'right' }, dlg.appendChild(E('div', { 'class': 'right' },
E('div', { E('div', {
'class': 'btn', 'class': 'btn',
'click': function() { 'click': L.bind(function(res) {
L.hideModal(); L.hideModal();
updateLists(); updateLists();
}
}, _('Dismiss')))); if (res.code !== 0)
rejectFn(new Error(res.stderr || 'opkg error %d'.format(res.code)));
else
resolveFn(res);
}, this, res)
}, _('Dismiss'))));
});
}); });
} }
function handleUpload(ev)
{
var path = '/tmp/upload.ipk';
return L.ui.uploadFile(path).then(L.bind(function(btn, res) {
L.showModal(_('Manually install package'), [
E('p', {}, _('Installing packages from untrusted sources is a potential security risk! Really attempt to install <em>%h</em>?').format(res.name)),
E('ul', {}, [
res.size ? E('li', {}, '%s: %1024.2mB'.format(_('Size'), res.size)) : '',
res.checksum ? E('li', {}, '%s: %s'.format(_('MD5'), res.checksum)) : '',
res.sha256sum ? E('li', {}, '%s: %s'.format(_('SHA256'), res.sha256sum)) : ''
]),
E('div', { 'class': 'right' }, [
E('div', {
'click': function(ev) {
L.hideModal();
L.fs.remove(path);
},
'class': 'btn cbi-button-neutral'
}, _('Cancel')), ' ',
E('div', {
'class': 'btn cbi-button-action',
'data-command': 'install',
'data-package': path,
'click': function(ev) {
handleOpkg(ev).finally(function() {
L.fs.remove(path)
});
}
}, _('Install'))
])
]);
}, this, ev.target));
}
function updateLists() function updateLists()
{ {
cbi_update_table('#packages', [], cbi_update_table('#packages', [],

View file

@ -28,6 +28,11 @@
min-width: 250px; min-width: 250px;
} }
.controls > *:nth-child(2),
.controls > *:nth-child(3) {
flex-basis: 20%;
}
.controls > * > .btn { .controls > * > .btn {
flex-basis: 20px; flex-basis: 20px;
text-align: center; text-align: center;
@ -107,6 +112,8 @@
<label><%:Actions%>:</label> <label><%:Actions%>:</label>
<button class="btn cbi-button-positive" data-command="update" onclick="handleOpkg(event)"><%:Update lists…%></button> <button class="btn cbi-button-positive" data-command="update" onclick="handleOpkg(event)"><%:Update lists…%></button>
&#160; &#160;
<button class="btn cbi-button-action" onclick="handleUpload(event)"><%:Upload Package…%></button>
&#160;
<button class="btn cbi-button-neutral" onclick="handleConfig(event)"><%:Configure opkg…%></button> <button class="btn cbi-button-neutral" onclick="handleConfig(event)"><%:Configure opkg…%></button>
</div> </div>
</div> </div>

View file

@ -69,7 +69,8 @@
"/bin/tar": [ "exec" ], "/bin/tar": [ "exec" ],
"/bin/umount": [ "exec" ], "/bin/umount": [ "exec" ],
"/tmp/backup.tar.gz": [ "write" ], "/tmp/backup.tar.gz": [ "write" ],
"/tmp/firmware.bin": [ "write" ] "/tmp/firmware.bin": [ "write" ],
"/tmp/upload.ipk": [ "write" ]
}, },
"ubus": { "ubus": {
"file": [ "write", "remove", "exec" ], "file": [ "write", "remove", "exec" ],