Updated on 2026-08-14

This commit is contained in:
Tangem 2020-05-12 11:17:43 +00:00
commit e26bd42888
11 changed files with 100 additions and 21 deletions

View file

@ -183,29 +183,51 @@ class TangemSdk(
}
/**
* This method launches a [WriteUserDataCommand] on a new thread.
* This method launches a [WriteUserDataCommand] on a new thread, writing UserData and UserCounter fields.
*
* This command writes some of UserData, UserProtectedData, UserCounter and UserProtectedCounter fields.
* User_Data and User_ProtectedData are never changed or parsed by the executable code the Tangem COS.
* The App defines purpose of use, format and it's payload. For example, this field may contain cashed information
* User_Data is never changed or parsed by the executable code the Tangem COS.
* The App defines purpose of use, format and its payload. For example, this field may contain cashed information
* from blockchain to accelerate preparing new transaction.
* User_Counter and User_ProtectedCounter are counters, that initial values can be set by App and increased on every signing
* The initial value of User_Counter can be set by an App and increased on every signing
* of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use.
* For example, this fields may contain blockchain nonce value.
*
* Writing of UserCounter and UserData is protected only by PIN1.
* UserProtectedCounter and UserProtectedData need additionally PIN2 to confirmation.
*/
fun writeUserData(
cardId: String,
userData: ByteArray? = null,
userProtectedData: ByteArray? = null,
userCounter: Int? = null,
initialMessage: Message? = null,
callback: (result: CompletionResult<WriteUserDataResponse>) -> Unit
) {
val command = WriteUserDataCommand(userData = userData,userCounter = userCounter)
startSessionWithRunnable(command, cardId, initialMessage, callback)
}
/**
* This method launches a [WriteUserDataCommand] on a new thread,
* writing UserProtectedData and UserProtectedCounter fields.
*
* User_ProtectedData is never changed or parsed by the executable code the Tangem COS.
* The App defines purpose of use, format and its payload. For example, this field may contain cashed information
* from blockchain to accelerate preparing new transaction.
* The initial value of User_ProtectedCounter can be set by an App and increased on every signing
* of a new transaction (on SIGN command that calculate new signatures). The App defines the purpose of use.
* For example, this fields may contain blockchain nonce value.
*
* UserProtectedCounter and UserProtectedData require PIN2 for confirmation.
*/
fun writeProtectedUserData(
cardId: String,
userProtectedData: ByteArray? = null,
userProtectedCounter: Int? = null,
initialMessage: Message? = null,
callback: (result: CompletionResult<WriteUserDataResponse>) -> Unit
) {
val command = WriteUserDataCommand(userData, userProtectedData, userCounter, userProtectedCounter)
val command = WriteUserDataCommand(
userProtectedData = userProtectedData, userProtectedCounter = userProtectedCounter
)
startSessionWithRunnable(command, cardId, initialMessage, callback)
}

View file

@ -50,9 +50,7 @@ class TestUserDataActivity : AppCompatActivity() {
tangemSdk.writeUserData(
writeOptions.cardId!!,
writeOptions.userData,
writeOptions.userProtectedData,
writeOptions.userCounter,
writeOptions.userProtectedCounter
writeOptions.userCounter
) {
when (it) {
is CompletionResult.Failure -> handleError(tv_write_result, it.error)

View file

@ -71,7 +71,8 @@ class ActionListFragment : BaseFragment() {
ActionType.ReadIssuerExData,
ActionType.WriteIssuerExData,
ActionType.ReadUserData,
ActionType.WriteUserData
ActionType.WriteUserData,
ActionType.WriteProtectedUserData
)
}
}

View file

@ -11,12 +11,10 @@ class WriteUserDataAction : BaseAction() {
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
val userData = (attrs.itemList.findItem(TlvId.UserData)?.getData() as? String)?.toByteArray()
?: return
val protectedUserData = (attrs.itemList.findItem(TlvId.ProtectedUserData)?.getData() as? String)?.toByteArray()
?: return
val cardId = attrs.itemList.findItem(TlvId.CardId)?.viewModel?.data ?: return
val counter = (attrs.itemList.findItem(TlvId.Counter)?.viewModel?.data as? Int) ?: 1
attrs.tangemSdk.writeUserData(stringOf(cardId), userData, protectedUserData, counter, counter) {
attrs.tangemSdk.writeUserData(stringOf(cardId), userData, counter) {
handleResult(payload, it, null, attrs, callback)
}
}
@ -24,7 +22,6 @@ class WriteUserDataAction : BaseAction() {
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
return when (id) {
TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) }
TlvId.Counter -> { callback -> ReadUserDataAction().executeMainAction(payload, attrs, callback) }
else -> null
}
}

View file

@ -0,0 +1,29 @@
package com.tangem.devkit.ucase.domain.actions
import com.tangem.devkit._arch.structure.Id
import com.tangem.devkit._arch.structure.PayloadHolder
import com.tangem.devkit._arch.structure.abstraction.findItem
import com.tangem.devkit.ucase.domain.paramsManager.ActionCallback
import com.tangem.devkit.ucase.variants.TlvId
import ru.dev.gbixahue.eu4d.lib.kotlin.stringOf
class WriteUserProtectedDataAction : BaseAction() {
override fun executeMainAction(payload: PayloadHolder, attrs: AttrForAction, callback: ActionCallback) {
val protectedUserData = (attrs.itemList.findItem(TlvId.ProtectedUserData)?.getData() as? String)?.toByteArray()
?: return
val cardId = attrs.itemList.findItem(TlvId.CardId)?.viewModel?.data ?: return
val counter = (attrs.itemList.findItem(TlvId.Counter)?.viewModel?.data as? Int) ?: 1
attrs.tangemSdk.writeProtectedUserData(stringOf(cardId), protectedUserData, counter) {
handleResult(payload, it, null, attrs, callback)
}
}
override fun getActionByTag(payload: PayloadHolder, id: Id, attrs: AttrForAction): ((ActionCallback) -> Unit)? {
return when (id) {
TlvId.CardId -> { callback -> ScanAction().executeMainAction(payload, attrs, callback) }
else -> null
}
}
}

View file

@ -96,9 +96,18 @@ class WriteUserDataItemsManager : BaseItemsManager(WriteUserDataAction()) {
setItems(listOf(
EditTextItem(TlvId.CardId, null),
EditTextItem(TlvId.Counter, "1"),
EditTextItem(TlvId.UserData, "User data to be written on a card"),
EditTextItem(TlvId.ProtectedUserData, "Protected user data to be written on a card")
EditTextItem(TlvId.UserData, "User data to be written on a card")
))
}
}
class WriteProtectedUserDataItemsManager : BaseItemsManager(WriteUserProtectedDataAction()) {
init {
setItemChangeConsequences(CardIdConsequence())
setItems(listOf(
EditTextItem(TlvId.CardId, null),
EditTextItem(TlvId.Counter, "1"),
EditTextItem(TlvId.ProtectedUserData, "Protected user data to be written on a card")
))
}
}

View file

@ -16,6 +16,7 @@ enum class ActionType : Id {
WriteIssuerExData,
ReadUserData,
WriteUserData,
WriteProtectedUserData,
Personalize,
Depersonalize,
Unknown,

View file

@ -24,6 +24,7 @@ class ActionResources {
holder.register(ActionType.WriteIssuerExData, ActionRes(R.string.action_issuer_write_ex_data, R.string.info_action_issuer_write_ex_data, R.id.action_nav_entry_point_to_nav_issuer_write_ex_data))
holder.register(ActionType.ReadUserData, ActionRes(R.string.action_user_read_data, R.string.info_action_user_read_data, R.id.action_nav_entry_point_to_nav_user_read_data))
holder.register(ActionType.WriteUserData, ActionRes(R.string.action_user_write_data, R.string.info_action_user_write_data, R.id.action_nav_entry_point_to_nav_user_write_data))
holder.register(ActionType.WriteProtectedUserData, ActionRes(R.string.action_user_write_protected_data, R.string.info_action_user_write_protected_data, R.id.action_nav_entry_point_to_nav_user_write_protected_data))
// holder.register(ActionType.Unknown, getIfNotContains())
}
}

View file

@ -0,0 +1,10 @@
package com.tangem.devkit.ucase.variants.userdata.ui
import com.tangem.devkit.ucase.domain.paramsManager.ItemsManager
import com.tangem.devkit.ucase.domain.paramsManager.managers.WriteProtectedUserDataItemsManager
import com.tangem.devkit.ucase.ui.BaseCardActionFragment
class WriteProtectedUserDataFragment : BaseCardActionFragment() {
override val itemsManager: ItemsManager by lazy { WriteProtectedUserDataItemsManager() }
}

View file

@ -44,6 +44,9 @@
<action
android:id="@+id/action_nav_entry_point_to_nav_user_write_data"
app:destination="@id/nav_user_write_data" />
<action
android:id="@+id/action_nav_entry_point_to_nav_user_write_protected_data"
app:destination="@id/nav_user_write_protected_data" />
<action
android:id="@+id/action_nav_entry_point_to_nav_wallet_create"
app:destination="@id/nav_wallet_create" />
@ -119,6 +122,12 @@
android:label="@string/action_user_write_data"
tools:layout="@layout/fg_base_action_layout" />
<fragment
android:id="@+id/nav_user_write_protected_data"
android:name="com.tangem.devkit.ucase.variants.userdata.ui.WriteProtectedUserDataFragment"
android:label="@string/action_user_write_protected_data"
tools:layout="@layout/fg_base_action_layout" />
<fragment
android:id="@+id/nav_wallet_create"
android:name="com.tangem.devkit.ucase.variants.createwallet.ui.CreateWalletActionFragment"

View file

@ -13,6 +13,7 @@
<string name="action_issuer_write_ex_data">Write Issuer Extra Data</string>
<string name="action_user_read_data">Read User Data</string>
<string name="action_user_write_data">Write User Data</string>
<string name="action_user_write_protected_data">Write Protected User Data</string>
<string name="info_action_card_scan">This command returns all data about the card and the wallet, including unique card number (CID) that has to be submitted while calling all other commands</string>
<string name="info_action_card_sign">Depending on Signing_Method parameter defined during personalization, this command signs data using Wallet_PrivateKey</string>
@ -26,7 +27,8 @@
<string name="info_action_issuer_read_ex_data">This command retrieves Issuer Extra Data field and its issuers signature.</string>
<string name="info_action_issuer_write_ex_data">This command writes Issuer Extra Data field and its issuers signature to the card.</string>
<string name="info_action_user_read_data">This command returns User Data and User Protected Data (up to 512-byte each) and two counters: User Counter and User Protected Counter.</string>
<string name="info_action_user_write_data"> This command writes to the card any of User Data, User Protected Data, User Counter and User Protected Counter fields.
</string>
<string name="info_action_user_write_data"> This command writes to the card User Data and User Counter fields.</string>
<string name="info_action_user_write_protected_data"> This command writes to the card User Protected Data and User Protected Counter fields.</string>
</resources>