| 
									
										
										
										
											2015-11-06 11:05:32 +00:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function loadCerts(secureContexts, certPaths, domainname, prevdomainname) { | 
					
						
							|  |  |  |   var PromiseA = require('bluebird'); | 
					
						
							|  |  |  |   var fs = PromiseA.promisifyAll(require('fs')); | 
					
						
							|  |  |  |   var path = require('path'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (/(^|\.)proxyable\./.test(domainname)) { | 
					
						
							|  |  |  |     // device-id-12345678.proxyable.myapp.mydomain.com => myapp.mydomain.com
 | 
					
						
							|  |  |  |     // proxyable.myapp.mydomain.com => myapp.mydomain.com
 | 
					
						
							|  |  |  |     // TODO myapp.mydomain.com.proxyable.com => myapp.mydomain.com
 | 
					
						
							|  |  |  |     domainname = domainname.replace(/.*\.?proxyable\./, ''); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (secureContexts[domainname]) { | 
					
						
							|  |  |  |     return PromiseA.resolve(secureContexts[domainname]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return PromiseA.some(certPaths.map(function (pathname) { | 
					
						
							|  |  |  |     return PromiseA.all([ | 
					
						
							|  |  |  |       fs.readFileAsync(path.join(pathname, domainname, 'privkey.pem'), 'ascii') | 
					
						
							|  |  |  |     , fs.readFileAsync(path.join(pathname, domainname, 'fullchain.pem'), 'ascii') | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  |   }), 1).then(function (some) { | 
					
						
							|  |  |  |     var one = some[0]; | 
					
						
							|  |  |  |     secureContexts[domainname] = require('tls').createSecureContext({ | 
					
						
							|  |  |  |       key:  one[0] | 
					
						
							|  |  |  |     , cert: one[1] | 
					
						
							|  |  |  |       // https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
 | 
					
						
							|  |  |  |       // https://nodejs.org/api/tls.html
 | 
					
						
							|  |  |  |       // removed :ECDH+AES256:DH+AES256 and added :!AES256 because AES-256 wastes CPU
 | 
					
						
							|  |  |  |     , ciphers: 'ECDH+AESGCM:DH+AESGCM:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS:!AES256' | 
					
						
							|  |  |  |     , honorCipherOrder: true | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // guard against race condition on Promise.some
 | 
					
						
							|  |  |  |     if (prevdomainname && !secureContexts[prevdomainname]) { | 
					
						
							|  |  |  |       // TODO XXX make sure that letsencrypt www. domains handle the bare domains also (and vice versa)
 | 
					
						
							| 
									
										
										
										
											2015-11-23 08:42:25 +00:00
										 |  |  |       secureContexts[prevdomainname] = secureContexts[domainname]; | 
					
						
							| 
									
										
										
										
											2015-11-06 11:05:32 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return secureContexts[domainname]; | 
					
						
							|  |  |  |   }, function (/*err*/) { | 
					
						
							|  |  |  |     // AggregateError means both promises failed
 | 
					
						
							|  |  |  |     // TODO check ENOENT
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // test "is this server <<domainname>>?"
 | 
					
						
							|  |  |  |     // try letsencrypt
 | 
					
						
							|  |  |  |     // fail with www.example.com
 | 
					
						
							|  |  |  |     if (/^www\./i.test(domainname)) { | 
					
						
							|  |  |  |       return loadCerts(secureContexts, certPaths, domainname.replace(/^www\./i, ''), domainname); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return (secureContexts['www.example.com'] || secureContexts['example.com']); | 
					
						
							|  |  |  |   }).then(function (ctx) { | 
					
						
							|  |  |  |     // TODO generate some self-signed certs?
 | 
					
						
							|  |  |  |     if (!ctx) { | 
					
						
							|  |  |  |       console.error("[loadCerts()] Could not load default HTTPS certificates!!!"); | 
					
						
							|  |  |  |       return PromiseA.reject({ | 
					
						
							|  |  |  |         message: "No default certificates for https" | 
					
						
							|  |  |  |       , code: 'E_NO_DEFAULT_CERTS' | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ctx; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module.exports.load = loadCerts; |