Updated on 2026-08-14
This commit is contained in:
parent
0594e1b680
commit
a8faaffcab
24 changed files with 561 additions and 61 deletions
|
|
@ -144,6 +144,7 @@ internal class DefaultOnboardingRepository @Inject constructor(
|
|||
currencyCode = fiatBalance.currency,
|
||||
customerWalletAddress = paymentAccount.customerWalletAddress,
|
||||
depositAddress = response.depositAddress,
|
||||
isPinSet = response.card?.isPinSet == true,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
|
|||
|
|
@ -82,12 +82,14 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
block = {
|
||||
val publicKeyBase64 = getPublicKeyBase64()
|
||||
val (secretKeyBytes, sessionId) = rainCryptoUtil.generateSecretKeyAndSessionId(publicKeyBase64)
|
||||
val result = requestHelper.performRequest(userWalletId = userWalletId) { authHeader ->
|
||||
tangemPayApi.revealCardDetails(
|
||||
authHeader = authHeader,
|
||||
body = CardDetailsRequest(sessionId = sessionId),
|
||||
)
|
||||
}.getOrNull()?.result ?: error("Cannot reveal card details")
|
||||
val result = requireNotNull(
|
||||
requestHelper.performRequest(userWalletId = userWalletId) { authHeader ->
|
||||
tangemPayApi.revealCardDetails(
|
||||
authHeader = authHeader,
|
||||
body = CardDetailsRequest(sessionId = sessionId),
|
||||
)
|
||||
}.getOrNull()?.result,
|
||||
)
|
||||
|
||||
val pan = rainCryptoUtil.decryptSecret(
|
||||
base64Secret = result.pan.secret,
|
||||
|
|
@ -113,6 +115,38 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
override suspend fun getPin(userWalletId: UserWalletId, cardId: String): Either<UniversalError, String?> {
|
||||
return catch(
|
||||
block = {
|
||||
val publicKeyBase64 = getPublicKeyBase64()
|
||||
val (secretKeyBytes, sessionId) = rainCryptoUtil.generateSecretKeyAndSessionId(publicKeyBase64)
|
||||
val result = requireNotNull(
|
||||
requestHelper.performRequest(userWalletId = userWalletId) { authHeader ->
|
||||
tangemPayApi.revealCardDetails(
|
||||
authHeader = authHeader,
|
||||
body = CardDetailsRequest(sessionId = sessionId),
|
||||
)
|
||||
}.getOrNull()?.result,
|
||||
)
|
||||
|
||||
val encryptedPin = result.pin
|
||||
val pin = if (encryptedPin != null) {
|
||||
rainCryptoUtil.decryptPin(
|
||||
base64Secret = encryptedPin.secret,
|
||||
base64Iv = encryptedPin.iv,
|
||||
secretKeyBytes = secretKeyBytes,
|
||||
).takeIf { !it.isNullOrEmpty() }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
secretKeyBytes.fill(0)
|
||||
|
||||
pin.right()
|
||||
},
|
||||
catch = ::catchException,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun setPin(userWalletId: UserWalletId, pin: String): Either<UniversalError, SetPinResult> {
|
||||
return requestHelper.runWithErrorLogs(TAG) {
|
||||
val publicKeyBase64 = getPublicKeyBase64()
|
||||
|
|
@ -120,16 +154,18 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
val encryptedData = rainCryptoUtil.encryptPin(pin = pin, secretKeyBytes = secretKeyBytes)
|
||||
secretKeyBytes.fill(0)
|
||||
|
||||
val status = requestHelper.request(userWalletId) { authHeader ->
|
||||
tangemPayApi.setPin(
|
||||
authHeader = authHeader,
|
||||
body = SetPinRequest(
|
||||
sessionId = sessionId,
|
||||
pin = encryptedData.encryptedBase64,
|
||||
iv = encryptedData.ivBase64,
|
||||
),
|
||||
)
|
||||
}.result?.result ?: error("Cannot set pin code")
|
||||
val status = requireNotNull(
|
||||
requestHelper.request(userWalletId) { authHeader ->
|
||||
tangemPayApi.setPin(
|
||||
authHeader = authHeader,
|
||||
body = SetPinRequest(
|
||||
sessionId = sessionId,
|
||||
pin = encryptedData.encryptedBase64,
|
||||
iv = encryptedData.ivBase64,
|
||||
),
|
||||
)
|
||||
}.result?.result,
|
||||
)
|
||||
when (status) {
|
||||
SetPinResult.SUCCESS.name -> SetPinResult.SUCCESS
|
||||
SetPinResult.PIN_TOO_WEAK.name -> SetPinResult.PIN_TOO_WEAK
|
||||
|
|
|
|||
|
|
@ -37,6 +37,15 @@ internal class RainCryptoUtil @Inject constructor(
|
|||
secretKeyBytes to sessionId
|
||||
}
|
||||
|
||||
suspend fun decryptPin(base64Secret: String, base64Iv: String, secretKeyBytes: ByteArray): String? {
|
||||
val pinBlock = decryptSecret(
|
||||
base64Secret = base64Secret,
|
||||
base64Iv = base64Iv,
|
||||
secretKeyBytes = secretKeyBytes,
|
||||
)
|
||||
return extractPinFromPinBlock(pinBlock)
|
||||
}
|
||||
|
||||
suspend fun encryptPin(pin: String, secretKeyBytes: ByteArray): EncryptedData = withContext(dispatchers.default) {
|
||||
val bytes = pinBlockByteArray(pin)
|
||||
try {
|
||||
|
|
@ -113,6 +122,17 @@ internal class RainCryptoUtil @Inject constructor(
|
|||
return hex.toByteArray(StandardCharsets.UTF_8)
|
||||
}
|
||||
|
||||
private suspend fun extractPinFromPinBlock(pinBlock: String): String? = withContext(dispatchers.default) {
|
||||
val pinLength = pinBlock[1].digitToIntOrNull()
|
||||
require(pinLength == PIN_LENGTH) { "Unexpected PIN length: ${pinBlock[1]}" }
|
||||
|
||||
val pinStartIndex = 2
|
||||
val pinEndIndex = pinStartIndex + pinLength
|
||||
val pin = pinBlock.substring(pinStartIndex, pinEndIndex)
|
||||
|
||||
pin.takeIf { value -> value.all { it.isDigit() } && value.length == PIN_LENGTH }
|
||||
}
|
||||
|
||||
private fun ByteArray.clear() {
|
||||
for (i in indices) this[i] = 0
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue