From b3fbf3298cf481355362cf8b3bbc59ca0bcae327 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 7 Jan 2025 13:43:04 +0100 Subject: [PATCH] wrap bytes if not wrapped before signing in DApp browser --- novawallet.xcodeproj/project.pbxproj | 4 ++ .../DAppOperationConfirmViewFactory.swift | 1 + .../DAppSignBytesConfirmInteractor.swift | 22 ++------- .../Model/DAppMessageSignFactory.swift | 49 +++++++++++++++++++ 4 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 novawallet/Modules/DApp/DAppOperationConfirm/Model/DAppMessageSignFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 5c9741530..8efd7e1f9 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -168,6 +168,7 @@ 0C28DF0D2D1AC69F0016DB8E /* SNAddressType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DAC197268D3DD9002D0DF4 /* SNAddressType.swift */; }; 0C28DF1C2D2008670016DB8E /* AssetFungibilityPreservationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C28DF1B2D2008670016DB8E /* AssetFungibilityPreservationProvider.swift */; }; 0C28DF272D22B90D0016DB8E /* NativeTokenDepositedEventMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C28DF262D22B90D0016DB8E /* NativeTokenDepositedEventMatcher.swift */; }; + 0C28DF292D2D38CF0016DB8E /* DAppMessageSignFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C28DF282D2D38CF0016DB8E /* DAppMessageSignFactory.swift */; }; 0C29B5382A4C68A500E35C6D /* AnimationUpdatibleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C29B5372A4C68A500E35C6D /* AnimationUpdatibleView.swift */; }; 0C2A3C932CDC813B00A0E2B3 /* AssetsExchangeOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C2A3C922CDC813B00A0E2B3 /* AssetsExchangeOperationFactory.swift */; }; 0C2A3C952CDC8ADB00A0E2B3 /* SwapAssetSelectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C2A3C942CDC8ADB00A0E2B3 /* SwapAssetSelectionModel.swift */; }; @@ -5462,6 +5463,7 @@ 0C259EA72B46C55C00CB86E4 /* ExtrinsicSigningErrorHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicSigningErrorHandling.swift; sourceTree = ""; }; 0C28DF1B2D2008670016DB8E /* AssetFungibilityPreservationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetFungibilityPreservationProvider.swift; sourceTree = ""; }; 0C28DF262D22B90D0016DB8E /* NativeTokenDepositedEventMatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeTokenDepositedEventMatcher.swift; sourceTree = ""; }; + 0C28DF282D2D38CF0016DB8E /* DAppMessageSignFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppMessageSignFactory.swift; sourceTree = ""; }; 0C29B5372A4C68A500E35C6D /* AnimationUpdatibleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationUpdatibleView.swift; sourceTree = ""; }; 0C2A3C922CDC813B00A0E2B3 /* AssetsExchangeOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetsExchangeOperationFactory.swift; sourceTree = ""; }; 0C2A3C942CDC8ADB00A0E2B3 /* SwapAssetSelectionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwapAssetSelectionModel.swift; sourceTree = ""; }; @@ -15446,6 +15448,7 @@ 843612C0278FE62900DC739E /* DAppOperationConfirmInteractorError.swift */, 843612C62790032400DC739E /* DAppOperationProcessedResult.swift */, 84E8BA0A29FF760400FD9F40 /* DAppExtrinsicBuilderOperationFactory.swift */, + 0C28DF282D2D38CF0016DB8E /* DAppMessageSignFactory.swift */, ); path = Model; sourceTree = ""; @@ -26147,6 +26150,7 @@ 84746B3028153E4C002642F4 /* GradientBannerModel.swift in Sources */, 0C61082A2CD5DE9500909928 /* AssetHubExchangeHost.swift in Sources */, 8433B34A29B63661005E5D0F /* ExtrinsicSplitter.swift in Sources */, + 0C28DF292D2D38CF0016DB8E /* DAppMessageSignFactory.swift in Sources */, 843B1D7A263EED5C00AF8957 /* StakingUnbondConfirmLayout.swift in Sources */, 0C3205DA2A896029002EB914 /* EvmConstantNonceProvider.swift in Sources */, 0CF6928C2C231CA5000FC395 /* SharedStatusView.swift in Sources */, diff --git a/novawallet/Modules/DApp/DAppOperationConfirm/DAppOperationConfirmViewFactory.swift b/novawallet/Modules/DApp/DAppOperationConfirm/DAppOperationConfirmViewFactory.swift index 23ae2cb30..f616183b9 100644 --- a/novawallet/Modules/DApp/DAppOperationConfirm/DAppOperationConfirmViewFactory.swift +++ b/novawallet/Modules/DApp/DAppOperationConfirm/DAppOperationConfirmViewFactory.swift @@ -201,6 +201,7 @@ struct DAppOperationConfirmViewFactory { request: request, chain: chain, signingWrapperFactory: SigningWrapperFactory(keystore: Keychain()), + serializationFactory: PolkadotExtensionMessageSignFactory(), operationQueue: OperationManagerFacade.sharedDefaultQueue ) } diff --git a/novawallet/Modules/DApp/DAppOperationConfirm/DAppSignBytesConfirmInteractor.swift b/novawallet/Modules/DApp/DAppOperationConfirm/DAppSignBytesConfirmInteractor.swift index 0e971f3af..ec78ef8ee 100644 --- a/novawallet/Modules/DApp/DAppOperationConfirm/DAppSignBytesConfirmInteractor.swift +++ b/novawallet/Modules/DApp/DAppOperationConfirm/DAppSignBytesConfirmInteractor.swift @@ -7,6 +7,7 @@ final class DAppSignBytesConfirmInteractor: DAppOperationBaseInteractor { let request: DAppOperationRequest let chain: ChainModel let signingWrapperFactory: SigningWrapperFactoryProtocol + let serializationFactory: DAppMessageSignFactoryProtocol let operationQueue: OperationQueue private(set) var account: ChainAccountResponse? @@ -15,11 +16,13 @@ final class DAppSignBytesConfirmInteractor: DAppOperationBaseInteractor { request: DAppOperationRequest, chain: ChainModel, signingWrapperFactory: SigningWrapperFactoryProtocol, + serializationFactory: DAppMessageSignFactoryProtocol, operationQueue: OperationQueue ) { self.request = request self.chain = chain self.signingWrapperFactory = signingWrapperFactory + self.serializationFactory = serializationFactory self.operationQueue = operationQueue } @@ -53,23 +56,6 @@ final class DAppSignBytesConfirmInteractor: DAppOperationBaseInteractor { presenter?.didReceive(feeResult: .success(feeModel)) presenter?.didReceive(priceResult: .success(nil)) } - - private func prepareRawBytes() throws -> Data { - if case let .stringValue(stringValue) = request.operationData { - if stringValue.isHex() { - return try Data(hexString: stringValue) - } else { - guard let data = stringValue.data(using: .utf8) else { - throw CommonError.dataCorruption - } - - return data - } - - } else { - return try JSONEncoder().encode(request.operationData) - } - } } extension DAppSignBytesConfirmInteractor: DAppOperationConfirmInteractorInputProtocol { @@ -98,7 +84,7 @@ extension DAppSignBytesConfirmInteractor: DAppOperationConfirmInteractorInputPro accountResponse: account ) - let rawBytes = try prepareRawBytes() + let rawBytes = try serializationFactory.serializeSigningMessage(from: request.operationData) let signingOperation = ClosureOperation { try signer.sign(rawBytes, context: .rawBytes).rawData() diff --git a/novawallet/Modules/DApp/DAppOperationConfirm/Model/DAppMessageSignFactory.swift b/novawallet/Modules/DApp/DAppOperationConfirm/Model/DAppMessageSignFactory.swift new file mode 100644 index 000000000..9f9340a09 --- /dev/null +++ b/novawallet/Modules/DApp/DAppOperationConfirm/Model/DAppMessageSignFactory.swift @@ -0,0 +1,49 @@ +import Foundation +import SubstrateSdk + +protocol DAppMessageSignFactoryProtocol { + func serializeSigningMessage(from message: JSON) throws -> Data +} + +final class PolkadotExtensionMessageSignFactory: DAppMessageSignFactoryProtocol { + private func serializeMessage(from message: JSON) throws -> Data { + if case let .stringValue(stringValue) = message { + if stringValue.isHex() { + return try Data(hexString: stringValue) + } else { + guard let data = stringValue.data(using: .utf8) else { + throw CommonError.dataCorruption + } + + return data + } + + } else { + throw CommonError.dataCorruption + } + } + + private func wrappingMessageIfNeeded(_ message: Data) throws -> Data { + let prefix = "" + let suffix = "" + + guard let suffixData = suffix.data(using: .ascii), let prefixData = prefix.data(using: .ascii) else { + throw CommonError.dataCorruption + } + + if + message.prefix(prefixData.count) == prefixData, + message.suffix(suffixData.count) == suffixData { + return message + } + + return prefixData + message + suffixData + } + + func serializeSigningMessage(from message: JSON) throws -> Data { + let serializedMessage = try serializeMessage(from: message) + let wrappedMessage = try wrappingMessageIfNeeded(serializedMessage) + + return wrappedMessage + } +}