diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ebc1ec5..984e195 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -21,6 +21,9 @@ android { vectorDrawables { useSupportLibrary = true } + + // Developer ID for VivoKey verify API (example/test ID) + buildConfigField("String", "VIVOKEY_DEV_ID", "\"YOUR_DEVELOPER_ID_HERE\"") } buildTypes { @@ -41,6 +44,7 @@ android { } buildFeatures { compose = true + buildConfig = true } composeOptions { kotlinCompilerExtensionVersion = "1.5.15" diff --git a/app/src/main/java/com/hoker/intra_example/presentation/IntraExampleActivity.kt b/app/src/main/java/com/hoker/intra_example/presentation/IntraExampleActivity.kt index f68cdda..718f909 100644 --- a/app/src/main/java/com/hoker/intra_example/presentation/IntraExampleActivity.kt +++ b/app/src/main/java/com/hoker/intra_example/presentation/IntraExampleActivity.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel -import com.hoker.intra.domain.NfcActivity +import com.vivokey.intra.domain.NfcActivity import com.hoker.intra_example.presentation.components.OperationTypeBottomBar import com.hoker.supra.presentation.scaffolds.SupraGyroScaffold import com.hoker.supra.presentation.scaffolds.SupraScaffold diff --git a/app/src/main/java/com/hoker/intra_example/presentation/IntraExampleViewModel.kt b/app/src/main/java/com/hoker/intra_example/presentation/IntraExampleViewModel.kt index 0eb95e1..02a16de 100644 --- a/app/src/main/java/com/hoker/intra_example/presentation/IntraExampleViewModel.kt +++ b/app/src/main/java/com/hoker/intra_example/presentation/IntraExampleViewModel.kt @@ -4,10 +4,11 @@ import android.nfc.Tag import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.viewModelScope -import com.hoker.intra.domain.NfcAdapterController -import com.hoker.intra.domain.NfcController -import com.hoker.intra.domain.NfcViewModel -import com.hoker.intra.domain.OperationResult +import com.vivokey.intra.domain.NfcAdapterController +import com.vivokey.intra.domain.NfcController +import com.vivokey.intra.domain.NfcViewModel +import com.vivokey.intra.domain.OperationResult +import com.hoker.intra_example.BuildConfig import com.hoker.intra_example.domain.models.OperationType import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers @@ -45,7 +46,7 @@ class IntraExampleViewModel @Inject constructor( nfcController.withConnection(tag) { when (_selectedCommand.value) { OperationType.JWT -> { - when (val result = nfcController.getVivokeyJwt(tag)) { + when (val result = nfcController.getVivokeyJwt(tag, BuildConfig.VIVOKEY_DEV_ID)) { is OperationResult.Success -> { _output.value = result.data } diff --git a/intra/build.gradle.kts b/intra/build.gradle.kts index 9f0cafb..7c61a66 100644 --- a/intra/build.gradle.kts +++ b/intra/build.gradle.kts @@ -7,7 +7,7 @@ plugins { } android { - namespace = "com.carbidecowboy.intra" + namespace = "com.vivokey.intra" compileSdk = 36 defaultConfig { @@ -59,9 +59,9 @@ afterEvaluate { publications { create("release") { from(components["release"]) - groupId = "com.github.h0ker" + groupId = "com.github.vivokey" artifactId = "Intra" - version = "1.3.9" + version = "2.0.0" } } } diff --git a/intra/src/main/java/com/hoker/intra/domain/AuthApiService.kt b/intra/src/main/java/com/hoker/intra/domain/AuthApiService.kt deleted file mode 100644 index e13e722..0000000 --- a/intra/src/main/java/com/hoker/intra/domain/AuthApiService.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.hoker.intra.domain - -import com.hoker.intra.domain.request.ChallengeRequest -import com.hoker.intra.domain.request.SessionRequest -import com.hoker.intra.domain.response.ChallengeResponse -import com.hoker.intra.domain.response.SessionResponse -import retrofit2.Response -import retrofit2.http.Body -import retrofit2.http.POST - -interface AuthApiService { - - @POST("challenge") - suspend fun postChallenge(@Body challengeRequest: ChallengeRequest): Response - - @POST("session") - suspend fun postSession(@Body sessionRequest: SessionRequest): Response -} \ No newline at end of file diff --git a/intra/src/main/java/com/hoker/intra/domain/request/SessionRequest.kt b/intra/src/main/java/com/hoker/intra/domain/request/SessionRequest.kt deleted file mode 100644 index dd2b023..0000000 --- a/intra/src/main/java/com/hoker/intra/domain/request/SessionRequest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.hoker.intra.domain.request - -data class SessionRequest( - val uid: String, - val response: String, - val token: String, - val cld: String? = null -) diff --git a/intra/src/main/java/com/hoker/intra/domain/response/SessionResponse.kt b/intra/src/main/java/com/hoker/intra/domain/response/SessionResponse.kt deleted file mode 100644 index 3d68561..0000000 --- a/intra/src/main/java/com/hoker/intra/domain/response/SessionResponse.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.hoker.intra.domain.response - -data class SessionResponse ( - val token: String -) \ No newline at end of file diff --git a/intra/src/main/java/com/hoker/intra/data/IsodepControllerImpl.kt b/intra/src/main/java/com/vivokey/intra/data/IsodepControllerImpl.kt similarity index 91% rename from intra/src/main/java/com/hoker/intra/data/IsodepControllerImpl.kt rename to intra/src/main/java/com/vivokey/intra/data/IsodepControllerImpl.kt index ddbe148..8aef4fa 100644 --- a/intra/src/main/java/com/hoker/intra/data/IsodepControllerImpl.kt +++ b/intra/src/main/java/com/vivokey/intra/data/IsodepControllerImpl.kt @@ -1,19 +1,19 @@ -package com.hoker.intra.data +package com.vivokey.intra.data import android.nfc.NdefMessage import android.nfc.Tag import android.nfc.tech.IsoDep import android.nfc.tech.Ndef import android.util.Log -import com.hoker.intra.di.IntraAuthApiService -import com.hoker.intra.domain.ApduUtils -import com.hoker.intra.domain.AuthApiService -import com.hoker.intra.domain.Consts -import com.hoker.intra.domain.NfcController -import com.hoker.intra.domain.OperationResult -import com.hoker.intra.domain.Timer -import com.hoker.intra.domain.request.ChallengeRequest -import com.hoker.intra.domain.request.SessionRequest +import com.vivokey.intra.di.IntraAuthApiService +import com.vivokey.intra.domain.ApduUtils +import com.vivokey.intra.domain.AuthApiService +import com.vivokey.intra.domain.Consts +import com.vivokey.intra.domain.NfcController +import com.vivokey.intra.domain.OperationResult +import com.vivokey.intra.domain.Timer +import com.vivokey.intra.domain.request.AuthenticateRequest +import com.vivokey.intra.domain.request.ChallengeRequest import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.async @@ -66,7 +66,7 @@ class IsodepControllerImpl @Inject constructor( it.timeout = 20000 _connectionStatus.emit(true) startConnectionCheckJob() - OperationResult.Success(Unit) + return OperationResult.Success(Unit) } OperationResult.Failure(Exception("IsoDep.connect() came back as null")) } catch (e: Exception) { @@ -138,6 +138,7 @@ class IsodepControllerImpl @Inject constructor( override suspend fun getVivokeyJwt( tag: Tag, + devId: String, cld: String? ): OperationResult { return try { @@ -239,25 +240,27 @@ class IsodepControllerImpl @Inject constructor( } responseString?.let { - val sessionRequest = SessionRequest( - uid = uid, - response = responseString, + // Use /authenticate endpoint with developer ID + // Returns encrypted JWE that must be sent to server for decryption + val authenticateRequest = AuthenticateRequest( token = challengeResponse.token, - cld = cld + response = responseString, + uid = uid, + dev_id = devId ) - val sessionResponse = async { - authApiService.postSession(sessionRequest) + val authenticateResponse = async { + authApiService.postAuthenticate(authenticateRequest) }.await() - if (!sessionResponse.isSuccessful) { + if (!authenticateResponse.isSuccessful) { OperationResult.Failure() } - val result = sessionResponse.body() - result?.token?.let { jwt -> - Log.i("JWT:", jwt) - return@withContext OperationResult.Success(jwt) + val result = authenticateResponse.body() + result?.token?.let { jwe -> + Log.i("JWE:", jwe) // This is encrypted - cannot be decoded by mobile app + return@withContext OperationResult.Success(jwe) } } @@ -385,4 +388,4 @@ class IsodepControllerImpl @Inject constructor( private fun stopConnectionCheckJob() { timerJob?.cancel() } -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/hoker/intra/data/NfcAControllerImpl.kt b/intra/src/main/java/com/vivokey/intra/data/NfcAControllerImpl.kt similarity index 96% rename from intra/src/main/java/com/hoker/intra/data/NfcAControllerImpl.kt rename to intra/src/main/java/com/vivokey/intra/data/NfcAControllerImpl.kt index 8375192..51f0350 100644 --- a/intra/src/main/java/com/hoker/intra/data/NfcAControllerImpl.kt +++ b/intra/src/main/java/com/vivokey/intra/data/NfcAControllerImpl.kt @@ -1,14 +1,14 @@ -package com.hoker.intra.data +package com.vivokey.intra.data import android.nfc.NdefMessage import android.nfc.Tag import android.nfc.tech.Ndef import android.nfc.tech.NfcA import android.util.Log -import com.hoker.intra.domain.ApduUtils -import com.hoker.intra.domain.NfcController -import com.hoker.intra.domain.OperationResult -import com.hoker.intra.domain.Timer +import com.vivokey.intra.domain.ApduUtils +import com.vivokey.intra.domain.NfcController +import com.vivokey.intra.domain.OperationResult +import com.vivokey.intra.domain.Timer import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -38,7 +38,7 @@ class NfcAControllerImpl @Inject constructor( Log.i("ApexConnection", "----NFC_A CONNECTED") startConnectionCheckJob() _connectionStatus.emit(true) - OperationResult.Success(Unit) + return OperationResult.Success(Unit) } OperationResult.Failure(Exception("NfcA.connect() came back as null")) } catch (e: Exception) { @@ -219,6 +219,7 @@ class NfcAControllerImpl @Inject constructor( override suspend fun getVivokeyJwt( tag: Tag, + devId: String, cld: String? ): OperationResult { return OperationResult.Failure(Exception("This operation is not currently supported with NfcA")) @@ -261,4 +262,4 @@ class NfcAControllerImpl @Inject constructor( OperationResult.Failure(e) } } -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/hoker/intra/data/NfcVControllerImpl.kt b/intra/src/main/java/com/vivokey/intra/data/NfcVControllerImpl.kt similarity index 85% rename from intra/src/main/java/com/hoker/intra/data/NfcVControllerImpl.kt rename to intra/src/main/java/com/vivokey/intra/data/NfcVControllerImpl.kt index 34f8e4a..f453a27 100644 --- a/intra/src/main/java/com/hoker/intra/data/NfcVControllerImpl.kt +++ b/intra/src/main/java/com/vivokey/intra/data/NfcVControllerImpl.kt @@ -1,19 +1,19 @@ -package com.hoker.intra.data +package com.vivokey.intra.data import android.nfc.NdefMessage import android.nfc.Tag import android.nfc.tech.Ndef import android.nfc.tech.NfcV import android.util.Log -import com.hoker.intra.di.IntraAuthApiService -import com.hoker.intra.domain.ApduUtils -import com.hoker.intra.domain.AuthApiService -import com.hoker.intra.domain.Consts.FUNCTION_NOT_SUPPORTED -import com.hoker.intra.domain.NfcController -import com.hoker.intra.domain.OperationResult -import com.hoker.intra.domain.Timer -import com.hoker.intra.domain.request.ChallengeRequest -import com.hoker.intra.domain.request.SessionRequest +import com.vivokey.intra.di.IntraAuthApiService +import com.vivokey.intra.domain.ApduUtils +import com.vivokey.intra.domain.AuthApiService +import com.vivokey.intra.domain.Consts.FUNCTION_NOT_SUPPORTED +import com.vivokey.intra.domain.NfcController +import com.vivokey.intra.domain.OperationResult +import com.vivokey.intra.domain.Timer +import com.vivokey.intra.domain.request.AuthenticateRequest +import com.vivokey.intra.domain.request.ChallengeRequest import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.async @@ -71,7 +71,7 @@ class NfcVControllerImpl @Inject constructor( it.connect() startConnectionCheckJob() _connectionStatus.emit(true) - OperationResult.Success(Unit) + return OperationResult.Success(Unit) } OperationResult.Failure(Exception("NfcV.connect() came back as null")) } catch (e: Exception) { @@ -186,13 +186,14 @@ class NfcVControllerImpl @Inject constructor( override suspend fun getVivokeyJwt( tag: Tag, + devId: String, cld: String? ): OperationResult { return try { withContext(Dispatchers.IO) { - //get challenge from + // Get challenge from API (scheme 1 for NfcV/Spark 1) val challengeRequest = ChallengeRequest(1) val challengeResponse = async { authApiService.postChallenge(challengeRequest).body() @@ -224,27 +225,33 @@ class NfcVControllerImpl @Inject constructor( // connect and send command Log.i("Command", Hex.encodeHexString(command)) val response = nfcV?.transceive(command) + ?: return@withContext OperationResult.Failure(Exception("NFC connection lost - please scan again")) Log.i("Response", Hex.encodeHexString(response)) - val sessionRequest = SessionRequest( - uid = Hex.encodeHexString(tag.id!!.reversedArray()), + val tagId = tag.id + ?: return@withContext OperationResult.Failure(Exception("Unable to read tag ID")) + + // Use /authenticate endpoint with developer ID + // Returns encrypted JWE that must be sent to server for decryption + val authenticateRequest = AuthenticateRequest( + uid = Hex.encodeHexString(tagId.reversedArray()), response = Hex.encodeHexString(response), token = challengeResponse.token, - cld = cld + dev_id = devId ) - val sessionResponse = async { - authApiService.postSession(sessionRequest) + val authenticateResponse = async { + authApiService.postAuthenticate(authenticateRequest) }.await() - if (!sessionResponse.isSuccessful) { + if (!authenticateResponse.isSuccessful) { OperationResult.Failure() } - val result = sessionResponse.body() - result?.token?.let { jwt -> - println(jwt) - return@withContext OperationResult.Success(jwt) + val result = authenticateResponse.body() + result?.token?.let { jwe -> + println(jwe) + return@withContext OperationResult.Success(jwe) } OperationResult.Failure() @@ -296,4 +303,4 @@ class NfcVControllerImpl @Inject constructor( OperationResult.Failure(e) } } -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/hoker/intra/di/NetworkModule.kt b/intra/src/main/java/com/vivokey/intra/di/NetworkModule.kt similarity index 68% rename from intra/src/main/java/com/hoker/intra/di/NetworkModule.kt rename to intra/src/main/java/com/vivokey/intra/di/NetworkModule.kt index d8c1e5a..b40e9d3 100644 --- a/intra/src/main/java/com/hoker/intra/di/NetworkModule.kt +++ b/intra/src/main/java/com/vivokey/intra/di/NetworkModule.kt @@ -1,6 +1,6 @@ -package com.hoker.intra.di +package com.vivokey.intra.di -import com.hoker.intra.domain.AuthApiService +import com.vivokey.intra.domain.AuthApiService import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -27,22 +27,13 @@ annotation class IntraAuthApiService @InstallIn(SingletonComponent::class) object NetworkModule { - private const val AUTH_BASE_URL = "https://auth.vivokey.com/" - private const val API_HEADER = "X-API-VIVOKEY" - private const val API_KEY = "9e084e64-eb74-41b8-a87d-4c0bdcd1be64" + private const val API_BASE_URL = "https://auth.vivokey.com/" @Provides @Singleton @IntraOkHttp fun provideOkHttpClient(): OkHttpClient { return OkHttpClient.Builder() - .addInterceptor { chain -> - val originalRequest = chain.request() - val newRequest = originalRequest.newBuilder() - .header(API_HEADER, API_KEY) - .build() - chain.proceed(newRequest) - } .build() } @@ -51,7 +42,7 @@ object NetworkModule { @IntraAuthRetrofit fun provideAuthRetrofit(@IntraOkHttp okHttpClient: OkHttpClient): Retrofit { return Retrofit.Builder() - .baseUrl(AUTH_BASE_URL) + .baseUrl(API_BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .client(okHttpClient) .build() @@ -63,4 +54,4 @@ object NetworkModule { fun provideAuthApiService(@IntraAuthRetrofit retrofit: Retrofit): AuthApiService { return retrofit.create(AuthApiService::class.java) } -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/hoker/intra/di/NfcModule.kt b/intra/src/main/java/com/vivokey/intra/di/NfcModule.kt similarity index 90% rename from intra/src/main/java/com/hoker/intra/di/NfcModule.kt rename to intra/src/main/java/com/vivokey/intra/di/NfcModule.kt index 57eb95b..4b77b18 100644 --- a/intra/src/main/java/com/hoker/intra/di/NfcModule.kt +++ b/intra/src/main/java/com/vivokey/intra/di/NfcModule.kt @@ -1,4 +1,4 @@ -package com.hoker.intra.di +package com.vivokey.intra.di import android.content.Context import android.nfc.NfcAdapter @@ -6,12 +6,12 @@ import android.nfc.Tag import android.nfc.tech.IsoDep import android.nfc.tech.NfcA import android.nfc.tech.NfcV -import com.hoker.intra.data.IsodepControllerImpl -import com.hoker.intra.data.NfcAControllerImpl -import com.hoker.intra.data.NfcVControllerImpl -import com.hoker.intra.domain.NfcAdapterController -import com.hoker.intra.domain.NfcController -import com.hoker.intra.domain.OperationResult +import com.vivokey.intra.data.IsodepControllerImpl +import com.vivokey.intra.data.NfcAControllerImpl +import com.vivokey.intra.data.NfcVControllerImpl +import com.vivokey.intra.domain.NfcAdapterController +import com.vivokey.intra.domain.NfcController +import com.vivokey.intra.domain.OperationResult import dagger.Binds import dagger.Module import dagger.Provides @@ -102,4 +102,4 @@ abstract class NfcModule { } } } -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/hoker/intra/domain/ApduUtils.kt b/intra/src/main/java/com/vivokey/intra/domain/ApduUtils.kt similarity index 97% rename from intra/src/main/java/com/hoker/intra/domain/ApduUtils.kt rename to intra/src/main/java/com/vivokey/intra/domain/ApduUtils.kt index 23f9767..76f30a0 100644 --- a/intra/src/main/java/com/hoker/intra/domain/ApduUtils.kt +++ b/intra/src/main/java/com/vivokey/intra/domain/ApduUtils.kt @@ -1,4 +1,4 @@ -package com.hoker.intra.domain +package com.vivokey.intra.domain import java.io.IOException import java.nio.ByteBuffer @@ -43,4 +43,4 @@ class ApduUtils { data class ApduResponse(val data: ByteArray, val statusCode: Int) } -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/vivokey/intra/domain/AuthApiService.kt b/intra/src/main/java/com/vivokey/intra/domain/AuthApiService.kt new file mode 100644 index 0000000..e8a6947 --- /dev/null +++ b/intra/src/main/java/com/vivokey/intra/domain/AuthApiService.kt @@ -0,0 +1,23 @@ +package com.vivokey.intra.domain + +import com.vivokey.intra.domain.request.AuthenticateRequest +import com.vivokey.intra.domain.request.ChallengeRequest +import com.vivokey.intra.domain.response.AuthenticateResponse +import com.vivokey.intra.domain.response.ChallengeResponse +import retrofit2.Response +import retrofit2.http.Body +import retrofit2.http.POST + +interface AuthApiService { + + @POST("challenge") + suspend fun postChallenge(@Body challengeRequest: ChallengeRequest): Response + + /** + * Authenticate with the VivoKey verify API using the encrypted JWE flow. + * Returns an encrypted JWE token that must be decrypted by your server. + * The mobile app passes the developer ID (dev_id) but never has the API key. + */ + @POST("authenticate") + suspend fun postAuthenticate(@Body authenticateRequest: AuthenticateRequest): Response +} diff --git a/intra/src/main/java/com/hoker/intra/domain/Consts.kt b/intra/src/main/java/com/vivokey/intra/domain/Consts.kt similarity index 98% rename from intra/src/main/java/com/hoker/intra/domain/Consts.kt rename to intra/src/main/java/com/vivokey/intra/domain/Consts.kt index 1beb112..7e8332c 100644 --- a/intra/src/main/java/com/hoker/intra/domain/Consts.kt +++ b/intra/src/main/java/com/vivokey/intra/domain/Consts.kt @@ -1,4 +1,4 @@ -package com.hoker.intra.domain +package com.vivokey.intra.domain object Consts { const val SUCCESS_RESPONSE = "9000" @@ -45,4 +45,4 @@ object Consts { const val GET_UID_APDU = "FFCA000000" const val GET_ATS_APDU = "FFCA010000" const val TEST_NFC_A_ATR = "3B8F8001804F0CA0000003060300030000000068" -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/hoker/intra/domain/NfcActivity.kt b/intra/src/main/java/com/vivokey/intra/domain/NfcActivity.kt similarity index 93% rename from intra/src/main/java/com/hoker/intra/domain/NfcActivity.kt rename to intra/src/main/java/com/vivokey/intra/domain/NfcActivity.kt index a8765d2..29993c7 100644 --- a/intra/src/main/java/com/hoker/intra/domain/NfcActivity.kt +++ b/intra/src/main/java/com/vivokey/intra/domain/NfcActivity.kt @@ -1,10 +1,10 @@ -package com.hoker.intra.domain +package com.vivokey.intra.domain import android.os.Bundle import android.os.PersistableBundle import android.widget.Toast import androidx.activity.ComponentActivity -import com.hoker.intra.di.NfcModule +import com.vivokey.intra.di.NfcModule import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.delay import javax.inject.Inject @@ -37,4 +37,4 @@ abstract class NfcActivity : ComponentActivity() { delay(500) nfcAdapterController.enableNfc(this) } -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/hoker/intra/domain/NfcAdapterController.kt b/intra/src/main/java/com/vivokey/intra/domain/NfcAdapterController.kt similarity index 97% rename from intra/src/main/java/com/hoker/intra/domain/NfcAdapterController.kt rename to intra/src/main/java/com/vivokey/intra/domain/NfcAdapterController.kt index 4e75026..ed92159 100644 --- a/intra/src/main/java/com/hoker/intra/domain/NfcAdapterController.kt +++ b/intra/src/main/java/com/vivokey/intra/domain/NfcAdapterController.kt @@ -1,11 +1,11 @@ -package com.hoker.intra.domain +package com.vivokey.intra.domain import android.app.Activity import android.nfc.NfcAdapter import android.nfc.Tag import android.os.Bundle import android.util.Log -import com.hoker.intra.di.NfcModule +import com.vivokey.intra.di.NfcModule import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow import javax.inject.Inject @@ -90,4 +90,4 @@ open class NfcAdapterController @Inject constructor( } Log.i(this@NfcAdapterController::class.simpleName, log) } -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/hoker/intra/domain/NfcController.kt b/intra/src/main/java/com/vivokey/intra/domain/NfcController.kt similarity index 86% rename from intra/src/main/java/com/hoker/intra/domain/NfcController.kt rename to intra/src/main/java/com/vivokey/intra/domain/NfcController.kt index b224b3e..63a7e33 100644 --- a/intra/src/main/java/com/hoker/intra/domain/NfcController.kt +++ b/intra/src/main/java/com/vivokey/intra/domain/NfcController.kt @@ -1,4 +1,4 @@ -package com.hoker.intra.domain +package com.vivokey.intra.domain import android.nfc.NdefMessage import android.nfc.Tag @@ -16,9 +16,19 @@ interface NfcController { suspend fun issueApdu(instruction: Byte, p1: Byte = 0, p2: Byte = 0, data: ByteBuffer.() -> Unit = {}): OperationResult suspend fun transceive(data: ByteArray): OperationResult suspend fun writeNdefMessage(tag: Tag, message: NdefMessage): OperationResult + /** + * Authenticates with VivoKey verify API and returns an encrypted JWE. + * The JWE must be sent to your server for decryption - mobile app cannot decrypt it. + * + * @param tag The NFC tag to authenticate + * @param devId The developer ID for the VivoKey verify API + * @param cld Optional custom client data to include in the JWT (max 2048 chars) + * @return Encrypted JWE token + */ suspend fun getVivokeyJwt( tag: Tag, - cid: String? = null + devId: String, + cld: String? = null ): OperationResult suspend fun getNdefCapacity(ndef: Ndef): OperationResult suspend fun getNdefMessage(ndef: Ndef): OperationResult @@ -82,4 +92,4 @@ interface NfcController { OperationResult.Failure(e) } } -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/hoker/intra/domain/NfcViewModel.kt b/intra/src/main/java/com/vivokey/intra/domain/NfcViewModel.kt similarity index 96% rename from intra/src/main/java/com/hoker/intra/domain/NfcViewModel.kt rename to intra/src/main/java/com/vivokey/intra/domain/NfcViewModel.kt index 75fce08..65ca0e1 100644 --- a/intra/src/main/java/com/hoker/intra/domain/NfcViewModel.kt +++ b/intra/src/main/java/com/vivokey/intra/domain/NfcViewModel.kt @@ -1,4 +1,4 @@ -package com.hoker.intra.domain +package com.vivokey.intra.domain import android.nfc.Tag import androidx.lifecycle.ViewModel @@ -30,4 +30,4 @@ abstract class NfcViewModel( super.onCleared() nfcAdapterController.removeOnTagDiscoveredListener(uuid) } -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/hoker/intra/domain/OperationResult.kt b/intra/src/main/java/com/vivokey/intra/domain/OperationResult.kt similarity index 84% rename from intra/src/main/java/com/hoker/intra/domain/OperationResult.kt rename to intra/src/main/java/com/vivokey/intra/domain/OperationResult.kt index f2aab70..568473c 100644 --- a/intra/src/main/java/com/hoker/intra/domain/OperationResult.kt +++ b/intra/src/main/java/com/vivokey/intra/domain/OperationResult.kt @@ -1,6 +1,6 @@ -package com.hoker.intra.domain +package com.vivokey.intra.domain sealed class OperationResult { data class Success(val data: T) : OperationResult() data class Failure(val exception: Throwable? = null) : OperationResult() -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/hoker/intra/domain/Timer.kt b/intra/src/main/java/com/vivokey/intra/domain/Timer.kt similarity index 97% rename from intra/src/main/java/com/hoker/intra/domain/Timer.kt rename to intra/src/main/java/com/vivokey/intra/domain/Timer.kt index 60c3919..83ec608 100644 --- a/intra/src/main/java/com/hoker/intra/domain/Timer.kt +++ b/intra/src/main/java/com/vivokey/intra/domain/Timer.kt @@ -1,4 +1,4 @@ -package com.hoker.intra.domain +package com.vivokey.intra.domain import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -41,4 +41,4 @@ class Timer @Inject constructor() { } } } -} \ No newline at end of file +} diff --git a/intra/src/main/java/com/vivokey/intra/domain/request/AuthenticateRequest.kt b/intra/src/main/java/com/vivokey/intra/domain/request/AuthenticateRequest.kt new file mode 100644 index 0000000..33f4ad1 --- /dev/null +++ b/intra/src/main/java/com/vivokey/intra/domain/request/AuthenticateRequest.kt @@ -0,0 +1,8 @@ +package com.vivokey.intra.domain.request + +data class AuthenticateRequest( + val token: String, + val response: String, + val uid: String, + val dev_id: String +) diff --git a/intra/src/main/java/com/hoker/intra/domain/request/ChallengeRequest.kt b/intra/src/main/java/com/vivokey/intra/domain/request/ChallengeRequest.kt similarity index 73% rename from intra/src/main/java/com/hoker/intra/domain/request/ChallengeRequest.kt rename to intra/src/main/java/com/vivokey/intra/domain/request/ChallengeRequest.kt index 5f9ef5a..c13b3cc 100644 --- a/intra/src/main/java/com/hoker/intra/domain/request/ChallengeRequest.kt +++ b/intra/src/main/java/com/vivokey/intra/domain/request/ChallengeRequest.kt @@ -1,4 +1,4 @@ -package com.hoker.intra.domain.request +package com.vivokey.intra.domain.request data class ChallengeRequest( val scheme: Int, diff --git a/intra/src/main/java/com/vivokey/intra/domain/response/AuthenticateResponse.kt b/intra/src/main/java/com/vivokey/intra/domain/response/AuthenticateResponse.kt new file mode 100644 index 0000000..e07b22e --- /dev/null +++ b/intra/src/main/java/com/vivokey/intra/domain/response/AuthenticateResponse.kt @@ -0,0 +1,10 @@ +package com.vivokey.intra.domain.response + +/** + * Response from the /authenticate endpoint. + * Contains an encrypted JWE token that must be sent to your server for decryption. + * The mobile app cannot decrypt this token - it's opaque to the client. + */ +data class AuthenticateResponse( + val token: String // Encrypted JWE +) diff --git a/intra/src/main/java/com/hoker/intra/domain/response/ChallengeResponse.kt b/intra/src/main/java/com/vivokey/intra/domain/response/ChallengeResponse.kt similarity index 63% rename from intra/src/main/java/com/hoker/intra/domain/response/ChallengeResponse.kt rename to intra/src/main/java/com/vivokey/intra/domain/response/ChallengeResponse.kt index 2ad20f9..18e9678 100644 --- a/intra/src/main/java/com/hoker/intra/domain/response/ChallengeResponse.kt +++ b/intra/src/main/java/com/vivokey/intra/domain/response/ChallengeResponse.kt @@ -1,6 +1,6 @@ -package com.hoker.intra.domain.response +package com.vivokey.intra.domain.response data class ChallengeResponse( val payload: String, val token: String -) \ No newline at end of file +)