show many more things
This commit is contained in:
		
							parent
							
								
									783dd3c53b
								
							
						
					
					
						commit
						90f5eb11d5
					
				| @ -18,24 +18,18 @@ | ||||
| 
 | ||||
|     <div class="container" ng-controller="LoginController as vm" ng-init="vm.setSimple()"> | ||||
|       <h1 ng-if="!vm.authnUpdated">Initializing... {{vm.hello}}</h1> | ||||
|       <div> | ||||
|       Configure Remote Server | ||||
|       <label>Configuration Address:</label> | ||||
|       <input type="text" placeholder="i.e. 192.168.1.100"> | ||||
|       <label>Configuration Name:</label> | ||||
|       <input type="text" placeholder="i.e. localhost.daplie.invalid"> | ||||
|       <label>Root Certificate Validation (optional):</label> | ||||
|       <textarea class="textarea" placeholder="paste the contents of a root.pem here"></textarea> | ||||
|       </div> | ||||
| 
 | ||||
| 
 | ||||
|       <div ng-if="!vm.authnUpdated"> | ||||
|       <button | ||||
|         type="button" | ||||
|         class="btn btn-link" | ||||
|         ng-if="!vm.advanced" | ||||
|         ng-click="vm.setAdvanced()" | ||||
|         >advanced</button> | ||||
|       <button | ||||
|         type="button" | ||||
|         class="btn btn-link" | ||||
|         ng-if="vm.advanced" | ||||
|         ng-click="vm.setSimple();" | ||||
|         >simple</button> | ||||
|       <input | ||||
|         type="text" | ||||
|         ng-if="vm.advanced" | ||||
|         ng-change="vm.checkProviderUri(vm.myProviderUri)" | ||||
|         ng-model="vm.myProviderUri"> | ||||
|       <button | ||||
|         type="button" | ||||
|         class="btn btn-default" | ||||
| @ -43,48 +37,143 @@ | ||||
|         ng-click="vm.authenticate()" | ||||
|         >Login</button> | ||||
|       </div> | ||||
|       <button | ||||
|         type="button" | ||||
|         class="btn btn-link" | ||||
|         ng-if="!vm.advanced" | ||||
|         ng-click="vm.setAdvanced()" | ||||
|         >advanced</button> | ||||
|       <div ng-if="vm.advanced"> | ||||
|         <button | ||||
|           type="button" | ||||
|           class="btn btn-link" | ||||
|           ng-click="vm.setSimple();" | ||||
|           >simple</button> | ||||
|         <input | ||||
|           type="text" | ||||
|           ng-change="vm.checkProviderUri(vm.myProviderUri)" | ||||
|           ng-model="vm.myProviderUri"> | ||||
|         <br/> | ||||
|         <small>todo: allow per-device authorization</small> | ||||
|       </div> | ||||
| 
 | ||||
|       <div ng-if="vm.config"> | ||||
|         <div class="input-group" ng-init="siteconf = vm.config.global"> | ||||
|         <div ng-init="siteconf = vm.config.global"> | ||||
|           <h1>Server Device Name: <span ng-bind="vm.config.device.hostname"></span></h1> | ||||
|           <!-- input class="form-control" ng-model="vm.config.device.hostname" / --> | ||||
| 
 | ||||
|           <h1>Server Working Directory:</h1> | ||||
|           <input class="form-control" ng-model="vm.config.cwd" /> | ||||
| 
 | ||||
|           <h1>Addresses:</h1> | ||||
|           <table class="table"> | ||||
|             <tr> | ||||
|               <th>Interface</th> | ||||
|               <th>Address</th> | ||||
|               <th>Family</th> | ||||
|               <th>Scope</th> | ||||
|             </tr> | ||||
|             <tr ng-repeat="addr in vm.config.addresses"> | ||||
|               <td ng-bind="addr.iface"></td> | ||||
|               <td ng-bind="addr.address"></td> | ||||
|               <td ng-bind="addr.family"></td> | ||||
|               <td ng-bind="addr.range"></td> | ||||
|             </tr> | ||||
|           </table> | ||||
| 
 | ||||
|           <h1>Managed Domains:</h1> | ||||
| 
 | ||||
|           <div ng-if="!vm.domains.length"> | ||||
|             You don't have any domains with this account. | ||||
|             <br/> | ||||
|             Try a different account? | ||||
|             <br/> | ||||
|             <input type="url" placeholder="https://daplie.domains"> | ||||
|             <button type="button" | ||||
|               class="btn" | ||||
|               disabled | ||||
|               >Login</button> | ||||
|           </div> | ||||
| 
 | ||||
|           <div ng-if="vm.domains.length"> | ||||
|             <h2>Enable Tunnel</h2> | ||||
|             <input type="radio" ng-model="vm.config.tunnel.enabled" ng-value="true"> | ||||
|             <input type="radio" ng-model="vm.config.tunnel.enabled" ng-value="false"> | ||||
| 
 | ||||
|             <table class="table"> | ||||
|               <tr> | ||||
|                 <th>Domain</th> | ||||
|                 <th>Sub</th> | ||||
|                 <th>Devices</th> | ||||
|               </tr> | ||||
|               <tr ng-repeat="d in vm.dns"> | ||||
|                 <td ng-bind="d.domain"></td> | ||||
|                 <td ng-bind="d.name"></td> | ||||
|                 <td> | ||||
|                   <span ng-if="!d.domain"> | ||||
|                     <div ng-repeat="dev in d.devices"> | ||||
|                       <span ng-bind="dev" | ||||
|                         ></span> <button | ||||
|                         type="button" | ||||
|                         class="btn btn-danger" | ||||
|                         ng-click="vm.removeDevice(d, dev)" | ||||
|                         >x</button> | ||||
|                     </div> | ||||
|                   </span> | ||||
|                 </td> | ||||
|               </tr> | ||||
|             </table> | ||||
|           </div> | ||||
| 
 | ||||
|           <h1>Global Settings:</h1> | ||||
|           <br/> | ||||
|           <div ng-repeat="path in siteconf.paths">Pathname: | ||||
|             <input class="form-control" ng-model="path.$id" /> | ||||
|             <div ng-repeat="module in path.modules">Modulename: {{module.$id}} | ||||
|               <div ng-repeat="(key, value) in module">{{key}}: | ||||
|                 <input class="form-control" ng-model="value" /> | ||||
|           <form class="form-inline"> | ||||
|           <div ng-repeat="path in siteconf.paths"> | ||||
|             <h2 ng-bind="path.$id"></h2> | ||||
|             <div ng-repeat="module in path.modules"> | ||||
|               <h3>{{module.$id}}</h3> | ||||
|               <div ng-repeat="(key, value) in module"> | ||||
|                 <label>{{key}}</label>: <input class="form-control" ng-model="module[key]" /> | ||||
|               </div> | ||||
|             </div> | ||||
|             <br/> | ||||
|             <br/> | ||||
|             <br/> | ||||
|           </div> | ||||
|           </form> | ||||
|         </div> | ||||
| 
 | ||||
|         <h1>Per-Domain Settings:</h1> | ||||
|         <div class="input-group" ng-repeat="siteconf in vm.config.sites"> | ||||
|           <label>Hostname:</label> <input class="form-control" ng-model="siteconf.$id" /> | ||||
|           <br/> | ||||
|           <div ng-repeat="path in siteconf.paths">Pathname: | ||||
|             <input class="form-control" ng-model="path.$id" /> | ||||
|             <div ng-repeat="module in path.modules">Modulename: {{module.$id}} | ||||
|               <div ng-repeat="(key, value) in module">{{key}}: | ||||
|                 <input class="form-control" ng-model="value" /> | ||||
|         <div ng-repeat="siteconf in vm.config.sites"> | ||||
|           <h2 ng-bind="siteconf.$id"></h2> | ||||
|           <div ng-repeat="path in siteconf.paths"> | ||||
|             <h2 ng-bind="path.$id"></h2> | ||||
|             <div ng-repeat="module in path.modules"> | ||||
|               <h3>{{module.$id}}</h3> | ||||
|               <div ng-repeat="(key, value) in module"> | ||||
|                 <label>{{key}}</label>: <input class="form-control" ng-model="module[key]" /> | ||||
|               </div> | ||||
|             </div> | ||||
|             <br/> | ||||
|             <br/> | ||||
|             <br/> | ||||
|           </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="input-group" ng-init="defaultsconf = vm.config.defaults"> | ||||
|         <div ng-init="defaultsconf = vm.config.defaults"> | ||||
|           <h1>Fallback Settings:</h1> | ||||
|           <br/> | ||||
|           <div ng-repeat="path in defaultsconf.paths">Pathname: | ||||
|             <input class="form-control" ng-model="path.$id" /> | ||||
|             <div ng-repeat="module in path.modules">Modulename: {{module.$id}} | ||||
|               <div ng-repeat="(key, value) in module">{{key}}: | ||||
|                 <input class="form-control" ng-model="value" /> | ||||
|           <div ng-repeat="path in siteconf.paths"> | ||||
|             <h2 ng-bind="path.$id"></h2> | ||||
|             <div ng-repeat="module in path.modules"> | ||||
|               <h3>{{module.$id}}</h3> | ||||
|               <div ng-repeat="(key, value) in module"> | ||||
|                 <label>{{key}}</label>: <input class="form-control" ng-model="module[key]" /> | ||||
|               </div> | ||||
|             </div> | ||||
|             <br/> | ||||
|             <br/> | ||||
|             <br/> | ||||
|           </div> | ||||
|         </div> | ||||
| 
 | ||||
| @ -104,6 +193,7 @@ | ||||
|     <script src="/assets/org.oauth3/oauth3.core.js"></script> | ||||
|     <script src="/assets/org.oauth3/oauth3.ng.js"></script> | ||||
|     <script src="/assets/org.oauth3/oauth3.domains.js"></script> | ||||
|     <script src="/assets/org.oauth3/oauth3.dns.js"></script> | ||||
|     <script src="/js/app.js"></script> | ||||
| 
 | ||||
|   </body> | ||||
|  | ||||
| @ -38,6 +38,91 @@ angular.module('com.daplie.cloud', [ 'org.oauth3' ]) | ||||
|       }, 250); | ||||
|     }; | ||||
| 
 | ||||
|     vm.sortDnsRecords = function (a, b) { | ||||
|       if (a.sld !== b.sld) { | ||||
|         return a.sld > b.sld ? 1 : -1; | ||||
|       } | ||||
|       if (a.tld !== b.tld) { | ||||
|         return a.tld > b.tld ? 1 : -1; | ||||
|       } | ||||
|       // TODO normalize
 | ||||
|       a.sub = a.sub || ''; | ||||
|       b.sub = b.sub || ''; | ||||
|       if (a.sub !== b.sub) { | ||||
|         if (!a.sub) { | ||||
|           return -1; | ||||
|         } | ||||
|         if (!b.sub) { | ||||
|           return 1; | ||||
|         } | ||||
|         return a.sub > b.sub ? 1 : -1; | ||||
|       } | ||||
|       if (a.domain !== b.domain) { | ||||
|         if (!a.domain) { | ||||
|           return 1; | ||||
|         } | ||||
|         if (!b.domain) { | ||||
|           return -1; | ||||
|         } | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     vm.viewDomains = function (config, domains, dns) { | ||||
|       vm.dns = dns.slice(0); | ||||
|       vm.domains = domains.slice(0); | ||||
|       vm.dns = vm.dns.filter(function (record) { | ||||
|         if (-1 === [ 'A', 'AAAA', 'ANAME' ].indexOf(record.type)) { | ||||
|           return false; | ||||
|         } | ||||
|         if (record.device !== config.device.hostname) { | ||||
|           return false; | ||||
|         } | ||||
|         return true; | ||||
|       }); | ||||
|       vm.dns.forEach(function (r) { | ||||
|         vm.domains.forEach(function (d) { | ||||
|           if (r.zone === d.domain) { | ||||
|             r.sub = r.name.substr(0, r.name.length - (d.domain.length + 1)); | ||||
|             r.tld = d.tld; | ||||
|             r.sld = d.sld; | ||||
|           } | ||||
|         }); | ||||
|       }); | ||||
|       vm.dns = vm.dns.concat(vm.domains); | ||||
|       vm.dns.sort(vm.sortDnsRecords); | ||||
|       vm.dns.forEach(function (r) { | ||||
|         if (r.domain) { | ||||
|           return; | ||||
|         } | ||||
|         r.devices = r.devices || [ r.device ]; | ||||
| 
 | ||||
|         dns.forEach(function (r2) { | ||||
|           if (r.name !== r2.name) { | ||||
|             return; | ||||
|           } | ||||
|           if (-1 !== r.devices.indexOf(r2.device)) { | ||||
|             return; | ||||
|           } | ||||
|           r.devices.push(r2.device); | ||||
|         }); | ||||
|       }); | ||||
|       console.log('vm.dns'); | ||||
|       console.log(vm.dns); | ||||
|       /* | ||||
|       vm.domains.forEach(function (d) { | ||||
|         d.devices = []; | ||||
|         dns.forEach(function (r) { | ||||
|           // 0 === r.name.split('').reverse().join('').indexOf(d.domain.split('').reverse().join(''))
 | ||||
|           if (r.zone === d.domain) { | ||||
|             d.devices.push({ | ||||
|               name: r.device | ||||
|             }); | ||||
|           } | ||||
|         }); | ||||
|       }); | ||||
|       */ | ||||
|     }; | ||||
| 
 | ||||
|     vm.authenticate = function () { | ||||
|       // TODO authorization redirect /api/org.oauth3.consumer/authorization_redirect/:provider_uri
 | ||||
| 
 | ||||
| @ -46,44 +131,50 @@ angular.module('com.daplie.cloud', [ 'org.oauth3' ]) | ||||
| 
 | ||||
|         return oauth3.api('domains.list').then(function (domains) { | ||||
|           console.info("domains owned", domains); | ||||
|           vm.domains = domains; | ||||
| 
 | ||||
|           return OAUTH3.request({ | ||||
|             method: 'POST' | ||||
|           , url: 'https://' + vm.clientUri + '/api/com.daplie.caddy/init' | ||||
|           , session: session | ||||
|           , data: { | ||||
|               access_token: session.access_token | ||||
|             , refresh_token: session.refresh_token | ||||
|             , expires_in: session.expires_in | ||||
|             , scope: session.scope | ||||
|             , provider_uri: OAUTH3.uri.normalize(session.provider_uri) | ||||
|             , client_uri: vm.clientUri | ||||
|             , domains: domains.map(function (d) { | ||||
|                 return { | ||||
|                   id: d.id | ||||
|                 , sub: d.sub | ||||
|                 , sld: d.sld | ||||
|                 , tld: d.tld | ||||
|                 }; | ||||
|               }) | ||||
|             , jwk: null // TODO publish public key
 | ||||
|             } | ||||
|           }).then(function (resp) { | ||||
|             // TODO resp should contain a token
 | ||||
|             console.info('Initialized Goldilocks', resp); | ||||
|           return oauth3.api('dns.list').then(function (dns) { | ||||
|             console.info("dns records", dns); | ||||
| 
 | ||||
|             return OAUTH3.request({ | ||||
|               method: 'GET' | ||||
|             , url: 'https://' + vm.clientUri + '/api/com.daplie.caddy/config' | ||||
|               method: 'POST' | ||||
|             , url: 'https://' + vm.clientUri + '/api/com.daplie.caddy/init' | ||||
|             , session: session | ||||
|             }).then(function (configResp) { | ||||
|               console.log('config', configResp.data); | ||||
|               vm.config = configResp.data; | ||||
|               return resp; | ||||
|             , data: { | ||||
|                 access_token: session.access_token | ||||
|               , refresh_token: session.refresh_token | ||||
|               , expires_in: session.expires_in | ||||
|               , scope: session.scope | ||||
|               , provider_uri: OAUTH3.uri.normalize(session.provider_uri) | ||||
|               , client_uri: vm.clientUri | ||||
|               , domains: domains.map(function (d) { | ||||
|                   return { | ||||
|                     id: d.id | ||||
|                   , sub: d.sub | ||||
|                   , sld: d.sld | ||||
|                   , tld: d.tld | ||||
|                   }; | ||||
|                 }) | ||||
|               , jwk: null // TODO publish public key
 | ||||
|               } | ||||
|             }).then(function (resp) { | ||||
|               // TODO resp should contain a token
 | ||||
|               console.info('Initialized Goldilocks', resp); | ||||
|               return OAUTH3.request({ | ||||
|                 method: 'GET' | ||||
|               , url: 'https://' + vm.clientUri + '/api/com.daplie.caddy/config' | ||||
|               , session: session | ||||
|               }).then(function (configResp) { | ||||
|                 console.log('config', configResp.data); | ||||
|                 vm.config = configResp.data; | ||||
|                 //vm.config.ifaces
 | ||||
|                 //vm.config.addresses = [];
 | ||||
|                 vm.viewDomains(vm.config, domains, dns); | ||||
|                 return resp; | ||||
|               }); | ||||
|             }, function (err) { | ||||
|               console.error(err); | ||||
|               window.alert("Initialization failed:" + err.message); | ||||
|             }); | ||||
|           }, function (err) { | ||||
|             console.error(err); | ||||
|             window.alert("Initialization failed:" + err.message); | ||||
|           }); | ||||
|         }); | ||||
|       }, function (err) { | ||||
|  | ||||
| @ -92,152 +92,191 @@ function createServer(port, _delete_me_, content, opts) { | ||||
| 
 | ||||
|   return new PromiseA(function (realResolve) { | ||||
|     var app = require('../lib/app.js'); | ||||
|     var ipaddr = require('ipaddr.js'); | ||||
|     var addresses = []; | ||||
| 
 | ||||
|     var directive = { | ||||
|       global: opts.global | ||||
|     , sites: opts.sites | ||||
|     , defaults: opts.defaults | ||||
|     , cwd: process.cwd() | ||||
|     }; | ||||
|     var server; | ||||
|     var insecureServer; | ||||
| 
 | ||||
|     function resolve() { | ||||
|       realResolve({ | ||||
|         plainServer: insecureServer | ||||
|       , server: server | ||||
|     Object.keys(opts.ifaces).forEach(function (ifacename) { | ||||
|       var iface = opts.ifaces[ifacename]; | ||||
|       iface.ipv4.forEach(function (ip) { | ||||
|         addresses.push(ip); | ||||
|       }); | ||||
|       iface.ipv6.forEach(function (ip) { | ||||
|         addresses.push(ip); | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     // returns an instance of node-letsencrypt with additional helper methods
 | ||||
|     var webrootPath = require('os').tmpdir(); | ||||
|     var leChallengeFs = require('le-challenge-fs').create({ webrootPath: webrootPath }); | ||||
|     //var leChallengeSni = require('le-challenge-sni').create({ webrootPath: webrootPath });
 | ||||
|     var leChallengeDdns = require('le-challenge-ddns').create({ ttl: 1 }); | ||||
|     var lex = require('greenlock-express').create({ | ||||
|       // set to https://acme-v01.api.letsencrypt.org/directory in production
 | ||||
|       server: opts.debug ? 'staging' : 'https://acme-v01.api.letsencrypt.org/directory' | ||||
| 
 | ||||
|     // If you wish to replace the default plugins, you may do so here
 | ||||
|     //
 | ||||
|     , challenges: { | ||||
|         'http-01': leChallengeFs | ||||
|       , 'tls-sni-01': leChallengeFs // leChallengeSni
 | ||||
|       , 'dns-01': leChallengeDdns | ||||
|       } | ||||
|     , challengeType: (opts.tunnel ? 'http-01' : 'dns-01') | ||||
|     , store: require('le-store-certbot').create({ | ||||
|         webrootPath: webrootPath | ||||
|       , configDir: path.join((opts.homedir || '~'), 'letsencrypt', 'etc') | ||||
|       , homedir: opts.homedir | ||||
|       }) | ||||
|     , webrootPath: webrootPath | ||||
| 
 | ||||
|     // You probably wouldn't need to replace the default sni handler
 | ||||
|     // See https://git.daplie.com/Daplie/le-sni-auto if you think you do
 | ||||
|     //, sni: require('le-sni-auto').create({})
 | ||||
| 
 | ||||
|     , approveDomains: approveDomains | ||||
|     }); | ||||
| 
 | ||||
|     var secureContexts = { | ||||
|       'localhost.daplie.me': null | ||||
|     }; | ||||
|     opts.httpsOptions.SNICallback = function (sni, cb ) { | ||||
|       var tlsOptions; | ||||
|       console.log('[https] sni', sni); | ||||
| 
 | ||||
|       // Static Certs
 | ||||
|       if (/.*localhost.*\.daplie\.me/.test(sni.toLowerCase())) { | ||||
|         // TODO implement
 | ||||
|         if (!secureContexts[sni]) { | ||||
|           tlsOptions = require('localhost.daplie.me-certificates').mergeTlsOptions(sni, {}); | ||||
|         } | ||||
|         if (tlsOptions) { | ||||
|           secureContexts[sni] = tls.createSecureContext(tlsOptions); | ||||
|         } | ||||
|         cb(null, secureContexts[sni]); | ||||
|         return; | ||||
|     addresses.sort(function (a, b) { | ||||
|       if (a.family !== b.family) { | ||||
|         return 'IPv4' === a.family ? 1 : -1; | ||||
|       } | ||||
| 
 | ||||
|       // Dynamic Certs
 | ||||
|       lex.httpsOptions.SNICallback(sni, cb); | ||||
|     }; | ||||
|     server = https.createServer(opts.httpsOptions); | ||||
| 
 | ||||
|     server.on('error', function (err) { | ||||
|       if (opts.errorPort || opts.manualPort) { | ||||
|         showError(err, port); | ||||
|         process.exit(1); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       opts.errorPort = err.toString(); | ||||
| 
 | ||||
|       return createServer(portFallback, null, content, opts).then(resolve); | ||||
|       return a.address > b.address ? 1 : -1; | ||||
|     }); | ||||
| 
 | ||||
|     server.listen(port, function () { | ||||
|       opts.port = port; | ||||
|       opts.redirectOptions.port = port; | ||||
|     addresses.forEach(function (addr) { | ||||
|       addr.range = ipaddr.parse(addr.address).range(); | ||||
|     }); | ||||
| 
 | ||||
|       if (opts.livereload) { | ||||
|         opts.lrPort = opts.lrPort || lrPort; | ||||
|         var livereload = require('livereload'); | ||||
|         var server2 = livereload.createServer({ | ||||
|           https: opts.httpsOptions | ||||
|         , port: opts.lrPort | ||||
|         , exclusions: [ 'node_modules' ] | ||||
|     var Oauth3 = require('oauth3-cli'); | ||||
|     var oauth3 = Oauth3.create({ device: { hostname: opts.device } }); | ||||
|     return Oauth3.Devices.one(oauth3).then(function (device) { | ||||
|       return Oauth3.Devices.all(oauth3).then(function (devices) { | ||||
|         return { devices: devices, device: device.device || device }; | ||||
|       }); | ||||
|     }).then(function (devices) { | ||||
|       devices.device.secret = undefined; | ||||
|       console.log('devices'); | ||||
|       console.log(devices); | ||||
|       var directive = { | ||||
|         global: opts.global | ||||
|       , sites: opts.sites | ||||
|       , defaults: opts.defaults | ||||
|       , cwd: process.cwd() | ||||
|       , ifaces: opts.ifaces | ||||
|       , addresses: addresses | ||||
|       , devices: devices.devices | ||||
|       , device: devices.device | ||||
|       }; | ||||
|       var server; | ||||
|       var insecureServer; | ||||
| 
 | ||||
|       function resolve() { | ||||
|         realResolve({ | ||||
|           plainServer: insecureServer | ||||
|         , server: server | ||||
|         }); | ||||
| 
 | ||||
|         console.info("[livereload] watching " + opts.pubdir); | ||||
|         console.warn("WARNING: If CPU usage spikes to 100% it's because too many files are being watched"); | ||||
|         // TODO create map of directories to watch from opts.sites and iterate over it
 | ||||
|         server2.watch(opts.pubdir); | ||||
|       } | ||||
| 
 | ||||
|       // if we haven't disabled insecure port
 | ||||
|       if ('false' !== opts.insecurePort) { | ||||
|         // and both ports are the default
 | ||||
|         if ((httpsPort === opts.port && httpPort === opts.insecurePort) | ||||
|           // or other case
 | ||||
|           || (httpPort !== opts.insecurePort && opts.port !== opts.insecurePort) | ||||
|         ) { | ||||
|           return createInsecureServer(opts.insecurePort, null, opts).then(function (_server) { | ||||
|             insecureServer = _server; | ||||
|             resolve(); | ||||
|           }); | ||||
|       // returns an instance of node-letsencrypt with additional helper methods
 | ||||
|       var webrootPath = require('os').tmpdir(); | ||||
|       var leChallengeFs = require('le-challenge-fs').create({ webrootPath: webrootPath }); | ||||
|       //var leChallengeSni = require('le-challenge-sni').create({ webrootPath: webrootPath });
 | ||||
|       var leChallengeDdns = require('le-challenge-ddns').create({ ttl: 1 }); | ||||
|       var lex = require('greenlock-express').create({ | ||||
|         // set to https://acme-v01.api.letsencrypt.org/directory in production
 | ||||
|         server: opts.debug ? 'staging' : 'https://acme-v01.api.letsencrypt.org/directory' | ||||
| 
 | ||||
|       // If you wish to replace the default plugins, you may do so here
 | ||||
|       //
 | ||||
|       , challenges: { | ||||
|           'http-01': leChallengeFs | ||||
|         , 'tls-sni-01': leChallengeFs // leChallengeSni
 | ||||
|         , 'dns-01': leChallengeDdns | ||||
|         } | ||||
|       } | ||||
|       , challengeType: (opts.tunnel ? 'http-01' : 'dns-01') | ||||
|       , store: require('le-store-certbot').create({ | ||||
|           webrootPath: webrootPath | ||||
|         , configDir: path.join((opts.homedir || '~'), 'letsencrypt', 'etc') | ||||
|         , homedir: opts.homedir | ||||
|         }) | ||||
|       , webrootPath: webrootPath | ||||
| 
 | ||||
|       opts.insecurePort = opts.port; | ||||
|       resolve(); | ||||
|       return; | ||||
|     }); | ||||
|       // You probably wouldn't need to replace the default sni handler
 | ||||
|       // See https://git.daplie.com/Daplie/le-sni-auto if you think you do
 | ||||
|       //, sni: require('le-sni-auto').create({})
 | ||||
| 
 | ||||
|     if ('function' === typeof app) { | ||||
|       app = app(directive); | ||||
|     } else if ('function' === typeof app.create) { | ||||
|       app = app.create(directive); | ||||
|     } | ||||
|       , approveDomains: approveDomains | ||||
|       }); | ||||
| 
 | ||||
|     server.on('request', function (req, res) { | ||||
|       console.log('[' + req.method + '] ' + req.url); | ||||
|       if (!req.socket.encrypted && !/\/\.well-known\/acme-challenge\//.test(req.url)) { | ||||
|         opts.redirectApp(req, res); | ||||
|       var secureContexts = { | ||||
|         'localhost.daplie.me': null | ||||
|       }; | ||||
|       opts.httpsOptions.SNICallback = function (sni, cb ) { | ||||
|         var tlsOptions; | ||||
|         console.log('[https] sni', sni); | ||||
| 
 | ||||
|         // Static Certs
 | ||||
|         if (/.*localhost.*\.daplie\.me/.test(sni.toLowerCase())) { | ||||
|           // TODO implement
 | ||||
|           if (!secureContexts[sni]) { | ||||
|             tlsOptions = require('localhost.daplie.me-certificates').mergeTlsOptions(sni, {}); | ||||
|           } | ||||
|           if (tlsOptions) { | ||||
|             secureContexts[sni] = tls.createSecureContext(tlsOptions); | ||||
|           } | ||||
|           cb(null, secureContexts[sni]); | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         // Dynamic Certs
 | ||||
|         lex.httpsOptions.SNICallback(sni, cb); | ||||
|       }; | ||||
|       server = https.createServer(opts.httpsOptions); | ||||
| 
 | ||||
|       server.on('error', function (err) { | ||||
|         if (opts.errorPort || opts.manualPort) { | ||||
|           showError(err, port); | ||||
|           process.exit(1); | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         opts.errorPort = err.toString(); | ||||
| 
 | ||||
|         return createServer(portFallback, null, content, opts).then(resolve); | ||||
|       }); | ||||
| 
 | ||||
|       server.listen(port, function () { | ||||
|         opts.port = port; | ||||
|         opts.redirectOptions.port = port; | ||||
| 
 | ||||
|         if (opts.livereload) { | ||||
|           opts.lrPort = opts.lrPort || lrPort; | ||||
|           var livereload = require('livereload'); | ||||
|           var server2 = livereload.createServer({ | ||||
|             https: opts.httpsOptions | ||||
|           , port: opts.lrPort | ||||
|           , exclusions: [ 'node_modules' ] | ||||
|           }); | ||||
| 
 | ||||
|           console.info("[livereload] watching " + opts.pubdir); | ||||
|           console.warn("WARNING: If CPU usage spikes to 100% it's because too many files are being watched"); | ||||
|           // TODO create map of directories to watch from opts.sites and iterate over it
 | ||||
|           server2.watch(opts.pubdir); | ||||
|         } | ||||
| 
 | ||||
|         // if we haven't disabled insecure port
 | ||||
|         if ('false' !== opts.insecurePort) { | ||||
|           // and both ports are the default
 | ||||
|           if ((httpsPort === opts.port && httpPort === opts.insecurePort) | ||||
|             // or other case
 | ||||
|             || (httpPort !== opts.insecurePort && opts.port !== opts.insecurePort) | ||||
|           ) { | ||||
|             return createInsecureServer(opts.insecurePort, null, opts).then(function (_server) { | ||||
|               insecureServer = _server; | ||||
|               resolve(); | ||||
|             }); | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         opts.insecurePort = opts.port; | ||||
|         resolve(); | ||||
|         return; | ||||
|       } | ||||
|       }); | ||||
| 
 | ||||
|       if ('function' === typeof app) { | ||||
|         app(req, res); | ||||
|         return; | ||||
|         app = app(directive); | ||||
|       } else if ('function' === typeof app.create) { | ||||
|         app = app.create(directive); | ||||
|       } | ||||
| 
 | ||||
|       res.end('not ready'); | ||||
|     }); | ||||
|       server.on('request', function (req, res) { | ||||
|         console.log('[' + req.method + '] ' + req.url); | ||||
|         if (!req.socket.encrypted && !/\/\.well-known\/acme-challenge\//.test(req.url)) { | ||||
|           opts.redirectApp(req, res); | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|     return PromiseA.resolve(app).then(function (_app) { | ||||
|       app = _app; | ||||
|         if ('function' === typeof app) { | ||||
|           app(req, res); | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         res.end('not ready'); | ||||
|       }); | ||||
| 
 | ||||
|       return PromiseA.resolve(app).then(function (_app) { | ||||
|         app = _app; | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| @ -47,6 +47,7 @@ | ||||
|     "greenlock": "git+https://git.daplie.com/Daplie/node-greenlock.git#master", | ||||
|     "greenlock-express": "git+https://git.daplie.com/Daplie/greenlock-express.git#master", | ||||
|     "httpolyglot": "^0.1.1", | ||||
|     "ipaddr.js": "git+https://github.com/whitequark/ipaddr.js.git#v1.3.0", | ||||
|     "ipify": "^1.1.0", | ||||
|     "js-yaml": "^3.8.1", | ||||
|     "le-challenge-ddns": "git+https://git.daplie.com/Daplie/le-challenge-ddns.git#master", | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit 356a2d3131bcc6d0f6199a1d2039dcdcee0e3481 | ||||
| Subproject commit d64699977e883871246d3fc062a384e88a554e2a | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user