extensions/net.sf.basedb.webauthn/trunk/resources/edit-user.js

Code
Comments
Other
Rev Date Author Line
6745 20 May 22 nicklas 1 'use strict';
6743 19 May 22 nicklas 2
6743 19 May 22 nicklas 3 var WebAuthn = function()
6743 19 May 22 nicklas 4 {
6743 19 May 22 nicklas 5   var wa = {};
6745 20 May 22 nicklas 6   var debug = 1;
6747 23 May 22 nicklas 7   var hasCreatedHiddenFormElements = false;
6743 19 May 22 nicklas 8   
6743 19 May 22 nicklas 9   wa.initPage = function()
6743 19 May 22 nicklas 10   {
6743 19 May 22 nicklas 11     // Disable WebAuthn fields on extended properties tab
6747 23 May 22 nicklas 12     Doc.element('ep.webAuthnSerial').disabled = true;
6747 23 May 22 nicklas 13     Doc.element('ep.webAuthnUserHandle').disabled = true;
6786 04 Aug 22 nicklas 14     Doc.element('ep.webAuthnPasswordLess.false').disabled = true;
6786 04 Aug 22 nicklas 15     Doc.element('ep.webAuthnPasswordLess.true').disabled = true;
6743 19 May 22 nicklas 16     
6743 19 May 22 nicklas 17     Events.addEventHandler('webAuthnSerial', 'blur', wa.copySerial);
6743 19 May 22 nicklas 18   
6743 19 May 22 nicklas 19     Buttons.addClickHandler('btnWebAuthnRegister', wa.startWebAuthnRegistration);
6747 23 May 22 nicklas 20     Buttons.addClickHandler('btnWebAuthnRemove', wa.removeWebAuthn);
6743 19 May 22 nicklas 21     
6743 19 May 22 nicklas 22     TabControl.addTabActivateListener('settings.webauthn-tab', wa.autoFocus);
6743 19 May 22 nicklas 23   }
6743 19 May 22 nicklas 24   
6743 19 May 22 nicklas 25   // Set focus to the serial number field
6743 19 May 22 nicklas 26   wa.autoFocus = function()
6743 19 May 22 nicklas 27   {
6743 19 May 22 nicklas 28     Doc.element('webAuthnSerial').focus();
6743 19 May 22 nicklas 29   }
6743 19 May 22 nicklas 30   
6743 19 May 22 nicklas 31   /* Copy serial number to extended properties tab */
6743 19 May 22 nicklas 32   wa.copySerial = function()
6743 19 May 22 nicklas 33   {
6747 23 May 22 nicklas 34     Doc.element('ep.webAuthnSerial').value = Doc.element('webAuthnSerial').value;
6743 19 May 22 nicklas 35   }
6747 23 May 22 nicklas 36
6747 23 May 22 nicklas 37   /* 
6747 23 May 22 nicklas 38     Create the hidden form elements that are needed for storing WebAuthn
6747 23 May 22 nicklas 39     data. The form elements are never created more than once.
6747 23 May 22 nicklas 40   */
6747 23 May 22 nicklas 41   wa.createHiddenFormElements = function()
6743 19 May 22 nicklas 42   {
6747 23 May 22 nicklas 43     if (hasCreatedHiddenFormElements) return;
6747 23 May 22 nicklas 44     wa.createHidden('webAuthnUserHandle');
6747 23 May 22 nicklas 45     wa.createHidden('webAuthnCredentialId');
6747 23 May 22 nicklas 46     wa.createHidden('webAuthnPublicKey');
6747 23 May 22 nicklas 47     wa.createHidden('webAuthnSignatureCount');
6786 04 Aug 22 nicklas 48     wa.createHidden('webAuthnPasswordLess');
6747 23 May 22 nicklas 49     hasCreatedHiddenFormElements = true;
6743 19 May 22 nicklas 50   }
6747 23 May 22 nicklas 51
6747 23 May 22 nicklas 52   wa.createHidden = function(id)
6743 19 May 22 nicklas 53   {
6747 23 May 22 nicklas 54     var frm = document.forms['user'];
6747 23 May 22 nicklas 55     var hidden = frm.ownerDocument.createElement('input');
6747 23 May 22 nicklas 56     hidden.setAttribute('type', 'hidden');
6747 23 May 22 nicklas 57     hidden.setAttribute('name', 'ep.'+id);
6747 23 May 22 nicklas 58     hidden.setAttribute('id', id);
6747 23 May 22 nicklas 59     hidden.setAttribute('value', '');
6747 23 May 22 nicklas 60     frm.appendChild(hidden);
6743 19 May 22 nicklas 61   }
6747 23 May 22 nicklas 62
6743 19 May 22 nicklas 63   /*
6743 19 May 22 nicklas 64     Remove all WebAuthn values for this user.
6743 19 May 22 nicklas 65     Switch to the no-WebAuthn form
6743 19 May 22 nicklas 66   */
6743 19 May 22 nicklas 67   wa.removeWebAuthn = function()
6743 19 May 22 nicklas 68   {
6747 23 May 22 nicklas 69     wa.createHiddenFormElements();
6747 23 May 22 nicklas 70     Doc.element('webAuthnUserHandle').value = '';
6747 23 May 22 nicklas 71     Doc.element('ep.webAuthnUserHandle').value = '';
6747 23 May 22 nicklas 72     Doc.element('webAuthnCredentialId').value = '';
6747 23 May 22 nicklas 73     Doc.element('webAuthnPublicKey').value = '';
6747 23 May 22 nicklas 74     Doc.element('webAuthnSignatureCount').value = '';
6747 23 May 22 nicklas 75     Doc.element('webAuthnSerial').value = '';
6786 04 Aug 22 nicklas 76     Doc.element('webAuthnPasswordLess').value = 'false';
6747 23 May 22 nicklas 77     Doc.element('ep.webAuthnSerial').value = '';
6743 19 May 22 nicklas 78     
6747 23 May 22 nicklas 79     Doc.element('webAuthnUserHandleHTML').innerHTML = '<i>No WebAuthn</i>';
6743 19 May 22 nicklas 80     Doc.hide('has-webauthn');
6743 19 May 22 nicklas 81     Doc.show('no-webauthn');
6743 19 May 22 nicklas 82   }
6743 19 May 22 nicklas 83   
6745 20 May 22 nicklas 84   wa.handleError = function(error)
6745 20 May 22 nicklas 85   {
6745 20 May 22 nicklas 86     console.log(error);
6745 20 May 22 nicklas 87     Doc.element('webauthn-error').innerHTML = Strings.encodeTags(error.toString ? error.toString() : error);
6745 20 May 22 nicklas 88     Doc.show('webauthn-error');
6745 20 May 22 nicklas 89   }
6745 20 May 22 nicklas 90   
6747 23 May 22 nicklas 91   wa.hideError = function()
6747 23 May 22 nicklas 92   {
6747 23 May 22 nicklas 93     Doc.element('webauthn-error').innerHTML = '';
6747 23 May 22 nicklas 94     Doc.hide('webauthn-error');
6747 23 May 22 nicklas 95   }
6747 23 May 22 nicklas 96     
6745 20 May 22 nicklas 97   // Step 1. Start the registration by sending some 
6745 20 May 22 nicklas 98   // information about the user to the server
6743 19 May 22 nicklas 99   wa.startWebAuthnRegistration = function()
6743 19 May 22 nicklas 100   {
6747 23 May 22 nicklas 101     wa.hideError();
6747 23 May 22 nicklas 102   
6743 19 May 22 nicklas 103     var frm = document.forms['user'];
6744 20 May 22 nicklas 104     var userId = frm.item_id.value;
6744 20 May 22 nicklas 105     var login = frm.login.value;
6744 20 May 22 nicklas 106     var name =   frm.name.value;
6745 20 May 22 nicklas 107     
6744 20 May 22 nicklas 108     var home = Data.get('webauthn-data', 'home');
6744 20 May 22 nicklas 109     var url = home + '/WebAuthn.servlet?ID='+App.getSessionId();
6744 20 May 22 nicklas 110     url += '&cmd=StartWebAuthnRegister';
6744 20 May 22 nicklas 111     url += '&userId='+encodeURIComponent(userId);
6744 20 May 22 nicklas 112     url += '&login='+encodeURIComponent(login);
6744 20 May 22 nicklas 113     url += '&name='+encodeURIComponent(name);
6786 04 Aug 22 nicklas 114     url += '&enablePasswordLess='+(frm.passwordLess.checked ? 1 : 0);
6744 20 May 22 nicklas 115     
6745 20 May 22 nicklas 116     try
6745 20 May 22 nicklas 117     {
6745 20 May 22 nicklas 118       if (debug) App.debug('AJAX request: '+url);
6745 20 May 22 nicklas 119       var request = Ajax.getXmlHttpRequest();
6745 20 May 22 nicklas 120       Ajax.setReadyStateHandler(request, wa.webAuthnRegistrationRequestRecieved, wa.webAuthnRegistrationRequestRecieved);
6745 20 May 22 nicklas 121       request.open("GET", url, true);
6745 20 May 22 nicklas 122       request.send(null);
6745 20 May 22 nicklas 123     }
6745 20 May 22 nicklas 124     catch (e)
6745 20 May 22 nicklas 125     {
6745 20 May 22 nicklas 126       wa.handleError(e);
6745 20 May 22 nicklas 127     }
6744 20 May 22 nicklas 128   }
6744 20 May 22 nicklas 129   
6745 20 May 22 nicklas 130   // Step 2. Pass the response from the server to the
6745 20 May 22 nicklas 131   // navigator.credentials.create() API
6744 20 May 22 nicklas 132   wa.webAuthnRegistrationRequestRecieved = function(request)
6744 20 May 22 nicklas 133   {
6745 20 May 22 nicklas 134     if (debug) App.debug(request.responseText);
6743 19 May 22 nicklas 135     try
6743 19 May 22 nicklas 136     {
6745 20 May 22 nicklas 137       var response = JSON.parse(request.responseText);
6745 20 May 22 nicklas 138       if (debug) App.debug(response);
6745 20 May 22 nicklas 139       if (response.status != 'ok')
6745 20 May 22 nicklas 140       {
6745 20 May 22 nicklas 141         throw new Error(response.message);
6745 20 May 22 nicklas 142       }
6743 19 May 22 nicklas 143       
6756 01 Jun 22 nicklas 144       var reg = response.registrationRequest.publicKey;
6785 03 Aug 22 nicklas 145       if (reg.authenticatorSelection.residentKey == 'required')
6785 03 Aug 22 nicklas 146       {
6785 03 Aug 22 nicklas 147         // This is an older, deprecaged, attribute but is needed in some browser
6785 03 Aug 22 nicklas 148         // Otherwise the registration will not be saved on the security key
6785 03 Aug 22 nicklas 149         reg.authenticatorSelection.requireResidentKey = true;
6785 03 Aug 22 nicklas 150       }
6785 03 Aug 22 nicklas 151       
6745 20 May 22 nicklas 152       // Re-encode the registration request to what the navigator.credentials.create() requires
6745 20 May 22 nicklas 153       // Mainly, we need to convert Base64-encoded values to Uint8Array object
6745 20 May 22 nicklas 154       var publicKey = {
6745 20 May 22 nicklas 155         'publicKey': {
6745 20 May 22 nicklas 156           'attestation': reg.attestation,
6785 03 Aug 22 nicklas 157           'authenticatorSelection': reg.authenticatorSelection,
6745 20 May 22 nicklas 158           'challenge': WAUtils.base64ToUint8Array(reg.challenge),
6745 20 May 22 nicklas 159           'pubKeyCredParams': reg.pubKeyCredParams,
6745 20 May 22 nicklas 160           'rp': reg.rp,
6745 20 May 22 nicklas 161           'user': {
6745 20 May 22 nicklas 162             'id': WAUtils.base64ToUint8Array(reg.user.id),
6745 20 May 22 nicklas 163             'name': reg.user.name,
6745 20 May 22 nicklas 164             'displayName': reg.user.displayName
6745 20 May 22 nicklas 165           }
6745 20 May 22 nicklas 166         }};
6745 20 May 22 nicklas 167       if (debug) App.debug(publicKey);
6743 19 May 22 nicklas 168       
6745 20 May 22 nicklas 169       // Send create() request to the security key
6745 20 May 22 nicklas 170       navigator.credentials.create(publicKey)
6745 20 May 22 nicklas 171         .then(wa.webAuthnRegistrationRequestCreated)
6745 20 May 22 nicklas 172         .catch(wa.handleError);
6745 20 May 22 nicklas 173     }
6745 20 May 22 nicklas 174     catch (e)
6745 20 May 22 nicklas 175     {
6745 20 May 22 nicklas 176       wa.handleError(e);
6745 20 May 22 nicklas 177     }
6745 20 May 22 nicklas 178   }
6745 20 May 22 nicklas 179   
6745 20 May 22 nicklas 180   // Step 3. Handle the response from the security key and send it to the server
6745 20 May 22 nicklas 181   wa.webAuthnRegistrationRequestCreated = function(publicKey)
6745 20 May 22 nicklas 182   {
6745 20 May 22 nicklas 183     if (debug) 
6745 20 May 22 nicklas 184     {
6745 20 May 22 nicklas 185       App.debug(publicKey);
6745 20 May 22 nicklas 186       console.log('rawId:'+WAUtils.byteArrayToBase64(publicKey.rawId));
6745 20 May 22 nicklas 187       console.log('attestationObject:'+WAUtils.byteArrayToBase64(publicKey.response.attestationObject));
6745 20 May 22 nicklas 188       console.log('clientDataJSON:'+WAUtils.byteArrayToBase64(publicKey.response.clientDataJSON));
6745 20 May 22 nicklas 189     }
6745 20 May 22 nicklas 190     try
6745 20 May 22 nicklas 191     {
6745 20 May 22 nicklas 192       // Convert and encode the response from the security key to what is expected by the server
6745 20 May 22 nicklas 193       var reg = {
6745 20 May 22 nicklas 194         'id': publicKey.id,
6745 20 May 22 nicklas 195         'response':
6745 20 May 22 nicklas 196         {
6745 20 May 22 nicklas 197           'attestationObject': WAUtils.byteArrayToBase64(publicKey.response.attestationObject),
6745 20 May 22 nicklas 198           'clientDataJSON': WAUtils.byteArrayToBase64(publicKey.response.clientDataJSON)
6745 20 May 22 nicklas 199         },
6745 20 May 22 nicklas 200         'clientExtensionResults': {},
6745 20 May 22 nicklas 201         'type': 'public-key'
6745 20 May 22 nicklas 202       };
6745 20 May 22 nicklas 203       
6745 20 May 22 nicklas 204       var home = Data.get('webauthn-data', 'home');
6745 20 May 22 nicklas 205       var url = home + '/WebAuthn.servlet?ID='+App.getSessionId();
6745 20 May 22 nicklas 206       url += '&cmd=FinalizeWebAuthnRegister';
6745 20 May 22 nicklas 207       
6745 20 May 22 nicklas 208       if (debug) 
6743 19 May 22 nicklas 209       {
6745 20 May 22 nicklas 210         App.debug('AJAX request: '+url);
6745 20 May 22 nicklas 211         App.debug(reg);
6743 19 May 22 nicklas 212       }
6745 20 May 22 nicklas 213       
6745 20 May 22 nicklas 214       var request = Ajax.getXmlHttpRequest();
6745 20 May 22 nicklas 215       Ajax.setReadyStateHandler(request, wa.webAuthnRegistrationCompleted, wa.webAuthnRegistrationCompleted);
6745 20 May 22 nicklas 216       request.open("POST", url, true);  
6745 20 May 22 nicklas 217       request.send(JSON.stringify(reg));
6743 19 May 22 nicklas 218     }
6743 19 May 22 nicklas 219     catch (e)
6743 19 May 22 nicklas 220     {
6745 20 May 22 nicklas 221       wa.handleError(e);
6743 19 May 22 nicklas 222     }
6745 20 May 22 nicklas 223   }
6745 20 May 22 nicklas 224     
6745 20 May 22 nicklas 225   // Step 4. Check the response from the server
6745 20 May 22 nicklas 226   wa.webAuthnRegistrationCompleted = function(request)
6745 20 May 22 nicklas 227   {
6745 20 May 22 nicklas 228     if (debug) App.debug(request.responseText);
6745 20 May 22 nicklas 229     try
6743 19 May 22 nicklas 230     {
6745 20 May 22 nicklas 231       var response = JSON.parse(request.responseText);
6745 20 May 22 nicklas 232       if (debug) App.debug(response);
6745 20 May 22 nicklas 233       if (response.status != 'ok')
6745 20 May 22 nicklas 234       {
6745 20 May 22 nicklas 235         throw new Error(response.message);
6745 20 May 22 nicklas 236       }
6745 20 May 22 nicklas 237       
6745 20 May 22 nicklas 238       // Update form elements and switch to the has-webauthn form
6747 23 May 22 nicklas 239       wa.createHiddenFormElements();
6747 23 May 22 nicklas 240       Doc.element('webAuthnUserHandle').value = response.userHandle;
6747 23 May 22 nicklas 241       Doc.element('ep.webAuthnUserHandle').value = response.userHandle;
6747 23 May 22 nicklas 242       Doc.element('webAuthnCredentialId').value = response.credentialId;
6747 23 May 22 nicklas 243       Doc.element('webAuthnPublicKey').value = response.publicKey;
6747 23 May 22 nicklas 244       Doc.element('webAuthnSignatureCount').value = response.signatureCount;
6786 04 Aug 22 nicklas 245       Doc.element('webAuthnPasswordLess').value = response.passwordLess;
6747 23 May 22 nicklas 246
6747 23 May 22 nicklas 247       Doc.element('webAuthnUserHandleHTML').innerHTML = Strings.encodeTags(response.userHandle);
6745 20 May 22 nicklas 248       Doc.show('has-webauthn');
6747 23 May 22 nicklas 249       Doc.hide('no-webauthn');
6745 20 May 22 nicklas 250       Doc.element('webAuthnSerial').focus();
6743 19 May 22 nicklas 251     }
6745 20 May 22 nicklas 252     catch (e)
6745 20 May 22 nicklas 253     {
6745 20 May 22 nicklas 254       wa.handleError(e);
6745 20 May 22 nicklas 255     }
6743 19 May 22 nicklas 256   }
6745 20 May 22 nicklas 257
6743 19 May 22 nicklas 258   return wa;
6743 19 May 22 nicklas 259 }();
6743 19 May 22 nicklas 260
6743 19 May 22 nicklas 261 Doc.onLoad(WebAuthn.initPage);
6743 19 May 22 nicklas 262