doauthor
Version:
A client for DoAuth: a fast, lean and reliable authentication server based on verifiable credentials standard
284 lines (279 loc) • 11.7 kB
HTML
<!doctype html>
<html>
<head>
<title>doauthor demo</title>
</head>
<body>
<label>Test ID:</label>
<pre id="test-id"></pre>
<label>Doauthor loading:</label>
<div id="doauthor-status" class="test">pending</div>
<label>Doauthor performing:</label>
<div id="performance-is-ok" class="test">pending</div>
<label>URLSafe Base64 is tripping:</label>
<div id="base64-suite" class="test">pending</div>
<label>KDF works and makes valid signing keys:</label>
<div id="kdf" class="test">pending</div>
<ul>
<li>
<label>The slip:</label>
<pre id="slip"></pre>
</li>
<li>
<label>Signing key used:</label>
<pre id="kdf-info"></pre>
</li>
</ul>
<label>MainKeyInit2 generates a distinct key:</label>
<div id="distinct" class="test">pending</div>
<label>Main key gets reproduced from stored slip:</label>
<div id="localstorage" class="test">pending</div>
<label>"Verify map" of "sign map" is "true":</label>
<div id="verify_map__sign_map" class="test">pending</div>
<label>Credential compliance with the reference implementation:</label>
<div id="credential-compatibility" class="test">pending</div>
<!--
iex(19)> %{public: "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ=", secret: "H9xUHnIAxdYuslQ8UULO8A0eXf6gH2ySEfo2-kdZZow32Nza1n_O_YdP4Qg7JuCbt8ieMOZkFypb-UbAWVLKCg=="} |> Witchcraft.Functor.map(fn x -> Uptight.Base.mk_url!(x).raw |> Uptight.Binary.new!() end) |> DoAuth.Credential.mk_credential!(%{"hello" => "world"}, issuanceDate: ~N[2021-08-17 22:49:56] |> DateTime.from_naive!("Etc/UTC")) |> Jason.encode!(pretty: true) |> IO.puts()
{
"@context": [],
"credentialSubject": {
"hello": "world"
},
"id": "5rQ5V1M3QzCCFOH_w1xu0ondNWLyn8sd4-p3-AiS3GXKLjO4J4BUWLM1xH-CfFcd-LPj-ys908SjHMa-WOq-AA==",
"issuanceDate": "2021-08-17T22:49:56Z",
"issuer": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ=",
"proof": {
"created": "2021-12-07T13:57:55.931383Z",
"proofPurpose": "assertionMethod",
"signature": "5rQ5V1M3QzCCFOH_w1xu0ondNWLyn8sd4-p3-AiS3GXKLjO4J4BUWLM1xH-CfFcd-LPj-ys908SjHMa-WOq-AA==",
"type": "Libsodium2021",
"verificationMethod": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ="
},
"type": []
}
:ok
-->
<pre id="credential-target">
{
"@context": [],
"credentialSubject": {
"hello": "world"
},
"id": "5rQ5V1M3QzCCFOH_w1xu0ondNWLyn8sd4-p3-AiS3GXKLjO4J4BUWLM1xH-CfFcd-LPj-ys908SjHMa-WOq-AA==",
"issuanceDate": "2021-08-17T22:49:56Z",
"issuer": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ=",
"proof": {
"created": "2021-12-07T13:57:55.931383Z",
"proofPurpose": "assertionMethod",
"signature": "5rQ5V1M3QzCCFOH_w1xu0ondNWLyn8sd4-p3-AiS3GXKLjO4J4BUWLM1xH-CfFcd-LPj-ys908SjHMa-WOq-AA==",
"type": "Libsodium2021",
"verificationMethod": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ="
},
"type": []
}
</pre>
<label>Presentations compliance with the reference implementation:</label>
<div id="presentation-compatibility" class="test">pending</div>
<!--
iex(18)> DoAuth.Credential.present_credential_map(kp, cred_map, issuanceDate: tau1) |> Uptight.Result.from_ok() |> Jason.encode!(pretty: true) |> IO.puts
{
"issuanceDate": "2021-12-19T02:31:30Z",
"issuer": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ=",
"proof": {
"signature": "RYa98wyKQ8Gl2GrtYVxUFXPs7m9PFL9wT09xv368dJzK9aJIJ8gZreiugOuKCLtljFex2QWH58Az79x99PyGAg==",
"timestamp": "2021-12-19 04:05:50.471122Z",
"verificationMethod": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ="
},
"verifiableCredential": {
"@context": [],
"credentialSubject": {
"hello": "world"
},
"id": "5rQ5V1M3QzCCFOH_w1xu0ondNWLyn8sd4-p3-AiS3GXKLjO4J4BUWLM1xH-CfFcd-LPj-ys908SjHMa-WOq-AA==",
"issuanceDate": "2021-08-17T22:49:56Z",
"issuer": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ=",
"proof": {
"created": "2021-12-07T13:57:55.931383Z",
"proofPurpose": "assertionMethod",
"signature": "5rQ5V1M3QzCCFOH_w1xu0ondNWLyn8sd4-p3-AiS3GXKLjO4J4BUWLM1xH-CfFcd-LPj-ys908SjHMa-WOq-AA==",
"type": "Libsodium2021",
"verificationMethod": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ="
},
"type": []
}
}
-->
<pre id="presentation-target">
{
"issuanceDate": "2021-12-19T02:31:30Z",
"issuer": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ=",
"proof": {
"signature": "RYa98wyKQ8Gl2GrtYVxUFXPs7m9PFL9wT09xv368dJzK9aJIJ8gZreiugOuKCLtljFex2QWH58Az79x99PyGAg==",
"timestamp": "2021-12-19 04:05:50.471122Z",
"verificationMethod": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ="
},
"verifiableCredential": {
"@context": [],
"credentialSubject": {
"hello": "world"
},
"id": "5rQ5V1M3QzCCFOH_w1xu0ondNWLyn8sd4-p3-AiS3GXKLjO4J4BUWLM1xH-CfFcd-LPj-ys908SjHMa-WOq-AA==",
"issuanceDate": "2021-08-17T22:49:56Z",
"issuer": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ=",
"proof": {
"created": "2021-12-07T13:57:55.931383Z",
"proofPurpose": "assertionMethod",
"signature": "5rQ5V1M3QzCCFOH_w1xu0ondNWLyn8sd4-p3-AiS3GXKLjO4J4BUWLM1xH-CfFcd-LPj-ys908SjHMa-WOq-AA==",
"type": "Libsodium2021",
"verificationMethod": "dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ="
},
"type": []
}
}
</pre>
<label>Credentials are verifiable:</label>
<div id="verifiable-credentials" class="test">pending</div>
<label>Presentations are verifiable:</label>
<div id="verifiable-presentations" class="test">pending</div>
</body>
<script src="/dist/doauthor.js"></script>
<script async defer src="/src/sodium.js"></script>
<script>
const i = (x) => document.getElementById(x);
const ok = (x) => { i(x).innerText = "ok" };
const nok = (x) => { i(x).innerText = "fail" };
const testLoaded = () => {
if (__doauthorHasLoaded__ === true) {
ok("doauthor-status");
} else {
nok("doauthor-status");
}
};
const testBase64 = () => {
const x = doauthor.crypto.show("show / read are tripping");
if (x === doauthor.crypto.show(doauthor.crypto.read(x))) {
ok("base64-suite");
} else {
nok("base64-suite");
}
};
const password = "this is a password";
const testMainKeyDerivation = () => {
const show = doauthor.crypto.show;
const mkey = doauthor.crypto.mainKey(password);
const skp = doauthor.crypto.deriveSigningKeypair(mkey, 4);
const msg = "this is an authenticated message";
const detachedSig = doauthor.crypto.sign(msg, skp);
if (true === doauthor.crypto.verify(
msg,
detachedSig
)) {
ok("kdf");
i("slip").innerText =
doauthor.util.prettyPrint(JSON.parse(localStorage.getItem("slip")));
i("kdf-info").innerText =
doauthor.util.prettyPrint({
"public": show(detachedSig.public),
"signature": show(detachedSig.signature)
});
} else {
nok("kdf");
}
return mkey;
}
const testCryptoVerifyMapOfSignMapIsTrue = async (skp) => {
const verifiable_map = doauthor.crypto.sign_map(skp, { "hello": { "dangerous": { "world": ["of", "JavaScript"] } } });
const res = await doauthor.crypto.verify_map(verifiable_map);
if (true === res) {
ok("verify_map__sign_map");
} else {
nok("verify_map__sign_map");
}
}
const testMainKeyInit2GeneratesDistinctKey = (mkey0) => {
const show = doauthor.crypto.show;
const mkey = doauthor.crypto.mainKey(password);
const [mkey1, _slip] = doauthor.crypto.mainKeyInit2(password, doauthor.crypto.slipConfig());
if (show(mkey) !== show(mkey1)) {
ok("distinct");
} else {
nok("distinct");
}
if (show(mkey0) === show(mkey)) {
ok("localstorage");
} else {
nok("localstorage");
}
return doauthor.crypto.deriveSigningKeypair(mkey, 20);
}
const testCredentialCompatibility = () => {
const kp = {
"public": doauthor.crypto.read("dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ="),
"secret": doauthor.crypto.read("H9xUHnIAxdYuslQ8UULO8A0eXf6gH2ySEfo2-kdZZow32Nza1n_O_YdP4Qg7JuCbt8ieMOZkFypb-UbAWVLKCg==")
};
const cred_ours = doauthor.credential.from_claim(kp, { "hello": "world" }, { "issuanceDate": "2021-08-17T22:49:56Z" });
const cred_ref = JSON.parse(i("credential-target").innerText);
const our_sig = cred_ours["proof"]["signature"];
const ref_sig = cred_ref["proof"]["signature"];
if (our_sig === ref_sig) {
ok("credential-compatibility");
} else {
nok("credential-compatibility");
}
doauthor.did.memorisePublicKey(kp["public"]);
if (doauthor.crypto.verify_map(cred_ours)) {
ok("verifiable-credentials");
} else {
nok("verifiable-credentials");
}
return cred_ours;
}
const testPresentationCompatibility = () => {
const kp = {
"public": doauthor.crypto.read("dW8Z2z2icecILIyAdrjaOqkurfC99ocFR87r9QX_mJQ="),
"secret": doauthor.crypto.read("H9xUHnIAxdYuslQ8UULO8A0eXf6gH2ySEfo2-kdZZow32Nza1n_O_YdP4Qg7JuCbt8ieMOZkFypb-UbAWVLKCg==")
};
cred = JSON.parse(i("credential-target").innerText);
const pres_ours = doauthor.credential.present_credential(kp, cred, { "issuanceDate": "2021-12-19T02:31:30Z" });
console.log(pres_ours, JSON.stringify(pres_ours, null, 2));
const pres_ref = JSON.parse(i("presentation-target").innerText);
const our_sig = pres_ours["proof"]["signature"];
const ref_sig = pres_ref["proof"]["signature"];
if (our_sig === ref_sig) {
ok("presentation-compatibility");
} else {
nok("presentation-compatibility");
}
doauthor.did.memorisePublicKey(kp["public"]);
if (doauthor.crypto.verify_map(pres_ours)) {
ok("verifiable-presentations");
} else {
nok("verifiable-presentations");
}
}
const testPerformanceIsOk = (t000, t290, t300) => {
if (t300 - t000 < 300 && t300 - t290 < 10) {
ok('performance-is-ok');
} else {
nok('performance-is-ok');
}
}
(async () => {
t000 = performance.now();
_ok1 = await DoAuthor.require();
t290 = performance.now();
_ok2 = await DoAuthor.require();
t300 = performance.now();
_ok3 = await DoAuthor.require();
i("test-id").innerText = doauthor.crypto.show(sodium.randombytes_buf(8));
testLoaded();
testPerformanceIsOk(t000, t290, t300);
testBase64();
const mkey = testMainKeyDerivation();
const skp = testMainKeyInit2GeneratesDistinctKey(mkey);
await testCryptoVerifyMapOfSignMapIsTrue(skp);
const cred = testCredentialCompatibility();
testPresentationCompatibility(cred);
})();
</script>
</html>