| 1 | // Copyright (c) 2018, Yubico AB | |
| 2 | // All rights reserved. | |
| 3 | // | |
| 4 | // Redistribution and use in source and binary forms, with or without | |
| 5 | // modification, are permitted provided that the following conditions are met: | |
| 6 | // | |
| 7 | // 1. Redistributions of source code must retain the above copyright notice, this | |
| 8 | // list of conditions and the following disclaimer. | |
| 9 | // | |
| 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |
| 11 | // this list of conditions and the following disclaimer in the documentation | |
| 12 | // and/or other materials provided with the distribution. | |
| 13 | // | |
| 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
| 18 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 19 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 20 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
| 21 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 22 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 23 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 24 | ||
| 25 | package com.yubico.webauthn; | |
| 26 | ||
| 27 | import com.fasterxml.jackson.annotation.JsonCreator; | |
| 28 | import com.fasterxml.jackson.annotation.JsonProperty; | |
| 29 | import com.fasterxml.jackson.core.JsonProcessingException; | |
| 30 | import com.yubico.internal.util.JacksonCodecs; | |
| 31 | import com.yubico.webauthn.data.ByteArray; | |
| 32 | import com.yubico.webauthn.data.PublicKeyCredentialRequestOptions; | |
| 33 | import java.util.Optional; | |
| 34 | import lombok.Builder; | |
| 35 | import lombok.NonNull; | |
| 36 | import lombok.Value; | |
| 37 | ||
| 38 | /** | |
| 39 | * A combination of a {@link PublicKeyCredentialRequestOptions} and, optionally, a {@link | |
| 40 | * #getUsername() username} or {@link #getUserHandle() user handle}. | |
| 41 | */ | |
| 42 | @Value | |
| 43 | @Builder(toBuilder = true) | |
| 44 | public class AssertionRequest { | |
| 45 | ||
| 46 | /** | |
| 47 | * An object that can be serialized to JSON and passed as the <code>publicKey</code> argument to | |
| 48 | * <code>navigator.credentials.get()</code>. | |
| 49 | */ | |
| 50 | @NonNull private final PublicKeyCredentialRequestOptions publicKeyCredentialRequestOptions; | |
| 51 | ||
| 52 | /** | |
| 53 | * The username of the user to authenticate, if the user has already been identified. | |
| 54 | * | |
| 55 | * <p>This is mutually exclusive with {@link #getUserHandle() userHandle}; setting this will unset | |
| 56 | * {@link #getUserHandle() userHandle}. When parsing from JSON, {@link #getUserHandle() | |
| 57 | * userHandle} takes precedence over this. | |
| 58 | * | |
| 59 | * <p>If both this and {@link #getUserHandle() userHandle} are empty, this indicates that this is | |
| 60 | * a request for an assertion by a <a | |
| 61 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#client-side-discoverable-public-key-credential-source">client-side-discoverable | |
| 62 | * credential</a> (passkey). Identification of the user is therefore deferred until the response | |
| 63 | * is received. | |
| 64 | * | |
| 65 | * @see <a href="https://passkeys.dev/docs/reference/terms/#passkey">Passkey</a> in <a | |
| 66 | * href="https://passkeys.dev">passkeys.dev</a> reference | |
| 67 | */ | |
| 68 | private final String username; | |
| 69 | ||
| 70 | /** | |
| 71 | * The user handle of the user to authenticate, if the user has already been identified. | |
| 72 | * | |
| 73 | * <p>This is mutually exclusive with {@link #getUsername() username}; setting this will unset | |
| 74 | * {@link #getUsername() username}. When parsing from JSON, this takes precedence over {@link | |
| 75 | * #getUsername() username}. | |
| 76 | * | |
| 77 | * <p>If both this and {@link #getUsername() username} are empty, this indicates that this is a | |
| 78 | * request for an assertion by a <a | |
| 79 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#client-side-discoverable-public-key-credential-source">client-side-discoverable | |
| 80 | * credential</a> (passkey). Identification of the user is therefore deferred until the response | |
| 81 | * is received. | |
| 82 | * | |
| 83 | * @see <a href="https://passkeys.dev/docs/reference/terms/#passkey">Passkey</a> in <a | |
| 84 | * href="https://passkeys.dev">passkeys.dev</a> reference | |
| 85 | */ | |
| 86 | private final ByteArray userHandle; | |
| 87 | ||
| 88 | @JsonCreator | |
| 89 | private AssertionRequest( | |
| 90 |
1
1. <init> : negated conditional → KILLED |
@NonNull @JsonProperty("publicKeyCredentialRequestOptions") |
| 91 | PublicKeyCredentialRequestOptions publicKeyCredentialRequestOptions, | |
| 92 | @JsonProperty("username") String username, | |
| 93 | @JsonProperty("userHandle") ByteArray userHandle) { | |
| 94 | this.publicKeyCredentialRequestOptions = publicKeyCredentialRequestOptions; | |
| 95 | ||
| 96 |
1
1. <init> : negated conditional → KILLED |
if (userHandle != null) { |
| 97 | this.username = null; | |
| 98 | this.userHandle = userHandle; | |
| 99 | } else { | |
| 100 | this.username = username; | |
| 101 | this.userHandle = null; | |
| 102 | } | |
| 103 | } | |
| 104 | ||
| 105 | /** | |
| 106 | * The username of the user to authenticate, if the user has already been identified. | |
| 107 | * | |
| 108 | * <p>This is mutually exclusive with {@link #getUserHandle()}; if this is present, then {@link | |
| 109 | * #getUserHandle()} will be empty. | |
| 110 | * | |
| 111 | * <p>If both this and {@link #getUserHandle()} are empty, this indicates that this is a request | |
| 112 | * for an assertion by a <a | |
| 113 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#client-side-discoverable-public-key-credential-source">client-side-discoverable | |
| 114 | * credential</a> (passkey). Identification of the user is therefore deferred until the response | |
| 115 | * is received. | |
| 116 | * | |
| 117 | * @see <a href="https://passkeys.dev/docs/reference/terms/#passkey">Passkey</a> in <a | |
| 118 | * href="https://passkeys.dev">passkeys.dev</a> reference | |
| 119 | */ | |
| 120 | public Optional<String> getUsername() { | |
| 121 |
1
1. getUsername : replaced return value with Optional.empty for com/yubico/webauthn/AssertionRequest::getUsername → KILLED |
return Optional.ofNullable(username); |
| 122 | } | |
| 123 | ||
| 124 | /** | |
| 125 | * The user handle of the user to authenticate, if the user has already been identified. | |
| 126 | * | |
| 127 | * <p>This is mutually exclusive with {@link #getUsername()}; if this is present, then {@link | |
| 128 | * #getUsername()} will be empty. | |
| 129 | * | |
| 130 | * <p>If both this and {@link #getUsername()} are empty, this indicates that this is a request for | |
| 131 | * an assertion by a <a | |
| 132 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#client-side-discoverable-public-key-credential-source">client-side-discoverable | |
| 133 | * credential</a> (passkey). Identification of the user is therefore deferred until the response | |
| 134 | * is received. | |
| 135 | * | |
| 136 | * @see <a href="https://passkeys.dev/docs/reference/terms/#passkey">Passkey</a> in <a | |
| 137 | * href="https://passkeys.dev">passkeys.dev</a> reference | |
| 138 | */ | |
| 139 | public Optional<ByteArray> getUserHandle() { | |
| 140 |
1
1. getUserHandle : replaced return value with Optional.empty for com/yubico/webauthn/AssertionRequest::getUserHandle → KILLED |
return Optional.ofNullable(userHandle); |
| 141 | } | |
| 142 | ||
| 143 | /** | |
| 144 | * Serialize this {@link AssertionRequest} value to JSON suitable for sending to the client. | |
| 145 | * | |
| 146 | * <p>This is an alias of <code>getPublicKeyCredentialRequestOptions().toCredentialsGetJson() | |
| 147 | * </code>. | |
| 148 | * | |
| 149 | * <p>Any {@link ByteArray} values in this data structure will be {@link ByteArray#getBase64Url() | |
| 150 | * Base64Url} encoded. Those values MUST be decoded into <code>BufferSource</code> values (such as | |
| 151 | * <code>Uint8Array</code>) on the client side before calling <code>navigator.credentials.get() | |
| 152 | * </code>. | |
| 153 | * | |
| 154 | * <p>After decoding binary values, the resulting JavaScript object is suitable for passing as an | |
| 155 | * argument to <code>navigator.credentials.get()</code>. | |
| 156 | * | |
| 157 | * @return a JSON value suitable for sending to the client and passing as an argument to <code> | |
| 158 | * navigator.credentials.get()</code>, after decoding binary options from Base64Url strings. | |
| 159 | * @throws JsonProcessingException if JSON serialization fails. | |
| 160 | */ | |
| 161 | public String toCredentialsGetJson() throws JsonProcessingException { | |
| 162 |
1
1. toCredentialsGetJson : replaced return value with "" for com/yubico/webauthn/AssertionRequest::toCredentialsGetJson → KILLED |
return publicKeyCredentialRequestOptions.toCredentialsGetJson(); |
| 163 | } | |
| 164 | ||
| 165 | /** | |
| 166 | * Encode this {@link AssertionRequest} to JSON. The inverse of {@link #fromJson(String)}. | |
| 167 | * | |
| 168 | * <p>This method is suitable for encoding the {@link AssertionRequest} for temporary storage so | |
| 169 | * that it can later be passed as an argument to {@link | |
| 170 | * RelyingParty#finishAssertion(FinishAssertionOptions)}. The {@link #fromJson(String)} factory | |
| 171 | * function is guaranteed to restore an identical {@link AssertionRequest} instance. | |
| 172 | * | |
| 173 | * <p>Note that encoding might not be needed if you can simply keep the {@link AssertionRequest} | |
| 174 | * instance in server memory. | |
| 175 | * | |
| 176 | * @return this {@link AssertionRequest} encoded to JSON. | |
| 177 | * @throws JsonProcessingException | |
| 178 | */ | |
| 179 | public String toJson() throws JsonProcessingException { | |
| 180 |
1
1. toJson : replaced return value with "" for com/yubico/webauthn/AssertionRequest::toJson → KILLED |
return JacksonCodecs.json().writeValueAsString(this); |
| 181 | } | |
| 182 | ||
| 183 | /** | |
| 184 | * Decode an {@link AssertionRequest} from JSON. The inverse of {@link #toJson()}. | |
| 185 | * | |
| 186 | * <p>If the JSON was generated by the {@link #toJson()} method, then {@link #fromJson(String)} in | |
| 187 | * the same library version guarantees to restore an identical {@link AssertionRequest} instance. | |
| 188 | * This is not guaranteed between different library versions. | |
| 189 | * | |
| 190 | * @return a {@link AssertionRequest} decoded from the input JSON. | |
| 191 | * @throws JsonProcessingException | |
| 192 | */ | |
| 193 | public static AssertionRequest fromJson(String json) throws JsonProcessingException { | |
| 194 |
1
1. fromJson : replaced return value with null for com/yubico/webauthn/AssertionRequest::fromJson → KILLED |
return JacksonCodecs.json().readValue(json, AssertionRequest.class); |
| 195 | } | |
| 196 | ||
| 197 | public static AssertionRequestBuilder.MandatoryStages builder() { | |
| 198 |
1
1. builder : replaced return value with null for com/yubico/webauthn/AssertionRequest::builder → KILLED |
return new AssertionRequestBuilder.MandatoryStages(); |
| 199 | } | |
| 200 | ||
| 201 | public static class AssertionRequestBuilder { | |
| 202 | private String username = null; | |
| 203 | private ByteArray userHandle = null; | |
| 204 | ||
| 205 | public static class MandatoryStages { | |
| 206 | private final AssertionRequestBuilder builder = new AssertionRequestBuilder(); | |
| 207 | ||
| 208 | /** | |
| 209 | * {@link | |
| 210 | * AssertionRequestBuilder#publicKeyCredentialRequestOptions(PublicKeyCredentialRequestOptions) | |
| 211 | * publicKeyCredentialRequestOptions} is a required parameter. | |
| 212 | * | |
| 213 | * @see | |
| 214 | * AssertionRequestBuilder#publicKeyCredentialRequestOptions(PublicKeyCredentialRequestOptions) | |
| 215 | */ | |
| 216 | public AssertionRequestBuilder publicKeyCredentialRequestOptions( | |
| 217 | PublicKeyCredentialRequestOptions publicKeyCredentialRequestOptions) { | |
| 218 |
1
1. publicKeyCredentialRequestOptions : replaced return value with null for com/yubico/webauthn/AssertionRequest$AssertionRequestBuilder$MandatoryStages::publicKeyCredentialRequestOptions → KILLED |
return builder.publicKeyCredentialRequestOptions(publicKeyCredentialRequestOptions); |
| 219 | } | |
| 220 | } | |
| 221 | ||
| 222 | /** | |
| 223 | * The username of the user to authenticate, if the user has already been identified. | |
| 224 | * | |
| 225 | * <p>This is mutually exclusive with {@link #userHandle(ByteArray)}; setting this to non-empty | |
| 226 | * will unset {@link #userHandle(ByteArray)}. | |
| 227 | * | |
| 228 | * <p>If this is empty, this indicates that this is a request for an assertion by a <a | |
| 229 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#client-side-discoverable-public-key-credential-source">client-side-discoverable | |
| 230 | * credential</a> (passkey). Identification of the user is therefore deferred until the response | |
| 231 | * is received. | |
| 232 | * | |
| 233 | * @see <a href="https://passkeys.dev/docs/reference/terms/#passkey">Passkey</a> in <a | |
| 234 | * href="https://passkeys.dev">passkeys.dev</a> reference | |
| 235 | */ | |
| 236 |
1
1. username : negated conditional → KILLED |
public AssertionRequestBuilder username(@NonNull Optional<String> username) { |
| 237 |
1
1. username : replaced return value with null for com/yubico/webauthn/AssertionRequest$AssertionRequestBuilder::username → KILLED |
return this.username(username.orElse(null)); |
| 238 | } | |
| 239 | ||
| 240 | /** | |
| 241 | * The username of the user to authenticate, if the user has already been identified. | |
| 242 | * | |
| 243 | * <p>This is mutually exclusive with {@link #userHandle(ByteArray)}; setting this to non-<code> | |
| 244 | * null</code> will unset {@link #userHandle(ByteArray)}. | |
| 245 | * | |
| 246 | * <p>If this is empty, this indicates that this is a request for an assertion by a <a | |
| 247 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#client-side-discoverable-public-key-credential-source">client-side-discoverable | |
| 248 | * credential</a> (passkey). Identification of the user is therefore deferred until the response | |
| 249 | * is received. | |
| 250 | * | |
| 251 | * @see <a href="https://passkeys.dev/docs/reference/terms/#passkey">Passkey</a> in <a | |
| 252 | * href="https://passkeys.dev">passkeys.dev</a> reference | |
| 253 | */ | |
| 254 | public AssertionRequestBuilder username(String username) { | |
| 255 | this.username = username; | |
| 256 |
1
1. username : negated conditional → KILLED |
if (username != null) { |
| 257 | this.userHandle = null; | |
| 258 | } | |
| 259 |
1
1. username : replaced return value with null for com/yubico/webauthn/AssertionRequest$AssertionRequestBuilder::username → KILLED |
return this; |
| 260 | } | |
| 261 | ||
| 262 | /** | |
| 263 | * The user handle of the user to authenticate, if the user has already been identified. | |
| 264 | * | |
| 265 | * <p>This is mutually exclusive with {@link #username(String)}; setting this to non-empty will | |
| 266 | * unset {@link #username(String)}. | |
| 267 | * | |
| 268 | * <p>If both this and {@link #username(String)} are empty, this indicates that this is a | |
| 269 | * request for an assertion by a <a | |
| 270 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#client-side-discoverable-public-key-credential-source">client-side-discoverable | |
| 271 | * credential</a> (passkey). Identification of the user is therefore deferred until the response | |
| 272 | * is received. | |
| 273 | * | |
| 274 | * @see <a href="https://passkeys.dev/docs/reference/terms/#passkey">Passkey</a> in <a | |
| 275 | * href="https://passkeys.dev">passkeys.dev</a> reference | |
| 276 | */ | |
| 277 |
1
1. userHandle : negated conditional → KILLED |
public AssertionRequestBuilder userHandle(@NonNull Optional<ByteArray> userHandle) { |
| 278 |
1
1. userHandle : replaced return value with null for com/yubico/webauthn/AssertionRequest$AssertionRequestBuilder::userHandle → KILLED |
return this.userHandle(userHandle.orElse(null)); |
| 279 | } | |
| 280 | ||
| 281 | /** | |
| 282 | * The user handle of the user to authenticate, if the user has already been identified. | |
| 283 | * | |
| 284 | * <p>This is mutually exclusive with {@link #username(String)}; setting this to non-<code>null | |
| 285 | * </code> will unset {@link #username(String)}. | |
| 286 | * | |
| 287 | * <p>If both this and {@link #username(String)} are empty, this indicates that this is a | |
| 288 | * request for an assertion by a <a | |
| 289 | * href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#client-side-discoverable-public-key-credential-source">client-side-discoverable | |
| 290 | * credential</a> (passkey). Identification of the user is therefore deferred until the response | |
| 291 | * is received. | |
| 292 | * | |
| 293 | * @see <a href="https://passkeys.dev/docs/reference/terms/#passkey">Passkey</a> in <a | |
| 294 | * href="https://passkeys.dev">passkeys.dev</a> reference | |
| 295 | */ | |
| 296 | public AssertionRequestBuilder userHandle(ByteArray userHandle) { | |
| 297 |
1
1. userHandle : negated conditional → KILLED |
if (userHandle != null) { |
| 298 | this.username = null; | |
| 299 | } | |
| 300 | this.userHandle = userHandle; | |
| 301 |
1
1. userHandle : replaced return value with null for com/yubico/webauthn/AssertionRequest$AssertionRequestBuilder::userHandle → KILLED |
return this; |
| 302 | } | |
| 303 | } | |
| 304 | } | |
Mutations | ||
| 90 |
1.1 |
|
| 96 |
1.1 |
|
| 121 |
1.1 |
|
| 140 |
1.1 |
|
| 162 |
1.1 |
|
| 180 |
1.1 |
|
| 194 |
1.1 |
|
| 198 |
1.1 |
|
| 218 |
1.1 |
|
| 236 |
1.1 |
|
| 237 |
1.1 |
|
| 256 |
1.1 |
|
| 259 |
1.1 |
|
| 277 |
1.1 |
|
| 278 |
1.1 |
|
| 297 |
1.1 |
|
| 301 |
1.1 |