Add online notary key registry, add button to erase private key, don't autogenerate keys (so user reads the docs first)
This commit is contained in:
parent
3db51d0cf5
commit
99b8173f7e
@ -72,23 +72,28 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||||||
Signatures are generated using your private key, which you must keep secret.
|
Signatures are generated using your private key, which you must keep secret.
|
||||||
Someone with the private key can modify a signed PDF without detection.
|
Someone with the private key can modify a signed PDF without detection.
|
||||||
<b>Protect your private key like you protect your notary stamp/seal.</b>
|
<b>Protect your private key like you protect your notary stamp/seal.</b>
|
||||||
<br>
|
<br><br>
|
||||||
A corresponding public key is also available; anyone with your public key can
|
A corresponding public key is also available; anyone with your public key can
|
||||||
verify you signed a document, but cannot do anything else.
|
verify you signed a document, but cannot do anything else.
|
||||||
It is recommended to post your public key somewhere public like a website.
|
To make verifying documents easier, the creator of this software
|
||||||
This way, people can ensure documents you notarized are valid without contacting you for a
|
maintains a public online registry of public keys; you can upload your
|
||||||
copy of your public key. It is also recommended to
|
key and notary profile with the button below.
|
||||||
<b>back up your private key</b> in case your computer malfunctions. This will ensure you don't need
|
<br><br>
|
||||||
to make a new one. A new key won't be able to verify older signatures or vice versa. Some states
|
It is also recommended to <b>back up your private key</b> in case your computer malfunctions.
|
||||||
require you use only one key for the entire term of your commission.
|
This will ensure you don't need to make a new one. A new key won't be able to verify older signatures or vice versa.
|
||||||
|
Some states require you use only one key for the entire term of your commission.
|
||||||
</p>
|
</p>
|
||||||
<a class="btn btn-info m-1" target="_blank" href="https://docs.netsyms.com/docs/IPENtool/Cryptography%20101/"><i class="fas fa-graduation-cap"></i> Learn More</a>
|
<a class="btn btn-info m-1" target="_blank" href="https://docs.netsyms.com/docs/IPENtool/Cryptography%20101/"><i class="fas fa-graduation-cap"></i> Learn More</a>
|
||||||
<div class="btn btn-primary m-1" onclick="loadKeyFromLocalStorageWithUserFeedback()"><i class="fas fa-unlock"></i> Create/unlock private key</div>
|
<div class="btn btn-primary m-1" onclick="createKeyWithUserFeedback()"><i class="fas fa-key"></i> Create new private key</div>
|
||||||
<div class="btn btn-primary m-1" onclick="unloadKey()"><i class="fas fa-lock"></i> Lock private key</div>
|
<div class="btn btn-primary m-1" onclick="unloadKey()"><i class="fas fa-lock"></i> Lock private key (require password on next use)</div>
|
||||||
<div class="btn btn-primary m-1" onclick="exportPublicKey()"><i class="fas fa-file-export"></i> Export public key</div>
|
|
||||||
<br>
|
<br>
|
||||||
<div class="btn btn-danger m-1" onclick="exportPrivateKey()"><i class="fas fa-download"></i> Back up private key</div>
|
<div class="btn btn-primary m-1" onclick="exportPrivateKey()"><i class="fas fa-download"></i> Back up private key</div>
|
||||||
<div class="btn btn-danger m-1" onclick="importPrivateKey()"><i class="fas fa-upload"></i> Restore private key</div>
|
<div class="btn btn-primary m-1" onclick="importPrivateKey()"><i class="fas fa-upload"></i> Restore private key</div>
|
||||||
|
<br>
|
||||||
|
<div class="btn btn-primary m-1" onclick="exportPublicKeyToFile()"><i class="fas fa-file-export"></i> Export public key to file</div>
|
||||||
|
<div class="btn btn-primary m-1" onclick="exportPublicKeyToRegistry()"><i class="fas fa-cloud-upload-alt"></i> Upload public key to online registry</div>
|
||||||
|
<br><br><br>
|
||||||
|
<div class="btn btn-danger m-1" onclick="erasePrivateKey()"><i class="fas fa-exclamation-triangle"></i> Erase private key</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-lg-4" id="appOptionsSettings">
|
<div class="col-12 col-md-6 col-lg-4" id="appOptionsSettings">
|
||||||
<h5><i class="fas fa-sliders-h"></i> App Options</h5>
|
<h5><i class="fas fa-sliders-h"></i> App Options</h5>
|
||||||
@ -281,6 +286,18 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="okCancelPromptModal" tabindex="-1" aria-labelledby="okCancelPromptModalText" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-body p-1" id="okCancelPromptModalText"></div>
|
||||||
|
<div class="modal-footer p-1">
|
||||||
|
<button type="button" class="btn btn-secondary" onclick="okCancelPromptModalCallback(false);" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="button" class="btn btn-primary" onclick="okCancelPromptModalCallback(true);" data-bs-dismiss="modal">Okay</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal fade" id="passwordModal" tabindex="-1" aria-labelledby="passwordModalLabel" aria-hidden="true">
|
<div class="modal fade" id="passwordModal" tabindex="-1" aria-labelledby="passwordModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -296,7 +313,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="position-fixed bottom-0 end-0 p-3" style="z-index: 999999;">
|
<div class="position-fixed bottom-0 start-50 translate-middle-x p-3" style="z-index: 999999;">
|
||||||
<div id="toastBox" class="toast hide" role="alert" aria-live="assertive" aria-atomic="true">
|
<div id="toastBox" class="toast hide" role="alert" aria-live="assertive" aria-atomic="true">
|
||||||
<div class="toast-body"></div>
|
<div class="toast-body"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
265
src/js/crypto.js
265
src/js/crypto.js
@ -9,7 +9,7 @@ var keymgr;
|
|||||||
var keyring = new kbpgp.keyring.KeyRing();
|
var keyring = new kbpgp.keyring.KeyRing();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load and unlock the private key in localstorage, prompting user as needed. If there is no key, generates, saves, and loads a new one.
|
* Load and unlock the private key in localstorage, prompting user as needed.
|
||||||
* @param {function} callback Passed two arguments: message for user, and boolean true if OK false if error.
|
* @param {function} callback Passed two arguments: message for user, and boolean true if OK false if error.
|
||||||
* @returns {undefined}
|
* @returns {undefined}
|
||||||
*/
|
*/
|
||||||
@ -20,18 +20,8 @@ function loadKeyFromLocalStorage(callback) {
|
|||||||
}
|
}
|
||||||
$("#lockstatus").css("display", "none");
|
$("#lockstatus").css("display", "none");
|
||||||
if (!inStorage("signingkey") || getStorage("signingkey") == "undefined") {
|
if (!inStorage("signingkey") || getStorage("signingkey") == "undefined") {
|
||||||
showPasswordPrompt("Generating a new signing key (might take a while, be patient). Enter a password to protect it. You'll need to save this password somewhere safe; it cannot be recovered.", function (pass) {
|
callback("You do not have a private key. Click Settings to create one.", false);
|
||||||
generatePrivateKey(getStorage("notary_name") + " <" + (inStorage("notary_email") ? getStorage("notary_email") : "null@null.com") + ">", pass, function (key) {
|
|
||||||
if (typeof key == "undefined") {
|
|
||||||
callback("Could not generate key.", false);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
keymgr = key;
|
|
||||||
keyring.add_key_manager(keymgr);
|
|
||||||
setStorage("signingkey", keymgr.armored_pgp_private);
|
|
||||||
callback("Signing key generated.", true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
showPasswordPrompt("Enter password to unlock signing key:", function (pass) {
|
showPasswordPrompt("Enter password to unlock signing key:", function (pass) {
|
||||||
loadPrivateKey(getStorage("signingkey"), pass, function (key) {
|
loadPrivateKey(getStorage("signingkey"), pass, function (key) {
|
||||||
@ -41,12 +31,31 @@ function loadKeyFromLocalStorage(callback) {
|
|||||||
}
|
}
|
||||||
keymgr = key;
|
keymgr = key;
|
||||||
keyring.add_key_manager(keymgr);
|
keyring.add_key_manager(keymgr);
|
||||||
callback("Signing key unlocked.", true);
|
callback("Private key unlocked.", true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createKey(callback) {
|
||||||
|
if (!inStorage("signingkey") || getStorage("signingkey") == "undefined") {
|
||||||
|
showPasswordPrompt("Generating a new private key (might take a while, be patient). Enter a password to protect it. You'll need to memorize or write down this password; it cannot be recovered.", function (pass) {
|
||||||
|
generatePrivateKey(getStorage("notary_name") + " <" + (inStorage("notary_email") ? getStorage("notary_email") : "noemailaddressprovided@example.com") + ">", pass, function (key) {
|
||||||
|
if (typeof key == "undefined") {
|
||||||
|
callback("Could not generate key.", false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
keymgr = key;
|
||||||
|
keyring.add_key_manager(keymgr);
|
||||||
|
setStorage("signingkey", keymgr.armored_pgp_private);
|
||||||
|
callback("Private key generated.", true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback("You already have a private key. You must erase it before generating a new one.", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function unloadKey() {
|
function unloadKey() {
|
||||||
keymgr = undefined;
|
keymgr = undefined;
|
||||||
$("#lockstatus").css("display", "");
|
$("#lockstatus").css("display", "");
|
||||||
@ -63,6 +72,16 @@ function loadKeyFromLocalStorageWithUserFeedback() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createKeyWithUserFeedback() {
|
||||||
|
createKey(function (msg, ok) {
|
||||||
|
if (ok) {
|
||||||
|
showToast("<i class='fas fa-check'></i> " + msg);
|
||||||
|
} else {
|
||||||
|
showAlert("Error: " + msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a private key.
|
* Load a private key.
|
||||||
* @param {string} armoredkey PGP private key
|
* @param {string} armoredkey PGP private key
|
||||||
@ -184,18 +203,68 @@ function generatePrivateKey(userid, passphrase, callback) {
|
|||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportPublicKey() {
|
function exportPublicKeyToFile() {
|
||||||
loadKeyFromLocalStorage(function (message, ok) {
|
getOwnPublicKey(function (pgp_public) {
|
||||||
if (ok) {
|
if (pgp_public == false) {
|
||||||
openSaveFileDialog(function (path) {
|
|
||||||
keymgr.export_pgp_public({}, function (err, pgp_public) {
|
|
||||||
if (err) {
|
|
||||||
showAlert("Something went wrong.");
|
showAlert("Something went wrong.");
|
||||||
} else {
|
} else {
|
||||||
|
openSaveFileDialog(function (path) {
|
||||||
writeToFile(path, pgp_public);
|
writeToFile(path, pgp_public);
|
||||||
|
showAlert("Public key saved.");
|
||||||
|
}, "public-key.asc", ".asc");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportPublicKeyToRegistry() {
|
||||||
|
if (!inStorage("signingkey") || getStorage("signingkey") == "undefined") {
|
||||||
|
showAlert("You must create and back up your private key first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showOkCancelPrompt("Double-check that your notary profile is complete and that you pressed the Save button after making any changes before continuing.", function (ok) {
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getOwnPublicKey(function (pgp_public) {
|
||||||
|
if (pgp_public == false) {
|
||||||
|
showAlert("Something went wrong.");
|
||||||
|
} else {
|
||||||
|
submitPublicKeyToRegistry(
|
||||||
|
pgp_public,
|
||||||
|
getStorage("notary_name"),
|
||||||
|
getStorage("notary_email"),
|
||||||
|
getStorage("notary_location"),
|
||||||
|
getStorage("notary_expires"),
|
||||||
|
getStorage("notary_idnumber"),
|
||||||
|
getStorage("notary_state"),
|
||||||
|
function (msg, ok) {
|
||||||
|
if (!ok) {
|
||||||
|
showAlert("Error: " + msg);
|
||||||
|
} else {
|
||||||
|
showAlert(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user's own public key, prompting for key password if needed.
|
||||||
|
* @param {function} callback cb(result): public key string or false on error
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function getOwnPublicKey(callback) {
|
||||||
|
loadKeyFromLocalStorage(function (message, ok) {
|
||||||
|
if (ok) {
|
||||||
|
keymgr.export_pgp_public({}, function (err, pgp_public) {
|
||||||
|
if (err) {
|
||||||
|
callback(false);
|
||||||
|
} else {
|
||||||
|
callback(pgp_public);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, "public-key.asc", ".asc");
|
|
||||||
} else {
|
} else {
|
||||||
showAlert("Error: " + message);
|
showAlert("Error: " + message);
|
||||||
}
|
}
|
||||||
@ -324,14 +393,11 @@ function calculateSHA256HashOfString(str) {
|
|||||||
function openPublicKeyFile() {
|
function openPublicKeyFile() {
|
||||||
openFileDialog(function (path, html5file) {
|
openFileDialog(function (path, html5file) {
|
||||||
var importpk = function (keyfile) {
|
var importpk = function (keyfile) {
|
||||||
kbpgp.KeyManager.import_from_armored_pgp({
|
addPublicKeyToKeyring(keyfile, function (res) {
|
||||||
armored: keyfile
|
if (res === true) {
|
||||||
}, function (err, pubkeymgr) {
|
|
||||||
if (!err) {
|
|
||||||
keyring.add_key_manager(pubkeymgr);
|
|
||||||
showAlert("Public key file loaded. You can now analyze PDFs signed by the key's owner.");
|
showAlert("Public key file loaded. You can now analyze PDFs signed by the key's owner.");
|
||||||
} else {
|
} else {
|
||||||
showAlert("Error loading public key: " + err);
|
showAlert("Error loading public key: " + res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -349,6 +415,150 @@ function openPublicKeyFile() {
|
|||||||
}, ".asc");
|
}, ".asc");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {type} keyfile
|
||||||
|
* @param {type} callback cb(result): result is true if successful, an error string if failed.
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function addPublicKeyToKeyring(keyfile, callback) {
|
||||||
|
kbpgp.KeyManager.import_from_armored_pgp({
|
||||||
|
armored: keyfile
|
||||||
|
}, function (err, pubkeymgr) {
|
||||||
|
if (!err) {
|
||||||
|
keyring.add_key_manager(pubkeymgr);
|
||||||
|
callback(true);
|
||||||
|
} else {
|
||||||
|
callback(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up a full or partial public key fingerprint with the Netsyms notary registry.
|
||||||
|
* @param {string} fingerprint
|
||||||
|
* @param {function} callback cb(result): `result` is an array of notary info and keys (see below), or `false` if there was an error or no results.
|
||||||
|
* @returns {undefined}
|
||||||
|
*
|
||||||
|
* result = [{
|
||||||
|
* fingerprint,
|
||||||
|
* name,
|
||||||
|
* email,
|
||||||
|
* location,
|
||||||
|
* commissionexpires,
|
||||||
|
* idnumber,
|
||||||
|
* state,
|
||||||
|
* publickey
|
||||||
|
* }]
|
||||||
|
*
|
||||||
|
* All but fingerprint and publickey could be null.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function lookupPublicKey(fingerprint, callback) {
|
||||||
|
$.ajax({
|
||||||
|
url: "https://data.netsyms.net/v1/notary/fetchkey/",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
fingerprint: fingerprint
|
||||||
|
},
|
||||||
|
success: function (resp) {
|
||||||
|
if (resp.count == 0) {
|
||||||
|
callback(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback(resp.results);
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
callback(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import multiple public keys and only callback when all are done.
|
||||||
|
* @param {type} keys see lookupPublicKey()
|
||||||
|
* @param {function} callback
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function importPublicKeysFromRegistry(keys, callback) {
|
||||||
|
var i = 0;
|
||||||
|
var loop = function (keys) {
|
||||||
|
addPublicKeyToKeyring(keys[i].publickey, function () {
|
||||||
|
i++;
|
||||||
|
if (i < keys.length) {
|
||||||
|
loop(keys);
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
loop(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload a public key to the Netsyms notary registry server.
|
||||||
|
* @param {string} pubkey PGP public key file contents, armored
|
||||||
|
* @param {string} name Notary name
|
||||||
|
* @param {string} email Notary email
|
||||||
|
* @param {string} location Notary location
|
||||||
|
* @param {string} expires Commission expiration date; server will parse.
|
||||||
|
* @param {string} idnumber Commission ID number
|
||||||
|
* @param {string} state Two-char state
|
||||||
|
* @param {function} callback ((string) message, (bool) okaytrue_errorfalse)
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function submitPublicKeyToRegistry(pubkey, name, email, location, expires, idnumber, state, callback) {
|
||||||
|
$.ajax({
|
||||||
|
url: "https://data.netsyms.net/v1/notary/publishkey/",
|
||||||
|
method: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
publickey: pubkey,
|
||||||
|
name: name,
|
||||||
|
email: email,
|
||||||
|
location: location,
|
||||||
|
commissionexpires: expires,
|
||||||
|
idnumber: idnumber,
|
||||||
|
state: state
|
||||||
|
},
|
||||||
|
success: function (resp) {
|
||||||
|
if (resp.status == "OK") {
|
||||||
|
callback(resp.msg, true);
|
||||||
|
} else if (resp.status == "ERROR") {
|
||||||
|
callback(resp.msg, false);
|
||||||
|
} else {
|
||||||
|
callback("The registry server didn't send a valid response.", false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
callback("There was a problem communicating with the registry server. Try again later.", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erase the local private key data with lots of prompting and dire warnings.
|
||||||
|
* @returns {undefined}
|
||||||
|
*/
|
||||||
|
function erasePrivateKey() {
|
||||||
|
showOkCancelPrompt("<div style=\"background: black; padding: 1rem;\"><b><i class='fas fa-skull-crossbones'></i> DANGER: THIS WILL RESULT IN DATA LOSS -- READ CAREFULLY</b><br><br>\n\
|
||||||
|
Erasing your private key means you won't be able to notarize or sign electronic documents without generating a new key. \n\
|
||||||
|
If you have not exported your public key, electronically verifying documents you have signed will be impossible.\n\
|
||||||
|
If you plan on using your private key in the future, press cancel and back up your private key to a file.\n\
|
||||||
|
Some states require you use the same key for the entire length of your commission.\n\
|
||||||
|
<br><br><b>IF YOU CONTINUE, YOUR PRIVATE KEY WILL NOT BE RECOVERABLE WITHOUT A BACKUP.</b></div>", function (ok) {
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var txt = prompt("To erase your private key, type \"ERASE MY SIGNING KEY\"");
|
||||||
|
if (txt.toUpperCase() != "ERASE MY SIGNING KEY") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unloadKey();
|
||||||
|
localStorage.removeItem("signingkey");
|
||||||
|
alert("Signing key erased.");
|
||||||
|
});
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Show visual indicator when private key is not loaded/unlocked.
|
* Show visual indicator when private key is not loaded/unlocked.
|
||||||
* @returns {undefined}
|
* @returns {undefined}
|
||||||
@ -359,4 +569,5 @@ setInterval(function () {
|
|||||||
} else {
|
} else {
|
||||||
$("#lockstatus").css("display", "none");
|
$("#lockstatus").css("display", "none");
|
||||||
}
|
}
|
||||||
}, 1000);
|
}
|
||||||
|
, 1000);
|
||||||
@ -70,31 +70,54 @@ function analyzeSignedPDF() {
|
|||||||
var pdfdata = pdf.slice(0, splitindex);
|
var pdfdata = pdf.slice(0, splitindex);
|
||||||
var sigdata = pdf.slice(splitindex).toString();
|
var sigdata = pdf.slice(splitindex).toString();
|
||||||
|
|
||||||
var verify = function (pdfhash) {
|
var verify = function (pdfhash, reload) {
|
||||||
loadKeyFromLocalStorage(function () {
|
loadKeyFromLocalStorage(function () {
|
||||||
verifyMessage(sigdata, function (msg, fprint) {
|
verifyMessage(sigdata, function (msg, fprint) {
|
||||||
parseAndDisplaySignature(msg, pdfhash, true, fprint);
|
parseAndDisplaySignature(msg, pdfhash, true, fprint);
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
console.log(sigdata);
|
|
||||||
var base64 = sigdata.split("\n\n", 2)[1].split("\n-----END PGP MESSAGE-----")[0];
|
|
||||||
base64 = base64.substring(0, base64.lastIndexOf("\n")).replaceAll("\n", "");
|
|
||||||
try {
|
try {
|
||||||
var msg = window.atob(base64).split("START", 2)[1].split("END", 2)[0];
|
|
||||||
parseAndDisplaySignature(msg, pdfhash, false, null);
|
|
||||||
} catch (ex) {
|
|
||||||
readSignatureExternally(sigdata, function (msg, keyprint, signername, verified, ok) {
|
readSignatureExternally(sigdata, function (msg, keyprint, signername, verified, ok) {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
showAlert("Error: could not parse signature data.");
|
showAlert("Error: could not parse signature data.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// If system GPG has the public key, use that.
|
||||||
|
// Otherwise, try looking up the fingerprint online and if we get hits
|
||||||
|
// add them to the local keyring and try verifying again.
|
||||||
|
if (verified) {
|
||||||
parseAndDisplaySignature(msg, pdfhash, verified, keyprint, signername);
|
parseAndDisplaySignature(msg, pdfhash, verified, keyprint, signername);
|
||||||
|
} else {
|
||||||
|
if (typeof reload == 'undefined' || reload == false) {
|
||||||
|
lookupPublicKey(keyprint, function (res) {
|
||||||
|
if (res == false) {
|
||||||
|
parseAndDisplaySignature(msg, pdfhash, verified, keyprint, signername);
|
||||||
|
} else {
|
||||||
|
importPublicKeysFromRegistry(res, function () {
|
||||||
|
verify(pdfhash, true);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
parseAndDisplaySignature(msg, pdfhash, verified, keyprint, signername);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (ex) {
|
||||||
console.error(ex);
|
console.error(ex);
|
||||||
|
var base64 = sigdata.split("\n\n", 2)[1].split("\n-----END PGP MESSAGE-----")[0];
|
||||||
|
base64 = base64.substring(0, base64.lastIndexOf("\n")).replaceAll("\n", "");
|
||||||
|
try {
|
||||||
|
var msg = window.atob(base64).split("START", 2)[1].split("END", 2)[0];
|
||||||
|
parseAndDisplaySignature(msg, pdfhash, false, null);
|
||||||
|
} catch (exx) {
|
||||||
|
console.error(exx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (typeof reload == 'undefined' || reload == false) {
|
||||||
if (typeof nw != 'undefined') {
|
if (typeof nw != 'undefined') {
|
||||||
pdfjsLib.getDocument(pdf).promise.then(function (pdfDoc_) {
|
pdfjsLib.getDocument(pdf).promise.then(function (pdfDoc_) {
|
||||||
pdfDoc = pdfDoc_;
|
pdfDoc = pdfDoc_;
|
||||||
@ -115,6 +138,7 @@ function analyzeSignedPDF() {
|
|||||||
fileReader.readAsArrayBuffer(html5file);
|
fileReader.readAsArrayBuffer(html5file);
|
||||||
}
|
}
|
||||||
$(".enable-when-doc-open").removeClass("disabled");
|
$(".enable-when-doc-open").removeClass("disabled");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof nw != 'undefined') {
|
if (typeof nw != 'undefined') {
|
||||||
|
|||||||
@ -26,3 +26,11 @@ function showPasswordPrompt(message, callback) {
|
|||||||
passwordModalCallback = callback;
|
passwordModalCallback = callback;
|
||||||
new bootstrap.Modal(document.getElementById('passwordModal')).show();
|
new bootstrap.Modal(document.getElementById('passwordModal')).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var okCancelPromptModalCallback = function (okay) {};
|
||||||
|
|
||||||
|
function showOkCancelPrompt(message, callback) {
|
||||||
|
$("#okCancelPromptModalText").html(message);
|
||||||
|
okCancelPromptModalCallback = callback;
|
||||||
|
new bootstrap.Modal(document.getElementById('okCancelPromptModal')).show();
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user