diff --git a/build.gradle b/build.gradle index 0aabd0c..f295d57 100644 --- a/build.gradle +++ b/build.gradle @@ -15,14 +15,14 @@ apply plugin: 'com.github.dcendents.android-maven' group='com.github.duo-labs' android { - compileSdkVersion 28 + compileSdkVersion 29 defaultConfig { - minSdkVersion 28 - targetSdkVersion 28 + minSdkVersion 23 + targetSdkVersion 29 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' javaCompileOptions { annotationProcessorOptions { @@ -42,29 +42,31 @@ android { dependencies { //implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'androidx.appcompat:appcompat:1.0.0' testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' //androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation 'co.nstant.in:cbor:0.8' implementation 'com.google.code.gson:gson:2.8.5' def lifecycle_version = "1.1.1" - implementation "android.arch.lifecycle:extensions:$lifecycle_version" + implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' //def room_version = "2.1.0-alpha02" //implementation "androidx.room:room-runtime:$room_version" //annotationProcessor "androidx.room:room-compiler:$room_version" def room_version = "1.1.1" - implementation "android.arch.persistence.room:runtime:$room_version" - annotationProcessor "android.arch.persistence.room:compiler:$room_version" + implementation 'androidx.room:room-runtime:2.0.0' + annotationProcessor 'androidx.room:room-compiler:2.0.0' // use kapt for Kotlin // optional - RxJava support for Room - implementation "android.arch.persistence.room:rxjava2:$room_version" + implementation 'androidx.room:room-rxjava2:2.0.0' // optional - Guava support for Room, including Optional and ListenableFuture - implementation "android.arch.persistence.room:guava:$room_version" + implementation 'androidx.room:room-guava:2.0.0' // Test helpers - testImplementation "android.arch.persistence.room:testing:$room_version" + testImplementation 'androidx.room:room-testing:2.0.0' // precis for unicode name validation implementation 'rocks.xmpp:precis:1.0.0' + + implementation 'androidx.security:security-crypto:1.1.0-alpha02' } allprojects { diff --git a/src/androidTest/java/duo/labs/webauthn/AuthenticatorTest.java b/src/androidTest/java/duo/labs/webauthn/AuthenticatorTest.java index d0f0a99..0708fe7 100644 --- a/src/androidTest/java/duo/labs/webauthn/AuthenticatorTest.java +++ b/src/androidTest/java/duo/labs/webauthn/AuthenticatorTest.java @@ -1,9 +1,8 @@ package duo.labs.webauthn; import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.util.Base64; +import androidx.test.InstrumentationRegistry; import org.junit.Assert; import org.junit.Before; import org.junit.Test; diff --git a/src/androidTest/java/duo/labs/webauthn/CredentialSafeTest.java b/src/androidTest/java/duo/labs/webauthn/CredentialSafeTest.java index ff353bf..d7d1a7c 100644 --- a/src/androidTest/java/duo/labs/webauthn/CredentialSafeTest.java +++ b/src/androidTest/java/duo/labs/webauthn/CredentialSafeTest.java @@ -1,8 +1,8 @@ package duo.labs.webauthn; import android.content.Context; -import android.support.test.InstrumentationRegistry; +import androidx.test.InstrumentationRegistry; import org.junit.Before; import org.junit.Test; diff --git a/src/androidTest/java/duo/labs/webauthn/WebAuthnCryptographyTest.java b/src/androidTest/java/duo/labs/webauthn/WebAuthnCryptographyTest.java index d084658..fc9a3b0 100644 --- a/src/androidTest/java/duo/labs/webauthn/WebAuthnCryptographyTest.java +++ b/src/androidTest/java/duo/labs/webauthn/WebAuthnCryptographyTest.java @@ -1,8 +1,8 @@ package duo.labs.webauthn; import android.content.Context; -import android.support.test.InstrumentationRegistry; +import androidx.test.InstrumentationRegistry; import org.junit.Before; import org.junit.Test; diff --git a/src/main/java/duo/labs/webauthn/Authenticator.java b/src/main/java/duo/labs/webauthn/Authenticator.java index c5eca19..d28e060 100644 --- a/src/main/java/duo/labs/webauthn/Authenticator.java +++ b/src/main/java/duo/labs/webauthn/Authenticator.java @@ -3,47 +3,30 @@ import android.content.Context; import android.content.DialogInterface; import android.hardware.biometrics.BiometricPrompt; +import android.os.Build; import android.os.CancellationSignal; import android.util.Log; -import android.util.Pair; +import duo.labs.webauthn.exceptions.UnknownError; +import duo.labs.webauthn.exceptions.*; +import duo.labs.webauthn.models.*; +import duo.labs.webauthn.util.*; import java.nio.ByteBuffer; import java.security.KeyPair; import java.security.PrivateKey; import java.security.Signature; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.Exchanger; -import duo.labs.webauthn.exceptions.ConstraintError; -import duo.labs.webauthn.exceptions.InvalidStateError; -import duo.labs.webauthn.exceptions.NotAllowedError; -import duo.labs.webauthn.exceptions.NotSupportedError; -import duo.labs.webauthn.exceptions.UnknownError; -import duo.labs.webauthn.exceptions.VirgilException; -import duo.labs.webauthn.exceptions.WebAuthnException; -import duo.labs.webauthn.models.AttestationObject; -import duo.labs.webauthn.models.AuthenticatorGetAssertionOptions; -import duo.labs.webauthn.models.AuthenticatorGetAssertionResult; -import duo.labs.webauthn.models.AuthenticatorMakeCredentialOptions; -import duo.labs.webauthn.models.NoneAttestationObject; -import duo.labs.webauthn.models.PublicKeyCredentialDescriptor; -import duo.labs.webauthn.models.PublicKeyCredentialSource; -import duo.labs.webauthn.util.BiometricGetAssertionCallback; -import duo.labs.webauthn.util.BiometricMakeCredentialCallback; -import duo.labs.webauthn.util.CredentialSelector; -import duo.labs.webauthn.util.CredentialSafe; -import duo.labs.webauthn.util.WebAuthnCryptography; - public class Authenticator { private static final String TAG = "WebauthnAuthenticator"; public static final int SHA_LENGTH = 32; public static final int AUTHENTICATOR_DATA_LENGTH = 141; - private static final Pair ES256_COSE = new Pair<>("public-key", (long) -7); + private static final PubKeyCredParam ES256_COSE = new PubKeyCredParam("public-key", -7); CredentialSafe credentialSafe; WebAuthnCryptography cryptoProvider; @@ -98,7 +81,7 @@ public AttestationObject makeCredential(AuthenticatorMakeCredentialOptions optio } // 2. Check if we support a compatible credential type - if (!options.credTypesAndPubKeyAlgs.contains(ES256_COSE)) { + if (!options.pubKeyCredParams.contains(ES256_COSE)) { Log.w(TAG, "only ES256 is supported"); throw new NotSupportedError(); } @@ -145,7 +128,7 @@ public AttestationObject makeCredential(AuthenticatorMakeCredentialOptions optio // if we need to obtain user verification, create a biometric prompt for that // else just generate a new credential/attestation object AttestationObject attestationObject = null; - if (credentialSafe.supportsUserVerification()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && credentialSafe.supportsUserVerification()) { if (ctx == null) { throw new VirgilException("User Verification requires passing a context to makeCredential"); } @@ -243,7 +226,7 @@ public AttestationObject makeInternalCredential(AuthenticatorMakeCredentialOptio byte[] authenticatorData = constructAuthenticatorData(rpIdHash, attestedCredentialData, 0); // 141 bytes // 13. Return attestation object - AttestationObject attestationObject = constructAttestationObject(authenticatorData, options.clientDataHash, credentialSource.keyPairAlias, signature); + AttestationObject attestationObject = constructAttestationObject(authenticatorData, options.clientDataHash, credentialSource.keyPairAlias, signature, options.attestation); return attestationObject; } @@ -293,7 +276,8 @@ public AuthenticatorGetAssertionResult getAssertion(AuthenticatorGetAssertionOpt } for (PublicKeyCredentialSource credential : credentials) { - if (allowedCredentialIds.contains(ByteBuffer.wrap(credential.id))) { + if (allowedCredentialIds.contains(ByteBuffer.wrap(credential.id)) + || allowedCredentialIds.contains(ByteBuffer.wrap(credential.userHandle))) { filteredCredentials.add(credential); } } @@ -321,7 +305,7 @@ public AuthenticatorGetAssertionResult getAssertion(AuthenticatorGetAssertionOpt // get verification, if necessary AuthenticatorGetAssertionResult result; boolean keyNeedsUnlocking = credentialSafe.keyRequiresVerification(selectedCredential.keyPairAlias); - if (options.requireUserVerification || keyNeedsUnlocking) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && (options.requireUserVerification || keyNeedsUnlocking)) { if (ctx == null) { throw new VirgilException("User Verification requires passing a context to getAssertion"); } @@ -500,10 +484,15 @@ private byte[] constructAuthenticatorData(byte[] rpIdHash, byte[] attestedCreden * @param authenticatorData byte array containing the raw authenticatorData object * @param clientDataHash byte array containing the sha256 hash of the client data object (request type, challenge, origin) * @param keyPairAlias alias to lookup the key pair to be used to sign the attestation object + * @param attestation * @return a well-formed AttestationObject structure * @throws VirgilException */ - private AttestationObject constructAttestationObject(byte[] authenticatorData, byte[] clientDataHash, String keyPairAlias, Signature signature) throws VirgilException { + private AttestationObject constructAttestationObject(byte[] authenticatorData, byte[] clientDataHash, String keyPairAlias, Signature signature, String attestation) throws VirgilException { + // No signature needed + if ("none".equals(attestation)) + return new NoneAttestationObject(authenticatorData); + // Our goal in this function is primarily to create a signature over the relevant data fields // From https://www.w3.org/TR/webauthn/#packed-attestation we can see that for self-signed attestation, // `sig` is generated by signing the concatenation of authenticatorData and clientDataHash @@ -527,13 +516,10 @@ private AttestationObject constructAttestationObject(byte[] authenticatorData, b // grab our keypair for this credential KeyPair keyPair = this.credentialSafe.getKeyPairByAlias(keyPairAlias); - byte[] signatureBytes = this.cryptoProvider.performSignature(keyPair.getPrivate(), toSign, signature); + byte[] signatureBytes = this.cryptoProvider.performSignature(keyPair.getPrivate(), toSign, signature); // construct our attestation object (attestationObject.asCBOR() can be used to generate the raw object in calling function) - // AttestationObject attestationObject = new PackedSelfAttestationObject(authenticatorData, signatureBytes); - // TODO: Discuss tradeoffs wrt none / packed attestation formats. Switching to none here because packed lacks support. - AttestationObject attestationObject = new NoneAttestationObject(authenticatorData); - return attestationObject; + return new PackedSelfAttestationObject(authenticatorData, signatureBytes); } diff --git a/src/main/java/duo/labs/webauthn/models/AuthenticatorGetAssertionOptions.java b/src/main/java/duo/labs/webauthn/models/AuthenticatorGetAssertionOptions.java index 3e62595..8bb3be1 100644 --- a/src/main/java/duo/labs/webauthn/models/AuthenticatorGetAssertionOptions.java +++ b/src/main/java/duo/labs/webauthn/models/AuthenticatorGetAssertionOptions.java @@ -22,12 +22,14 @@ public class AuthenticatorGetAssertionOptions { public String rpId; @SerializedName("clientDataHash") public byte[] clientDataHash; - @SerializedName("allowCredentialDescriptorList") + @SerializedName("allowCredentials") public List allowCredentialDescriptorList; @SerializedName("requireUserPresence") public boolean requireUserPresence; @SerializedName("requireUserVerification") public boolean requireUserVerification; + @SerializedName("challenge") + public String challenge; // TODO: authenticatorExtensions public boolean areWellFormed() { diff --git a/src/main/java/duo/labs/webauthn/models/AuthenticatorMakeCredentialOptions.java b/src/main/java/duo/labs/webauthn/models/AuthenticatorMakeCredentialOptions.java index edf820a..0937b0f 100644 --- a/src/main/java/duo/labs/webauthn/models/AuthenticatorMakeCredentialOptions.java +++ b/src/main/java/duo/labs/webauthn/models/AuthenticatorMakeCredentialOptions.java @@ -1,6 +1,7 @@ package duo.labs.webauthn.models; import android.util.Base64; +import android.util.Log; import android.util.Pair; import com.google.gson.Gson; @@ -23,8 +24,12 @@ import rocks.xmpp.precis.PrecisProfiles; public class AuthenticatorMakeCredentialOptions { + @SerializedName("attestation") + public String attestation; @SerializedName("clientDataHash") public byte[] clientDataHash; + @SerializedName("challenge") + public String challenge; @SerializedName("rp") public RpEntity rpEntity; @SerializedName("user") @@ -35,8 +40,8 @@ public class AuthenticatorMakeCredentialOptions { public boolean requireUserPresence; @SerializedName("requireUserVerification") public boolean requireUserVerification; - @SerializedName("credTypesAndPubKeyAlgs") - public List> credTypesAndPubKeyAlgs; + @SerializedName("pubKeyCredParams") + public List pubKeyCredParams; @SerializedName("excludeCredentials") public List excludeCredentialDescriptorList; // TODO: possibly support extensions in the future @@ -54,15 +59,15 @@ public boolean areWellFormed() { profile.enforce(rpEntity.name); profile.enforce(userEntity.name); } catch (Exception e) { - return false; + Log.d("AuthMakeCredentialO", String.format("Failed to enforce profile, '%s', '%s'", rpEntity.name, userEntity.name), e); } - if (userEntity.id.length <= 0 || userEntity.id.length > 64) { + if (userEntity.id.length > 64) { return false; } if (!(requireUserPresence ^ requireUserVerification)) { // only one may be set return false; } - if (credTypesAndPubKeyAlgs.isEmpty()) { + if (pubKeyCredParams.isEmpty()) { return false; } return true; diff --git a/src/main/java/duo/labs/webauthn/models/PubKeyCredParam.java b/src/main/java/duo/labs/webauthn/models/PubKeyCredParam.java new file mode 100644 index 0000000..7d1a084 --- /dev/null +++ b/src/main/java/duo/labs/webauthn/models/PubKeyCredParam.java @@ -0,0 +1,27 @@ +package duo.labs.webauthn.models; + +import java.util.Objects; + +public class PubKeyCredParam { + public String type; + public int alg; + + public PubKeyCredParam(String type, int alg) { + this.type = type; + this.alg = alg; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof PubKeyCredParam)) return false; + PubKeyCredParam that = (PubKeyCredParam) o; + return alg == that.alg && + Objects.equals(type, that.type); + } + + @Override + public int hashCode() { + return Objects.hash(type, alg); + } +} diff --git a/src/main/java/duo/labs/webauthn/models/PublicKeyCredentialSource.java b/src/main/java/duo/labs/webauthn/models/PublicKeyCredentialSource.java index bc63ba2..6f91c12 100644 --- a/src/main/java/duo/labs/webauthn/models/PublicKeyCredentialSource.java +++ b/src/main/java/duo/labs/webauthn/models/PublicKeyCredentialSource.java @@ -1,10 +1,10 @@ package duo.labs.webauthn.models; -import android.arch.persistence.room.Entity; -import android.arch.persistence.room.Ignore; -import android.arch.persistence.room.Index; -import android.arch.persistence.room.PrimaryKey; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.Ignore; +import androidx.room.Index; +import androidx.room.PrimaryKey; import android.util.Base64; import java.security.SecureRandom; diff --git a/src/main/java/duo/labs/webauthn/util/BiometricGetAssertionCallback.java b/src/main/java/duo/labs/webauthn/util/BiometricGetAssertionCallback.java index cafc4b1..4858a48 100644 --- a/src/main/java/duo/labs/webauthn/util/BiometricGetAssertionCallback.java +++ b/src/main/java/duo/labs/webauthn/util/BiometricGetAssertionCallback.java @@ -1,23 +1,22 @@ package duo.labs.webauthn.util; import android.hardware.biometrics.BiometricPrompt; -import android.os.AsyncTask; +import android.os.Build; import android.util.Log; - -import java.security.Signature; -import java.util.concurrent.Exchanger; - +import androidx.annotation.RequiresApi; import duo.labs.webauthn.Authenticator; import duo.labs.webauthn.exceptions.VirgilException; import duo.labs.webauthn.exceptions.WebAuthnException; -import duo.labs.webauthn.models.AttestationObject; import duo.labs.webauthn.models.AuthenticatorGetAssertionOptions; import duo.labs.webauthn.models.AuthenticatorGetAssertionResult; -import duo.labs.webauthn.models.AuthenticatorMakeCredentialOptions; import duo.labs.webauthn.models.PublicKeyCredentialSource; +import java.security.Signature; +import java.util.concurrent.Exchanger; + +@RequiresApi(api = Build.VERSION_CODES.P) public class BiometricGetAssertionCallback extends BiometricPrompt.AuthenticationCallback { - private static final String TAG = "BiometricGetAssertionCallback"; + private static final String TAG = "BiometricGetAssertionC"; private Authenticator authenticator; private AuthenticatorGetAssertionOptions options; diff --git a/src/main/java/duo/labs/webauthn/util/BiometricMakeCredentialCallback.java b/src/main/java/duo/labs/webauthn/util/BiometricMakeCredentialCallback.java index c2ce58d..be77db0 100644 --- a/src/main/java/duo/labs/webauthn/util/BiometricMakeCredentialCallback.java +++ b/src/main/java/duo/labs/webauthn/util/BiometricMakeCredentialCallback.java @@ -1,11 +1,9 @@ package duo.labs.webauthn.util; import android.hardware.biometrics.BiometricPrompt; +import android.os.Build; import android.util.Log; - -import java.security.Signature; -import java.util.concurrent.Exchanger; - +import androidx.annotation.RequiresApi; import duo.labs.webauthn.Authenticator; import duo.labs.webauthn.exceptions.VirgilException; import duo.labs.webauthn.exceptions.WebAuthnException; @@ -13,8 +11,12 @@ import duo.labs.webauthn.models.AuthenticatorMakeCredentialOptions; import duo.labs.webauthn.models.PublicKeyCredentialSource; +import java.security.Signature; +import java.util.concurrent.Exchanger; + +@RequiresApi(api = Build.VERSION_CODES.P) public class BiometricMakeCredentialCallback extends BiometricPrompt.AuthenticationCallback { - private static final String TAG = "BiometricMakeCredentialCallback"; + private static final String TAG = "BiometricMCredentialC"; private Authenticator authenticator; private AuthenticatorMakeCredentialOptions options; diff --git a/src/main/java/duo/labs/webauthn/util/CredentialSafe.java b/src/main/java/duo/labs/webauthn/util/CredentialSafe.java index ec8c9a2..52b023c 100644 --- a/src/main/java/duo/labs/webauthn/util/CredentialSafe.java +++ b/src/main/java/duo/labs/webauthn/util/CredentialSafe.java @@ -1,24 +1,21 @@ package duo.labs.webauthn.util; import android.content.Context; +import android.os.Build; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyInfo; import android.security.keystore.KeyProperties; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; +import co.nstant.in.cbor.CborBuilder; +import co.nstant.in.cbor.CborEncoder; +import co.nstant.in.cbor.CborException; +import duo.labs.webauthn.exceptions.VirgilException; +import duo.labs.webauthn.models.PublicKeyCredentialSource; +import duo.labs.webauthn.util.database.CredentialDatabase; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.UnrecoverableEntryException; +import java.security.*; import java.security.cert.CertificateException; import java.security.interfaces.ECPublicKey; import java.security.spec.ECGenParameterSpec; @@ -26,13 +23,6 @@ import java.security.spec.InvalidKeySpecException; import java.util.List; -import co.nstant.in.cbor.CborBuilder; -import co.nstant.in.cbor.CborEncoder; -import co.nstant.in.cbor.CborException; -import duo.labs.webauthn.exceptions.VirgilException; -import duo.labs.webauthn.models.PublicKeyCredentialSource; -import duo.labs.webauthn.util.database.CredentialDatabase; - /** * CredentialSafe uses the Android KeyStore to generate and store @@ -102,14 +92,19 @@ public boolean supportsUserVerification() { * @throws VirgilException */ private KeyPair generateNewES256KeyPair(String alias) throws VirgilException { - KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_SIGN) + KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_SIGN) .setAlgorithmParameterSpec(new ECGenParameterSpec(CURVE_NAME)) .setDigests(KeyProperties.DIGEST_SHA256) - .setUserAuthenticationRequired(this.authenticationRequired) // fingerprint or similar - .setUserConfirmationRequired(false) // TODO: Decide if we support Android Trusted Confirmations - .setInvalidatedByBiometricEnrollment(false) - .setIsStrongBoxBacked(this.strongboxRequired) - .build(); + .setUserAuthenticationRequired(this.authenticationRequired); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + specBuilder.setInvalidatedByBiometricEnrollment(false); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) + specBuilder.setUserConfirmationRequired(false) + .setIsStrongBoxBacked(this.strongboxRequired); + } + KeyGenParameterSpec spec = specBuilder.build(); try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, KEYSTORE_TYPE); keyPairGenerator.initialize(spec); diff --git a/src/main/java/duo/labs/webauthn/util/SelectCredentialDialogFragment.java b/src/main/java/duo/labs/webauthn/util/SelectCredentialDialogFragment.java index 4b87058..fc3f6d3 100644 --- a/src/main/java/duo/labs/webauthn/util/SelectCredentialDialogFragment.java +++ b/src/main/java/duo/labs/webauthn/util/SelectCredentialDialogFragment.java @@ -4,8 +4,8 @@ import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentActivity; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentActivity; import android.util.Log; import java.lang.ref.WeakReference; diff --git a/src/main/java/duo/labs/webauthn/util/database/CredentialDao.java b/src/main/java/duo/labs/webauthn/util/database/CredentialDao.java index 191a52b..ac88669 100644 --- a/src/main/java/duo/labs/webauthn/util/database/CredentialDao.java +++ b/src/main/java/duo/labs/webauthn/util/database/CredentialDao.java @@ -1,12 +1,12 @@ package duo.labs.webauthn.util.database; -import android.arch.lifecycle.LiveData; -import android.arch.persistence.room.Dao; -import android.arch.persistence.room.Delete; -import android.arch.persistence.room.Insert; -import android.arch.persistence.room.Query; -import android.arch.persistence.room.Transaction; -import android.arch.persistence.room.Update; +import androidx.lifecycle.LiveData; +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.Query; +import androidx.room.Transaction; +import androidx.room.Update; import java.util.List; diff --git a/src/main/java/duo/labs/webauthn/util/database/CredentialDatabase.java b/src/main/java/duo/labs/webauthn/util/database/CredentialDatabase.java index d53a886..b3b0b60 100644 --- a/src/main/java/duo/labs/webauthn/util/database/CredentialDatabase.java +++ b/src/main/java/duo/labs/webauthn/util/database/CredentialDatabase.java @@ -1,9 +1,9 @@ package duo.labs.webauthn.util.database; -import android.arch.persistence.room.Database; -import android.arch.persistence.room.Room; -import android.arch.persistence.room.RoomDatabase; +import androidx.room.Database; +import androidx.room.Room; +import androidx.room.RoomDatabase; import android.content.Context; import duo.labs.webauthn.models.PublicKeyCredentialSource; diff --git a/src/main/java/duo/labs/webauthn/util/database/CredentialListViewModel.java b/src/main/java/duo/labs/webauthn/util/database/CredentialListViewModel.java index 8b95b47..610765e 100644 --- a/src/main/java/duo/labs/webauthn/util/database/CredentialListViewModel.java +++ b/src/main/java/duo/labs/webauthn/util/database/CredentialListViewModel.java @@ -1,8 +1,8 @@ package duo.labs.webauthn.util.database; import android.app.Application; -import android.arch.lifecycle.AndroidViewModel; -import android.arch.lifecycle.LiveData; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; import android.os.AsyncTask; import java.security.PublicKey;