luci-app-olsr: handle empty result for non-status tables
[oweals/luci.git] / modules / luci-mod-system / luasrc / view / admin_system / sshkeys.htm
index acf008adf3c6227bda573328e5878f842ea4a8b3..ac453f3f6c5056ee9525c6cbd86e3ac5c62f9ab2 100644 (file)
        .cbi-dynlist {
                max-width: 100%;
        }
-</style>
-
-<script type="application/javascript">//<![CDATA[
-       SSHPubkeyDecoder.prototype = {
-               lengthDecode: function(s, off)
-               {
-                       var l = (s.charCodeAt(off++) << 24) |
-                                       (s.charCodeAt(off++) << 16) |
-                                       (s.charCodeAt(off++) <<  8) |
-                                        s.charCodeAt(off++);
-
-                       if (l < 0 || (off + l) > s.length)
-                               return -1;
-
-                       return l;
-               },
-
-               decode: function(s)
-               {
-                       var parts = s.split(/\s+/);
-                       if (parts.length < 2)
-                               return null;
-
-                       var key = null;
-                       try { key = atob(parts[1]); } catch(e) {}
-                       if (!key)
-                               return null;
-
-                       var off, len;
-
-                       off = 0;
-                       len = this.lengthDecode(key, off);
-
-                       if (len <= 0)
-                               return null;
-
-                       var type = key.substr(off + 4, len);
-                       if (type !== parts[0])
-                               return null;
-
-                       off += 4 + len;
-
-                       var len1 = off < key.length ? this.lengthDecode(key, off) : 0;
-                       if (len1 <= 0)
-                               return null;
-
-                       var curve = null;
-                       if (type.indexOf('ecdsa-sha2-') === 0) {
-                               curve = key.substr(off + 4, len1);
-
-                               if (!len1 || type.substr(11) !== curve)
-                                       return null;
-
-                               type = 'ecdsa-sha2';
-                               curve = curve.replace(/^nistp(\d+)$/, 'NIST P-$1');
-                       }
-
-                       off += 4 + len1;
-
-                       var len2 = off < key.length ? this.lengthDecode(key, off) : 0;
-                       if (len2 < 0)
-                               return null;
-
-                       if (len1 & 1)
-                               len1--;
-
-                       if (len2 & 1)
-                               len2--;
-
-                       var comment = parts.slice(2).join(' '),
-                           fprint = parts[1].length > 68 ? parts[1].substr(0, 33) + '…' + parts[1].substr(-34) : parts[1];
-
-                       switch (type)
-                       {
-                       case 'ssh-rsa':
-                               return { type: 'RSA', bits: len2 * 8, comment: comment, fprint: fprint };
-
-                       case 'ssh-dss':
-                               return { type: 'DSA', bits: len1 * 8, comment: comment, fprint: fprint };
-
-                       case 'ssh-ed25519':
-                               return { type: 'ECDH', curve: 'Curve25519', comment: comment, fprint: fprint };
-
-                       case 'ecdsa-sha2':
-                               return { type: 'ECDSA', curve: curve, comment: comment, fprint: fprint };
 
-                       default:
-                               return null;
-                       }
-               }
-       };
-
-       function SSHPubkeyDecoder() {}
-
-       function renderKeys(keys) {
-               var list = document.querySelector('.cbi-dynlist[name="sshkeys"]'),
-                   decoder = new SSHPubkeyDecoder();
-
-               while (!matchesElem(list.firstElementChild, '.add-item'))
-                       list.removeChild(list.firstElementChild);
-
-               keys.forEach(function(key) {
-                       var pubkey = decoder.decode(key);
-                       if (pubkey)
-                               list.insertBefore(E('div', {
-                                       class: 'item',
-                                       click: removeKey,
-                                       'data-key': key
-                               }, [
-                                       E('strong', pubkey.comment || _('Unnamed key')), E('br'),
-                                       E('small', [
-                                               '%s, %s'.format(pubkey.type, pubkey.curve || _('%d Bit').format(pubkey.bits)),
-                                               E('br'), E('code', pubkey.fprint)
-                                       ])
-                               ]), list.lastElementChild);
-               });
-
-               if (list.firstElementChild === list.lastElementChild)
-                       list.insertBefore(E('p', _('No public keys present yet.')), list.lastElementChild);
-       }
-
-       function saveKeys(keys) {
-               showModal('<%:Add key%>', E('div', { class: 'spinning' }, _('Saving keys…')));
-               (new XHR()).post('<%=url("admin/system/admin/sshkeys/json")%>', { token: '<%=token%>', keys: JSON.stringify(keys) }, function(xhr, keys) {
-                       renderKeys(keys);
-                       hideModal();
-               });
+       .cbi-dynlist .item > small {
+               display: block;
+               direction: rtl;
+               overflow: hidden;
+               text-align: left;
        }
 
-       function addKey(ev) {
-               var decoder = new SSHPubkeyDecoder(),
-                   list = findParent(ev.target, '.cbi-dynlist'),
-                   input = list.querySelector('input[type="text"]'),
-                   key = input.value.trim(),
-                   pubkey = decoder.decode(key),
-                   keys = [];
-
-               if (!key.length)
-                       return;
-
-               list.querySelectorAll('.item').forEach(function(item) {
-                       keys.push(item.getAttribute('data-key'));
-               });
-
-               if (keys.indexOf(key) !== -1) {
-                       showModal('<%:Add key%>', [
-                               E('div', { class: 'alert-message warning' }, _('The given SSH public key has already been added.')),
-                               E('div', { class: 'right' }, E('div', { class: 'btn', click: hideModal }, _('Close')))
-                       ]);
-               }
-               else if (!pubkey) {
-                       showModal('<%:Add key%>', [
-                               E('div', { class: 'alert-message warning' }, _('The given SSH public key is invalid. Please supply proper public RSA or ECDSA keys.')),
-                               E('div', { class: 'right' }, E('div', { class: 'btn', click: hideModal }, _('Close')))
-                       ]);
-               }
-               else {
-                       keys.push(key);
-                       saveKeys(keys);
-                       input.value = '';
-               }
+       .cbi-dynlist .item > small > code {
+               direction: ltr;
+               white-space: nowrap;
+               unicode-bidi: bidi-override;
        }
 
-       function removeKey(ev) {
-               var list = findParent(ev.target, '.cbi-dynlist'),
-                   delkey = ev.target.getAttribute('data-key'),
-                   keys = [];
-
-               list.querySelectorAll('.item').forEach(function(item) {
-                       var key = item.getAttribute('data-key');
-                       if (key !== delkey)
-                               keys.push(key);
-               });
-
-               showModal('<%:Delete key%>', [
-                       E('div', _('Do you really want to delete the following SSH key?')),
-                       E('pre', delkey),
-                       E('div', { class: 'right' }, [
-                               E('div', { class: 'btn', click: hideModal }, _('Cancel')),
-                               ' ',
-                               E('div', { class: 'btn danger', click: function(ev) { saveKeys(keys) } }, _('Delete key')),
-                       ])
-               ]);
+       @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
+               .cbi-dynlist .item > small { direction: ltr }
        }
-
-       function dragKey(ev) {
-               ev.stopPropagation();
-               ev.preventDefault();
-               ev.dataTransfer.dropEffect = 'copy';
-       }
-
-       function dropKey(ev) {
-               var file = ev.dataTransfer.files[0],
-                   input = ev.currentTarget.querySelector('input[type="text"]'),
-                   reader = new FileReader();
-
-               if (file) {
-                       reader.onload = function(rev) {
-                               input.value = rev.target.result.trim();
-                               addKey(ev);
-                               input.value = '';
-                       };
-
-                       reader.readAsText(file);
-               }
-
-               ev.stopPropagation();
-               ev.preventDefault();
-       }
-
-       window.addEventListener('dragover', function(ev) { ev.preventDefault() });
-       window.addEventListener('drop', function(ev) { ev.preventDefault() });
-
-       requestAnimationFrame(function() {
-               XHR.get('<%=url("admin/system/admin/sshkeys/json")%>', null, function(xhr, keys) {
-                       renderKeys(keys);
-               });
-       });
-//]]></script>
+</style>
 
 <div class="cbi-map">
        <h2><%:SSH-Keys%></h2>
                <div class="cbi-dynlist" name="sshkeys">
                        <p class="spinning"><%:Loading SSH keys…%></p>
                        <div class="add-item" ondragover="dragKey(event)" ondrop="dropKey(event)">
-                               <input class="cbi-input-text" type="text" placeholder="<%:Paste or drag SSH key file…%>" onkeydown="if (event.keyCode === 13) addKey(event)" /><!--
-                               --><div class="cbi-button" onclick="addKey(event)"><%:Add key%></div>
+                               <input class="cbi-input-text" type="text" placeholder="<%:Paste or drag SSH key file…%>" onkeydown="if (event.keyCode === 13) addKey(event)" />
+                               <button class="cbi-button" onclick="addKey(event)"><%:Add key%></button>
                        </div>
                </div>
        </div>
 </div>
 
+<script type="application/javascript" src="<%=resource%>/view/system/sshkeys.js"></script>
+
 <%+footer%>