mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-20 19:55:54 +00:00
Validator Domain Verifier tool
Complted and tested toml parsing and domain verification Edited HTML for more clarity Included source for domain-verifier-bundle.js Added build instructions and source for domain-verifier-bundle.js Updated and separated build instructions Minified domain-verifier-bundle.js using webpack Updated build instructions with webpack and added extra manifest checks Added query parameter to request, made relative url change, and added attestation check Added newline to html validator-domain-verifier-tool: use <pre>
This commit is contained in:
19
README.md
19
README.md
@@ -16,5 +16,22 @@ To build the site locally:
|
|||||||
|
|
||||||
dactyl_build -t en
|
dactyl_build -t en
|
||||||
|
|
||||||
|
|
||||||
For more details, see the [contribution guidelines](CONTRIBUTING.md).
|
For more details, see the [contribution guidelines](CONTRIBUTING.md).
|
||||||
|
|
||||||
|
|
||||||
|
If you make changes to the [Domain Verification Checker](https://xrpl.org/validator-domain-verifier.html) tool and edit the domain-verifier-checker.js file, you will need to do the following:
|
||||||
|
|
||||||
|
1. Install [webpack](https://webpack.js.org/) and required libraries via npm:
|
||||||
|
|
||||||
|
npm install webpack webpack-cli --save-dev
|
||||||
|
npm install ripple-binary-codec ripple-address-codec ripple-keypairs
|
||||||
|
|
||||||
|
2. From the project root directory (this step may be different depending on how you installed webpack)
|
||||||
|
|
||||||
|
cd assets/js
|
||||||
|
webpack-cli domain-verifier-checker.js --optimize-minimize -o domain-verifier-bundle.js
|
||||||
|
|
||||||
|
3. Build the site:
|
||||||
|
|
||||||
|
cd ../..
|
||||||
|
dactyl_build -t en
|
||||||
|
|||||||
27
assets/js/domain-verifier-bundle.js
Normal file
27
assets/js/domain-verifier-bundle.js
Normal file
File diff suppressed because one or more lines are too long
199
assets/js/domain-verifier-checker.js
Normal file
199
assets/js/domain-verifier-checker.js
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
//Browserify was used to create domain-verifier-bundle.js so that we can use 'require' in the browser
|
||||||
|
|
||||||
|
const codec = require("ripple-binary-codec");
|
||||||
|
const addressCodec = require("ripple-address-codec");
|
||||||
|
const keyCodec = require("ripple-keypairs");
|
||||||
|
|
||||||
|
const TIPS =
|
||||||
|
'<p>Check if the xrp-ledger.toml file is actually hosted in the /.well-known/ location at the domain in your manifest. Check your server\'s HTTPS settings and certificate, and make sure your server provides the required <a href="xrp-ledger-toml.html#cors-setup">CORS header.</a></p>';
|
||||||
|
const TOML_PATH = "/.well-known/xrp-ledger.toml";
|
||||||
|
const CLASS_GOOD = "badge badge-success";
|
||||||
|
const CLASS_BAD = "badge badge-danger";
|
||||||
|
|
||||||
|
var query_param = 0;
|
||||||
|
|
||||||
|
//This function makes the lists that output the status.
|
||||||
|
function makeLogEntry(text, raw) {
|
||||||
|
let log;
|
||||||
|
if (raw) {
|
||||||
|
log = $("<li></li>")
|
||||||
|
.appendTo("#log")
|
||||||
|
.append(text);
|
||||||
|
} else {
|
||||||
|
log = $("<li></li>")
|
||||||
|
.text(text + " ")
|
||||||
|
.appendTo("#log");
|
||||||
|
}
|
||||||
|
log.resolve = function(text) {
|
||||||
|
return $("<span></span>")
|
||||||
|
.html(text)
|
||||||
|
.appendTo(log);
|
||||||
|
};
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
//3.
|
||||||
|
//Find the validator entry in the TOML file and verify the signature of the attestation.
|
||||||
|
async function parse_xrpl_toml(data, public_key_hex, public_key, message) {
|
||||||
|
let parsed;
|
||||||
|
let log1 = makeLogEntry("Parsing TOML data...");
|
||||||
|
try {
|
||||||
|
parsed = TOML(data);
|
||||||
|
log1.resolve("SUCCESS").addClass(CLASS_GOOD);
|
||||||
|
} catch (e) {
|
||||||
|
log1.resolve(e).addClass(CLASS_BAD);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(parsed);
|
||||||
|
|
||||||
|
let validator_entries = parsed.VALIDATORS;
|
||||||
|
|
||||||
|
if (validator_entries) {
|
||||||
|
if (!Array.isArray(validator_entries)) {
|
||||||
|
makeLogEntry("Validators:")
|
||||||
|
.resolve("Wrong type - should be table-array")
|
||||||
|
.addClass(CLASS_BAD);
|
||||||
|
} else {
|
||||||
|
let validator_found = false;
|
||||||
|
for (i = 0; i < validator_entries.length; i++) {
|
||||||
|
let pk = validator_entries[i]["public_key"];
|
||||||
|
|
||||||
|
if (pk == public_key) {
|
||||||
|
validator_found = true;
|
||||||
|
try {
|
||||||
|
var attestation = validator_entries[i]["attestation"];
|
||||||
|
} catch {
|
||||||
|
makeLogEntry("Attestation Not found").addClass(CLASS_BAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var verify = keyCodec.verify(
|
||||||
|
ascii_to_hexa(message),
|
||||||
|
attestation,
|
||||||
|
public_key_hex
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
makeLogEntry("Domain Verification Failed")
|
||||||
|
.resolve(e)
|
||||||
|
.addClass(CLASS_BAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verify) {
|
||||||
|
makeLogEntry("Domain Verification Succeeded").addClass(CLASS_GOOD);
|
||||||
|
} else {
|
||||||
|
makeLogEntry("Domain Verification Failed").addClass(CLASS_BAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!validator_found) {
|
||||||
|
makeLogEntry(
|
||||||
|
"The validator key for this manifest was not found in the TOML file"
|
||||||
|
).addClass(CLASS_BAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
makeLogEntry("No Validators Found")
|
||||||
|
.resolve("Failure")
|
||||||
|
.addClass(CLASS_BAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//2.
|
||||||
|
//Decompose the manifest to obtain the domain and public key.
|
||||||
|
//Use these to create the message that should have been signed by the validator's private key (the attestation).
|
||||||
|
//Go to the domain and verify the signature of the attestation field in the appropriate validator entry.
|
||||||
|
function parse_manifest() {
|
||||||
|
const manhex = $("#manifest").val();
|
||||||
|
|
||||||
|
try {
|
||||||
|
var man = codec.decode(manhex);
|
||||||
|
} catch (e) {
|
||||||
|
makeLogEntry("Error decoding manifest")
|
||||||
|
.resolve(e)
|
||||||
|
.addClass(CLASS_BAD);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let public_key_hex = man["PublicKey"];
|
||||||
|
let buff = new Buffer(public_key_hex, "hex").toJSON().data;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var domain = hex_to_ascii(man["Domain"]);
|
||||||
|
} catch {
|
||||||
|
makeLogEntry("Domain not found in manifest").addClass(CLASS_BAD);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let public_key = addressCodec.encodeNodePublic(buff);
|
||||||
|
|
||||||
|
//This is the message that was signed by the validator's private key.
|
||||||
|
let message = "[domain-attestation-blob:" + domain + ":" + public_key + "]";
|
||||||
|
const url = "https://" + domain + TOML_PATH + "?v=" + query_param++;
|
||||||
|
const log = makeLogEntry("Checking " + url + "...");
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
dataType: "text",
|
||||||
|
success: function(data) {
|
||||||
|
log.resolve("FOUND").addClass(CLASS_GOOD);
|
||||||
|
parse_xrpl_toml(data, public_key_hex, public_key, message);
|
||||||
|
},
|
||||||
|
error: function(jqxhr, status, error) {
|
||||||
|
switch (status) {
|
||||||
|
case "timeout":
|
||||||
|
err = "TIMEOUT";
|
||||||
|
break;
|
||||||
|
case "abort":
|
||||||
|
err = "ABORTED";
|
||||||
|
break;
|
||||||
|
case "error":
|
||||||
|
err = "ERROR";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = "UNKNOWN";
|
||||||
|
}
|
||||||
|
log
|
||||||
|
.resolve(err)
|
||||||
|
.addClass(CLASS_BAD)
|
||||||
|
.after(TIPS);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nifty hex/ascii helpers:
|
||||||
|
//https://www.w3resource.com/javascript-exercises/javascript-string-exercise-28.php
|
||||||
|
function hex_to_ascii(str1) {
|
||||||
|
var hex = str1.toString();
|
||||||
|
var str = "";
|
||||||
|
for (var n = 0; n < hex.length; n += 2) {
|
||||||
|
str += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
//https://www.w3resource.com/javascript-exercises/javascript-string-exercise-27.php
|
||||||
|
function ascii_to_hexa(str) {
|
||||||
|
var arr1 = [];
|
||||||
|
for (var n = 0, l = str.length; n < l; n++) {
|
||||||
|
var hex = Number(str.charCodeAt(n)).toString(16);
|
||||||
|
arr1.push(hex);
|
||||||
|
}
|
||||||
|
return arr1.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_submit(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
$(".result-title").show();
|
||||||
|
$("#result").show();
|
||||||
|
$("#log").empty();
|
||||||
|
|
||||||
|
parse_manifest();
|
||||||
|
}
|
||||||
|
|
||||||
|
//1.
|
||||||
|
//Start the verification process when the user enters a manifest.
|
||||||
|
$(document).ready(() => {
|
||||||
|
$("#manifest-entry").submit(handle_submit);
|
||||||
|
});
|
||||||
|
|
||||||
33
tool/template-validator-domain-verifier.html
Normal file
33
tool/template-validator-domain-verifier.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{% extends "template-base.html" %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<section class="container-fluid p-3">
|
||||||
|
<h1>Domain Verification Checker</h1>
|
||||||
|
|
||||||
|
<p>This tool allows you to verify that <a href="xrp-ledger-toml.html#domain-verification">domain verification</a> is properly configured. </p>
|
||||||
|
<p>Enter the manifest found in your validator-keys.json file. Do not confuse this with your validator's secret key.</p>
|
||||||
|
<p>To do this with the validator-keys-tool use the following command:</p>
|
||||||
|
<pre><code>$ validator-keys show_manifest hex</code></pre>
|
||||||
|
<form id="manifest-entry">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="manifest" type="text" class="form-control" required
|
||||||
|
placeholder="Your Manifest Here"
|
||||||
|
pattern="[0-9A-F]+"><br>
|
||||||
|
<button class="btn btn-primary form-control">Check Domain Verification</button>
|
||||||
|
</div><!--/.input-group-->
|
||||||
|
</form>
|
||||||
|
<div id="result">
|
||||||
|
<h5 class='result-title'>Result</h5>
|
||||||
|
<ul id="log">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block endbody %}
|
||||||
|
<script type='text/javascript' src='assets/vendor/iarna-toml-parse.js'></script>
|
||||||
|
<script type='text/javascript' src='assets/js/domain-verifier-bundle.js'></script>
|
||||||
|
<script type="application/javascript">
|
||||||
|
gtag('set', {'content_group1': 'API Tools'});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user