MAJOR: Updates for Authenticated Web UI and CLI #30
| @ -637,7 +637,7 @@ function handleApi(req, res) { | |||||||
|         , active: !!myRemote |         , active: !!myRemote | ||||||
|         , initialized: (state.config.relay && state.config.token && state.config.agreeTos) ? true : false |         , initialized: (state.config.relay && state.config.token && state.config.agreeTos) ? true : false | ||||||
|         , connected: isConnected |         , connected: isConnected | ||||||
|         , proctime: Math.round(process.uptime() * 1000) |         //, proctime: Math.round(process.uptime() * 1000)
 | ||||||
|         , uptime: now - startTime |         , uptime: now - startTime | ||||||
|         , runtime: isConnected && connectTimes.length && (now - connectTimes[0]) || 0 |         , runtime: isConnected && connectTimes.length && (now - connectTimes[0]) || 0 | ||||||
|         , reconnects: connectTimes.length |         , reconnects: connectTimes.length | ||||||
|  | |||||||
| @ -115,74 +115,95 @@ | |||||||
|     </section> |     </section> | ||||||
| 
 | 
 | ||||||
|     <section v-if="views.section.status"> |     <section v-if="views.section.status"> | ||||||
|       <button v-if="!status.enabled" v-on:click="enable">Enable Traffic</button> |  | ||||||
|       <button v-if="status.enabled" v-on:click="disable">Disable Traffic</button> |  | ||||||
|       <br> |  | ||||||
|       <br> |  | ||||||
| 
 |  | ||||||
|       http://localhost:{{ status.port }} |       http://localhost:{{ status.port }} | ||||||
|       <br> |       <br> | ||||||
|       <br> |       <br> | ||||||
| 
 | 
 | ||||||
|       SSH: |       <section v-if="views.section.status_chooser"> | ||||||
|       <span v-if="status.ssh">{{ status.ssh }} |         <button v-on:click.prevent.stop="changeState('status/share')">Share Files & Folders</button> | ||||||
|         <button v-on:click="ssh(-1)">Disable SSH</button></span> |         <button v-on:click.prevent.stop="changeState('status/host')">Host a Website or Webapp</button> | ||||||
|       <span v-if="!status.ssh"><input type="text" v-model="state.ssh" placeholder="22"> |         <button v-on:click.prevent.stop="changeState('status/access')">Remote Access via SSH</button> | ||||||
|         <button v-on:click="ssh(state.ssh)">Enable SSH</button></span> |       </section> | ||||||
|       <br> |  | ||||||
|       <br> |  | ||||||
| 
 | 
 | ||||||
|       Path Hosting: |       <section v-if="views.section.status_access"> | ||||||
|       <ul> |         SSH: | ||||||
|         <li v-for="domain in status.pathHosting"> |         <span v-if="status.ssh">{{ status.ssh }} | ||||||
|           {{ domain.name }} |           <button v-on:click="ssh(-1)">Disable SSH</button></span> | ||||||
|           <input type="text" v-model="domain.path" v-bind:placeholder="domain.handler"> |         <span v-if="!status.ssh"><input type="text" v-model="state.ssh" placeholder="22"> | ||||||
|           <button |           <button v-on:click="ssh(state.ssh)">Enable SSH</button></span> | ||||||
|             v-if="domain.handler == domain.path" |         <br> | ||||||
|             v-on:click="changePathHost(domain, domain.path)">Save</button> |         <br> | ||||||
|           <button v-on:click="deletePathHost(domain)">X</button> |         <div v-if="state.ssh_active">SSH is currently running</div> | ||||||
|         </li> |         <div v-if="!state.ssh_active">SSH is not currently running</div> | ||||||
|       </ul> |         <br> | ||||||
|       <form v-on:submit="createHttp(newHttp.name, newHttp.handler)"> |         <div v-if="state.ssh_insecure">Password Authentication is NOT disabled. | ||||||
|         <input v-model="newHttp.sub" type="text" placeholder="subdomain (ex: api)"> |           Please consider updating your <code>sshd_config</code> and restarting ssh. | ||||||
|         <select v-model="newHttp.name"> |           <pre><code>{{ status }}</code></pre> | ||||||
|           <option v-for="w in status.wildDomains" v-bind:value="w.name">{{ w.name }}</option> |         </div> | ||||||
|         </select> |         <div v-if="!state.ssh_insecure">Key-Only Authentication is enabled :)</div> | ||||||
|         <input v-model="newHttp.handler" type="text" placeholder="path (ex: ~/Public)" required> |         <br> | ||||||
|         <button>Add</button> |       </section> | ||||||
|       </form> |  | ||||||
|       <br> |  | ||||||
| 
 | 
 | ||||||
|       Port Forwarding: |       <section v-if="views.section.status_share"> | ||||||
|       <ul> |         Path Hosting: | ||||||
|         <li v-for="domain in status.portForwards"> |         <ul> | ||||||
|           {{ domain.name }} |           <li v-for="domain in status.pathHosting"> | ||||||
|           <input type="text" v-model="domain._port" v-bind:placeholder="domain.handler"> |             {{ domain.name }} | ||||||
|           <button |             <input type="text" v-model="domain.path" v-bind:placeholder="domain.handler"> | ||||||
|             v-if="domain.handler == domain._port" |             <button | ||||||
|             v-on:click="changePortForward(domain, domain._port)">Save</button> |               v-if="domain.handler == domain.path" | ||||||
|           <button v-on:click="deletePortForward(domain)">X</button> |               v-on:click="changePathHost(domain, domain.path)">Save</button> | ||||||
|         </li> |             <button v-on:click="deletePathHost(domain)">X</button> | ||||||
|       </ul> |           </li> | ||||||
|       <form v-on:submit="createHttp(newHttp.name, newHttp.handler)"> |         </ul> | ||||||
|         <input v-model="newHttp.sub" type="text" placeholder="subdomain (ex: api)"> |         <form v-on:submit="createHttp(newHttp.name, newHttp.handler)"> | ||||||
|         <select v-model="newHttp.name"> |           <input v-model="newHttp.sub" type="text" placeholder="subdomain (ex: api)"> | ||||||
|           <option v-for="w in status.wildDomains" v-bind:value="w.name">{{ w.name }}</option> |           <select v-model="newHttp.name"> | ||||||
|         </select> |             <option v-for="w in status.wildDomains" v-bind:value="w.name">{{ w.name }}</option> | ||||||
|         <input v-model="newHttp.handler" type="number" placeholder="port (ex: 3000)" required> |           </select> | ||||||
|         <button>Add</button> |           <input v-model="newHttp.handler" type="text" placeholder="path (ex: ~/Public)" required> | ||||||
|       </form> |           <button>Add</button> | ||||||
|  |         </form> | ||||||
|  |         <br> | ||||||
|  |       </section> | ||||||
|  | 
 | ||||||
|  |       <section v-if="views.section.status_host"> | ||||||
|  |         Port Forwarding: | ||||||
|  |         <ul> | ||||||
|  |           <li v-for="domain in status.portForwards"> | ||||||
|  |             {{ domain.name }} | ||||||
|  |             <input type="text" v-model="domain._port" v-bind:placeholder="domain.handler"> | ||||||
|  |             <button | ||||||
|  |               v-if="domain.handler == domain._port" | ||||||
|  |               v-on:click="changePortForward(domain, domain._port)">Save</button> | ||||||
|  |             <button v-on:click="deletePortForward(domain)">X</button> | ||||||
|  |           </li> | ||||||
|  |         </ul> | ||||||
|  |         <form v-on:submit="createHttp(newHttp.name, newHttp.handler)"> | ||||||
|  |           <input v-model="newHttp.sub" type="text" placeholder="subdomain (ex: api)"> | ||||||
|  |           <select v-model="newHttp.name"> | ||||||
|  |             <option v-for="w in status.wildDomains" v-bind:value="w.name">{{ w.name }}</option> | ||||||
|  |           </select> | ||||||
|  |           <input v-model="newHttp.handler" type="number" placeholder="port (ex: 3000)" required> | ||||||
|  |           <button>Add</button> | ||||||
|  |         </form> | ||||||
|  |       </section> | ||||||
| 
 | 
 | ||||||
|       <br> |  | ||||||
|       Proctime: {{ statusProctime }} |  | ||||||
|       <br> |       <br> | ||||||
|       Uptime: {{ statusUptime }} |       Uptime: {{ statusUptime }} | ||||||
|       <br> |       <br> | ||||||
|       Runtime: {{ statusRuntime }} |       Runtime: {{ statusRuntime }} | ||||||
|       <br> |       <br> | ||||||
|       Reconnects: {{ status.reconnects }} |       Reconnects: {{ status.reconnects }} | ||||||
|  | 
 | ||||||
|  |       <details><summary><small>Advanced</small></summary> | ||||||
|  |       <button v-if="!status.enabled" v-on:click="enable">Enable Traffic</button> | ||||||
|  |       <button v-if="status.enabled" v-on:click="disable">Disable Traffic</button> | ||||||
|       <br> |       <br> | ||||||
|  |       <br> | ||||||
|  | 
 | ||||||
|       <pre><code>{{ status }}</code></pre> |       <pre><code>{{ status }}</code></pre> | ||||||
|  |       </details> | ||||||
|     </section> |     </section> | ||||||
| 
 | 
 | ||||||
|   </div> |   </div> | ||||||
|  | |||||||
| @ -247,6 +247,7 @@ var appMethods = { | |||||||
| , deletePathHost: function (domain) { | , deletePathHost: function (domain) { | ||||||
|     api.http(domain.name, 'none'); |     api.http(domain.name, 'none'); | ||||||
|   } |   } | ||||||
|  | , changeState: changeState | ||||||
| }; | }; | ||||||
| var appStates = { | var appStates = { | ||||||
|   setup: function () { |   setup: function () { | ||||||
| @ -263,51 +264,113 @@ var appStates = { | |||||||
|       clearInterval(tok); |       clearInterval(tok); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function updateStatus() { |  | ||||||
|       return api.status().then(function (status) { |  | ||||||
|         if (status.error) { |  | ||||||
|           appData.views.flash.error = status.error.message || JSON.stringify(status.error, null, 2); |  | ||||||
|         } |  | ||||||
|         var wilddomains = []; |  | ||||||
|         var rootdomains = []; |  | ||||||
|         var subdomains = []; |  | ||||||
|         var directories = []; |  | ||||||
|         var portforwards = []; |  | ||||||
|         var free = []; |  | ||||||
|         appData.status = status; |  | ||||||
|         Object.keys(appData.status.servernames).forEach(function (k) { |  | ||||||
|           var s = appData.status.servernames[k]; |  | ||||||
|           s.name = k; |  | ||||||
|           if (s.wildcard) { wilddomains.push(s); } |  | ||||||
|           if (!s.sub && !s.wildcard) { rootdomains.push(s); } |  | ||||||
|           if (s.sub) { subdomains.push(s); } |  | ||||||
|           if (s.handler) { |  | ||||||
|             if (s.handler.toString() === parseInt(s.handler, 10).toString()) { |  | ||||||
|               s._port = s.handler; |  | ||||||
|               portforwards.push(s); |  | ||||||
|             } else { |  | ||||||
|               s.path = s.handler; |  | ||||||
|               directories.push(s); |  | ||||||
|             } |  | ||||||
|           } else { |  | ||||||
|             free.push(s); |  | ||||||
|           } |  | ||||||
|         }); |  | ||||||
|         appData.status.portForwards = portforwards; |  | ||||||
|         appData.status.pathHosting = directories; |  | ||||||
|         appData.status.wildDomains = wilddomains; |  | ||||||
|         appData.newHttp.name = (appData.status.wildDomains[0] || {}).name; |  | ||||||
|         appData.state.ssh = (appData.status.ssh > 0) && appData.status.ssh || undefined; |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|     var tok = setInterval(updateStatus, 2000); |     var tok = setInterval(updateStatus, 2000); | ||||||
| 
 | 
 | ||||||
|     return updateStatus().then(function () { |     return updateStatus().then(function () { | ||||||
|       appData.views.section = { status: true }; |       appData.views.section = { status: true, status_chooser: true }; | ||||||
|       return exitState; |       return exitState; | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  | appStates.status.share = function () { | ||||||
|  |   function exitState() { | ||||||
|  |     clearInterval(tok); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   var tok = setInterval(updateStatus, 2000); | ||||||
|  | 
 | ||||||
|  |   appData.views.section = { status: true, status_share: true }; | ||||||
|  |   return updateStatus().then(function () { | ||||||
|  |     return exitState; | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | appStates.status.host = function () { | ||||||
|  |   function exitState() { | ||||||
|  |     clearInterval(tok); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   var tok = setInterval(updateStatus, 2000); | ||||||
|  | 
 | ||||||
|  |   appData.views.section = { status: true, status_host: true }; | ||||||
|  |   return updateStatus().then(function () { | ||||||
|  |     return exitState; | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | appStates.status.access = function () { | ||||||
|  |   function exitState() { | ||||||
|  |     clearInterval(tok); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   var tok = setInterval(updateStatus, 2000); | ||||||
|  | 
 | ||||||
|  |   appData.views.section = { status: true, status_access: true }; | ||||||
|  |   return updateStatus().then(function () { | ||||||
|  |     return exitState; | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | function updateStatus() { | ||||||
|  |   return api.status().then(function (status) { | ||||||
|  |     if (status.error) { | ||||||
|  |       appData.views.flash.error = status.error.message || JSON.stringify(status.error, null, 2); | ||||||
|  |     } | ||||||
|  |     var wilddomains = []; | ||||||
|  |     var rootdomains = []; | ||||||
|  |     var subdomains = []; | ||||||
|  |     var directories = []; | ||||||
|  |     var portforwards = []; | ||||||
|  |     var free = []; | ||||||
|  |     appData.status = status; | ||||||
|  |     if ('maybe' === status.ssh_requests_password) { | ||||||
|  |       appData.status.ssh_active = false; | ||||||
|  |     } else { | ||||||
|  |       appData.status.ssh_active = true; | ||||||
|  |       if ('yes' === status.ssh_requests_password) { | ||||||
|  |         appData.status.ssh_insecure = true; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if ('yes' === status.ssh_password_authentication) { | ||||||
|  |       appData.status.ssh_insecure = true; | ||||||
|  |     } | ||||||
|  |     if ('yes' === status.ssh_permit_root_login) { | ||||||
|  |       appData.status.ssh_insecure = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // only update what's changed
 | ||||||
|  |     if (appData.state.ssh !== appData.status.ssh) { | ||||||
|  |       appData.state.ssh = appData.status.ssh; | ||||||
|  |     } | ||||||
|  |     if (appData.state.ssh_insecure !== appData.status.ssh_insecure) { | ||||||
|  |       appData.state.ssh_insecure = appData.status.ssh_insecure; | ||||||
|  |     } | ||||||
|  |     if (appData.state.ssh_active !== appData.status.ssh_active) { | ||||||
|  |       appData.state.ssh_active = appData.status.ssh_active; | ||||||
|  |     } | ||||||
|  |     Object.keys(appData.status.servernames).forEach(function (k) { | ||||||
|  |       var s = appData.status.servernames[k]; | ||||||
|  |       s.name = k; | ||||||
|  |       if (s.wildcard) { wilddomains.push(s); } | ||||||
|  |       if (!s.sub && !s.wildcard) { rootdomains.push(s); } | ||||||
|  |       if (s.sub) { subdomains.push(s); } | ||||||
|  |       if (s.handler) { | ||||||
|  |         if (s.handler.toString() === parseInt(s.handler, 10).toString()) { | ||||||
|  |           s._port = s.handler; | ||||||
|  |           portforwards.push(s); | ||||||
|  |         } else { | ||||||
|  |           s.path = s.handler; | ||||||
|  |           directories.push(s); | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|  |         free.push(s); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     appData.status.portForwards = portforwards; | ||||||
|  |     appData.status.pathHosting = directories; | ||||||
|  |     appData.status.wildDomains = wilddomains; | ||||||
|  |     appData.newHttp.name = (appData.status.wildDomains[0] || {}).name; | ||||||
|  |     appData.state.ssh = (appData.status.ssh > 0) && appData.status.ssh || undefined; | ||||||
|  |   }); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| function changeState(newstate) { | function changeState(newstate) { | ||||||
|   var newhash = '#/' + newstate + '/'; |   var newhash = '#/' + newstate + '/'; | ||||||
| @ -325,13 +388,14 @@ function setState(/*ev*/) { | |||||||
|   //ev.oldURL
 |   //ev.oldURL
 | ||||||
|   //ev.newURL
 |   //ev.newURL
 | ||||||
|   if (appData.exit) { |   if (appData.exit) { | ||||||
|  |     console.log('previous state exiting'); | ||||||
|     appData.exit.then(function (exit) { |     appData.exit.then(function (exit) { | ||||||
|       if ('function' === typeof appData.exit) { |       if ('function' === typeof appData.exit) { | ||||||
|         exit(); |         exit(); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|   var parts = location.hash.substr(1).replace(/^\//, '').replace(/\/$/, '').split('/'); |   var parts = location.hash.substr(1).replace(/^\//, '').replace(/\/$/, '').split('/').filter(Boolean); | ||||||
|   var fn = appStates; |   var fn = appStates; | ||||||
|   parts.forEach(function (s) { |   parts.forEach(function (s) { | ||||||
|     console.log("state:", s); |     console.log("state:", s); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user