001package Torello.Browser;
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.Java.Additional.*;
013import Torello.Java.JSON.*;
014
015import static Torello.Java.JSON.JFlag.*;
016
017import Torello.Java.StrCmpr;
018import Torello.JavaDoc.StaticFunctional;
019import Torello.JavaDoc.JDHeaderBackgroundImg;
020import Torello.JavaDoc.Excuse;
021
022/**
023 * <SPAN CLASS=COPIEDJDK><B>This domain allows configuring virtual authenticators to test the WebAuthn
024 * API.</B></SPAN>
025 * 
026 * <EMBED CLASS='external-html' DATA-FILE-ID=CODE_GEN_NOTE>
027 */
028@StaticFunctional(Excused={"counter"}, Excuses={Excuse.CONFIGURATION})
029@JDHeaderBackgroundImg(EmbedTagFileID="WOOD_PLANK_NOTE")
030public class WebAuthn
031{
032    // ********************************************************************************************
033    // ********************************************************************************************
034    // Class Header Stuff
035    // ********************************************************************************************
036    // ********************************************************************************************
037
038
039    // No Pubic Constructors
040    private WebAuthn () { }
041
042    // These two Vector's are used by all the "Methods" exported by this class.  java.lang.reflect
043    // is used to generate the JSON String's.  It saves thousands of lines of Auto-Generated Code.
044    private static final Map<String, Vector<String>>    parameterNames = new HashMap<>();
045    private static final Map<String, Vector<Class<?>>>  parameterTypes = new HashMap<>();
046
047    // Some Methods do not take any parameters - for instance all the "enable()" and "disable()"
048    // I simply could not get ride of RAW-TYPES and UNCHECKED warnings... so there are now,
049    // offically, two empty-vectors.  One for String's, and the other for Classes.
050
051    private static final Vector<String>     EMPTY_VEC_STR = new Vector<>();
052    private static final Vector<Class<?>>   EMPTY_VEC_CLASS = new Vector<>();
053
054    static
055    {
056        for (Method m : WebAuthn.class.getMethods())
057        {
058            // This doesn't work!  The parameter names are all "arg0" ... "argN"
059            // It works for java.lang.reflect.Field, BUT NOT java.lang.reflect.Parameter!
060            //
061            // Vector<String> parameterNamesList = new Vector<>(); -- NOPE!
062
063            Vector<Class<?>> parameterTypesList = new Vector<>();
064        
065            for (Parameter p : m.getParameters()) parameterTypesList.add(p.getType());
066
067            parameterTypes.put(
068                m.getName(),
069                (parameterTypesList.size() > 0) ? parameterTypesList : EMPTY_VEC_CLASS
070            );
071        }
072    }
073
074    static
075    {
076        Vector<String> v = null;
077
078        parameterNames.put("enable", EMPTY_VEC_STR);
079
080        parameterNames.put("disable", EMPTY_VEC_STR);
081
082        v = new Vector<String>(1);
083        parameterNames.put("addVirtualAuthenticator", v);
084        Collections.addAll(v, new String[]
085        { "options", });
086
087        v = new Vector<String>(1);
088        parameterNames.put("removeVirtualAuthenticator", v);
089        Collections.addAll(v, new String[]
090        { "authenticatorId", });
091
092        v = new Vector<String>(2);
093        parameterNames.put("addCredential", v);
094        Collections.addAll(v, new String[]
095        { "authenticatorId", "credential", });
096
097        v = new Vector<String>(2);
098        parameterNames.put("getCredential", v);
099        Collections.addAll(v, new String[]
100        { "authenticatorId", "credentialId", });
101
102        v = new Vector<String>(1);
103        parameterNames.put("getCredentials", v);
104        Collections.addAll(v, new String[]
105        { "authenticatorId", });
106
107        v = new Vector<String>(2);
108        parameterNames.put("removeCredential", v);
109        Collections.addAll(v, new String[]
110        { "authenticatorId", "credentialId", });
111
112        v = new Vector<String>(1);
113        parameterNames.put("clearCredentials", v);
114        Collections.addAll(v, new String[]
115        { "authenticatorId", });
116
117        v = new Vector<String>(2);
118        parameterNames.put("setUserVerified", v);
119        Collections.addAll(v, new String[]
120        { "authenticatorId", "isUserVerified", });
121
122        v = new Vector<String>(2);
123        parameterNames.put("setAutomaticPresenceSimulation", v);
124        Collections.addAll(v, new String[]
125        { "authenticatorId", "enabled", });
126    }
127
128
129    // ********************************************************************************************
130    // ********************************************************************************************
131    // Types - Static Inner Classes
132    // ********************************************************************************************
133    // ********************************************************************************************
134
135    // public static class AuthenticatorId => String
136    
137    /** <CODE>[No Description Provided by Google]</CODE> */
138    public static final String[] AuthenticatorProtocol =
139    { "u2f", "ctap2", };
140    
141    /** <CODE>[No Description Provided by Google]</CODE> */
142    public static final String[] Ctap2Version =
143    { "ctap2_0", "ctap2_1", };
144    
145    /** <CODE>[No Description Provided by Google]</CODE> */
146    public static final String[] AuthenticatorTransport =
147    { "usb", "nfc", "ble", "cable", "internal", };
148    
149    /** <CODE>[No Description Provided by Google]</CODE> */
150    public static class VirtualAuthenticatorOptions
151        extends BaseType
152        implements java.io.Serializable
153    {
154        /** For Object Serialization.  java.io.Serializable */
155        protected static final long serialVersionUID = 1;
156        
157        public boolean[] optionals()
158        { return new boolean[] { false, true, false, true, true, true, true, true, true, }; }
159        
160        /** <CODE>[No Description Provided by Google]</CODE> */
161        public final String protocol;
162        
163        /**
164         * Defaults to ctap2_0. Ignored if |protocol| == u2f.
165         * <BR />
166         * <BR /><B>OPTIONAL</B>
167         */
168        public final String ctap2Version;
169        
170        /** <CODE>[No Description Provided by Google]</CODE> */
171        public final String transport;
172        
173        /**
174         * Defaults to false.
175         * <BR />
176         * <BR /><B>OPTIONAL</B>
177         */
178        public final Boolean hasResidentKey;
179        
180        /**
181         * Defaults to false.
182         * <BR />
183         * <BR /><B>OPTIONAL</B>
184         */
185        public final Boolean hasUserVerification;
186        
187        /**
188         * If set to true, the authenticator will support the largeBlob extension.
189         * https://w3c.github.io/webauthn#largeBlob
190         * Defaults to false.
191         * <BR />
192         * <BR /><B>OPTIONAL</B>
193         */
194        public final Boolean hasLargeBlob;
195        
196        /**
197         * If set to true, the authenticator will support the credBlob extension.
198         * https://fidoalliance.org/specs/fido-v2.1-rd-20201208/fido-client-to-authenticator-protocol-v2.1-rd-20201208.html#sctn-credBlob-extension
199         * Defaults to false.
200         * <BR />
201         * <BR /><B>OPTIONAL</B>
202         */
203        public final Boolean hasCredBlob;
204        
205        /**
206         * If set to true, tests of user presence will succeed immediately.
207         * Otherwise, they will not be resolved. Defaults to true.
208         * <BR />
209         * <BR /><B>OPTIONAL</B>
210         */
211        public final Boolean automaticPresenceSimulation;
212        
213        /**
214         * Sets whether User Verification succeeds or fails for an authenticator.
215         * Defaults to false.
216         * <BR />
217         * <BR /><B>OPTIONAL</B>
218         */
219        public final Boolean isUserVerified;
220        
221        /**
222         * Constructor
223         *
224         * @param protocol -
225         * 
226         * @param ctap2Version Defaults to ctap2_0. Ignored if |protocol| == u2f.
227         * <BR /><B>OPTIONAL</B>
228         * 
229         * @param transport -
230         * 
231         * @param hasResidentKey Defaults to false.
232         * <BR /><B>OPTIONAL</B>
233         * 
234         * @param hasUserVerification Defaults to false.
235         * <BR /><B>OPTIONAL</B>
236         * 
237         * @param hasLargeBlob 
238         * If set to true, the authenticator will support the largeBlob extension.
239         * https://w3c.github.io/webauthn#largeBlob
240         * Defaults to false.
241         * <BR /><B>OPTIONAL</B>
242         * 
243         * @param hasCredBlob 
244         * If set to true, the authenticator will support the credBlob extension.
245         * https://fidoalliance.org/specs/fido-v2.1-rd-20201208/fido-client-to-authenticator-protocol-v2.1-rd-20201208.html#sctn-credBlob-extension
246         * Defaults to false.
247         * <BR /><B>OPTIONAL</B>
248         * 
249         * @param automaticPresenceSimulation 
250         * If set to true, tests of user presence will succeed immediately.
251         * Otherwise, they will not be resolved. Defaults to true.
252         * <BR /><B>OPTIONAL</B>
253         * 
254         * @param isUserVerified 
255         * Sets whether User Verification succeeds or fails for an authenticator.
256         * Defaults to false.
257         * <BR /><B>OPTIONAL</B>
258         */
259        public VirtualAuthenticatorOptions(
260                String protocol, String ctap2Version, String transport, Boolean hasResidentKey, 
261                Boolean hasUserVerification, Boolean hasLargeBlob, Boolean hasCredBlob, 
262                Boolean automaticPresenceSimulation, Boolean isUserVerified
263            )
264        {
265            // Exception-Check(s) to ensure that if any parameters which are not declared as
266            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
267            
268            if (protocol == null)  BRDPC.throwNPE("protocol");
269            if (transport == null) BRDPC.throwNPE("transport");
270            
271            // Exception-Check(s) to ensure that if any parameters which must adhere to a
272            // provided List of Enumerated Values, fails, then IllegalArgumentException shall throw.
273            
274            BRDPC.checkIAE("protocol", protocol, "WebAuthn.AuthenticatorProtocol", WebAuthn.AuthenticatorProtocol);
275            BRDPC.checkIAE("ctap2Version", ctap2Version, "WebAuthn.Ctap2Version", WebAuthn.Ctap2Version);
276            BRDPC.checkIAE("transport", transport, "WebAuthn.AuthenticatorTransport", WebAuthn.AuthenticatorTransport);
277            
278            this.protocol                     = protocol;
279            this.ctap2Version                 = ctap2Version;
280            this.transport                    = transport;
281            this.hasResidentKey               = hasResidentKey;
282            this.hasUserVerification          = hasUserVerification;
283            this.hasLargeBlob                 = hasLargeBlob;
284            this.hasCredBlob                  = hasCredBlob;
285            this.automaticPresenceSimulation  = automaticPresenceSimulation;
286            this.isUserVerified               = isUserVerified;
287        }
288        
289        /**
290         * JSON Object Constructor
291         * @param jo A Json-Object having data about an instance of {@code 'VirtualAuthenticatorOptions'}.
292         */
293        public VirtualAuthenticatorOptions (JsonObject jo)
294        {
295            this.protocol                     = ReadJSON.getString(jo, "protocol", false, true);
296            this.ctap2Version                 = ReadJSON.getString(jo, "ctap2Version", true, false);
297            this.transport                    = ReadJSON.getString(jo, "transport", false, true);
298            this.hasResidentKey               = ReadBoxedJSON.getBoolean(jo, "hasResidentKey", true);
299            this.hasUserVerification          = ReadBoxedJSON.getBoolean(jo, "hasUserVerification", true);
300            this.hasLargeBlob                 = ReadBoxedJSON.getBoolean(jo, "hasLargeBlob", true);
301            this.hasCredBlob                  = ReadBoxedJSON.getBoolean(jo, "hasCredBlob", true);
302            this.automaticPresenceSimulation  = ReadBoxedJSON.getBoolean(jo, "automaticPresenceSimulation", true);
303            this.isUserVerified               = ReadBoxedJSON.getBoolean(jo, "isUserVerified", true);
304        }
305        
306        
307        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
308        public boolean equals(Object other)
309        {
310            if (other == null)                       return false;
311            if (other.getClass() != this.getClass()) return false;
312        
313            VirtualAuthenticatorOptions o = (VirtualAuthenticatorOptions) other;
314        
315            return
316                    Objects.equals(this.protocol, o.protocol)
317                &&  Objects.equals(this.ctap2Version, o.ctap2Version)
318                &&  Objects.equals(this.transport, o.transport)
319                &&  Objects.equals(this.hasResidentKey, o.hasResidentKey)
320                &&  Objects.equals(this.hasUserVerification, o.hasUserVerification)
321                &&  Objects.equals(this.hasLargeBlob, o.hasLargeBlob)
322                &&  Objects.equals(this.hasCredBlob, o.hasCredBlob)
323                &&  Objects.equals(this.automaticPresenceSimulation, o.automaticPresenceSimulation)
324                &&  Objects.equals(this.isUserVerified, o.isUserVerified);
325        }
326        
327        /** Generates a Hash-Code for {@code 'this'} instance */
328        public int hashCode()
329        {
330            return
331                    Objects.hashCode(this.protocol)
332                +   Objects.hashCode(this.ctap2Version)
333                +   Objects.hashCode(this.transport)
334                +   Objects.hashCode(this.hasResidentKey)
335                +   Objects.hashCode(this.hasUserVerification)
336                +   Objects.hashCode(this.hasLargeBlob)
337                +   Objects.hashCode(this.hasCredBlob)
338                +   Objects.hashCode(this.automaticPresenceSimulation)
339                +   Objects.hashCode(this.isUserVerified);
340        }
341    }
342    
343    /** <CODE>[No Description Provided by Google]</CODE> */
344    public static class Credential
345        extends BaseType
346        implements java.io.Serializable
347    {
348        /** For Object Serialization.  java.io.Serializable */
349        protected static final long serialVersionUID = 1;
350        
351        public boolean[] optionals()
352        { return new boolean[] { false, false, true, false, true, false, true, }; }
353        
354        /** <CODE>[No Description Provided by Google]</CODE> */
355        public final String credentialId;
356        
357        /** <CODE>[No Description Provided by Google]</CODE> */
358        public final boolean isResidentCredential;
359        
360        /**
361         * Relying Party ID the credential is scoped to. Must be set when adding a
362         * credential.
363         * <BR />
364         * <BR /><B>OPTIONAL</B>
365         */
366        public final String rpId;
367        
368        /** The ECDSA P-256 private key in PKCS#8 format. (Encoded as a base64 string when passed over JSON) */
369        public final String privateKey;
370        
371        /**
372         * An opaque byte sequence with a maximum size of 64 bytes mapping the
373         * credential to a specific user. (Encoded as a base64 string when passed over JSON)
374         * <BR />
375         * <BR /><B>OPTIONAL</B>
376         */
377        public final String userHandle;
378        
379        /**
380         * Signature counter. This is incremented by one for each successful
381         * assertion.
382         * See https://w3c.github.io/webauthn/#signature-counter
383         */
384        public final int signCount;
385        
386        /**
387         * The large blob associated with the credential.
388         * See https://w3c.github.io/webauthn/#sctn-large-blob-extension (Encoded as a base64 string when passed over JSON)
389         * <BR />
390         * <BR /><B>OPTIONAL</B>
391         */
392        public final String largeBlob;
393        
394        /**
395         * Constructor
396         *
397         * @param credentialId -
398         * 
399         * @param isResidentCredential -
400         * 
401         * @param rpId 
402         * Relying Party ID the credential is scoped to. Must be set when adding a
403         * credential.
404         * <BR /><B>OPTIONAL</B>
405         * 
406         * @param privateKey The ECDSA P-256 private key in PKCS#8 format. (Encoded as a base64 string when passed over JSON)
407         * 
408         * @param userHandle 
409         * An opaque byte sequence with a maximum size of 64 bytes mapping the
410         * credential to a specific user. (Encoded as a base64 string when passed over JSON)
411         * <BR /><B>OPTIONAL</B>
412         * 
413         * @param signCount 
414         * Signature counter. This is incremented by one for each successful
415         * assertion.
416         * See https://w3c.github.io/webauthn/#signature-counter
417         * 
418         * @param largeBlob 
419         * The large blob associated with the credential.
420         * See https://w3c.github.io/webauthn/#sctn-large-blob-extension (Encoded as a base64 string when passed over JSON)
421         * <BR /><B>OPTIONAL</B>
422         */
423        public Credential(
424                String credentialId, boolean isResidentCredential, String rpId, String privateKey, 
425                String userHandle, int signCount, String largeBlob
426            )
427        {
428            // Exception-Check(s) to ensure that if any parameters which are not declared as
429            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
430            
431            if (credentialId == null) BRDPC.throwNPE("credentialId");
432            if (privateKey == null)   BRDPC.throwNPE("privateKey");
433            
434            this.credentialId          = credentialId;
435            this.isResidentCredential  = isResidentCredential;
436            this.rpId                  = rpId;
437            this.privateKey            = privateKey;
438            this.userHandle            = userHandle;
439            this.signCount             = signCount;
440            this.largeBlob             = largeBlob;
441        }
442        
443        /**
444         * JSON Object Constructor
445         * @param jo A Json-Object having data about an instance of {@code 'Credential'}.
446         */
447        public Credential (JsonObject jo)
448        {
449            this.credentialId          = ReadJSON.getString(jo, "credentialId", false, true);
450            this.isResidentCredential  = ReadPrimJSON.getBoolean(jo, "isResidentCredential");
451            this.rpId                  = ReadJSON.getString(jo, "rpId", true, false);
452            this.privateKey            = ReadJSON.getString(jo, "privateKey", false, true);
453            this.userHandle            = ReadJSON.getString(jo, "userHandle", true, false);
454            this.signCount             = ReadPrimJSON.getInt(jo, "signCount");
455            this.largeBlob             = ReadJSON.getString(jo, "largeBlob", true, false);
456        }
457        
458        
459        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
460        public boolean equals(Object other)
461        {
462            if (other == null)                       return false;
463            if (other.getClass() != this.getClass()) return false;
464        
465            Credential o = (Credential) other;
466        
467            return
468                    Objects.equals(this.credentialId, o.credentialId)
469                &&  (this.isResidentCredential == o.isResidentCredential)
470                &&  Objects.equals(this.rpId, o.rpId)
471                &&  Objects.equals(this.privateKey, o.privateKey)
472                &&  Objects.equals(this.userHandle, o.userHandle)
473                &&  (this.signCount == o.signCount)
474                &&  Objects.equals(this.largeBlob, o.largeBlob);
475        }
476        
477        /** Generates a Hash-Code for {@code 'this'} instance */
478        public int hashCode()
479        {
480            return
481                    Objects.hashCode(this.credentialId)
482                +   (this.isResidentCredential ? 1 : 0)
483                +   Objects.hashCode(this.rpId)
484                +   Objects.hashCode(this.privateKey)
485                +   Objects.hashCode(this.userHandle)
486                +   this.signCount
487                +   Objects.hashCode(this.largeBlob);
488        }
489    }
490    
491    
492    // Counter for keeping the WebSocket Request ID's distinct.
493    private static int counter = 1;
494    
495    /**
496     * Enable the WebAuthn domain and start intercepting credential storage and
497     * retrieval with a virtual authenticator.
498     * 
499     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
500     * {@link Ret0}&gt;</CODE>
501     *
502     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
503     * browser receives the invocation-request.
504     *
505     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
506     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
507     * {@code >} to ensure the Browser Function has run to completion.
508     */
509    public static Script<String, JsonObject, Ret0> enable()
510    {
511        final int          webSocketID = 44000000 + counter++;
512        final boolean[]    optionals   = new boolean[0];
513        
514        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
515        String requestJSON = WriteJSON.get(
516            parameterTypes.get("enable"),
517            parameterNames.get("enable"),
518            optionals, webSocketID,
519            "WebAuthn.enable"
520        );
521        
522        // This Remote Command does not have a Return-Value.
523        return new Script<>
524            (BRDPC.defaultSender, webSocketID, requestJSON, BRDPC.NoReturnValues);
525    }
526    
527    /**
528     * Disable the WebAuthn domain.
529     * 
530     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
531     * {@link Ret0}&gt;</CODE>
532     *
533     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
534     * browser receives the invocation-request.
535     *
536     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
537     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
538     * {@code >} to ensure the Browser Function has run to completion.
539     */
540    public static Script<String, JsonObject, Ret0> disable()
541    {
542        final int          webSocketID = 44001000 + counter++;
543        final boolean[]    optionals   = new boolean[0];
544        
545        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
546        String requestJSON = WriteJSON.get(
547            parameterTypes.get("disable"),
548            parameterNames.get("disable"),
549            optionals, webSocketID,
550            "WebAuthn.disable"
551        );
552        
553        // This Remote Command does not have a Return-Value.
554        return new Script<>
555            (BRDPC.defaultSender, webSocketID, requestJSON, BRDPC.NoReturnValues);
556    }
557    
558    /**
559     * Creates and adds a virtual authenticator.
560     * 
561     * @param options -
562     * 
563     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
564     * String&gt;</CODE>
565     * 
566     * <BR /><BR />This <B>script</B> may be <B STYLE='color: red'>executed</B>, using
567     * {@link Script#exec()}, and afterwards, a {@link Promise}<CODE>&lt;JsonObject,
568     * String&gt;</CODE> will be returned.
569     *
570     * <BR /><BR />Finally, the <B>{@code Promise}</B> may be <B STYLE='color: red'>awaited</B>,
571     * using {@link Promise#await()}, <I>and the returned result of this Browser Function may
572      * may be retrieved.</I>
573     *
574     * <BR /><BR />This Browser Function <B STYLE='color: red'>returns</B>
575     * <BR /><BR /><UL CLASS=JDUL>
576     * <LI><CODE>String (<B>authenticatorId</B></CODE>)
577     *     <BR />-
578     * </LI>
579     * </UL> */
580    public static Script<String, JsonObject, String> addVirtualAuthenticator
581        (WebAuthn.VirtualAuthenticatorOptions options)
582    {
583        // Exception-Check(s) to ensure that if any parameters which are not declared as
584        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
585        
586        if (options == null) BRDPC.throwNPE("options");
587        
588        final int       webSocketID = 44002000 + counter++;
589        final boolean[] optionals   = { false, };
590        
591        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
592        String requestJSON = WriteJSON.get(
593            parameterTypes.get("addVirtualAuthenticator"),
594            parameterNames.get("addVirtualAuthenticator"),
595            optionals, webSocketID,
596            "WebAuthn.addVirtualAuthenticator",
597            options
598        );
599        
600        // 'JSON Binding' ... Converts Browser Response-JSON to 'String'
601        Function<JsonObject, String> responseProcessor = (JsonObject jo) ->
602            ReadJSON.getString(jo, "authenticatorId", false, true);
603        
604        // Pass the 'defaultSender' to Script-Constructor
605        // The sender that is used can be changed before executing script.
606        return new Script<>(BRDPC.defaultSender, webSocketID, requestJSON, responseProcessor);
607    }
608    
609    /**
610     * Removes the given authenticator.
611     * 
612     * @param authenticatorId -
613     * 
614     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
615     * {@link Ret0}&gt;</CODE>
616     *
617     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
618     * browser receives the invocation-request.
619     *
620     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
621     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
622     * {@code >} to ensure the Browser Function has run to completion.
623     */
624    public static Script<String, JsonObject, Ret0> removeVirtualAuthenticator
625        (String authenticatorId)
626    {
627        // Exception-Check(s) to ensure that if any parameters which are not declared as
628        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
629        
630        if (authenticatorId == null) BRDPC.throwNPE("authenticatorId");
631        
632        final int       webSocketID = 44003000 + counter++;
633        final boolean[] optionals   = { false, };
634        
635        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
636        String requestJSON = WriteJSON.get(
637            parameterTypes.get("removeVirtualAuthenticator"),
638            parameterNames.get("removeVirtualAuthenticator"),
639            optionals, webSocketID,
640            "WebAuthn.removeVirtualAuthenticator",
641            authenticatorId
642        );
643        
644        // This Remote Command does not have a Return-Value.
645        return new Script<>
646            (BRDPC.defaultSender, webSocketID, requestJSON, BRDPC.NoReturnValues);
647    }
648    
649    /**
650     * Adds the credential to the specified authenticator.
651     * 
652     * @param authenticatorId -
653     * 
654     * @param credential -
655     * 
656     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
657     * {@link Ret0}&gt;</CODE>
658     *
659     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
660     * browser receives the invocation-request.
661     *
662     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
663     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
664     * {@code >} to ensure the Browser Function has run to completion.
665     */
666    public static Script<String, JsonObject, Ret0> addCredential
667        (String authenticatorId, WebAuthn.Credential credential)
668    {
669        // Exception-Check(s) to ensure that if any parameters which are not declared as
670        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
671        
672        if (authenticatorId == null) BRDPC.throwNPE("authenticatorId");
673        if (credential == null)      BRDPC.throwNPE("credential");
674        
675        final int       webSocketID = 44004000 + counter++;
676        final boolean[] optionals   = { false, false, };
677        
678        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
679        String requestJSON = WriteJSON.get(
680            parameterTypes.get("addCredential"),
681            parameterNames.get("addCredential"),
682            optionals, webSocketID,
683            "WebAuthn.addCredential",
684            authenticatorId, credential
685        );
686        
687        // This Remote Command does not have a Return-Value.
688        return new Script<>
689            (BRDPC.defaultSender, webSocketID, requestJSON, BRDPC.NoReturnValues);
690    }
691    
692    /**
693     * Returns a single credential stored in the given virtual authenticator that
694     * matches the credential ID.
695     * 
696     * @param authenticatorId -
697     * 
698     * @param credentialId -
699     * 
700     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
701     * {@link WebAuthn.Credential}&gt;</CODE>
702     * 
703     * <BR /><BR />This <B>script</B> may be <B STYLE='color: red'>executed</B>, using
704     * {@link Script#exec()}, and afterwards, a {@link Promise}<CODE>&lt;JsonObject,
705     * {@link WebAuthn.Credential}&gt;</CODE> will be returned.
706     *
707     * <BR /><BR />Finally, the <B>{@code Promise}</B> may be <B STYLE='color: red'>awaited</B>,
708     * using {@link Promise#await()}, <I>and the returned result of this Browser Function may
709      * may be retrieved.</I>
710     *
711     * <BR /><BR />This Browser Function <B STYLE='color: red'>returns</B>
712     * <BR /><BR /><UL CLASS=JDUL>
713     * <LI><CODE>{@link WebAuthn.Credential} (<B>credential</B></CODE>)
714     *     <BR />-
715     * </LI>
716     * </UL> */
717    public static Script<String, JsonObject, WebAuthn.Credential> getCredential
718        (String authenticatorId, String credentialId)
719    {
720        // Exception-Check(s) to ensure that if any parameters which are not declared as
721        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
722        
723        if (authenticatorId == null) BRDPC.throwNPE("authenticatorId");
724        if (credentialId == null)    BRDPC.throwNPE("credentialId");
725        
726        final int       webSocketID = 44005000 + counter++;
727        final boolean[] optionals   = { false, false, };
728        
729        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
730        String requestJSON = WriteJSON.get(
731            parameterTypes.get("getCredential"),
732            parameterNames.get("getCredential"),
733            optionals, webSocketID,
734            "WebAuthn.getCredential",
735            authenticatorId, credentialId
736        );
737        
738        // 'JSON Binding' ... Converts Browser Response-JSON to 'WebAuthn.Credential'
739        Function<JsonObject, WebAuthn.Credential> responseProcessor = (JsonObject jo) ->
740            ReadJSON.getObject(jo, "credential", WebAuthn.Credential.class, false, true);
741        
742        // Pass the 'defaultSender' to Script-Constructor
743        // The sender that is used can be changed before executing script.
744        return new Script<>(BRDPC.defaultSender, webSocketID, requestJSON, responseProcessor);
745    }
746    
747    /**
748     * Returns all the credentials stored in the given virtual authenticator.
749     * 
750     * @param authenticatorId -
751     * 
752     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
753     * {@link WebAuthn.Credential}[]&gt;</CODE>
754     * 
755     * <BR /><BR />This <B>script</B> may be <B STYLE='color: red'>executed</B>, using
756     * {@link Script#exec()}, and afterwards, a {@link Promise}<CODE>&lt;JsonObject,
757     * {@link WebAuthn.Credential}[]&gt;</CODE> will be returned.
758     *
759     * <BR /><BR />Finally, the <B>{@code Promise}</B> may be <B STYLE='color: red'>awaited</B>,
760     * using {@link Promise#await()}, <I>and the returned result of this Browser Function may
761      * may be retrieved.</I>
762     *
763     * <BR /><BR />This Browser Function <B STYLE='color: red'>returns</B>
764     * <BR /><BR /><UL CLASS=JDUL>
765     * <LI><CODE>{@link WebAuthn.Credential}[] (<B>credentials</B></CODE>)
766     *     <BR />-
767     * </LI>
768     * </UL> */
769    public static Script<String, JsonObject, WebAuthn.Credential[]> getCredentials
770        (String authenticatorId)
771    {
772        // Exception-Check(s) to ensure that if any parameters which are not declared as
773        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
774        
775        if (authenticatorId == null) BRDPC.throwNPE("authenticatorId");
776        
777        final int       webSocketID = 44006000 + counter++;
778        final boolean[] optionals   = { false, };
779        
780        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
781        String requestJSON = WriteJSON.get(
782            parameterTypes.get("getCredentials"),
783            parameterNames.get("getCredentials"),
784            optionals, webSocketID,
785            "WebAuthn.getCredentials",
786            authenticatorId
787        );
788        
789        // 'JSON Binding' ... Converts Browser Response-JSON to 'WebAuthn.Credential[]'
790        Function<JsonObject, WebAuthn.Credential[]> responseProcessor = (JsonObject jo) ->
791            (jo.getJsonArray("credentials") == null)
792                ? null
793                : ReadArrJSON.DimN.objArr(jo.getJsonArray("credentials"), null, 0, WebAuthn.Credential[].class);
794        
795        // Pass the 'defaultSender' to Script-Constructor
796        // The sender that is used can be changed before executing script.
797        return new Script<>(BRDPC.defaultSender, webSocketID, requestJSON, responseProcessor);
798    }
799    
800    /**
801     * Removes a credential from the authenticator.
802     * 
803     * @param authenticatorId -
804     * 
805     * @param credentialId -
806     * 
807     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
808     * {@link Ret0}&gt;</CODE>
809     *
810     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
811     * browser receives the invocation-request.
812     *
813     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
814     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
815     * {@code >} to ensure the Browser Function has run to completion.
816     */
817    public static Script<String, JsonObject, Ret0> removeCredential
818        (String authenticatorId, String credentialId)
819    {
820        // Exception-Check(s) to ensure that if any parameters which are not declared as
821        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
822        
823        if (authenticatorId == null) BRDPC.throwNPE("authenticatorId");
824        if (credentialId == null)    BRDPC.throwNPE("credentialId");
825        
826        final int       webSocketID = 44007000 + counter++;
827        final boolean[] optionals   = { false, false, };
828        
829        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
830        String requestJSON = WriteJSON.get(
831            parameterTypes.get("removeCredential"),
832            parameterNames.get("removeCredential"),
833            optionals, webSocketID,
834            "WebAuthn.removeCredential",
835            authenticatorId, credentialId
836        );
837        
838        // This Remote Command does not have a Return-Value.
839        return new Script<>
840            (BRDPC.defaultSender, webSocketID, requestJSON, BRDPC.NoReturnValues);
841    }
842    
843    /**
844     * Clears all the credentials from the specified device.
845     * 
846     * @param authenticatorId -
847     * 
848     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
849     * {@link Ret0}&gt;</CODE>
850     *
851     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
852     * browser receives the invocation-request.
853     *
854     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
855     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
856     * {@code >} to ensure the Browser Function has run to completion.
857     */
858    public static Script<String, JsonObject, Ret0> clearCredentials(String authenticatorId)
859    {
860        // Exception-Check(s) to ensure that if any parameters which are not declared as
861        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
862        
863        if (authenticatorId == null) BRDPC.throwNPE("authenticatorId");
864        
865        final int       webSocketID = 44008000 + counter++;
866        final boolean[] optionals   = { false, };
867        
868        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
869        String requestJSON = WriteJSON.get(
870            parameterTypes.get("clearCredentials"),
871            parameterNames.get("clearCredentials"),
872            optionals, webSocketID,
873            "WebAuthn.clearCredentials",
874            authenticatorId
875        );
876        
877        // This Remote Command does not have a Return-Value.
878        return new Script<>
879            (BRDPC.defaultSender, webSocketID, requestJSON, BRDPC.NoReturnValues);
880    }
881    
882    /**
883     * Sets whether User Verification succeeds or fails for an authenticator.
884     * The default is true.
885     * 
886     * @param authenticatorId -
887     * 
888     * @param isUserVerified -
889     * 
890     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
891     * {@link Ret0}&gt;</CODE>
892     *
893     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
894     * browser receives the invocation-request.
895     *
896     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
897     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
898     * {@code >} to ensure the Browser Function has run to completion.
899     */
900    public static Script<String, JsonObject, Ret0> setUserVerified
901        (String authenticatorId, boolean isUserVerified)
902    {
903        // Exception-Check(s) to ensure that if any parameters which are not declared as
904        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
905        
906        if (authenticatorId == null) BRDPC.throwNPE("authenticatorId");
907        
908        final int       webSocketID = 44009000 + counter++;
909        final boolean[] optionals   = { false, false, };
910        
911        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
912        String requestJSON = WriteJSON.get(
913            parameterTypes.get("setUserVerified"),
914            parameterNames.get("setUserVerified"),
915            optionals, webSocketID,
916            "WebAuthn.setUserVerified",
917            authenticatorId, isUserVerified
918        );
919        
920        // This Remote Command does not have a Return-Value.
921        return new Script<>
922            (BRDPC.defaultSender, webSocketID, requestJSON, BRDPC.NoReturnValues);
923    }
924    
925    /**
926     * Sets whether tests of user presence will succeed immediately (if true) or fail to resolve (if false) for an authenticator.
927     * The default is true.
928     * 
929     * @param authenticatorId -
930     * 
931     * @param enabled -
932     * 
933     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
934     * {@link Ret0}&gt;</CODE>
935     *
936     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
937     * browser receives the invocation-request.
938     *
939     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
940     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
941     * {@code >} to ensure the Browser Function has run to completion.
942     */
943    public static Script<String, JsonObject, Ret0> setAutomaticPresenceSimulation
944        (String authenticatorId, boolean enabled)
945    {
946        // Exception-Check(s) to ensure that if any parameters which are not declared as
947        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
948        
949        if (authenticatorId == null) BRDPC.throwNPE("authenticatorId");
950        
951        final int       webSocketID = 44010000 + counter++;
952        final boolean[] optionals   = { false, false, };
953        
954        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
955        String requestJSON = WriteJSON.get(
956            parameterTypes.get("setAutomaticPresenceSimulation"),
957            parameterNames.get("setAutomaticPresenceSimulation"),
958            optionals, webSocketID,
959            "WebAuthn.setAutomaticPresenceSimulation",
960            authenticatorId, enabled
961        );
962        
963        // This Remote Command does not have a Return-Value.
964        return new Script<>
965            (BRDPC.defaultSender, webSocketID, requestJSON, BRDPC.NoReturnValues);
966    }
967    
968}