Skip to content

Commit

Permalink
Release 0.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mobile-tangem committed Apr 19, 2020
1 parent d6a11da commit 5badc73
Show file tree
Hide file tree
Showing 88 changed files with 1,386 additions and 592 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2019 Tangem

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

[![Release](https://jitpack.io/v/Tangem/tangem-sdk-android.svg)]

![Release](https://jitpack.io/v/Tangem/tangem-sdk-android.svg)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
# Welcome to Tangem

The Tangem card is a self-custodial hardware wallet for blockchain assets. The main functions of Tangem cards are to securely create and store a private key from a blockchain wallet and sign blockchain transactions. The Tangem card does not allow users to import/export, backup/restore private keys, thereby guaranteeing that the wallet is unique and unclonable.
Expand Down Expand Up @@ -228,4 +227,4 @@ cardManager.runCommand(readCommand) { taskEvent ->
}
}
}
```
```
2 changes: 1 addition & 1 deletion dependencies.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ext.versions = [
kotlin : '1.3.71',
kotlin : '1.3.72',
build_gradle: '3.6.2',
]
2 changes: 1 addition & 1 deletion jitpack.gradle
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ext.jitpackSdk = [group: 'com.github.Tangem', version : '0.4.0']
ext.jitpackSdk = [group: 'com.github.Tangem', version : '0.5.0']
6 changes: 4 additions & 2 deletions tangem-core/src/main/java/com/tangem/CardSession.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ class CardSession(
}

runnable.run(this) { result ->
stop()
when (result) {
is CompletionResult.Success -> stop()
is CompletionResult.Failure -> stopWithError(result.error)
}
callback(result)
}
}
Expand All @@ -99,7 +102,6 @@ class CardSession(
}
is CompletionResult.Success -> {
callback(this, null)

}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tangem-core/src/main/java/com/tangem/commands/Command.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ abstract class Command<T : CommandResponse> : CardSessionRunnable<T> {
}
}
is CompletionResult.Failure ->
if (result.error == SessionError.TagLost()) {
if (result.error is SessionError.TagLost) {
session.viewDelegate.onTagLost()
} else {
callback(CompletionResult.Failure(result.error))
Expand Down
112 changes: 48 additions & 64 deletions tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,67 +14,50 @@ import java.util.*
/**
* Determines which type of data is required for signing.
*/
data class SigningMethod(val rawValue: Int) {
data class SigningMethodMask(val rawValue: Int) {

fun contains(value: Int): Boolean {
fun contains(signingMethod: SigningMethod): Boolean {
return if (rawValue and 0x80 == 0) {
value == rawValue
signingMethod.code == rawValue
} else {
rawValue and (0x01 shl value) != 0
rawValue and (0x01 shl signingMethod.code) != 0
}
}
}

companion object {
const val signHash = 0
const val signRaw = 1
const val signHashValidatedByIssuer = 2
const val signRawValidatedByIssuer = 3
const val signHashValidatedByIssuerAndWriteIssuerData = 4
const val signRawValidatedByIssuerAndWriteIssuerData = 5
const val signPos = 6

fun build(
signHash: Boolean = false,
signRaw: Boolean = false,
signHashValidatedByIssuer: Boolean = false,
signRawValidatedByIssuer: Boolean = false,
signHashValidatedByIssuerAndWriteIssuerData: Boolean = false,
signRawValidatedByIssuerAndWriteIssuerData: Boolean = false,
signPos: Boolean = false

): SigningMethod {
fun Boolean.toInt() = if (this) 1 else 0

val signingMethodsCount = 0 +
signHash.toInt() +
signRaw.toInt() +
signHashValidatedByIssuer.toInt() +
signRawValidatedByIssuer.toInt() +
signHashValidatedByIssuerAndWriteIssuerData.toInt() +
signRawValidatedByIssuerAndWriteIssuerData.toInt() +
signPos.toInt()

var signingMethod: Int = 0
if (signingMethodsCount == 1) {
if (signHash) signingMethod += SigningMethod.signHash
if (signRaw) signingMethod += SigningMethod.signRaw
if (signHashValidatedByIssuer) signingMethod += SigningMethod.signHashValidatedByIssuer
if (signRawValidatedByIssuer) signingMethod += SigningMethod.signRawValidatedByIssuer
if (signHashValidatedByIssuerAndWriteIssuerData) signingMethod += SigningMethod.signHashValidatedByIssuerAndWriteIssuerData
if (signRawValidatedByIssuerAndWriteIssuerData) signingMethod += SigningMethod.signRawValidatedByIssuerAndWriteIssuerData
if (signPos) signingMethod += SigningMethod.signPos
} else if (signingMethodsCount > 1) {
signingMethod = 0x80
if (signHash) signingMethod += 0x01
if (signRaw) signingMethod += 0x01 shl SigningMethod.signRaw
if (signHashValidatedByIssuer) signingMethod += 0x01 shl SigningMethod.signHashValidatedByIssuer
if (signRawValidatedByIssuer) signingMethod += 0x01 shl SigningMethod.signRawValidatedByIssuer
if (signHashValidatedByIssuerAndWriteIssuerData) signingMethod += 0x01 shl SigningMethod.signHashValidatedByIssuerAndWriteIssuerData
if (signRawValidatedByIssuerAndWriteIssuerData) signingMethod += 0x01 shl SigningMethod.signRawValidatedByIssuerAndWriteIssuerData
if (signPos) signingMethod += 0x01 shl SigningMethod.signPos
enum class SigningMethod(val code: Int) {
SignHash(0),
SignRaw(1),
SignHashValidateByIssuer(2),
SignRawValidateByIssuer(3),
SignHashValidateByIssuerWriteIssuerData(4),
SignRawValidateByIssuerWriteIssuerData(5),
SignPos(6)
}

class SigningMethodMaskBuilder() {

private val signingMethods = mutableSetOf<SigningMethod>()

fun add(signingMethod: SigningMethod) {
signingMethods.add(signingMethod)
}

fun build(): SigningMethodMask {
val rawValue: Int = when {
signingMethods.count() == 0 -> {
0
}
signingMethods.count() == 1 -> {
signingMethods.iterator().next().code
}
else -> {
signingMethods.fold(
0x80, { acc, singingMethod -> acc + (0x01 shl singingMethod.code) }
)
}
return SigningMethod(signingMethod)
}
return SigningMethodMask(rawValue)
}
}

Expand Down Expand Up @@ -113,22 +96,23 @@ enum class CardStatus(val code: Int) {
*/
data class ProductMask(val rawValue: Int) {

fun contains(value: Int): Boolean = (rawValue and value) != 0
fun contains(product: Product): Boolean = (rawValue and product.code) != 0

companion object {
const val note = 0x01
const val tag = 0x02
const val idCard = 0x04
const val idIssuer = 0x08
}
}

enum class Product(val code: Int) {
Note(0x01),
Tag(0x02),
IdCard(0x04),
IdIssuer(0x08)
}

class ProductMaskBuilder() {

private var productMaskValue = 0

fun add(productCode: Int) {
productMaskValue = productMaskValue or productCode
fun add(product: Product) {
productMaskValue = productMaskValue or product.code
}

fun build() = ProductMask(productMaskValue)
Expand Down Expand Up @@ -299,7 +283,7 @@ class Card(
/**
* Defines what data should be submitted to SIGN command.
*/
val signingMethod: SigningMethod?,
val signingMethods: SigningMethodMask?,

/**
* Delay in seconds before COS executes commands protected by PIN2.
Expand Down Expand Up @@ -415,7 +399,7 @@ class ReadCommand : Command<Card>() {
issuerPublicKey = decoder.decodeOptional(TlvTag.IssuerDataPublicKey),
curve = decoder.decodeOptional(TlvTag.CurveId),
maxSignatures = decoder.decodeOptional(TlvTag.MaxSignatures),
signingMethod = decoder.decodeOptional(TlvTag.SigningMethod),
signingMethods = decoder.decodeOptional(TlvTag.SigningMethod),
pauseBeforePin2 = decoder.decodeOptional(TlvTag.PauseBeforePin2),
walletPublicKey = decoder.decodeOptional(TlvTag.WalletPublicKey),
walletRemainingSignatures = decoder.decodeOptional(TlvTag.RemainingSignatures),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class PersonalizeCommand(
issuerPublicKey = decoder.decodeOptional(TlvTag.IssuerDataPublicKey),
curve = decoder.decodeOptional(TlvTag.CurveId),
maxSignatures = decoder.decodeOptional(TlvTag.MaxSignatures),
signingMethod = decoder.decodeOptional(TlvTag.SigningMethod),
signingMethods = decoder.decodeOptional(TlvTag.SigningMethod),
pauseBeforePin2 = decoder.decodeOptional(TlvTag.PauseBeforePin2),
walletPublicKey = decoder.decodeOptional(TlvTag.WalletPublicKey),
walletRemainingSignatures = decoder.decodeOptional(TlvTag.RemainingSignatures),
Expand Down Expand Up @@ -105,7 +105,7 @@ class PersonalizeCommand(
tlvBuilder.append(TlvTag.CardId, cardId)
tlvBuilder.append(TlvTag.CurveId, config.curveID)
tlvBuilder.append(TlvTag.MaxSignatures, config.maxSignatures)
tlvBuilder.append(TlvTag.SigningMethod, config.signingMethod)
tlvBuilder.append(TlvTag.SigningMethod, config.signingMethods)
tlvBuilder.append(TlvTag.SettingsMask, config.createSettingsMask())
tlvBuilder.append(TlvTag.PauseBeforePin2, config.pauseBeforePin2 / 10)
tlvBuilder.append(TlvTag.Cvc, config.cvc.toByteArray())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.tangem.commands.personalization.entities

import com.tangem.commands.CardData
import com.tangem.commands.EllipticCurve
import com.tangem.commands.SigningMethod
import com.tangem.commands.SigningMethodMask

data class NdefRecord(
val type: Type,
Expand Down Expand Up @@ -33,7 +33,7 @@ data class CardConfig(
val pauseBeforePin2: Int,
val smartSecurityDelay: Boolean,
val curveID: EllipticCurve,
val signingMethod: SigningMethod,
val signingMethods: SigningMethodMask,
val maxSignatures: Int,
val isReusable: Boolean,
val allowSwapPin: Boolean,
Expand Down
4 changes: 2 additions & 2 deletions tangem-core/src/main/java/com/tangem/common/tlv/TlvDecoder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ class TlvDecoder(val tlvList: List<Tlv>) {
}
}
TlvValueType.SigningMethod -> {
typeCheck<T, SigningMethod>(tag)
typeCheck<T, SigningMethodMask>(tag)
try {
SigningMethod(tlvValue.toInt()) as T
SigningMethodMask(tlvValue.toInt()) as T
} catch (exception: Exception) {
logException(tag, tlvValue.toInt().toString(), exception)
throw SessionError.DecodingFailed()
Expand Down
4 changes: 2 additions & 2 deletions tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ class TlvEncoder {
(value as CardStatus).code.toByteArray()
}
TlvValueType.SigningMethod -> {
typeCheck<T, SigningMethod>(tag)
byteArrayOf((value as SigningMethod).rawValue.toByte())
typeCheck<T, SigningMethodMask>(tag)
byteArrayOf((value as SigningMethodMask).rawValue.toByte())
}
TlvValueType.IssuerDataMode -> {
typeCheck<T, IssuerDataMode>(tag)
Expand Down
2 changes: 1 addition & 1 deletion tangem-core/src/main/java/com/tangem/tasks/ScanTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal class ScanTask : CardSessionRunnable<Card> {
if (card == null) {
callback(CompletionResult.Failure(SessionError.MissingPreflightRead()))

} else if (card.cardData?.productMask?.contains(ProductMask.tag) != false) {
} else if (card.cardData?.productMask?.contains(Product.Tag) != false) {
callback(CompletionResult.Success(card))

} else if (card.status != CardStatus.Loaded) {
Expand Down
24 changes: 12 additions & 12 deletions tangem-core/src/test/java/com/tangem/common/tlv/TlvDecoderTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -82,29 +82,29 @@ class TlvDecoderTest {

@Test
fun `map SigningMethods single value returns correct value`() {
val signingMethods: SigningMethod = tlvMapper.decode(TlvTag.SigningMethod)
assertThat(signingMethods.contains(SigningMethod.signHash))
val signingMethods: SigningMethodMask = tlvMapper.decode(TlvTag.SigningMethod)
assertThat(signingMethods.contains(SigningMethod.SignHash))
.isTrue()
}

@Test
fun `map SigningMethods set of methods returns correct value`() {
val localMapper = TlvDecoder(Tlv.deserialize("070195".hexToBytes())!!)

val signingMethod: SigningMethod = localMapper.decode(TlvTag.SigningMethod)
assertThat(signingMethod.contains(SigningMethod.signHash))
val signingMethods: SigningMethodMask = localMapper.decode(TlvTag.SigningMethod)
assertThat(signingMethods.contains(SigningMethod.SignHash))
.isTrue()
assertThat(signingMethod.contains(SigningMethod.signHashValidatedByIssuer))
assertThat(signingMethods.contains(SigningMethod.SignHashValidateByIssuer))
.isTrue()
assertThat(signingMethod.contains(SigningMethod.signHashValidatedByIssuerAndWriteIssuerData))
assertThat(signingMethods.contains(SigningMethod.SignHashValidateByIssuerWriteIssuerData))
.isTrue()
assertThat(signingMethod.contains(SigningMethod.signRaw))
assertThat(signingMethods.contains(SigningMethod.SignRaw))
.isFalse()
assertThat(signingMethod.contains(SigningMethod.signRawValidatedByIssuer))
assertThat(signingMethods.contains(SigningMethod.SignRawValidateByIssuer))
.isFalse()
assertThat(signingMethod.contains(SigningMethod.signRawValidatedByIssuerAndWriteIssuerData))
assertThat(signingMethods.contains(SigningMethod.SignRawValidateByIssuerWriteIssuerData))
.isFalse()
assertThat(signingMethod.contains(SigningMethod.signPos))
assertThat(signingMethods.contains(SigningMethod.SignPos))
.isFalse()
}

Expand All @@ -119,15 +119,15 @@ class TlvDecoderTest {
fun `map ProductMask with raw value 5 returns correct value`() {
val localMapper = TlvDecoder(listOf(Tlv(TlvTag.ProductMask, byteArrayOf(5))))
val productMask: ProductMask = localMapper.decode(TlvTag.ProductMask)
assertThat(productMask.contains(ProductMask.note) && productMask.contains(ProductMask.idCard))
assertThat(productMask.contains(Product.Note) && productMask.contains(Product.IdCard))
.isTrue()
}

@Test
fun `map ProductMask with raw value 1 returns correct value`() {
val localMapper = TlvDecoder(listOf(Tlv(TlvTag.ProductMask, byteArrayOf(1))))
val productMask: ProductMask = localMapper.decode(TlvTag.ProductMask)
assertThat(productMask.contains(ProductMask.note))
assertThat(productMask.contains(Product.Note))
.isTrue()
}

Expand Down
5 changes: 3 additions & 2 deletions tangem-demo/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ dependencies {
implementation "androidx.constraintlayout:constraintlayout:2.0.0-beta4"
implementation "androidx.navigation:navigation-fragment-ktx:2.2.1"
implementation "androidx.navigation:navigation-ui-ktx:2.2.1"
implementation "androidx.recyclerview:recyclerview:1.2.0-alpha01"
implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
implementation "com.google.android.material:material:1.2.0-alpha05"
implementation "androidx.viewpager2:viewpager2:1.0.0"

implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.github.gbIxaHue:eu4d:0.3.7'
implementation 'com.github.gbIxaHue:eu4d:0.3.8'
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ fun List<Item>.iterate(func: (Item) -> Unit) {
forEach {
when (it) {
is BaseItem -> func(it)
is ItemGroup -> it.itemList.iterate(func)
is ItemGroup -> {
func(it)
it.itemList.iterate(func)
}
}
}
}
Loading

0 comments on commit 5badc73

Please sign in to comment.