acme.js/examples/app.js

341 lines
9.6 KiB
JavaScript
Raw Permalink Normal View History

2019-05-06 09:45:11 +00:00
/*global Promise*/
2020-07-28 21:53:50 +00:00
(function () {
2019-10-08 19:02:56 +00:00
'use strict';
2019-04-18 06:20:51 +00:00
2019-10-08 20:50:53 +00:00
var Keypairs = require('@root/keypairs');
var Rasha = require('@root/acme/rsa');
var Eckles = require('@root/acme/ecdsa');
var x509 = require('@root/acme/x509');
var CSR = require('@root/csr');
var ACME = require('@root/acme');
2019-10-08 19:02:56 +00:00
var accountStuff = {};
2019-04-18 06:20:51 +00:00
2019-10-08 19:02:56 +00:00
function $(sel) {
return document.querySelector(sel);
}
function $$(sel) {
return Array.prototype.slice.call(document.querySelectorAll(sel));
}
2019-04-18 06:20:51 +00:00
2019-10-08 19:02:56 +00:00
function checkTos(tos) {
if ($('input[name="tos"]:checked')) {
return tos;
} else {
return '';
}
}
2019-05-07 07:52:33 +00:00
2019-10-08 19:02:56 +00:00
function run() {
console.log('hello');
2019-04-18 06:20:51 +00:00
2019-10-08 19:02:56 +00:00
// Show different options for ECDSA vs RSA
2020-07-28 21:53:50 +00:00
$$('input[name="kty"]').forEach(function ($el) {
$el.addEventListener('change', function (ev) {
2019-10-08 19:02:56 +00:00
console.log(this);
console.log(ev);
if ('RSA' === ev.target.value) {
$('.js-rsa-opts').hidden = false;
$('.js-ec-opts').hidden = true;
} else {
$('.js-rsa-opts').hidden = true;
$('.js-ec-opts').hidden = false;
}
});
});
2019-04-18 06:20:51 +00:00
2019-10-08 19:02:56 +00:00
// Generate a key on submit
2020-07-28 21:53:50 +00:00
$('form.js-keygen').addEventListener('submit', function (ev) {
2019-10-08 19:02:56 +00:00
ev.preventDefault();
ev.stopPropagation();
$('.js-loading').hidden = false;
$('.js-jwk').hidden = true;
$('.js-toc-der-public').hidden = true;
$('.js-toc-der-private').hidden = true;
2020-07-28 21:53:50 +00:00
$$('.js-toc-pem').forEach(function ($el) {
2019-10-08 19:02:56 +00:00
$el.hidden = true;
});
2020-07-28 21:53:50 +00:00
$$('input').map(function ($el) {
2019-10-08 19:02:56 +00:00
$el.disabled = true;
});
2020-07-28 21:53:50 +00:00
$$('button').map(function ($el) {
2019-10-08 19:02:56 +00:00
$el.disabled = true;
});
var opts = {
kty: $('input[name="kty"]:checked').value,
namedCurve: $('input[name="ec-crv"]:checked').value,
modulusLength: $('input[name="rsa-len"]:checked').value
};
var then = Date.now();
console.log('opts', opts);
2020-07-28 21:53:50 +00:00
Keypairs.generate(opts).then(function (results) {
2019-10-08 19:02:56 +00:00
console.log('Key generation time:', Date.now() - then + 'ms');
var pubDer;
var privDer;
if (/EC/i.test(opts.kty)) {
privDer = x509.packPkcs8(results.private);
pubDer = x509.packSpki(results.public);
Eckles.export({
jwk: results.private,
format: 'sec1'
2020-07-28 21:53:50 +00:00
}).then(function (pem) {
2019-10-08 19:02:56 +00:00
$('.js-input-pem-sec1-private').innerText = pem;
$('.js-toc-pem-sec1-private').hidden = false;
});
Eckles.export({
jwk: results.private,
format: 'pkcs8'
2020-07-28 21:53:50 +00:00
}).then(function (pem) {
2019-10-08 19:02:56 +00:00
$('.js-input-pem-pkcs8-private').innerText = pem;
$('.js-toc-pem-pkcs8-private').hidden = false;
});
Eckles.export({ jwk: results.public, public: true }).then(
2020-07-28 21:53:50 +00:00
function (pem) {
2019-10-08 19:02:56 +00:00
$('.js-input-pem-spki-public').innerText = pem;
$('.js-toc-pem-spki-public').hidden = false;
}
);
} else {
privDer = x509.packPkcs8(results.private);
pubDer = x509.packSpki(results.public);
Rasha.export({
jwk: results.private,
format: 'pkcs1'
2020-07-28 21:53:50 +00:00
}).then(function (pem) {
2019-10-08 19:02:56 +00:00
$('.js-input-pem-pkcs1-private').innerText = pem;
$('.js-toc-pem-pkcs1-private').hidden = false;
});
Rasha.export({
jwk: results.private,
format: 'pkcs8'
2020-07-28 21:53:50 +00:00
}).then(function (pem) {
2019-10-08 19:02:56 +00:00
$('.js-input-pem-pkcs8-private').innerText = pem;
$('.js-toc-pem-pkcs8-private').hidden = false;
});
Rasha.export({ jwk: results.public, format: 'pkcs1' }).then(
2020-07-28 21:53:50 +00:00
function (pem) {
2019-10-08 19:02:56 +00:00
$('.js-input-pem-pkcs1-public').innerText = pem;
$('.js-toc-pem-pkcs1-public').hidden = false;
}
);
Rasha.export({ jwk: results.public, format: 'spki' }).then(
2020-07-28 21:53:50 +00:00
function (pem) {
2019-10-08 19:02:56 +00:00
$('.js-input-pem-spki-public').innerText = pem;
$('.js-toc-pem-spki-public').hidden = false;
}
);
}
2019-04-27 04:09:57 +00:00
2019-10-08 19:02:56 +00:00
$('.js-der-public').innerText = pubDer;
$('.js-toc-der-public').hidden = false;
$('.js-der-private').innerText = privDer;
$('.js-toc-der-private').hidden = false;
$('.js-jwk').innerText = JSON.stringify(results, null, 2);
$('.js-loading').hidden = true;
$('.js-jwk').hidden = false;
2020-07-28 21:53:50 +00:00
$$('input').map(function ($el) {
2019-10-08 19:02:56 +00:00
$el.disabled = false;
});
2020-07-28 21:53:50 +00:00
$$('button').map(function ($el) {
2019-10-08 19:02:56 +00:00
$el.disabled = false;
});
$('.js-toc-jwk').hidden = false;
2019-05-06 09:45:11 +00:00
2019-10-08 19:02:56 +00:00
$('.js-create-account').hidden = false;
$('.js-create-csr').hidden = false;
});
});
2019-04-18 06:20:51 +00:00
2020-07-28 21:53:50 +00:00
$('form.js-acme-account').addEventListener('submit', function (ev) {
2019-10-08 19:02:56 +00:00
ev.preventDefault();
ev.stopPropagation();
$('.js-loading').hidden = false;
var acme = ACME.create({
Keypairs: Keypairs,
CSR: CSR
});
acme.init(
'https://acme-staging-v02.api.letsencrypt.org/directory'
2020-07-28 21:53:50 +00:00
).then(function (result) {
2019-10-08 19:02:56 +00:00
console.log('acme result', result);
var privJwk = JSON.parse($('.js-jwk').innerText).private;
var email = $('.js-email').value;
return acme.accounts
.create({
email: email,
agreeToTerms: checkTos,
accountKeypair: { privateKeyJwk: privJwk }
})
2020-07-28 21:53:50 +00:00
.then(function (account) {
2019-10-08 19:02:56 +00:00
console.log('account created result:', account);
accountStuff.account = account;
accountStuff.privateJwk = privJwk;
accountStuff.email = email;
accountStuff.acme = acme;
$('.js-create-order').hidden = false;
$('.js-toc-acme-account-response').hidden = false;
$(
'.js-acme-account-response'
).innerText = JSON.stringify(account, null, 2);
})
2020-07-28 21:53:50 +00:00
.catch(function (err) {
2019-10-08 19:02:56 +00:00
console.error('A bad thing happened:');
console.error(err);
window.alert(
err.message || JSON.stringify(err, null, 2)
);
});
});
});
2019-05-07 07:52:33 +00:00
2020-07-28 21:53:50 +00:00
$('form.js-csr').addEventListener('submit', function (ev) {
2019-10-08 19:02:56 +00:00
ev.preventDefault();
ev.stopPropagation();
generateCsr();
});
2019-05-07 07:52:33 +00:00
2020-07-28 21:53:50 +00:00
$('form.js-acme-order').addEventListener('submit', function (ev) {
2019-10-08 19:02:56 +00:00
ev.preventDefault();
ev.stopPropagation();
var account = accountStuff.account;
var privJwk = accountStuff.privateJwk;
var email = accountStuff.email;
var acme = accountStuff.acme;
2019-05-07 07:52:33 +00:00
2019-10-08 19:02:56 +00:00
var domains = ($('.js-domains').value || 'example.com').split(
/[, ]+/g
);
2020-07-28 21:53:50 +00:00
return getDomainPrivkey().then(function (domainPrivJwk) {
2019-10-08 19:02:56 +00:00
console.log('Has CSR already?');
console.log(accountStuff.csr);
return acme.certificates
.create({
accountKeypair: { privateKeyJwk: privJwk },
account: account,
serverKeypair: { privateKeyJwk: domainPrivJwk },
csr: accountStuff.csr,
domains: domains,
skipDryRun:
$('input[name="skip-dryrun"]:checked') && true,
agreeToTerms: checkTos,
challenges: {
'dns-01': {
2020-07-28 21:53:50 +00:00
set: function (opts) {
2019-10-08 19:02:56 +00:00
console.info('dns-01 set challenge:');
console.info('TXT', opts.dnsHost);
console.info(opts.dnsAuthorization);
2020-07-28 21:53:50 +00:00
return new Promise(function (resolve) {
2019-10-08 19:02:56 +00:00
while (
!window.confirm(
'Did you set the challenge?'
)
) {}
resolve();
});
},
2020-07-28 21:53:50 +00:00
remove: function (opts) {
2019-10-08 19:02:56 +00:00
console.log('dns-01 remove challenge:');
console.info('TXT', opts.dnsHost);
console.info(opts.dnsAuthorization);
2020-07-28 21:53:50 +00:00
return new Promise(function (resolve) {
2019-10-08 19:02:56 +00:00
while (
!window.confirm(
'Did you delete the challenge?'
)
) {}
resolve();
});
}
},
'http-01': {
2020-07-28 21:53:50 +00:00
set: function (opts) {
2019-10-08 19:02:56 +00:00
console.info('http-01 set challenge:');
console.info(opts.challengeUrl);
console.info(opts.keyAuthorization);
2020-07-28 21:53:50 +00:00
return new Promise(function (resolve) {
2019-10-08 19:02:56 +00:00
while (
!window.confirm(
'Did you set the challenge?'
)
) {}
resolve();
});
},
2020-07-28 21:53:50 +00:00
remove: function (opts) {
2019-10-08 19:02:56 +00:00
console.log('http-01 remove challenge:');
console.info(opts.challengeUrl);
console.info(opts.keyAuthorization);
2020-07-28 21:53:50 +00:00
return new Promise(function (resolve) {
2019-10-08 19:02:56 +00:00
while (
!window.confirm(
'Did you delete the challenge?'
)
) {}
resolve();
});
}
}
},
challengeTypes: [
$('input[name="acme-challenge-type"]:checked').value
]
})
2020-07-28 21:53:50 +00:00
.then(function (results) {
2019-10-08 19:02:56 +00:00
console.log('Got Certificates:');
console.log(results);
$('.js-toc-acme-order-response').hidden = false;
$('.js-acme-order-response').innerText = JSON.stringify(
results,
null,
2
);
})
2020-07-28 21:53:50 +00:00
.catch(function (err) {
2019-10-08 19:02:56 +00:00
console.error('challenge failed:');
console.error(err);
window.alert(
'failed! ' + err.message || JSON.stringify(err)
);
});
});
});
2019-05-07 07:52:33 +00:00
2019-10-08 19:02:56 +00:00
$('.js-generate').hidden = false;
}
2019-05-07 07:52:33 +00:00
2019-10-08 19:02:56 +00:00
function getDomainPrivkey() {
if (accountStuff.domainPrivateJwk) {
return Promise.resolve(accountStuff.domainPrivateJwk);
}
return Keypairs.generate({
kty: $('input[name="kty"]:checked').value,
namedCurve: $('input[name="ec-crv"]:checked').value,
modulusLength: $('input[name="rsa-len"]:checked').value
2020-07-28 21:53:50 +00:00
}).then(function (pair) {
2019-10-08 19:02:56 +00:00
console.log('domain keypair:', pair);
accountStuff.domainPrivateJwk = pair.private;
return pair.private;
});
}
2019-04-18 06:20:51 +00:00
2019-10-08 19:02:56 +00:00
function generateCsr() {
var domains = ($('.js-domains').value || 'example.com').split(/[, ]+/g);
//var privJwk = JSON.parse($('.js-jwk').innerText).private;
2020-07-28 21:53:50 +00:00
return getDomainPrivkey().then(function (privJwk) {
2019-10-08 19:02:56 +00:00
accountStuff.domainPrivateJwk = privJwk;
2020-07-28 21:53:50 +00:00
return CSR({ jwk: privJwk, domains: domains }).then(function (pem) {
2019-10-08 19:02:56 +00:00
// Verify with https://www.sslshopper.com/csr-decoder.html
accountStuff.csr = pem;
console.log('Created CSR:');
console.log(pem);
2019-05-07 07:52:33 +00:00
2019-10-08 19:02:56 +00:00
console.log('CSR info:');
console.log(CSR._info(pem));
2019-05-07 07:52:33 +00:00
2019-10-08 19:02:56 +00:00
return pem;
});
});
}
2019-05-07 07:52:33 +00:00
2019-10-08 19:02:56 +00:00
window.addEventListener('load', run);
})();