Skip to content

Commit

Permalink
IOS-3290 Add usersettings support
Browse files Browse the repository at this point in the history
  • Loading branch information
tureck1y committed Mar 29, 2023
1 parent e2604c2 commit 16856f6
Show file tree
Hide file tree
Showing 24 changed files with 349 additions and 15 deletions.
13 changes: 13 additions & 0 deletions Example/TangemSdkExample/AppModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class AppModel: ObservableObject {
@Published var json: String = ""
//Personalization
@Published var personalizationConfig: String = ""
//Set resetting user codes
@Published var isResettingUserCodesAllowed: Bool = false

//MARK:- Outputs
@Published var logText: String = DebugLogger.logPlaceholder
Expand Down Expand Up @@ -579,6 +581,15 @@ extension AppModel {
func resetToFactory() {
tangemSdk.startSession(with: ResetToFactorySettingsTask(), completion: handleCompletion)
}

func setResettingUserCodesAllowed() {
guard let cardId = card?.cardId else {
self.complete(with: "Please, scan card before")
return
}

tangemSdk.setResettingUserCodesAllowed(isResettingUserCodesAllowed, cardId: cardId, completion: handleCompletion)
}
}

//MARK:- Json RPC
Expand Down Expand Up @@ -674,6 +685,7 @@ extension AppModel {
case personalize
case resetBackup
case resetToFactory
case setResettingUserCodesAllowed
}

private func chooseMethod(walletPublicKey: Data? = nil) {
Expand Down Expand Up @@ -706,6 +718,7 @@ extension AppModel {
case .personalize: personalize()
case .resetBackup: resetBackup()
case .resetToFactory: resetToFactory()
case .setResettingUserCodesAllowed: setResettingUserCodesAllowed()
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion Example/TangemSdkExample/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@ struct ContentView: View {
.overlay(RoundedRectangle(cornerRadius: 8)
.stroke(Color.orange, lineWidth: 2))
.onAppear(perform: model.onAppear)

case .setResettingUserCodesAllowed:
Toggle(isOn: $model.isResettingUserCodesAllowed) {
Text("Is resetting user codes allowed")
}
default:
EmptyView()
}
Expand Down
24 changes: 24 additions & 0 deletions TangemSdk/TangemSdk.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -311,13 +311,17 @@
DC1244E429BB806E0037BC05 /* WIFTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC1244E329BB806E0037BC05 /* WIFTests.swift */; };
DC1244E629BB8E580037BC05 /* NetworkType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC1244E529BB8E580037BC05 /* NetworkType.swift */; };
DC1244E829BB9E0C0037BC05 /* ExtendedKeySerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC1244E729BB9E0C0037BC05 /* ExtendedKeySerializer.swift */; };
DC22228729D431AB001129F8 /* SetResettingUserCodesAllowed.json in Resources */ = {isa = PBXBuildFile; fileRef = DC22228629D431AB001129F8 /* SetResettingUserCodesAllowed.json */; };
DC4E442929BF42630088617C /* Base58Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4E442829BF42630088617C /* Base58Tests.swift */; };
DC59CB0429AF597900EC14E1 /* Wordlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC59CB0329AF597900EC14E1 /* Wordlist.swift */; };
DC59CB0A29AF6F9C00EC14E1 /* EntropyLength.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC59CB0929AF6F9C00EC14E1 /* EntropyLength.swift */; };
DC59CB0C29AF706100EC14E1 /* MnemonicError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC59CB0B29AF706100EC14E1 /* MnemonicError.swift */; };
DC59CB0E29AF70C700EC14E1 /* Mnemonic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC59CB0D29AF70C700EC14E1 /* Mnemonic.swift */; };
DC8B0E3F286F221D009D64F7 /* BiometricsUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8B0E3E286F221D009D64F7 /* BiometricsUtil.swift */; };
DCA9706628E35EAD0046E62E /* GenerateOTPCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA9706528E35EAD0046E62E /* GenerateOTPCommand.swift */; };
DCC0A21129D3146100C45B13 /* SetUserSettingsCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC0A21029D3146100C45B13 /* SetUserSettingsCommand.swift */; };
DCC0A21429D3201300C45B13 /* SetResettingUserCodesAllowedTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC0A21329D3201300C45B13 /* SetResettingUserCodesAllowedTask.swift */; };
DCC0A21629D3216100C45B13 /* UserSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC0A21529D3216100C45B13 /* UserSettings.swift */; };
DCEA3ABC2875AEBA00B0B0DA /* BiometricsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCEA3ABB2875AEBA00B0B0DA /* BiometricsStorage.swift */; };
DCEA3ABE2875AF0F00B0B0DA /* SecureStorageKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCEA3ABD2875AF0F00B0B0DA /* SecureStorageKey.swift */; };
DCFCA17728F5629F0037586C /* FocusableTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFCA17628F5629F0037586C /* FocusableTextField.swift */; };
Expand Down Expand Up @@ -646,13 +650,17 @@
DC1244E329BB806E0037BC05 /* WIFTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WIFTests.swift; sourceTree = "<group>"; };
DC1244E529BB8E580037BC05 /* NetworkType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkType.swift; sourceTree = "<group>"; };
DC1244E729BB9E0C0037BC05 /* ExtendedKeySerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtendedKeySerializer.swift; sourceTree = "<group>"; };
DC22228629D431AB001129F8 /* SetResettingUserCodesAllowed.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = SetResettingUserCodesAllowed.json; sourceTree = "<group>"; };
DC4E442829BF42630088617C /* Base58Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Base58Tests.swift; sourceTree = "<group>"; };
DC59CB0329AF597900EC14E1 /* Wordlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wordlist.swift; sourceTree = "<group>"; };
DC59CB0929AF6F9C00EC14E1 /* EntropyLength.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntropyLength.swift; sourceTree = "<group>"; };
DC59CB0B29AF706100EC14E1 /* MnemonicError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MnemonicError.swift; sourceTree = "<group>"; };
DC59CB0D29AF70C700EC14E1 /* Mnemonic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mnemonic.swift; sourceTree = "<group>"; };
DC8B0E3E286F221D009D64F7 /* BiometricsUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BiometricsUtil.swift; sourceTree = "<group>"; };
DCA9706528E35EAD0046E62E /* GenerateOTPCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateOTPCommand.swift; sourceTree = "<group>"; };
DCC0A21029D3146100C45B13 /* SetUserSettingsCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetUserSettingsCommand.swift; sourceTree = "<group>"; };
DCC0A21329D3201300C45B13 /* SetResettingUserCodesAllowedTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetResettingUserCodesAllowedTask.swift; sourceTree = "<group>"; };
DCC0A21529D3216100C45B13 /* UserSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettings.swift; sourceTree = "<group>"; };
DCEA3ABB2875AEBA00B0B0DA /* BiometricsStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BiometricsStorage.swift; sourceTree = "<group>"; };
DCEA3ABD2875AF0F00B0B0DA /* SecureStorageKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureStorageKey.swift; sourceTree = "<group>"; };
DCFCA17628F5629F0037586C /* FocusableTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FocusableTextField.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -828,6 +836,7 @@
5D3B9F0226BD678500532CC7 /* SignHashes.json */,
5D38D06D26790B1A0052F67C /* Scan.json */,
5D5440892682260000F7D05B /* SetAccessCode.json */,
DC22228629D431AB001129F8 /* SetResettingUserCodesAllowed.json */,
5D46F536274D68010004681F /* DeriveWalletPublicKey.json */,
5D46F53B274E41100004681F /* DeriveWalletPublicKeys.json */,
5D54408B2682269400F7D05B /* SetPasscode.json */,
Expand Down Expand Up @@ -982,6 +991,7 @@
5D6A92E12345F28F00158457 /* Operations */ = {
isa = PBXGroup;
children = (
DCC0A21229D31FDD00C45B13 /* UserSettings */,
5D445B6E26E2944300F6F0FE /* ResetCode */,
5D4B128126D40C67006E173C /* Backup */,
5D46F538274E29490004681F /* Derivation */,
Expand Down Expand Up @@ -1404,6 +1414,7 @@
5D6508222672755600A8D45B /* Wallet.swift */,
5D379C26268FA47600C7F473 /* EncryptionMode.swift */,
5D270F2426A0199100D2EDC1 /* WalletData.swift */,
DCC0A21529D3216100C45B13 /* UserSettings.swift */,
);
path = Card;
sourceTree = "<group>";
Expand Down Expand Up @@ -1480,6 +1491,15 @@
path = Wordlists;
sourceTree = "<group>";
};
DCC0A21229D31FDD00C45B13 /* UserSettings */ = {
isa = PBXGroup;
children = (
DCC0A21029D3146100C45B13 /* SetUserSettingsCommand.swift */,
DCC0A21329D3201300C45B13 /* SetResettingUserCodesAllowedTask.swift */,
);
path = UserSettings;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand Down Expand Up @@ -1644,6 +1664,7 @@
5D54408A2682260000F7D05B /* SetAccessCode.json in Resources */,
DC1244C529B769400037BC05 /* mnemonic_invalid_test_vectors.json in Resources */,
5D46F537274D68010004681F /* DeriveWalletPublicKey.json in Resources */,
DC22228729D431AB001129F8 /* SetResettingUserCodesAllowed.json in Resources */,
5D54408E268226B600F7D05B /* Depersonalize.json in Resources */,
5D3217462684B1DB000C3AAF /* v3.05ada.json in Resources */,
5D544090268226BC00F7D05B /* PurgeWallet.json in Resources */,
Expand Down Expand Up @@ -1732,6 +1753,7 @@
5D0243BE26CACACD00B76F37 /* IndicatorView.swift in Sources */,
5D1D945C2722FD7400FD6DAB /* CreateWalletTask.swift in Sources */,
5DE59F2D23D96FE500312DA4 /* TerminalKeysService.swift in Sources */,
DCC0A21629D3216100C45B13 /* UserSettings.swift in Sources */,
DC59CB0A29AF6F9C00EC14E1 /* EntropyLength.swift in Sources */,
DCEA3ABE2875AF0F00B0B0DA /* SecureStorageKey.swift in Sources */,
DC8B0E3F286F221D009D64F7 /* BiometricsUtil.swift in Sources */,
Expand Down Expand Up @@ -1769,6 +1791,7 @@
5DE43A6226D5157900ECA36A /* ReadBackupDataCommand.swift in Sources */,
B006971825FFABA10040D203 /* InteractionMode.swift in Sources */,
DC1244E029BB6D460037BC05 /* Base58.swift in Sources */,
DCC0A21129D3146100C45B13 /* SetUserSettingsCommand.swift in Sources */,
5DDD6C5625D2D14000E48D7B /* TlvLogging.swift in Sources */,
5D58202024221E060057EF40 /* CardSession.swift in Sources */,
B0390F92256590250061E5ED /* EllipticCurve.swift in Sources */,
Expand Down Expand Up @@ -1814,6 +1837,7 @@
5D86665627315F050095CC82 /* ResetCodesViewDelegate.swift in Sources */,
5DE59F2F23D9703A00312DA4 /* SecureStorage.swift in Sources */,
5DEFA99526D7F40300E5CDE4 /* FinalizeBackupCardTask.swift in Sources */,
DCC0A21429D3201300C45B13 /* SetResettingUserCodesAllowedTask.swift in Sources */,
5D445B7226E295A700F6F0FE /* AuthorizeResetPinToken.swift in Sources */,
B0EC6500260110530088F03D /* WalletDeserializer.swift in Sources */,
DC1244CB29B9ECAA0037BC05 /* HexConvertible.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions TangemSdk/TangemSdk/Common/APDU/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ public enum Instruction: Byte {
case authorize = 0xD3
case backupReset = 0xEE
case generateOTP = 0xE2
case setUserSettings = 0xD5
}
28 changes: 21 additions & 7 deletions TangemSdk/TangemSdk/Common/Card/CardSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public extension Card {
/// Is allowed to change passcode
public internal(set) var isSettingPasscodeAllowed: Bool
/// Is allowed to remove access code
public internal(set) var isResettingUserCodesAllowed: Bool
public internal(set) var isRemovingUserCodesAllowed: Bool
/// Is LinkedTerminal feature enabled
public let isLinkedTerminalEnabled: Bool
/// All encryption modes supported by the card
Expand All @@ -32,6 +32,8 @@ public extension Card {
public let isHDWalletAllowed: Bool
/// Is allowed to create backup
public let isBackupAllowed: Bool
/// Is allowed to reset user codes
public internal(set) var isResettingUserCodesAllowed: Bool
/// Is allowed to delete wallet. COS before v4
@SkipEncoding
var isPermanentWallet: Bool
Expand All @@ -53,7 +55,7 @@ public extension Card {

@available(iOS 13.0, *)
extension Card.Settings {
init(securityDelay: Int, maxWalletsCount: Int, mask: CardSettingsMask,
init(securityDelay: Int, maxWalletsCount: Int, mask: CardSettingsMask, userSettings: UserSettings,
defaultSigningMethods: SigningMethod? = nil, defaultCurve: EllipticCurve? = nil) {
self.securityDelay = securityDelay
self.maxWalletsCount = maxWalletsCount
Expand All @@ -62,7 +64,7 @@ extension Card.Settings {

self.isSettingAccessCodeAllowed = mask.contains(.allowSetPIN1)
self.isSettingPasscodeAllowed = mask.contains(.allowSetPIN2)
self.isResettingUserCodesAllowed = !mask.contains(.prohibitDefaultPIN1)
self.isRemovingUserCodesAllowed = !mask.contains(.prohibitDefaultPIN1)
self.isLinkedTerminalEnabled = mask.contains(.skipSecurityDelayIfValidatedByLinkedTerminal)
self.isOverwritingIssuerExtraDataRestricted = mask.contains(.restrictOverwriteIssuerExtraData)
self.isIssuerDataProtectedAgainstReplay = mask.contains(.protectIssuerDataAgainstReplay)
Expand All @@ -81,19 +83,29 @@ extension Card.Settings {
}

self.supportedEncryptionModes = encryptionModes

// user settings
self.isResettingUserCodesAllowed = userSettings.isResettingUserCodesAllowed
}

func updated(with mask: CardSettingsMask) -> Card.Settings {
return .init(securityDelay: self.securityDelay,
maxWalletsCount: self.maxWalletsCount,
mask: mask,
userSettings: .init(isResettingUserCodesAllowed: self.isResettingUserCodesAllowed),
defaultSigningMethods: self.defaultSigningMethods,
defaultCurve: self.defaultCurve)
}


func updated(with userSettings: UserSettings) -> Card.Settings {
var copy = self
copy.isResettingUserCodesAllowed = userSettings.isResettingUserCodesAllowed
return copy
}
}

//MARK:- CardSettingsMask
// MARK: - CardSettingsMask

@available(iOS 13.0, *)
typealias CardSettingsMask = Card.Settings.Mask

Expand All @@ -116,7 +128,8 @@ extension CardSettingsMask {
}
}

//MARK:- CardSettingsMask Constants
// MARK: - CardSettingsMask Constants

@available(iOS 13.0, *)
extension CardSettingsMask {
static let useActivation = CardSettingsMask(rawValue: 0x0002)
Expand Down Expand Up @@ -147,7 +160,8 @@ extension CardSettingsMask {
static let allowBackup = CardSettingsMask(rawValue: 0x00400000)
}

//MARK:- CardSettingsMask OptionSetCodable conformance
// MARK: - CardSettingsMask OptionSetCodable conformance

@available(iOS 13.0, *)
extension CardSettingsMask: OptionSetCodable {
enum OptionKeys: String, OptionKey {
Expand Down
68 changes: 68 additions & 0 deletions TangemSdk/TangemSdk/Common/Card/UserSettings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// UserSettings.swift
// TangemSdk
//
// Created by Alexander Osokin on 28.03.2023.
// Copyright © 2023 Tangem AG. All rights reserved.
//

import Foundation

// MARK: - UserSettings
@available(iOS 13.0, *)
struct UserSettings: JSONStringConvertible {
var isResettingUserCodesAllowed: Bool

var mask: UserSettingsMask {
let builder = MaskBuilder<UserSettingsMask>()

if !isResettingUserCodesAllowed {
builder.add(.forbidResetPIN)
}

return builder.build()
}
}

@available(iOS 13.0, *)
extension UserSettings {
init(from mask: UserSettingsMask) {
self.isResettingUserCodesAllowed = !mask.contains(.forbidResetPIN)
}

init(from cardSettings: Card.Settings) {
self.isResettingUserCodesAllowed = cardSettings.isResettingUserCodesAllowed
}
}

// MARK: - UserSettingsMask

@available(iOS 13.0, *)
struct UserSettingsMask: OptionSet, OptionSetCustomStringConvertible {
let rawValue: Int

init(rawValue: Int) {
self.rawValue = rawValue
}
}

@available(iOS 13.0, *)
extension UserSettingsMask {
static let forbidResetPIN = UserSettingsMask(rawValue: 0x00000001)
}

// MARK: - OptionSetCodable conformance

@available(iOS 13.0, *)
extension UserSettingsMask: OptionSetCodable {
enum OptionKeys: String, OptionKey {
case forbidResetPIN

var value: UserSettingsMask {
switch self {
case .forbidResetPIN:
return .forbidResetPIN
}
}
}
}
2 changes: 2 additions & 0 deletions TangemSdk/TangemSdk/Common/Core/TangemSdkError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ public enum TangemSdkError: Error, LocalizedError, Encodable {
//MARK: Settings
case filesDisabled
case hdWalletDisabled
case userCodeResettingDisabled

case resetPinNoCardToReset
case resetPinWrongCard(internalCode: Int? = nil)
Expand Down Expand Up @@ -399,6 +400,7 @@ public enum TangemSdkError: Error, LocalizedError, Encodable {

case .filesDisabled: return 42002
case .hdWalletDisabled: return 42003
case .userCodeResettingDisabled: return 42005

// MARK: 5xxxx Errors
// SDK error. Errors, that occurred in the upper level of SDK, like device restrictions, user canceled the operation or SDK is busy and can’t open the new session right now.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct CardDeserializer {

let firmware = FirmwareVersion(stringValue: try decoder.decode(.firmwareVersion))
let cardSettingsMask: CardSettingsMask = try decoder.decode(.settingsMask)

let isPasscodeSet: Bool? = firmware >= .isPasscodeStatusAvailable ?
!(try decoder.decode(.pin2IsDefault)) : nil

Expand Down Expand Up @@ -74,10 +74,21 @@ struct CardDeserializer {
publicKey: try decoder.decode(.issuerPublicKey))

let securityDelay: Int? = try decoder.decode(.pauseBeforePin2)

let securityDelayMs = securityDelay.map { $0 * 10 } ?? 0

var userSettings: UserSettings
let userSettingsMask: UserSettingsMask? = try decoder.decode(.userSettingsMask)
if let userSettingsMask {
userSettings = .init(from: userSettingsMask)
} else {
userSettings = .init(isResettingUserCodesAllowed: firmware >= .backupAvailable)
}

let settings = Card.Settings(securityDelay: securityDelayMs,
maxWalletsCount: try decoder.decode(.walletsCount) ?? 1, //Cos before v4 always has 1 wallet
mask: cardSettingsMask,
userSettings: userSettings,
defaultSigningMethods: try decoder.decode(.signingMethod),
defaultCurve: defaultCurve)

Expand Down
12 changes: 12 additions & 0 deletions TangemSdk/TangemSdk/Common/JSON/Handlers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,15 @@ class DeriveWalletPublicKeysHandler: JSONRPCHandler {
return command.eraseToAnyRunnable()
}
}

@available(iOS 13.0, *)
class SetResettingUserCodesAllowedHandler: JSONRPCHandler {
var method: String { "SET_RESETTING_USERCODES_ALLOWED" }

func makeRunnable(from parameters: [String : Any]) throws -> AnyJSONRPCRunnable {
let isResettingUserCodesAllowed: Bool = try parameters.value(for: "isResettingUserCodesAllowed")

let command = SetResettingUserCodesAllowedTask(isResettingUserCodesAllowed: isResettingUserCodesAllowed)
return command.eraseToAnyRunnable()
}
}
1 change: 1 addition & 0 deletions TangemSdk/TangemSdk/Common/JSON/JSONRPC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public final class JSONRPCConverter {
converter.register(ChangeFileSettingsHandler())
converter.register(DeriveWalletPublicKeyHandler())
converter.register(DeriveWalletPublicKeysHandler())
converter.register(SetResettingUserCodesAllowedHandler())
return converter
}()

Expand Down
Loading

0 comments on commit 16856f6

Please sign in to comment.