442 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			442 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| "use strict";
 | |
| 
 | |
| var request = require("@root/request");
 | |
| 
 | |
| // For most tests
 | |
| var siteSubject = "xx.com";
 | |
| var siteAltname = "www.foo.xx.com";
 | |
| var siteWildname = "*.xx.com";
 | |
| var siteMatch = "foo.xx.com";
 | |
| var domains = [siteSubject, siteAltname, siteWildname];
 | |
| 
 | |
| // Similar, but non-matching subjects
 | |
| var noExistWild = "*.foo.xx.com";
 | |
| var noExistAlt = "bar.xx.com";
 | |
| 
 | |
| // For wildcard-as-subject test
 | |
| var siteWildnameNet = "*.xx.net";
 | |
| var siteMatchNet = "foo.xx.net";
 | |
| 
 | |
| module.exports.test = async function(pkg, config) {
 | |
|     if ("function" !== typeof pkg.create) {
 | |
|         throw new Error(
 | |
|             "must have a create function that accepts a single options object"
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     var features = {
 | |
|         altnames: false,
 | |
|         wildcard: false,
 | |
|         renewal: false
 | |
|     };
 | |
|     var manager = pkg.create(config);
 | |
|     var initVal;
 | |
| 
 | |
|     if (manager.init) {
 | |
|         initVal = await manager.init({
 | |
|             request: request
 | |
|         });
 | |
|         if (!initVal && initVal !== null) {
 | |
|             console.warn(
 | |
|                 "WARN: `init()` returned `undefined`, but should return `null`"
 | |
|             );
 | |
|         }
 | |
|     }
 | |
|     console.info("PASS:  init(deps)");
 | |
| 
 | |
|     await manager.set({
 | |
|         subject: siteSubject,
 | |
|         altnames: domains
 | |
|     });
 | |
|     var site = await manager.get({
 | |
|         servername: siteSubject
 | |
|         // *.com is an invalid wildname
 | |
|     });
 | |
|     if (!site || site.subject !== siteSubject) {
 | |
|         throw new Error(
 | |
|             "set({ subject: '" +
 | |
|                 siteSubject +
 | |
|                 "'}), but could not `get()` or `find()` it"
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Test for altname support
 | |
|     //
 | |
|     site = await get({
 | |
|         servername: siteAltname,
 | |
|         wildname: untame(siteAltname)
 | |
|     });
 | |
|     if (site) {
 | |
|         if (site.subject !== siteSubject) {
 | |
|             throw new Error("found incorrect site");
 | |
|         }
 | |
|         features.altnames = true;
 | |
|     } else {
 | |
|         console.warn("WARN: Does not support altnames.");
 | |
|         console.warn(
 | |
|             "      (searched for %s but did not find site '%s')",
 | |
|             siteAltname,
 | |
|             domains.join(" ")
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Test for wildcard support
 | |
|     //
 | |
|     if (features.altnames) {
 | |
|         // Set the wildcard as an altname
 | |
|         site = await get({
 | |
|             servername: siteMatch,
 | |
|             wildname: siteWildname
 | |
|         });
 | |
|         if (site) {
 | |
|             if (site.subject !== siteSubject) {
 | |
|                 throw new Error(
 | |
|                     "found %s when looking for %s",
 | |
|                     site.subject,
 | |
|                     siteSubject
 | |
|                 );
 | |
|             }
 | |
|             features.wildcard = true;
 | |
|         } else {
 | |
|             console.warn("WARN: Does not support wildcard domains.");
 | |
|             console.warn(
 | |
|                 "      (searched for %s but did not find site %s)",
 | |
|                 siteMatch,
 | |
|                 siteSubject
 | |
|             );
 | |
|         }
 | |
|     }
 | |
|     // Set the wildcard as the subject
 | |
|     await manager.set({
 | |
|         subject: siteWildnameNet,
 | |
|         altnames: [siteWildnameNet]
 | |
|     });
 | |
|     site = await get({
 | |
|         servername: siteMatchNet,
 | |
|         wildname: siteWildnameNet
 | |
|     });
 | |
|     if (site) {
 | |
|         if (site.subject !== siteWildnameNet) {
 | |
|             throw new Error("found incorrect site");
 | |
|         }
 | |
|         features.wildcard = true;
 | |
|     } else {
 | |
|         if (features.wildcard) {
 | |
|             throw new Error(
 | |
|                 "searched for wildcard subject " +
 | |
|                     siteWildnameNet +
 | |
|                     " but did not find it"
 | |
|             );
 | |
|         }
 | |
|         if (!features.altnames) {
 | |
|             console.warn(
 | |
|                 "WARN: Does not support wildcard domains as certificate subjects."
 | |
|             );
 | |
|             console.warn(
 | |
|                 "      (searched for %s as %s but did not find site %s)",
 | |
|                 siteMatchNet,
 | |
|                 siteWildnameNet,
 | |
|                 siteWildnameNet
 | |
|             );
 | |
|         }
 | |
|     }
 | |
|     await remove({ subject: siteWildnameNet });
 | |
| 
 | |
|     var wasSet = false;
 | |
|     if (manager.find) {
 | |
|         await manager.find({}).then(function(results) {
 | |
|             if (!results.length) {
 | |
|                 //console.error(results);
 | |
|                 throw new Error("should have found all managed sites");
 | |
|             }
 | |
|             wasSet = results.some(function(site) {
 | |
|                 return site.subject === siteSubject;
 | |
|             });
 | |
|             if (!wasSet) {
 | |
|                 throw new Error("should have found " + siteSubject);
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     if (manager.get) {
 | |
|         await manager.get({ servername: siteSubject }).then(function(site) {
 | |
|             if (!site || site.subject !== siteSubject) {
 | |
|                 throw new Error("should have found " + siteSubject);
 | |
|             }
 | |
|             wasSet = true;
 | |
|         });
 | |
|         if (features.altnames) {
 | |
|             wasSet = false;
 | |
|             await manager.get({ servername: siteAltname }).then(function(site) {
 | |
|                 if (!site || site.subject !== siteSubject) {
 | |
|                     throw new Error("should have found " + siteAltname);
 | |
|                 }
 | |
|             });
 | |
|             await manager
 | |
|                 .get({ servername: siteMatch, wildname: siteWildname })
 | |
|                 .then(function(site) {
 | |
|                     if (!site || site.subject !== siteSubject) {
 | |
|                         throw new Error(
 | |
|                             "did not find " +
 | |
|                                 siteMatch +
 | |
|                                 ", which matches " +
 | |
|                                 siteWildname
 | |
|                         );
 | |
|                     }
 | |
|                     wasSet = true;
 | |
|                 });
 | |
|         }
 | |
|         console.info("PASS:  get({ servername, wildname })");
 | |
|     } else {
 | |
|         console.info("[skip] get({ servername, wildname }) not implemented");
 | |
|     }
 | |
| 
 | |
|     if (wasSet) {
 | |
|         console.info("PASS:  set({ subject })");
 | |
|     } else {
 | |
|         throw new Error("neither `get()` nor `find()` was implemented");
 | |
|     }
 | |
| 
 | |
|     if (manager.find) {
 | |
|         await manager.find({ subject: siteAltname }).then(function(results) {
 | |
|             if (results.length) {
 | |
|                 console.error(results);
 | |
|                 throw new Error(
 | |
|                     "shouldn't find what doesn't exist, exactly, by subject"
 | |
|                 );
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         await manager
 | |
|             .find({ servernames: [siteAltname], altnames: [siteAltname] })
 | |
|             .then(function(results) {
 | |
|                 if (!results.length) {
 | |
|                     console.error(results);
 | |
|                     throw new Error("should have found sites matching altname");
 | |
|                 }
 | |
|             });
 | |
|         console.info("PASS:  find({ servernames, renewBefore })");
 | |
|     } else {
 | |
|         console.info(
 | |
|             "[skip] find({ servernames, renewBefore }) not implemented"
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     await remove({ subject: noExistWild }).then(function(result) {
 | |
|         if (result) {
 | |
|             console.error(siteWildname, result);
 | |
|             throw new Error(
 | |
|                 "should not return prior object when deleting non-existing wildcard domain: " +
 | |
|                     noExistWild
 | |
|             );
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     await remove({ subject: noExistAlt }).then(function(result) {
 | |
|         if (result) {
 | |
|             throw new Error(
 | |
|                 "should not return prior object when deleting non-existing site: " +
 | |
|                     noExistAlt
 | |
|             );
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     await remove({ subject: siteWildname }).then(function(result) {
 | |
|         if (result) {
 | |
|             throw new Error("should not delete by wildname: " + siteWildname);
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     await remove({ subject: siteAltname }).then(function(result) {
 | |
|         if (result) {
 | |
|             throw new Error("should not delete by altname: " + siteAltname);
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     await remove({ subject: siteSubject }).then(function(result) {
 | |
|         if (!result || !result.subject || !result.altnames) {
 | |
|             throw new Error("should return prior object when deleting site");
 | |
|         }
 | |
|     });
 | |
|     if (!manager.remove) {
 | |
|         console.info(
 | |
|             "[skip] remove() not implemented - using set({ deletedAt }) instead"
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     await manager.set({ subject: siteSubject, altnames: domains.slice(0, 2) });
 | |
|     if (manager.find) {
 | |
|         await manager
 | |
|             .find({ servernames: [noExistWild], altnames: [noExistWild] })
 | |
|             .then(function(results) {
 | |
|                 if (results.length) {
 | |
|                     console.error(results);
 | |
|                     throw new Error(
 | |
|                         "should only find an exact (literal) wildcard match"
 | |
|                     );
 | |
|                 }
 | |
|             });
 | |
|     }
 | |
|     await remove({ subject: siteSubject }).then(function(result) {
 | |
|         if (!result || !result.subject || !result.altnames) {
 | |
|             console.error(
 | |
|                 "Could not find",
 | |
|                 siteSubject,
 | |
|                 "to delete it:",
 | |
|                 result
 | |
|             );
 | |
|             throw new Error("should return prior object when deleting site");
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     if (manager.find) {
 | |
|         await manager
 | |
|             .find({ servernames: domains, altnames: domains })
 | |
|             .then(function(results) {
 | |
|                 if (results.length) {
 | |
|                     console.error(results);
 | |
|                     throw new Error("should not find() deleted sites");
 | |
|                 }
 | |
|             });
 | |
|     } else {
 | |
|         await get({ servername: siteAltname }).then(function(result) {
 | |
|             if (result) {
 | |
|                 console.error(result);
 | |
|                 throw new Error("should not get() deleted sites");
 | |
|             }
 | |
|         });
 | |
|     }
 | |
|     console.info("PASS:  remove({ subject })");
 | |
| 
 | |
|     var originalInput = {
 | |
|         serverKeyType: "RSA-2048",
 | |
|         accountKeyType: "P-256",
 | |
|         subscriberEmail: "jon@example.com",
 | |
|         agreeToTerms: true,
 | |
|         store: { module: "/path/to/store-module", foo: "foo" },
 | |
|         challenges: {
 | |
|             "http-01": { module: "/path/to/http-01-module", bar: "bar" },
 | |
|             "dns-01": { module: "/path/to/dns-01-module", baz: "baz" },
 | |
|             "tls-alpn-01": {
 | |
|                 module: "/path/to/tls-alpn-01-module",
 | |
|                 qux: "quux"
 | |
|             }
 | |
|         },
 | |
|         customerEmail: "jane@example.com"
 | |
|     };
 | |
|     //var backup = JSON.parse(JSON.stringify(originalInput));
 | |
|     var configUpdate = {
 | |
|         renewOffset: "45d",
 | |
|         renewStagger: "12h",
 | |
|         subscriberEmail: "pat@example.com"
 | |
|     };
 | |
| 
 | |
|     var internalConfig;
 | |
|     if (manager.defaults) {
 | |
|         await manager.defaults().then(function(result) {
 | |
|             internalConfig = result;
 | |
|             if (!result) {
 | |
|                 throw new Error(
 | |
|                     "should at least return an empty object, perhaps one with some defaults set"
 | |
|                 );
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         await manager.defaults(originalInput).then(function(result) {
 | |
|             // can't say much... what _should_ this return?
 | |
|             // probably nothing? or maybe the full config object?
 | |
|             if (internalConfig === result) {
 | |
|                 console.warn(
 | |
|                     "WARN: should return a new copy, not the same internal object"
 | |
|                 );
 | |
|             }
 | |
|             if (originalInput === result) {
 | |
|                 console.warn(
 | |
|                     "WARN: should probably return a copy, not the original input"
 | |
|                 );
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         await manager.defaults().then(function(result) {
 | |
|             if (originalInput === result) {
 | |
|                 console.warn(
 | |
|                     "WARN: should probably return a copy, not the prior input"
 | |
|                 );
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         await manager.defaults(configUpdate).then(function() {
 | |
|             if (originalInput.renewOffset) {
 | |
|                 console.warn("WARN: should probably modify the prior input");
 | |
|             }
 | |
|         });
 | |
|         console.info("PASS:  defaults(conf)");
 | |
| 
 | |
|         await manager.defaults().then(function(result) {
 | |
|             if (!result.subscriberEmail || !result.renewOffset) {
 | |
|                 throw new Error("should merge config values together");
 | |
|             }
 | |
|         });
 | |
|         console.info("PASS:  defaults()");
 | |
|     } else {
 | |
|         console.info(
 | |
|             "[skip] defaults({ store, challenges, ... }) not implemented"
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     features.renewal = !!manager.find;
 | |
|     var featureNames = {
 | |
|         altnames: "Multiple Domains per Certificate",
 | |
|         wildcard:
 | |
|             "Wildcard Certificates" +
 | |
|             (features.altnames ? "" : " (subject only)"),
 | |
|         renewal: "Fully Automatic Renewal"
 | |
|     };
 | |
|     return Object.keys(features).map(function(k) {
 | |
|         return {
 | |
|             name: k,
 | |
|             description: featureNames[k],
 | |
|             supported: features[k]
 | |
|         };
 | |
|     });
 | |
| 
 | |
|     function get(opts) {
 | |
|         if (manager.get) {
 | |
|             opts.servername = opts.servername || opts.subject;
 | |
|             delete opts.subject;
 | |
|             return manager.get(opts);
 | |
|         } else {
 | |
|             return manager.find(opts);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     function remove(opts) {
 | |
|         if (manager.remove) {
 | |
|             return manager.remove(opts);
 | |
|         } else {
 | |
|             return get(opts).then(function(site) {
 | |
|                 // get matches servername, but remove should only match subject
 | |
|                 if (site && site.subject === opts.servername) {
 | |
|                     site.deletedAt = Date.now();
 | |
|                     return manager.set(site).then(function() {
 | |
|                         return site;
 | |
|                     });
 | |
|                 }
 | |
|                 return null;
 | |
|             });
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     function untame(str) {
 | |
|         return (
 | |
|             "*." +
 | |
|             str
 | |
|                 .split(".")
 | |
|                 .slice(1)
 | |
|                 .join(".")
 | |
|         );
 | |
|     }
 | |
| };
 |