Add CA chain to download, improve UI
This commit is contained in:
parent
a960a60ecd
commit
b748050de3
6 changed files with 222 additions and 97 deletions
|
@ -5,8 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="css/styles.min.css"
|
||||
integrity="sha384-vKuz4xd0kXa+x9wRdibDAVE8gXC/1up2T9QVSas8Rk07AZhzOzbwFdj00XUjOO4i" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="css/styles.min.css">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<title>{{ .Title }}</title>
|
||||
|
@ -45,40 +44,39 @@
|
|||
</div>
|
||||
<small id="keySizeHelp" class="form-text text-muted">{{ .RSAHelpText }}</small>
|
||||
</fieldset>
|
||||
<button type="submit" id="gen-csr-button" class="btn btn-primary">{{ .CSRButtonLabel }}</button>
|
||||
<button type="submit" id="action-button" class="btn btn-primary">{{ .CSRButtonLabel }}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div id="status-block" class="d-none row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex align-items-center">
|
||||
<strong id="status-text">{{ .StatusLoading }}</strong>
|
||||
<div class="spinner-border ml-auto" id="status-spinner" role="status" aria-hidden="true"></div>
|
||||
<div class="row d-none" id="status-block">
|
||||
<div class="col-12 py-3">
|
||||
<div class="progress" style="height: 2rem">
|
||||
<div id="progress-bar" class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0"
|
||||
aria-valuemax="4">{{ .StatusLoading }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div id="result">
|
||||
<button type="button" disabled id="send-button" class="btn btn-default disabled">
|
||||
{{ .SendCSRButtonLabel }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-12 d-none" id="download-wrapper">
|
||||
<p class="text-info">{{ .DownloadDescription }}</p>
|
||||
<a href="#" class="btn btn-success" id="download-link">
|
||||
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-download" fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/>
|
||||
<path fill-rule="evenodd"
|
||||
d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z"/>
|
||||
</svg>
|
||||
{{ .DownloadLabel }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<pre id="key"></pre>
|
||||
<pre id="csr"></pre>
|
||||
<pre id="crt"></pre>
|
||||
<pre id="key" class="d-none"></pre>
|
||||
<pre id="csr" class="d-none"></pre>
|
||||
<pre id="crt" class="d-none"></pre>
|
||||
</div>
|
||||
<script src="js/jquery.min.js" integrity="sha384-ZvpUoO/+PpLXR1lu4jmpXWu80pZlYUAfxl5NsBMWOEPSjUn/6Z/hRTt8+pR6L4N2"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="js/forge.all.min.js" integrity="sha384-VfWVy4csHnuL0Tq/vQkZtIpDf4yhSLNf3aBffGj3wKUmyn1UPNx4v0Pzo9chiHu1"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="js/i18next.min.js" integrity="sha384-Juj1kpjwKBUTV6Yp9WHG4GdeoMxCmx0zBN9SkwlyrAh5QYWb3l4WrfG7oTv/b00a"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="js/jquery.min.js"></script>
|
||||
<script src="js/forge.all.min.js"></script>
|
||||
<script src="js/bootstrap.bundle.min.js"></script>
|
||||
<script src="js/i18next.min.js"></script>
|
||||
<script>
|
||||
async function postData(url = '', data = {}, csrfToken) {
|
||||
const response = await fetch(url, {
|
||||
|
@ -98,7 +96,7 @@
|
|||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
i18n.init({fallbackLng: 'en', debug: true}, (err) => {
|
||||
i18n.init({fallbackLng: 'en', debug: true, useCookie: false}, (err) => {
|
||||
if (err) return console.log('something went wrong loading', err);
|
||||
});
|
||||
|
||||
|
@ -111,24 +109,27 @@
|
|||
if (isNaN(keySize)) {
|
||||
return false;
|
||||
}
|
||||
const spinner = document.getElementById('status-spinner');
|
||||
const statusText = document.getElementById('status-text');
|
||||
const statusBlock = document.getElementById('status-block');
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
statusBlock.classList.remove('d-none');
|
||||
spinner.classList.remove('d-none');
|
||||
|
||||
progressBar.classList.add('progress-bar-striped', 'progress-bar-animated');
|
||||
progressBar.style.width = "25%";
|
||||
progressBar.setAttribute("aria-valuenow", "1");
|
||||
const state = forge.pki.rsa.createKeyPairGenerationState(keySize, 0x10001);
|
||||
statusText.innerHTML = i18n.t('keygen.started');
|
||||
progressBar.innerHTML = i18n.t('keygen.started');
|
||||
const startDate = new Date();
|
||||
const step = function () {
|
||||
let duration = (new Date()).getTime() - startDate.getTime();
|
||||
let seconds = Math.floor(duration / 100) / 10;
|
||||
if (!forge.pki.rsa.stepKeyPairGenerationState(state, 100)) {
|
||||
setTimeout(step, 1);
|
||||
statusText.innerHTML = i18n.t('keygen.running', {seconds: seconds}); // `key generation running for ${seconds} seconds`;
|
||||
progressBar.innerHTML = i18n.t('keygen.running', {seconds: seconds});
|
||||
} else {
|
||||
statusText.innerHTML = i18n.t('keygen.generated', {seconds: seconds}); // ``
|
||||
spinner.classList.add('d-none');
|
||||
progressBar.classList.remove("progress-bar-animated", 'progress-bar-striped');
|
||||
progressBar.style.width = "50%";
|
||||
progressBar.setAttribute("aria-valuenow", "2");
|
||||
progressBar.innerHTML = i18n.t('keygen.generated', {seconds: seconds});
|
||||
const keys = state.keys;
|
||||
keyElement.innerHTML = forge.pki.privateKeyToPem(keys.privateKey);
|
||||
const csr = forge.pki.createCertificationRequest();
|
||||
|
@ -145,31 +146,34 @@
|
|||
if (verified) {
|
||||
let csrPem = forge.pki.certificationRequestToPem(csr);
|
||||
document.getElementById("csr").innerHTML = csrPem;
|
||||
const sendButton =
|
||||
document.getElementById("send-button");
|
||||
sendButton.addEventListener("click", function () {
|
||||
postData("/sign/", {"csr": csrPem, "commonName": subject}, csrfToken)
|
||||
.then(data => {
|
||||
console.log(data);
|
||||
document.getElementById("crt").innerHTML = data["certificate"];
|
||||
const certificate = forge.pki.certificateFromPem(data["certificate"]);
|
||||
// browsers have trouble importing anything but 3des encrypted PKCS#12
|
||||
const p12asn1 = forge.pkcs12.toPkcs12Asn1(
|
||||
keys.privateKey, certificate, password,
|
||||
{algorithm: '3des'}
|
||||
);
|
||||
const p12Der = forge.asn1.toDer(p12asn1).getBytes();
|
||||
const p12B64 = forge.util.encode64(p12Der);
|
||||
progressBar.style.width = "75%";
|
||||
progressBar.setAttribute("aria-valuenow", "3");
|
||||
postData("/sign/", {"csr": csrPem, "commonName": subject}, csrfToken)
|
||||
.then(data => {
|
||||
document.getElementById("crt").innerHTML = data["certificate"];
|
||||
let certificates = []
|
||||
certificates.push(forge.pki.certificateFromPem(data["certificate"]));
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.download = 'client_certificate.p12';
|
||||
a.setAttribute('href', 'data:application/x-pkcs12;base64,' + p12B64);
|
||||
a.appendChild(document.createTextNode("Download"));
|
||||
document.getElementById('result').appendChild(a);
|
||||
});
|
||||
});
|
||||
sendButton.removeAttribute("disabled");
|
||||
sendButton.classList.remove("disabled");
|
||||
for (let certificatePemData of data["ca_chain"]) {
|
||||
certificates.push(forge.pki.certificateFromPem(certificatePemData));
|
||||
}
|
||||
|
||||
// browsers have trouble importing anything but 3des encrypted PKCS#12
|
||||
const p12asn1 = forge.pkcs12.toPkcs12Asn1(
|
||||
keys.privateKey, certificates, password,
|
||||
{algorithm: '3des'}
|
||||
);
|
||||
const p12Der = forge.asn1.toDer(p12asn1).getBytes();
|
||||
const p12B64 = forge.util.encode64(p12Der);
|
||||
|
||||
const downloadLink = document.getElementById('download-link');
|
||||
downloadLink.download = 'client_certificate.p12';
|
||||
downloadLink.setAttribute('href', 'data:application/x-pkcs12;base64,' + p12B64);
|
||||
|
||||
document.getElementById('download-wrapper').classList.remove("d-none");
|
||||
progressBar.style.width = "100%";
|
||||
progressBar.setAttribute("aria-valuenow", "4");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue