|
|
@@ -0,0 +1,115 @@
|
|
|
+
|
|
|
+coerceToArrayBuffer = function (thing, name) {
|
|
|
+ if (typeof thing === "string") {
|
|
|
+ // base64url to base64
|
|
|
+ thing = thing.replace(/-/g, "+").replace(/_/g, "/");
|
|
|
+
|
|
|
+ // base64 to Uint8Array
|
|
|
+ const str = atob(thing);
|
|
|
+ const bytes = new Uint8Array(str.length);
|
|
|
+ for (let i = 0; i < str.length; i++) {
|
|
|
+ bytes[i] = str.charCodeAt(i);
|
|
|
+ }
|
|
|
+ return bytes;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+class Registration {
|
|
|
+ constructor() {
|
|
|
+ document.getElementById('start').addEventListener('click', this.registerAccount.bind(this));
|
|
|
+ }
|
|
|
+
|
|
|
+ async registerAccount(event) {
|
|
|
+ event.preventDefault();
|
|
|
+
|
|
|
+ const username = 'Foo! That Bar';
|
|
|
+ const login = btoa(username);
|
|
|
+
|
|
|
+ const response = await fetch(`/buildCredentialOptions?login=${login}`, {
|
|
|
+ method: 'GET',
|
|
|
+ headers: {
|
|
|
+ 'Accept': 'application/json'
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ const options = await response.json();
|
|
|
+
|
|
|
+ if (options.status !== "ok") {
|
|
|
+ console.error("Error in buildCredentialOptions");
|
|
|
+ console.error(options.errorMessage);
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ console.log("Got options", options);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Turn the challenge back into the accepted format of padded base64
|
|
|
+ options.challenge = coerceToArrayBuffer(options.challenge);
|
|
|
+ // Turn ID into a UInt8Array Buffer for some reason
|
|
|
+ options.user.id = coerceToArrayBuffer(options.user.id);
|
|
|
+
|
|
|
+ options.excludeCredentials = options.excludeCredentials.map((c) => {
|
|
|
+ c.id = coerceToArrayBuffer(c.id);
|
|
|
+ return c;
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log("Options Formatted", options);
|
|
|
+
|
|
|
+ // Create the Credential with navigator.credentials.create API
|
|
|
+
|
|
|
+ let newCredential;
|
|
|
+ try {
|
|
|
+ newCredential = await navigator.credentials.create({
|
|
|
+ publicKey: options
|
|
|
+ });
|
|
|
+ } catch (e) {
|
|
|
+ console.error("credentials.create failed with exception", e);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log("PublicKeyCredential created", newCredential);
|
|
|
+
|
|
|
+ // try {
|
|
|
+ // register(newCredential);
|
|
|
+ // } catch (e) {
|
|
|
+ // console.error("Registering new credentials with the server failed with exception", e);
|
|
|
+ // }
|
|
|
+ }
|
|
|
+
|
|
|
+ async register(newCredential) {
|
|
|
+ // Move data into Arrays in case it is super long
|
|
|
+ // TODO: check!
|
|
|
+ let attestationObject = new Uint8Array(newCredential.response.attestationObject);
|
|
|
+ let clientDataJSON = new Uint8Array(newCredential.response.clientDataJSON);
|
|
|
+ let rawId = new Uint8Array(newCredential.rawId);
|
|
|
+
|
|
|
+ const data = {
|
|
|
+ id: newCredential.id,
|
|
|
+ //rawId: coerceToBase64Url(rawId),
|
|
|
+ type: newCredential.type,
|
|
|
+ extensions: newCredential.getClientExtensionResults(),
|
|
|
+ response: {
|
|
|
+ AttestationObject: coerceToBase64Url(attestationObject),
|
|
|
+ clientDataJSON: coerceToBase64Url(clientDataJSON),
|
|
|
+ transports: newCredential.response.getTransports()
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ let response = await fetch(`/registerCredential?login=`, {
|
|
|
+ method: 'POST', // or 'PUT'
|
|
|
+ body: JSON.stringify(formData), // data can be `string` or {object}!
|
|
|
+ headers: {
|
|
|
+ 'Accept': 'application/json',
|
|
|
+ 'Content-Type': 'application/json'
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ const result = await response.json();
|
|
|
+
|
|
|
+ console.log("Credential Object", result);
|
|
|
+
|
|
|
+ if (result.status !== "ok") {
|
|
|
+ throw new Error(`Error creating credential: ${result.errorMessage}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+window.registration = new Registration();
|