001package Torello.Browser.BrowserAPI;
002
003import java.util.*;
004import javax.json.*;
005import javax.json.stream.*;
006import java.io.*;
007
008import java.lang.reflect.Method;
009import java.lang.reflect.Parameter;
010import java.util.function.Function;
011
012import Torello.Browser.BrowserEvent;
013import Torello.Browser.JavaScriptAPI.*;
014import Torello.Browser.helper.*;
015
016import Torello.Java.Additional.*;
017import Torello.Java.JSON.*;
018
019import static Torello.Java.JSON.JFlag.*;
020
021import Torello.Java.StrCmpr;
022import Torello.JavaDoc.StaticFunctional;
023import Torello.JavaDoc.JDHeaderBackgroundImg;
024import Torello.JavaDoc.Excuse;
025
026/**
027 * <SPAN CLASS=COPIEDJDK><B>This domain allows configuring virtual authenticators to test the WebAuthn
028 * API.</B></SPAN>
029 * 
030 * <EMBED CLASS='external-html' DATA-FILE-ID=CODE_GEN_NOTE>
031 */
032@StaticFunctional(Excused={"counter"}, Excuses={Excuse.CONFIGURATION})
033@JDHeaderBackgroundImg(EmbedTagFileID="WOOD_PLANK_NOTE")
034public class WebAuthn
035{
036    // ********************************************************************************************
037    // ********************************************************************************************
038    // Class Header Stuff
039    // ********************************************************************************************
040    // ********************************************************************************************
041
042
043    // No Pubic Constructors
044    private WebAuthn () { }
045
046    // These two Vector's are used by all the "Methods" exported by this class.  java.lang.reflect
047    // is used to generate the JSON String's.  It saves thousands of lines of Auto-Generated Code.
048    private static final Map<String, Vector<String>>    parameterNames = new HashMap<>();
049    private static final Map<String, Vector<Class<?>>>  parameterTypes = new HashMap<>();
050
051    // Some Methods do not take any parameters - for instance all the "enable()" and "disable()"
052    // I simply could not get ride of RAW-TYPES and UNCHECKED warnings... so there are now,
053    // offically, two empty-vectors.  One for String's, and the other for Classes.
054
055    private static final Vector<String>     EMPTY_VEC_STR = new Vector<>();
056    private static final Vector<Class<?>>   EMPTY_VEC_CLASS = new Vector<>();
057
058    static
059    {
060        for (Method m : WebAuthn.class.getMethods())
061        {
062            // This doesn't work!  The parameter names are all "arg0" ... "argN"
063            // It works for java.lang.reflect.Field, BUT NOT java.lang.reflect.Parameter!
064            //
065            // Vector<String> parameterNamesList = new Vector<>(); -- NOPE!
066
067            Vector<Class<?>> parameterTypesList = new Vector<>();
068        
069            for (Parameter p : m.getParameters()) parameterTypesList.add(p.getType());
070
071            parameterTypes.put(
072                m.getName(),
073                (parameterTypesList.size() > 0) ? parameterTypesList : EMPTY_VEC_CLASS
074            );
075        }
076    }
077
078    static
079    {
080        Vector<String> v = null;
081
082        v = new Vector<String>(1);
083        parameterNames.put("enable", v);
084        Collections.addAll(v, new String[]
085        { "enableUI", });
086
087        parameterNames.put("disable", EMPTY_VEC_STR);
088
089        v = new Vector<String>(1);
090        parameterNames.put("addVirtualAuthenticator", v);
091        Collections.addAll(v, new String[]
092        { "options", });
093
094        v = new Vector<String>(4);
095        parameterNames.put("setResponseOverrideBits", v);
096        Collections.addAll(v, new String[]
097        { "authenticatorId", "isBogusSignature", "isBadUV", "isBadUP", });
098
099        v = new Vector<String>(1);
100        parameterNames.put("removeVirtualAuthenticator", v);
101        Collections.addAll(v, new String[]
102        { "authenticatorId", });
103
104        v = new Vector<String>(2);
105        parameterNames.put("addCredential", v);
106        Collections.addAll(v, new String[]
107        { "authenticatorId", "credential", });
108
109        v = new Vector<String>(2);
110        parameterNames.put("getCredential", v);
111        Collections.addAll(v, new String[]
112        { "authenticatorId", "credentialId", });
113
114        v = new Vector<String>(1);
115        parameterNames.put("getCredentials", v);
116        Collections.addAll(v, new String[]
117        { "authenticatorId", });
118
119        v = new Vector<String>(2);
120        parameterNames.put("removeCredential", v);
121        Collections.addAll(v, new String[]
122        { "authenticatorId", "credentialId", });
123
124        v = new Vector<String>(1);
125        parameterNames.put("clearCredentials", v);
126        Collections.addAll(v, new String[]
127        { "authenticatorId", });
128
129        v = new Vector<String>(2);
130        parameterNames.put("setUserVerified", v);
131        Collections.addAll(v, new String[]
132        { "authenticatorId", "isUserVerified", });
133
134        v = new Vector<String>(2);
135        parameterNames.put("setAutomaticPresenceSimulation", v);
136        Collections.addAll(v, new String[]
137        { "authenticatorId", "enabled", });
138
139        v = new Vector<String>(4);
140        parameterNames.put("setCredentialProperties", v);
141        Collections.addAll(v, new String[]
142        { "authenticatorId", "credentialId", "backupEligibility", "backupState", });
143    }
144
145
146    // ********************************************************************************************
147    // ********************************************************************************************
148    // Types - Static Inner Classes
149    // ********************************************************************************************
150    // ********************************************************************************************
151
152    // public static class AuthenticatorId => String
153    
154    /** <CODE>[No Description Provided by Google]</CODE> */
155    public static final String[] AuthenticatorProtocol =
156    { "u2f", "ctap2", };
157    
158    /** <CODE>[No Description Provided by Google]</CODE> */
159    public static final String[] Ctap2Version =
160    { "ctap2_0", "ctap2_1", };
161    
162    /** <CODE>[No Description Provided by Google]</CODE> */
163    public static final String[] AuthenticatorTransport =
164    { "usb", "nfc", "ble", "cable", "internal", };
165    
166    /** <CODE>[No Description Provided by Google]</CODE> */
167    public static class VirtualAuthenticatorOptions
168        extends BaseType
169        implements java.io.Serializable
170    {
171        /** For Object Serialization.  java.io.Serializable */
172        protected static final long serialVersionUID = 1;
173        
174        public boolean[] optionals()
175        { return new boolean[] { false, true, false, true, true, true, true, true, true, true, true, true, true, }; }
176        
177        /** <CODE>[No Description Provided by Google]</CODE> */
178        public final String protocol;
179        
180        /**
181         * Defaults to ctap2_0. Ignored if |protocol| == u2f.
182         * <BR /><B CLASS=Opt>OPTIONAL</B>
183         */
184        public final String ctap2Version;
185        
186        /** <CODE>[No Description Provided by Google]</CODE> */
187        public final String transport;
188        
189        /**
190         * Defaults to false.
191         * <BR /><B CLASS=Opt>OPTIONAL</B>
192         */
193        public final Boolean hasResidentKey;
194        
195        /**
196         * Defaults to false.
197         * <BR /><B CLASS=Opt>OPTIONAL</B>
198         */
199        public final Boolean hasUserVerification;
200        
201        /**
202         * If set to true, the authenticator will support the largeBlob extension.
203         * https://w3c.github.io/webauthn#largeBlob
204         * Defaults to false.
205         * <BR /><B CLASS=Opt>OPTIONAL</B>
206         */
207        public final Boolean hasLargeBlob;
208        
209        /**
210         * If set to true, the authenticator will support the credBlob extension.
211         * https://fidoalliance.org/specs/fido-v2.1-rd-20201208/fido-client-to-authenticator-protocol-v2.1-rd-20201208.html#sctn-credBlob-extension
212         * Defaults to false.
213         * <BR /><B CLASS=Opt>OPTIONAL</B>
214         */
215        public final Boolean hasCredBlob;
216        
217        /**
218         * If set to true, the authenticator will support the minPinLength extension.
219         * https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#sctn-minpinlength-extension
220         * Defaults to false.
221         * <BR /><B CLASS=Opt>OPTIONAL</B>
222         */
223        public final Boolean hasMinPinLength;
224        
225        /**
226         * If set to true, the authenticator will support the prf extension.
227         * https://w3c.github.io/webauthn/#prf-extension
228         * Defaults to false.
229         * <BR /><B CLASS=Opt>OPTIONAL</B>
230         */
231        public final Boolean hasPrf;
232        
233        /**
234         * If set to true, tests of user presence will succeed immediately.
235         * Otherwise, they will not be resolved. Defaults to true.
236         * <BR /><B CLASS=Opt>OPTIONAL</B>
237         */
238        public final Boolean automaticPresenceSimulation;
239        
240        /**
241         * Sets whether User Verification succeeds or fails for an authenticator.
242         * Defaults to false.
243         * <BR /><B CLASS=Opt>OPTIONAL</B>
244         */
245        public final Boolean isUserVerified;
246        
247        /**
248         * Credentials created by this authenticator will have the backup
249         * eligibility (BE) flag set to this value. Defaults to false.
250         * https://w3c.github.io/webauthn/#sctn-credential-backup
251         * <BR /><B CLASS=Opt>OPTIONAL</B>
252         */
253        public final Boolean defaultBackupEligibility;
254        
255        /**
256         * Credentials created by this authenticator will have the backup state
257         * (BS) flag set to this value. Defaults to false.
258         * https://w3c.github.io/webauthn/#sctn-credential-backup
259         * <BR /><B CLASS=Opt>OPTIONAL</B>
260         */
261        public final Boolean defaultBackupState;
262        
263        /**
264         * Constructor
265         *
266         * @param protocol -
267         * 
268         * @param ctap2Version Defaults to ctap2_0. Ignored if |protocol| == u2f.
269         * <BR /><B CLASS=Opt>OPTIONAL</B>
270         * 
271         * @param transport -
272         * 
273         * @param hasResidentKey Defaults to false.
274         * <BR /><B CLASS=Opt>OPTIONAL</B>
275         * 
276         * @param hasUserVerification Defaults to false.
277         * <BR /><B CLASS=Opt>OPTIONAL</B>
278         * 
279         * @param hasLargeBlob 
280         * If set to true, the authenticator will support the largeBlob extension.
281         * https://w3c.github.io/webauthn#largeBlob
282         * Defaults to false.
283         * <BR /><B CLASS=Opt>OPTIONAL</B>
284         * 
285         * @param hasCredBlob 
286         * If set to true, the authenticator will support the credBlob extension.
287         * https://fidoalliance.org/specs/fido-v2.1-rd-20201208/fido-client-to-authenticator-protocol-v2.1-rd-20201208.html#sctn-credBlob-extension
288         * Defaults to false.
289         * <BR /><B CLASS=Opt>OPTIONAL</B>
290         * 
291         * @param hasMinPinLength 
292         * If set to true, the authenticator will support the minPinLength extension.
293         * https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#sctn-minpinlength-extension
294         * Defaults to false.
295         * <BR /><B CLASS=Opt>OPTIONAL</B>
296         * 
297         * @param hasPrf 
298         * If set to true, the authenticator will support the prf extension.
299         * https://w3c.github.io/webauthn/#prf-extension
300         * Defaults to false.
301         * <BR /><B CLASS=Opt>OPTIONAL</B>
302         * 
303         * @param automaticPresenceSimulation 
304         * If set to true, tests of user presence will succeed immediately.
305         * Otherwise, they will not be resolved. Defaults to true.
306         * <BR /><B CLASS=Opt>OPTIONAL</B>
307         * 
308         * @param isUserVerified 
309         * Sets whether User Verification succeeds or fails for an authenticator.
310         * Defaults to false.
311         * <BR /><B CLASS=Opt>OPTIONAL</B>
312         * 
313         * @param defaultBackupEligibility 
314         * Credentials created by this authenticator will have the backup
315         * eligibility (BE) flag set to this value. Defaults to false.
316         * https://w3c.github.io/webauthn/#sctn-credential-backup
317         * <BR /><B CLASS=Opt>OPTIONAL</B>
318         * 
319         * @param defaultBackupState 
320         * Credentials created by this authenticator will have the backup state
321         * (BS) flag set to this value. Defaults to false.
322         * https://w3c.github.io/webauthn/#sctn-credential-backup
323         * <BR /><B CLASS=Opt>OPTIONAL</B>
324         */
325        public VirtualAuthenticatorOptions(
326                String protocol, String ctap2Version, String transport, Boolean hasResidentKey, 
327                Boolean hasUserVerification, Boolean hasLargeBlob, Boolean hasCredBlob, 
328                Boolean hasMinPinLength, Boolean hasPrf, Boolean automaticPresenceSimulation, 
329                Boolean isUserVerified, Boolean defaultBackupEligibility, Boolean defaultBackupState
330            )
331        {
332            // Exception-Check(s) to ensure that if any parameters which are not declared as
333            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
334            
335            if (protocol == null)  THROWS.throwNPE("protocol");
336            if (transport == null) THROWS.throwNPE("transport");
337            
338            // Exception-Check(s) to ensure that if any parameters which must adhere to a
339            // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw.
340            
341            THROWS.checkIAE("protocol", protocol, "WebAuthn.AuthenticatorProtocol", WebAuthn.AuthenticatorProtocol);
342            THROWS.checkIAE("ctap2Version", ctap2Version, "WebAuthn.Ctap2Version", WebAuthn.Ctap2Version);
343            THROWS.checkIAE("transport", transport, "WebAuthn.AuthenticatorTransport", WebAuthn.AuthenticatorTransport);
344            
345            this.protocol                     = protocol;
346            this.ctap2Version                 = ctap2Version;
347            this.transport                    = transport;
348            this.hasResidentKey               = hasResidentKey;
349            this.hasUserVerification          = hasUserVerification;
350            this.hasLargeBlob                 = hasLargeBlob;
351            this.hasCredBlob                  = hasCredBlob;
352            this.hasMinPinLength              = hasMinPinLength;
353            this.hasPrf                       = hasPrf;
354            this.automaticPresenceSimulation  = automaticPresenceSimulation;
355            this.isUserVerified               = isUserVerified;
356            this.defaultBackupEligibility     = defaultBackupEligibility;
357            this.defaultBackupState           = defaultBackupState;
358        }
359        
360        /**
361         * JSON Object Constructor
362         * @param jo A Json-Object having data about an instance of {@code 'VirtualAuthenticatorOptions'}.
363         */
364        public VirtualAuthenticatorOptions (JsonObject jo)
365        {
366            this.protocol                     = ReadJSON.getString(jo, "protocol", false, true);
367            this.ctap2Version                 = ReadJSON.getString(jo, "ctap2Version", true, false);
368            this.transport                    = ReadJSON.getString(jo, "transport", false, true);
369            this.hasResidentKey               = ReadBoxedJSON.getBoolean(jo, "hasResidentKey", true);
370            this.hasUserVerification          = ReadBoxedJSON.getBoolean(jo, "hasUserVerification", true);
371            this.hasLargeBlob                 = ReadBoxedJSON.getBoolean(jo, "hasLargeBlob", true);
372            this.hasCredBlob                  = ReadBoxedJSON.getBoolean(jo, "hasCredBlob", true);
373            this.hasMinPinLength              = ReadBoxedJSON.getBoolean(jo, "hasMinPinLength", true);
374            this.hasPrf                       = ReadBoxedJSON.getBoolean(jo, "hasPrf", true);
375            this.automaticPresenceSimulation  = ReadBoxedJSON.getBoolean(jo, "automaticPresenceSimulation", true);
376            this.isUserVerified               = ReadBoxedJSON.getBoolean(jo, "isUserVerified", true);
377            this.defaultBackupEligibility     = ReadBoxedJSON.getBoolean(jo, "defaultBackupEligibility", true);
378            this.defaultBackupState           = ReadBoxedJSON.getBoolean(jo, "defaultBackupState", true);
379        }
380        
381        
382        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
383        public boolean equals(Object other)
384        {
385            if (this == other)                       return true;
386            if (other == null)                       return false;
387            if (other.getClass() != this.getClass()) return false;
388        
389            VirtualAuthenticatorOptions o = (VirtualAuthenticatorOptions) other;
390        
391            return
392                    Objects.equals(this.protocol, o.protocol)
393                &&  Objects.equals(this.ctap2Version, o.ctap2Version)
394                &&  Objects.equals(this.transport, o.transport)
395                &&  Objects.equals(this.hasResidentKey, o.hasResidentKey)
396                &&  Objects.equals(this.hasUserVerification, o.hasUserVerification)
397                &&  Objects.equals(this.hasLargeBlob, o.hasLargeBlob)
398                &&  Objects.equals(this.hasCredBlob, o.hasCredBlob)
399                &&  Objects.equals(this.hasMinPinLength, o.hasMinPinLength)
400                &&  Objects.equals(this.hasPrf, o.hasPrf)
401                &&  Objects.equals(this.automaticPresenceSimulation, o.automaticPresenceSimulation)
402                &&  Objects.equals(this.isUserVerified, o.isUserVerified)
403                &&  Objects.equals(this.defaultBackupEligibility, o.defaultBackupEligibility)
404                &&  Objects.equals(this.defaultBackupState, o.defaultBackupState);
405        }
406        
407        /** Generates a Hash-Code for {@code 'this'} instance */
408        public int hashCode()
409        {
410            return
411                    Objects.hashCode(this.protocol)
412                +   Objects.hashCode(this.ctap2Version)
413                +   Objects.hashCode(this.transport)
414                +   Objects.hashCode(this.hasResidentKey)
415                +   Objects.hashCode(this.hasUserVerification)
416                +   Objects.hashCode(this.hasLargeBlob)
417                +   Objects.hashCode(this.hasCredBlob)
418                +   Objects.hashCode(this.hasMinPinLength)
419                +   Objects.hashCode(this.hasPrf)
420                +   Objects.hashCode(this.automaticPresenceSimulation)
421                +   Objects.hashCode(this.isUserVerified)
422                +   Objects.hashCode(this.defaultBackupEligibility)
423                +   Objects.hashCode(this.defaultBackupState);
424        }
425    }
426    
427    /** <CODE>[No Description Provided by Google]</CODE> */
428    public static class Credential
429        extends BaseType
430        implements java.io.Serializable
431    {
432        /** For Object Serialization.  java.io.Serializable */
433        protected static final long serialVersionUID = 1;
434        
435        public boolean[] optionals()
436        { return new boolean[] { false, false, true, false, true, false, true, true, true, true, true, }; }
437        
438        /** <CODE>[No Description Provided by Google]</CODE> */
439        public final String credentialId;
440        
441        /** <CODE>[No Description Provided by Google]</CODE> */
442        public final boolean isResidentCredential;
443        
444        /**
445         * Relying Party ID the credential is scoped to. Must be set when adding a
446         * credential.
447         * <BR /><B CLASS=Opt>OPTIONAL</B>
448         */
449        public final String rpId;
450        
451        /** The ECDSA P-256 private key in PKCS#8 format. (Encoded as a base64 string when passed over JSON) */
452        public final String privateKey;
453        
454        /**
455         * An opaque byte sequence with a maximum size of 64 bytes mapping the
456         * credential to a specific user. (Encoded as a base64 string when passed over JSON)
457         * <BR /><B CLASS=Opt>OPTIONAL</B>
458         */
459        public final String userHandle;
460        
461        /**
462         * Signature counter. This is incremented by one for each successful
463         * assertion.
464         * See https://w3c.github.io/webauthn/#signature-counter
465         */
466        public final int signCount;
467        
468        /**
469         * The large blob associated with the credential.
470         * See https://w3c.github.io/webauthn/#sctn-large-blob-extension (Encoded as a base64 string when passed over JSON)
471         * <BR /><B CLASS=Opt>OPTIONAL</B>
472         */
473        public final String largeBlob;
474        
475        /**
476         * Assertions returned by this credential will have the backup eligibility
477         * (BE) flag set to this value. Defaults to the authenticator's
478         * defaultBackupEligibility value.
479         * <BR /><B CLASS=Opt>OPTIONAL</B>
480         */
481        public final Boolean backupEligibility;
482        
483        /**
484         * Assertions returned by this credential will have the backup state (BS)
485         * flag set to this value. Defaults to the authenticator's
486         * defaultBackupState value.
487         * <BR /><B CLASS=Opt>OPTIONAL</B>
488         */
489        public final Boolean backupState;
490        
491        /**
492         * The credential's user.name property. Equivalent to empty if not set.
493         * https://w3c.github.io/webauthn/#dom-publickeycredentialentity-name
494         * <BR /><B CLASS=Opt>OPTIONAL</B>
495         */
496        public final String userName;
497        
498        /**
499         * The credential's user.displayName property. Equivalent to empty if
500         * not set.
501         * https://w3c.github.io/webauthn/#dom-publickeycredentialuserentity-displayname
502         * <BR /><B CLASS=Opt>OPTIONAL</B>
503         */
504        public final String userDisplayName;
505        
506        /**
507         * Constructor
508         *
509         * @param credentialId -
510         * 
511         * @param isResidentCredential -
512         * 
513         * @param rpId 
514         * Relying Party ID the credential is scoped to. Must be set when adding a
515         * credential.
516         * <BR /><B CLASS=Opt>OPTIONAL</B>
517         * 
518         * @param privateKey The ECDSA P-256 private key in PKCS#8 format. (Encoded as a base64 string when passed over JSON)
519         * 
520         * @param userHandle 
521         * An opaque byte sequence with a maximum size of 64 bytes mapping the
522         * credential to a specific user. (Encoded as a base64 string when passed over JSON)
523         * <BR /><B CLASS=Opt>OPTIONAL</B>
524         * 
525         * @param signCount 
526         * Signature counter. This is incremented by one for each successful
527         * assertion.
528         * See https://w3c.github.io/webauthn/#signature-counter
529         * 
530         * @param largeBlob 
531         * The large blob associated with the credential.
532         * See https://w3c.github.io/webauthn/#sctn-large-blob-extension (Encoded as a base64 string when passed over JSON)
533         * <BR /><B CLASS=Opt>OPTIONAL</B>
534         * 
535         * @param backupEligibility 
536         * Assertions returned by this credential will have the backup eligibility
537         * (BE) flag set to this value. Defaults to the authenticator's
538         * defaultBackupEligibility value.
539         * <BR /><B CLASS=Opt>OPTIONAL</B>
540         * 
541         * @param backupState 
542         * Assertions returned by this credential will have the backup state (BS)
543         * flag set to this value. Defaults to the authenticator's
544         * defaultBackupState value.
545         * <BR /><B CLASS=Opt>OPTIONAL</B>
546         * 
547         * @param userName 
548         * The credential's user.name property. Equivalent to empty if not set.
549         * https://w3c.github.io/webauthn/#dom-publickeycredentialentity-name
550         * <BR /><B CLASS=Opt>OPTIONAL</B>
551         * 
552         * @param userDisplayName 
553         * The credential's user.displayName property. Equivalent to empty if
554         * not set.
555         * https://w3c.github.io/webauthn/#dom-publickeycredentialuserentity-displayname
556         * <BR /><B CLASS=Opt>OPTIONAL</B>
557         */
558        public Credential(
559                String credentialId, boolean isResidentCredential, String rpId, String privateKey, 
560                String userHandle, int signCount, String largeBlob, Boolean backupEligibility, 
561                Boolean backupState, String userName, String userDisplayName
562            )
563        {
564            // Exception-Check(s) to ensure that if any parameters which are not declared as
565            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
566            
567            if (credentialId == null) THROWS.throwNPE("credentialId");
568            if (privateKey == null)   THROWS.throwNPE("privateKey");
569            
570            this.credentialId          = credentialId;
571            this.isResidentCredential  = isResidentCredential;
572            this.rpId                  = rpId;
573            this.privateKey            = privateKey;
574            this.userHandle            = userHandle;
575            this.signCount             = signCount;
576            this.largeBlob             = largeBlob;
577            this.backupEligibility     = backupEligibility;
578            this.backupState           = backupState;
579            this.userName              = userName;
580            this.userDisplayName       = userDisplayName;
581        }
582        
583        /**
584         * JSON Object Constructor
585         * @param jo A Json-Object having data about an instance of {@code 'Credential'}.
586         */
587        public Credential (JsonObject jo)
588        {
589            this.credentialId          = ReadJSON.getString(jo, "credentialId", false, true);
590            this.isResidentCredential  = ReadPrimJSON.getBoolean(jo, "isResidentCredential");
591            this.rpId                  = ReadJSON.getString(jo, "rpId", true, false);
592            this.privateKey            = ReadJSON.getString(jo, "privateKey", false, true);
593            this.userHandle            = ReadJSON.getString(jo, "userHandle", true, false);
594            this.signCount             = ReadPrimJSON.getInt(jo, "signCount");
595            this.largeBlob             = ReadJSON.getString(jo, "largeBlob", true, false);
596            this.backupEligibility     = ReadBoxedJSON.getBoolean(jo, "backupEligibility", true);
597            this.backupState           = ReadBoxedJSON.getBoolean(jo, "backupState", true);
598            this.userName              = ReadJSON.getString(jo, "userName", true, false);
599            this.userDisplayName       = ReadJSON.getString(jo, "userDisplayName", true, false);
600        }
601        
602        
603        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
604        public boolean equals(Object other)
605        {
606            if (this == other)                       return true;
607            if (other == null)                       return false;
608            if (other.getClass() != this.getClass()) return false;
609        
610            Credential o = (Credential) other;
611        
612            return
613                    Objects.equals(this.credentialId, o.credentialId)
614                &&  (this.isResidentCredential == o.isResidentCredential)
615                &&  Objects.equals(this.rpId, o.rpId)
616                &&  Objects.equals(this.privateKey, o.privateKey)
617                &&  Objects.equals(this.userHandle, o.userHandle)
618                &&  (this.signCount == o.signCount)
619                &&  Objects.equals(this.largeBlob, o.largeBlob)
620                &&  Objects.equals(this.backupEligibility, o.backupEligibility)
621                &&  Objects.equals(this.backupState, o.backupState)
622                &&  Objects.equals(this.userName, o.userName)
623                &&  Objects.equals(this.userDisplayName, o.userDisplayName);
624        }
625        
626        /** Generates a Hash-Code for {@code 'this'} instance */
627        public int hashCode()
628        {
629            return
630                    Objects.hashCode(this.credentialId)
631                +   (this.isResidentCredential ? 1 : 0)
632                +   Objects.hashCode(this.rpId)
633                +   Objects.hashCode(this.privateKey)
634                +   Objects.hashCode(this.userHandle)
635                +   this.signCount
636                +   Objects.hashCode(this.largeBlob)
637                +   Objects.hashCode(this.backupEligibility)
638                +   Objects.hashCode(this.backupState)
639                +   Objects.hashCode(this.userName)
640                +   Objects.hashCode(this.userDisplayName);
641        }
642    }
643    
644    /** Triggered when a credential is added to an authenticator. */
645    public static class credentialAdded
646        extends BrowserEvent
647        implements java.io.Serializable
648    {
649        /** For Object Serialization.  java.io.Serializable */
650        protected static final long serialVersionUID = 1;
651        
652        public boolean[] optionals()
653        { return new boolean[] { false, false, }; }
654        
655        /** <CODE>[No Description Provided by Google]</CODE> */
656        public final String authenticatorId;
657        
658        /** <CODE>[No Description Provided by Google]</CODE> */
659        public final WebAuthn.Credential credential;
660        
661        /**
662         * Constructor
663         *
664         * @param authenticatorId -
665         * 
666         * @param credential -
667         */
668        public credentialAdded(String authenticatorId, WebAuthn.Credential credential)
669        {
670            super("WebAuthn", "credentialAdded", 2);
671            
672            // Exception-Check(s) to ensure that if any parameters which are not declared as
673            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
674            
675            if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
676            if (credential == null)      THROWS.throwNPE("credential");
677            
678            this.authenticatorId  = authenticatorId;
679            this.credential       = credential;
680        }
681        
682        /**
683         * JSON Object Constructor
684         * @param jo A Json-Object having data about an instance of {@code 'credentialAdded'}.
685         */
686        public credentialAdded (JsonObject jo)
687        {
688            super("WebAuthn", "credentialAdded", 2);
689        
690            this.authenticatorId  = ReadJSON.getString(jo, "authenticatorId", false, true);
691            this.credential       = ReadJSON.getObject(jo, "credential", WebAuthn.Credential.class, false, true);
692        }
693        
694        
695        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
696        public boolean equals(Object other)
697        {
698            if (this == other)                       return true;
699            if (other == null)                       return false;
700            if (other.getClass() != this.getClass()) return false;
701        
702            credentialAdded o = (credentialAdded) other;
703        
704            return
705                    Objects.equals(this.authenticatorId, o.authenticatorId)
706                &&  Objects.equals(this.credential, o.credential);
707        }
708        
709        /** Generates a Hash-Code for {@code 'this'} instance */
710        public int hashCode()
711        {
712            return
713                    Objects.hashCode(this.authenticatorId)
714                +   this.credential.hashCode();
715        }
716    }
717    
718    /**
719     * Triggered when a credential is deleted, e.g. through
720     * PublicKeyCredential.signalUnknownCredential().
721     */
722    public static class credentialDeleted
723        extends BrowserEvent
724        implements java.io.Serializable
725    {
726        /** For Object Serialization.  java.io.Serializable */
727        protected static final long serialVersionUID = 1;
728        
729        public boolean[] optionals()
730        { return new boolean[] { false, false, }; }
731        
732        /** <CODE>[No Description Provided by Google]</CODE> */
733        public final String authenticatorId;
734        
735        /** <CODE>[No Description Provided by Google]</CODE> */
736        public final String credentialId;
737        
738        /**
739         * Constructor
740         *
741         * @param authenticatorId -
742         * 
743         * @param credentialId -
744         */
745        public credentialDeleted(String authenticatorId, String credentialId)
746        {
747            super("WebAuthn", "credentialDeleted", 2);
748            
749            // Exception-Check(s) to ensure that if any parameters which are not declared as
750            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
751            
752            if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
753            if (credentialId == null)    THROWS.throwNPE("credentialId");
754            
755            this.authenticatorId  = authenticatorId;
756            this.credentialId     = credentialId;
757        }
758        
759        /**
760         * JSON Object Constructor
761         * @param jo A Json-Object having data about an instance of {@code 'credentialDeleted'}.
762         */
763        public credentialDeleted (JsonObject jo)
764        {
765            super("WebAuthn", "credentialDeleted", 2);
766        
767            this.authenticatorId  = ReadJSON.getString(jo, "authenticatorId", false, true);
768            this.credentialId     = ReadJSON.getString(jo, "credentialId", false, true);
769        }
770        
771        
772        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
773        public boolean equals(Object other)
774        {
775            if (this == other)                       return true;
776            if (other == null)                       return false;
777            if (other.getClass() != this.getClass()) return false;
778        
779            credentialDeleted o = (credentialDeleted) other;
780        
781            return
782                    Objects.equals(this.authenticatorId, o.authenticatorId)
783                &&  Objects.equals(this.credentialId, o.credentialId);
784        }
785        
786        /** Generates a Hash-Code for {@code 'this'} instance */
787        public int hashCode()
788        {
789            return
790                    Objects.hashCode(this.authenticatorId)
791                +   Objects.hashCode(this.credentialId);
792        }
793    }
794    
795    /**
796     * Triggered when a credential is updated, e.g. through
797     * PublicKeyCredential.signalCurrentUserDetails().
798     */
799    public static class credentialUpdated
800        extends BrowserEvent
801        implements java.io.Serializable
802    {
803        /** For Object Serialization.  java.io.Serializable */
804        protected static final long serialVersionUID = 1;
805        
806        public boolean[] optionals()
807        { return new boolean[] { false, false, }; }
808        
809        /** <CODE>[No Description Provided by Google]</CODE> */
810        public final String authenticatorId;
811        
812        /** <CODE>[No Description Provided by Google]</CODE> */
813        public final WebAuthn.Credential credential;
814        
815        /**
816         * Constructor
817         *
818         * @param authenticatorId -
819         * 
820         * @param credential -
821         */
822        public credentialUpdated(String authenticatorId, WebAuthn.Credential credential)
823        {
824            super("WebAuthn", "credentialUpdated", 2);
825            
826            // Exception-Check(s) to ensure that if any parameters which are not declared as
827            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
828            
829            if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
830            if (credential == null)      THROWS.throwNPE("credential");
831            
832            this.authenticatorId  = authenticatorId;
833            this.credential       = credential;
834        }
835        
836        /**
837         * JSON Object Constructor
838         * @param jo A Json-Object having data about an instance of {@code 'credentialUpdated'}.
839         */
840        public credentialUpdated (JsonObject jo)
841        {
842            super("WebAuthn", "credentialUpdated", 2);
843        
844            this.authenticatorId  = ReadJSON.getString(jo, "authenticatorId", false, true);
845            this.credential       = ReadJSON.getObject(jo, "credential", WebAuthn.Credential.class, false, true);
846        }
847        
848        
849        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
850        public boolean equals(Object other)
851        {
852            if (this == other)                       return true;
853            if (other == null)                       return false;
854            if (other.getClass() != this.getClass()) return false;
855        
856            credentialUpdated o = (credentialUpdated) other;
857        
858            return
859                    Objects.equals(this.authenticatorId, o.authenticatorId)
860                &&  Objects.equals(this.credential, o.credential);
861        }
862        
863        /** Generates a Hash-Code for {@code 'this'} instance */
864        public int hashCode()
865        {
866            return
867                    Objects.hashCode(this.authenticatorId)
868                +   this.credential.hashCode();
869        }
870    }
871    
872    /** Triggered when a credential is used in a webauthn assertion. */
873    public static class credentialAsserted
874        extends BrowserEvent
875        implements java.io.Serializable
876    {
877        /** For Object Serialization.  java.io.Serializable */
878        protected static final long serialVersionUID = 1;
879        
880        public boolean[] optionals()
881        { return new boolean[] { false, false, }; }
882        
883        /** <CODE>[No Description Provided by Google]</CODE> */
884        public final String authenticatorId;
885        
886        /** <CODE>[No Description Provided by Google]</CODE> */
887        public final WebAuthn.Credential credential;
888        
889        /**
890         * Constructor
891         *
892         * @param authenticatorId -
893         * 
894         * @param credential -
895         */
896        public credentialAsserted(String authenticatorId, WebAuthn.Credential credential)
897        {
898            super("WebAuthn", "credentialAsserted", 2);
899            
900            // Exception-Check(s) to ensure that if any parameters which are not declared as
901            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
902            
903            if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
904            if (credential == null)      THROWS.throwNPE("credential");
905            
906            this.authenticatorId  = authenticatorId;
907            this.credential       = credential;
908        }
909        
910        /**
911         * JSON Object Constructor
912         * @param jo A Json-Object having data about an instance of {@code 'credentialAsserted'}.
913         */
914        public credentialAsserted (JsonObject jo)
915        {
916            super("WebAuthn", "credentialAsserted", 2);
917        
918            this.authenticatorId  = ReadJSON.getString(jo, "authenticatorId", false, true);
919            this.credential       = ReadJSON.getObject(jo, "credential", WebAuthn.Credential.class, false, true);
920        }
921        
922        
923        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
924        public boolean equals(Object other)
925        {
926            if (this == other)                       return true;
927            if (other == null)                       return false;
928            if (other.getClass() != this.getClass()) return false;
929        
930            credentialAsserted o = (credentialAsserted) other;
931        
932            return
933                    Objects.equals(this.authenticatorId, o.authenticatorId)
934                &&  Objects.equals(this.credential, o.credential);
935        }
936        
937        /** Generates a Hash-Code for {@code 'this'} instance */
938        public int hashCode()
939        {
940            return
941                    Objects.hashCode(this.authenticatorId)
942                +   this.credential.hashCode();
943        }
944    }
945    
946    
947    // Counter for keeping the WebSocket Request ID's distinct.
948    private static int counter = 1;
949    
950    /**
951     * Enable the WebAuthn domain and start intercepting credential storage and
952     * retrieval with a virtual authenticator.
953     * 
954     * @param enableUI 
955     * Whether to enable the WebAuthn user interface. Enabling the UI is
956     * recommended for debugging and demo purposes, as it is closer to the real
957     * experience. Disabling the UI is recommended for automated testing.
958     * Supported at the embedder's discretion if UI is available.
959     * Defaults to false.
960     * <BR /><B CLASS=Opt>OPTIONAL</B>
961     * 
962     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
963     * {@link Ret0}&gt;</CODE>
964     *
965     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
966     * browser receives the invocation-request.
967     *
968     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
969     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
970     * {@code >} to ensure the Browser Function has run to completion.
971     */
972    public static Script<String, JsonObject, Ret0> enable(Boolean enableUI)
973    {
974        final int       webSocketID = 47000000 + counter++;
975        final boolean[] optionals   = { true, };
976        
977        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
978        String requestJSON = WriteJSON.get(
979            parameterTypes.get("enable"),
980            parameterNames.get("enable"),
981            optionals, webSocketID,
982            "WebAuthn.enable",
983            enableUI
984        );
985        
986        // This Remote Command does not have a Return-Value.
987        return new Script<>
988            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
989    }
990    
991    /**
992     * Disable the WebAuthn domain.
993     * 
994     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
995     * {@link Ret0}&gt;</CODE>
996     *
997     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
998     * browser receives the invocation-request.
999     *
1000     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
1001     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
1002     * {@code >} to ensure the Browser Function has run to completion.
1003     */
1004    public static Script<String, JsonObject, Ret0> disable()
1005    {
1006        final int          webSocketID = 47001000 + counter++;
1007        final boolean[]    optionals   = new boolean[0];
1008        
1009        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1010        String requestJSON = WriteJSON.get(
1011            parameterTypes.get("disable"),
1012            parameterNames.get("disable"),
1013            optionals, webSocketID,
1014            "WebAuthn.disable"
1015        );
1016        
1017        // This Remote Command does not have a Return-Value.
1018        return new Script<>
1019            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
1020    }
1021    
1022    /**
1023     * Creates and adds a virtual authenticator.
1024     * 
1025     * @param options -
1026     * 
1027     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
1028     * String&gt;</CODE>
1029     * 
1030     * <BR /><BR />This <B>script</B> may be <B STYLE='color: red'>executed</B>, using
1031     * {@link Script#exec()}, and afterwards, a {@link Promise}<CODE>&lt;JsonObject,
1032     * String&gt;</CODE> will be returned.
1033     *
1034     * <BR /><BR />Finally, the <B>{@code Promise}</B> may be <B STYLE='color: red'>awaited</B>,
1035     * using {@link Promise#await()}, <I>and the returned result of this Browser Function may
1036      * may be retrieved.</I>
1037     *
1038     * <BR /><BR />This Browser Function <B STYLE='color: red'>returns</B>
1039     * <BR /><BR /><UL CLASS=JDUL>
1040     * <LI><CODE>String (<B>authenticatorId</B></CODE>)
1041     *     <BR />-
1042     * </LI>
1043     * </UL> */
1044    public static Script<String, JsonObject, String> addVirtualAuthenticator
1045        (WebAuthn.VirtualAuthenticatorOptions options)
1046    {
1047        // Exception-Check(s) to ensure that if any parameters which are not declared as
1048        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
1049        
1050        if (options == null) THROWS.throwNPE("options");
1051        
1052        final int       webSocketID = 47002000 + counter++;
1053        final boolean[] optionals   = { false, };
1054        
1055        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1056        String requestJSON = WriteJSON.get(
1057            parameterTypes.get("addVirtualAuthenticator"),
1058            parameterNames.get("addVirtualAuthenticator"),
1059            optionals, webSocketID,
1060            "WebAuthn.addVirtualAuthenticator",
1061            options
1062        );
1063        
1064        // 'JSON Binding' ... Converts Browser Response-JSON to 'String'
1065        Function<JsonObject, String> responseProcessor = (JsonObject jo) ->
1066            ReadJSON.getString(jo, "authenticatorId", false, true);
1067        
1068        return new Script<>(webSocketID, requestJSON, responseProcessor);
1069    }
1070    
1071    /**
1072     * Resets parameters isBogusSignature, isBadUV, isBadUP to false if they are not present.
1073     * 
1074     * @param authenticatorId -
1075     * 
1076     * @param isBogusSignature 
1077     * If isBogusSignature is set, overrides the signature in the authenticator response to be zero.
1078     * Defaults to false.
1079     * <BR /><B CLASS=Opt>OPTIONAL</B>
1080     * 
1081     * @param isBadUV 
1082     * If isBadUV is set, overrides the UV bit in the flags in the authenticator response to
1083     * be zero. Defaults to false.
1084     * <BR /><B CLASS=Opt>OPTIONAL</B>
1085     * 
1086     * @param isBadUP 
1087     * If isBadUP is set, overrides the UP bit in the flags in the authenticator response to
1088     * be zero. Defaults to false.
1089     * <BR /><B CLASS=Opt>OPTIONAL</B>
1090     * 
1091     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
1092     * {@link Ret0}&gt;</CODE>
1093     *
1094     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
1095     * browser receives the invocation-request.
1096     *
1097     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
1098     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
1099     * {@code >} to ensure the Browser Function has run to completion.
1100     */
1101    public static Script<String, JsonObject, Ret0> setResponseOverrideBits
1102        (String authenticatorId, Boolean isBogusSignature, Boolean isBadUV, Boolean isBadUP)
1103    {
1104        // Exception-Check(s) to ensure that if any parameters which are not declared as
1105        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
1106        
1107        if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
1108        
1109        final int       webSocketID = 47003000 + counter++;
1110        final boolean[] optionals   = { false, true, true, true, };
1111        
1112        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1113        String requestJSON = WriteJSON.get(
1114            parameterTypes.get("setResponseOverrideBits"),
1115            parameterNames.get("setResponseOverrideBits"),
1116            optionals, webSocketID,
1117            "WebAuthn.setResponseOverrideBits",
1118            authenticatorId, isBogusSignature, isBadUV, isBadUP
1119        );
1120        
1121        // This Remote Command does not have a Return-Value.
1122        return new Script<>
1123            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
1124    }
1125    
1126    /**
1127     * Removes the given authenticator.
1128     * 
1129     * @param authenticatorId -
1130     * 
1131     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
1132     * {@link Ret0}&gt;</CODE>
1133     *
1134     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
1135     * browser receives the invocation-request.
1136     *
1137     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
1138     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
1139     * {@code >} to ensure the Browser Function has run to completion.
1140     */
1141    public static Script<String, JsonObject, Ret0> removeVirtualAuthenticator
1142        (String authenticatorId)
1143    {
1144        // Exception-Check(s) to ensure that if any parameters which are not declared as
1145        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
1146        
1147        if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
1148        
1149        final int       webSocketID = 47004000 + counter++;
1150        final boolean[] optionals   = { false, };
1151        
1152        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1153        String requestJSON = WriteJSON.get(
1154            parameterTypes.get("removeVirtualAuthenticator"),
1155            parameterNames.get("removeVirtualAuthenticator"),
1156            optionals, webSocketID,
1157            "WebAuthn.removeVirtualAuthenticator",
1158            authenticatorId
1159        );
1160        
1161        // This Remote Command does not have a Return-Value.
1162        return new Script<>
1163            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
1164    }
1165    
1166    /**
1167     * Adds the credential to the specified authenticator.
1168     * 
1169     * @param authenticatorId -
1170     * 
1171     * @param credential -
1172     * 
1173     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
1174     * {@link Ret0}&gt;</CODE>
1175     *
1176     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
1177     * browser receives the invocation-request.
1178     *
1179     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
1180     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
1181     * {@code >} to ensure the Browser Function has run to completion.
1182     */
1183    public static Script<String, JsonObject, Ret0> addCredential
1184        (String authenticatorId, WebAuthn.Credential credential)
1185    {
1186        // Exception-Check(s) to ensure that if any parameters which are not declared as
1187        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
1188        
1189        if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
1190        if (credential == null)      THROWS.throwNPE("credential");
1191        
1192        final int       webSocketID = 47005000 + counter++;
1193        final boolean[] optionals   = { false, false, };
1194        
1195        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1196        String requestJSON = WriteJSON.get(
1197            parameterTypes.get("addCredential"),
1198            parameterNames.get("addCredential"),
1199            optionals, webSocketID,
1200            "WebAuthn.addCredential",
1201            authenticatorId, credential
1202        );
1203        
1204        // This Remote Command does not have a Return-Value.
1205        return new Script<>
1206            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
1207    }
1208    
1209    /**
1210     * Returns a single credential stored in the given virtual authenticator that
1211     * matches the credential ID.
1212     * 
1213     * @param authenticatorId -
1214     * 
1215     * @param credentialId -
1216     * 
1217     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
1218     * {@link WebAuthn.Credential}&gt;</CODE>
1219     * 
1220     * <BR /><BR />This <B>script</B> may be <B STYLE='color: red'>executed</B>, using
1221     * {@link Script#exec()}, and afterwards, a {@link Promise}<CODE>&lt;JsonObject,
1222     * {@link WebAuthn.Credential}&gt;</CODE> will be returned.
1223     *
1224     * <BR /><BR />Finally, the <B>{@code Promise}</B> may be <B STYLE='color: red'>awaited</B>,
1225     * using {@link Promise#await()}, <I>and the returned result of this Browser Function may
1226      * may be retrieved.</I>
1227     *
1228     * <BR /><BR />This Browser Function <B STYLE='color: red'>returns</B>
1229     * <BR /><BR /><UL CLASS=JDUL>
1230     * <LI><CODE>{@link WebAuthn.Credential} (<B>credential</B></CODE>)
1231     *     <BR />-
1232     * </LI>
1233     * </UL> */
1234    public static Script<String, JsonObject, WebAuthn.Credential> getCredential
1235        (String authenticatorId, String credentialId)
1236    {
1237        // Exception-Check(s) to ensure that if any parameters which are not declared as
1238        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
1239        
1240        if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
1241        if (credentialId == null)    THROWS.throwNPE("credentialId");
1242        
1243        final int       webSocketID = 47006000 + counter++;
1244        final boolean[] optionals   = { false, false, };
1245        
1246        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1247        String requestJSON = WriteJSON.get(
1248            parameterTypes.get("getCredential"),
1249            parameterNames.get("getCredential"),
1250            optionals, webSocketID,
1251            "WebAuthn.getCredential",
1252            authenticatorId, credentialId
1253        );
1254        
1255        // 'JSON Binding' ... Converts Browser Response-JSON to 'WebAuthn.Credential'
1256        Function<JsonObject, WebAuthn.Credential> responseProcessor = (JsonObject jo) ->
1257            ReadJSON.getObject(jo, "credential", WebAuthn.Credential.class, false, true);
1258        
1259        return new Script<>(webSocketID, requestJSON, responseProcessor);
1260    }
1261    
1262    /**
1263     * Returns all the credentials stored in the given virtual authenticator.
1264     * 
1265     * @param authenticatorId -
1266     * 
1267     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
1268     * {@link WebAuthn.Credential}[]&gt;</CODE>
1269     * 
1270     * <BR /><BR />This <B>script</B> may be <B STYLE='color: red'>executed</B>, using
1271     * {@link Script#exec()}, and afterwards, a {@link Promise}<CODE>&lt;JsonObject,
1272     * {@link WebAuthn.Credential}[]&gt;</CODE> will be returned.
1273     *
1274     * <BR /><BR />Finally, the <B>{@code Promise}</B> may be <B STYLE='color: red'>awaited</B>,
1275     * using {@link Promise#await()}, <I>and the returned result of this Browser Function may
1276      * may be retrieved.</I>
1277     *
1278     * <BR /><BR />This Browser Function <B STYLE='color: red'>returns</B>
1279     * <BR /><BR /><UL CLASS=JDUL>
1280     * <LI><CODE>{@link WebAuthn.Credential}[] (<B>credentials</B></CODE>)
1281     *     <BR />-
1282     * </LI>
1283     * </UL> */
1284    public static Script<String, JsonObject, WebAuthn.Credential[]> getCredentials
1285        (String authenticatorId)
1286    {
1287        // Exception-Check(s) to ensure that if any parameters which are not declared as
1288        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
1289        
1290        if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
1291        
1292        final int       webSocketID = 47007000 + counter++;
1293        final boolean[] optionals   = { false, };
1294        
1295        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1296        String requestJSON = WriteJSON.get(
1297            parameterTypes.get("getCredentials"),
1298            parameterNames.get("getCredentials"),
1299            optionals, webSocketID,
1300            "WebAuthn.getCredentials",
1301            authenticatorId
1302        );
1303        
1304        // 'JSON Binding' ... Converts Browser Response-JSON to 'WebAuthn.Credential[]'
1305        Function<JsonObject, WebAuthn.Credential[]> responseProcessor = (JsonObject jo) ->
1306            (jo.getJsonArray("credentials") == null)
1307                ? null
1308                : RJArrIntoStream.objArr(jo.getJsonArray("credentials"), null, 0, WebAuthn.Credential.class).toArray(WebAuthn.Credential[]::new);
1309        
1310        return new Script<>(webSocketID, requestJSON, responseProcessor);
1311    }
1312    
1313    /**
1314     * Removes a credential from the authenticator.
1315     * 
1316     * @param authenticatorId -
1317     * 
1318     * @param credentialId -
1319     * 
1320     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
1321     * {@link Ret0}&gt;</CODE>
1322     *
1323     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
1324     * browser receives the invocation-request.
1325     *
1326     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
1327     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
1328     * {@code >} to ensure the Browser Function has run to completion.
1329     */
1330    public static Script<String, JsonObject, Ret0> removeCredential
1331        (String authenticatorId, String credentialId)
1332    {
1333        // Exception-Check(s) to ensure that if any parameters which are not declared as
1334        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
1335        
1336        if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
1337        if (credentialId == null)    THROWS.throwNPE("credentialId");
1338        
1339        final int       webSocketID = 47008000 + counter++;
1340        final boolean[] optionals   = { false, false, };
1341        
1342        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1343        String requestJSON = WriteJSON.get(
1344            parameterTypes.get("removeCredential"),
1345            parameterNames.get("removeCredential"),
1346            optionals, webSocketID,
1347            "WebAuthn.removeCredential",
1348            authenticatorId, credentialId
1349        );
1350        
1351        // This Remote Command does not have a Return-Value.
1352        return new Script<>
1353            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
1354    }
1355    
1356    /**
1357     * Clears all the credentials from the specified device.
1358     * 
1359     * @param authenticatorId -
1360     * 
1361     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
1362     * {@link Ret0}&gt;</CODE>
1363     *
1364     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
1365     * browser receives the invocation-request.
1366     *
1367     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
1368     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
1369     * {@code >} to ensure the Browser Function has run to completion.
1370     */
1371    public static Script<String, JsonObject, Ret0> clearCredentials(String authenticatorId)
1372    {
1373        // Exception-Check(s) to ensure that if any parameters which are not declared as
1374        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
1375        
1376        if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
1377        
1378        final int       webSocketID = 47009000 + counter++;
1379        final boolean[] optionals   = { false, };
1380        
1381        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1382        String requestJSON = WriteJSON.get(
1383            parameterTypes.get("clearCredentials"),
1384            parameterNames.get("clearCredentials"),
1385            optionals, webSocketID,
1386            "WebAuthn.clearCredentials",
1387            authenticatorId
1388        );
1389        
1390        // This Remote Command does not have a Return-Value.
1391        return new Script<>
1392            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
1393    }
1394    
1395    /**
1396     * Sets whether User Verification succeeds or fails for an authenticator.
1397     * The default is true.
1398     * 
1399     * @param authenticatorId -
1400     * 
1401     * @param isUserVerified -
1402     * 
1403     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
1404     * {@link Ret0}&gt;</CODE>
1405     *
1406     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
1407     * browser receives the invocation-request.
1408     *
1409     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
1410     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
1411     * {@code >} to ensure the Browser Function has run to completion.
1412     */
1413    public static Script<String, JsonObject, Ret0> setUserVerified
1414        (String authenticatorId, boolean isUserVerified)
1415    {
1416        // Exception-Check(s) to ensure that if any parameters which are not declared as
1417        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
1418        
1419        if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
1420        
1421        final int       webSocketID = 47010000 + counter++;
1422        final boolean[] optionals   = { false, false, };
1423        
1424        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1425        String requestJSON = WriteJSON.get(
1426            parameterTypes.get("setUserVerified"),
1427            parameterNames.get("setUserVerified"),
1428            optionals, webSocketID,
1429            "WebAuthn.setUserVerified",
1430            authenticatorId, isUserVerified
1431        );
1432        
1433        // This Remote Command does not have a Return-Value.
1434        return new Script<>
1435            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
1436    }
1437    
1438    /**
1439     * Sets whether tests of user presence will succeed immediately (if true) or fail to resolve (if false) for an authenticator.
1440     * The default is true.
1441     * 
1442     * @param authenticatorId -
1443     * 
1444     * @param enabled -
1445     * 
1446     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
1447     * {@link Ret0}&gt;</CODE>
1448     *
1449     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
1450     * browser receives the invocation-request.
1451     *
1452     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
1453     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
1454     * {@code >} to ensure the Browser Function has run to completion.
1455     */
1456    public static Script<String, JsonObject, Ret0> setAutomaticPresenceSimulation
1457        (String authenticatorId, boolean enabled)
1458    {
1459        // Exception-Check(s) to ensure that if any parameters which are not declared as
1460        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
1461        
1462        if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
1463        
1464        final int       webSocketID = 47011000 + counter++;
1465        final boolean[] optionals   = { false, false, };
1466        
1467        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1468        String requestJSON = WriteJSON.get(
1469            parameterTypes.get("setAutomaticPresenceSimulation"),
1470            parameterNames.get("setAutomaticPresenceSimulation"),
1471            optionals, webSocketID,
1472            "WebAuthn.setAutomaticPresenceSimulation",
1473            authenticatorId, enabled
1474        );
1475        
1476        // This Remote Command does not have a Return-Value.
1477        return new Script<>
1478            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
1479    }
1480    
1481    /**
1482     * Allows setting credential properties.
1483     * https://w3c.github.io/webauthn/#sctn-automation-set-credential-properties
1484     * 
1485     * @param authenticatorId -
1486     * 
1487     * @param credentialId -
1488     * 
1489     * @param backupEligibility -
1490     * <BR /><B CLASS=Opt>OPTIONAL</B>
1491     * 
1492     * @param backupState -
1493     * <BR /><B CLASS=Opt>OPTIONAL</B>
1494     * 
1495     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
1496     * {@link Ret0}&gt;</CODE>
1497     *
1498     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
1499     * browser receives the invocation-request.
1500     *
1501     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
1502     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
1503     * {@code >} to ensure the Browser Function has run to completion.
1504     */
1505    public static Script<String, JsonObject, Ret0> setCredentialProperties(
1506            String authenticatorId, String credentialId, Boolean backupEligibility, 
1507            Boolean backupState
1508        )
1509    {
1510        // Exception-Check(s) to ensure that if any parameters which are not declared as
1511        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
1512        
1513        if (authenticatorId == null) THROWS.throwNPE("authenticatorId");
1514        if (credentialId == null)    THROWS.throwNPE("credentialId");
1515        
1516        final int       webSocketID = 47012000 + counter++;
1517        final boolean[] optionals   = { false, false, true, true, };
1518        
1519        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
1520        String requestJSON = WriteJSON.get(
1521            parameterTypes.get("setCredentialProperties"),
1522            parameterNames.get("setCredentialProperties"),
1523            optionals, webSocketID,
1524            "WebAuthn.setCredentialProperties",
1525            authenticatorId, credentialId, backupEligibility, backupState
1526        );
1527        
1528        // This Remote Command does not have a Return-Value.
1529        return new Script<>
1530            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
1531    }
1532    
1533}