Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -41,6 +44,7 @@ android {
}
buildFeatures {
compose = true
buildConfig = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.15"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down
6 changes: 3 additions & 3 deletions intra/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
}

android {
namespace = "com.carbidecowboy.intra"
namespace = "com.vivokey.intra"
compileSdk = 36

defaultConfig {
Expand Down Expand Up @@ -59,9 +59,9 @@ afterEvaluate {
publications {
create<MavenPublication>("release") {
from(components["release"])
groupId = "com.github.h0ker"
groupId = "com.github.vivokey"
artifactId = "Intra"
version = "1.3.9"
version = "2.0.0"
}
}
}
Expand Down
18 changes: 0 additions & 18 deletions intra/src/main/java/com/hoker/intra/domain/AuthApiService.kt

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -138,6 +138,7 @@ class IsodepControllerImpl @Inject constructor(

override suspend fun getVivokeyJwt(
tag: Tag,
devId: String,
cld: String?
): OperationResult<String> {
return try {
Expand Down Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -385,4 +388,4 @@ class IsodepControllerImpl @Inject constructor(
private fun stopConnectionCheckJob() {
timerJob?.cancel()
}
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -219,6 +219,7 @@ class NfcAControllerImpl @Inject constructor(

override suspend fun getVivokeyJwt(
tag: Tag,
devId: String,
cld: String?
): OperationResult<String> {
return OperationResult.Failure(Exception("This operation is not currently supported with NfcA"))
Expand Down Expand Up @@ -261,4 +262,4 @@ class NfcAControllerImpl @Inject constructor(
OperationResult.Failure(e)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -186,13 +186,14 @@ class NfcVControllerImpl @Inject constructor(

override suspend fun getVivokeyJwt(
tag: Tag,
devId: String,
cld: String?
): OperationResult<String> {
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()
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -296,4 +303,4 @@ class NfcVControllerImpl @Inject constructor(
OperationResult.Failure(e)
}
}
}
}
Loading