luci-mod-system: move password and sshkey JS code into external files
authorJo-Philipp Wich <jo@mein.io>
Wed, 21 Nov 2018 19:04:55 +0000 (20:04 +0100)
committerJo-Philipp Wich <jo@mein.io>
Thu, 22 Nov 2018 11:49:14 +0000 (12:49 +0100)
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-mod-system/htdocs/luci-static/resources/view/system/password.js [new file with mode: 0644]
modules/luci-mod-system/htdocs/luci-static/resources/view/system/sshkeys.js [new file with mode: 0644]
modules/luci-mod-system/luasrc/view/admin_system/password.htm
modules/luci-mod-system/luasrc/view/admin_system/sshkeys.htm

diff --git a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/password.js b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/password.js
new file mode 100644 (file)
index 0000000..7a79d7e
--- /dev/null
@@ -0,0 +1,31 @@
+function submitPassword(ev) {
+       var pw1 = document.body.querySelector('[name="pw1"]'),
+           pw2 = document.body.querySelector('[name="pw2"]');
+
+       if (!pw1.value.length || !pw2.value.length)
+               return;
+
+       if (pw1.value === pw2.value) {
+               L.showModal(_('Change login password'),
+                       E('p', { class: 'spinning' }, _('Changing password…')));
+
+               L.post('admin/system/admin/password/json', { password: pw1.value },
+                       function() {
+                               showModal(_('Change login password'), [
+                                       E('div', _('The system password has been successfully changed.')),
+                                       E('div', { 'class': 'right' },
+                                               E('div', { class: 'btn', click: L.hideModal }, _('Dismiss')))
+                               ]);
+
+                               pw1.value = pw2.value = '';
+                       });
+       }
+       else {
+               L.showModal(_('Change login password'), [
+                       E('div', { class: 'alert-message warning' },
+                               _('Given password confirmation did not match, password not changed!')),
+                       E('div', { 'class': 'right' },
+                               E('div', { class: 'btn', click: L.hideModal }, _('Dismiss')))
+               ]);
+       }
+}
diff --git a/modules/luci-mod-system/htdocs/luci-static/resources/view/system/sshkeys.js b/modules/luci-mod-system/htdocs/luci-static/resources/view/system/sshkeys.js
new file mode 100644 (file)
index 0000000..d298b3b
--- /dev/null
@@ -0,0 +1,215 @@
+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) {
+       L.showModal(_('Add key'), E('div', { class: 'spinning' }, _('Saving keys…')));
+       L.post('admin/system/admin/sshkeys/json', { keys: JSON.stringify(keys) }, function(xhr, keys) {
+               renderKeys(keys);
+               L.hideModal();
+       });
+}
+
+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) {
+               L.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: L.hideModal }, _('Close')))
+               ]);
+       }
+       else if (!pubkey) {
+               L.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: L.hideModal }, _('Close')))
+               ]);
+       }
+       else {
+               keys.push(key);
+               saveKeys(keys);
+               input.value = '';
+       }
+}
+
+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);
+       });
+
+       L.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: L.hideModal }, _('Cancel')),
+                       ' ',
+                       E('div', { class: 'btn danger', click: function(ev) { saveKeys(keys) } }, _('Delete key')),
+               ])
+       ]);
+}
+
+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() {
+       L.get('admin/system/admin/sshkeys/json', null, function(xhr, keys) {
+               renderKeys(keys);
+       });
+});
index db35fb01e8e958e470b05919ce04b06989a28584..09cea4f74af50e31f772e42fc8a2b285e34a34fe 100644 (file)
@@ -1,40 +1,5 @@
 <%+header%>
 
-<script type="application/javascript">//<![CDATA[
-       function submitPassword(ev) {
-               var pw1 = document.body.querySelector('[name="pw1"]'),
-                   pw2 = document.body.querySelector('[name="pw2"]');
-
-               if (!pw1.value.length || !pw2.value.length)
-                       return;
-
-               if (pw1.value === pw2.value) {
-                       showModal('<%:Change login password%>',
-                               E('p', { class: 'spinning' }, '<%:Changing password…%>'));
-
-                       (new XHR()).post('<%=url("admin/system/admin/password/json")%>',
-                               { token: '<%=token%>', password: pw1.value },
-                               function() {
-                                       showModal('<%:Change login password%>', [
-                                               E('div', _('The system password has been successfully changed.')),
-                                               E('div', { 'class': 'right' },
-                                                       E('div', { class: 'btn', click: hideModal }, '<%:Dismiss%>'))
-                                       ]);
-
-                                       pw1.value = pw2.value = '';
-                               });
-               }
-               else {
-                       showModal('<%:Change login password%>', [
-                               E('div', { class: 'alert-message warning' },
-                                       _('Given password confirmation did not match, password not changed!')),
-                               E('div', { 'class': 'right' },
-                                       E('div', { class: 'btn', click: hideModal }, '<%:Dismiss%>'))
-                       ]);
-               }
-       }
-//]]></script>
-
 <input type="password" aria-hidden="true" style="position:absolute; left:-10000px" />
 
 <div class="cbi-map">
@@ -67,4 +32,6 @@
        <button class="btn cbi-button-apply" onclick="submitPassword(event)"><%:Save%></button>
 </div>
 
+<script type="application/javascript" src="<%=resource%>/view/system/password.js"></script>
+
 <%+footer%>
index acf008adf3c6227bda573328e5878f842ea4a8b3..77efa11a0f935e942076496deb837398e411d942 100644 (file)
@@ -6,224 +6,6 @@
        }
 </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();
-               });
-       }
-
-       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 = '';
-               }
-       }
-
-       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')),
-                       ])
-               ]);
-       }
-
-       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>
-
 <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%>