diff --git a/Shared/Defaults.swift b/Balance Shared/Defaults.swift similarity index 100% rename from Shared/Defaults.swift rename to Balance Shared/Defaults.swift diff --git a/Shared/Ethereum/Ethereum.swift b/Balance Shared/Ethereum/Ethereum.swift similarity index 100% rename from Shared/Ethereum/Ethereum.swift rename to Balance Shared/Ethereum/Ethereum.swift diff --git a/Shared/Ethereum/EthereumNetwork.swift b/Balance Shared/Ethereum/EthereumNetwork.swift similarity index 100% rename from Shared/Ethereum/EthereumNetwork.swift rename to Balance Shared/Ethereum/EthereumNetwork.swift diff --git a/Shared/Ethereum/Transaction.swift b/Balance Shared/Ethereum/Transaction.swift similarity index 100% rename from Shared/Ethereum/Transaction.swift rename to Balance Shared/Ethereum/Transaction.swift diff --git a/Shared/Models/ApprovalSubject.swift b/Balance Shared/Models/ApprovalSubject.swift similarity index 100% rename from Shared/Models/ApprovalSubject.swift rename to Balance Shared/Models/ApprovalSubject.swift diff --git a/Shared/Models/AuthenticationReason.swift b/Balance Shared/Models/AuthenticationReason.swift similarity index 100% rename from Shared/Models/AuthenticationReason.swift rename to Balance Shared/Models/AuthenticationReason.swift diff --git a/Shared/Models/PeerMeta.swift b/Balance Shared/Models/PeerMeta.swift similarity index 100% rename from Shared/Models/PeerMeta.swift rename to Balance Shared/Models/PeerMeta.swift diff --git a/Shared/Models/SafariRequest+Helpers.swift b/Balance Shared/Models/SafariRequest+Helpers.swift similarity index 100% rename from Shared/Models/SafariRequest+Helpers.swift rename to Balance Shared/Models/SafariRequest+Helpers.swift diff --git a/Shared/Services/GasService.swift b/Balance Shared/Services/GasService.swift similarity index 100% rename from Shared/Services/GasService.swift rename to Balance Shared/Services/GasService.swift diff --git a/Shared/Services/NetworkMonitor.swift b/Balance Shared/Services/NetworkMonitor.swift similarity index 100% rename from Shared/Services/NetworkMonitor.swift rename to Balance Shared/Services/NetworkMonitor.swift diff --git a/Shared/Services/PriceService.swift b/Balance Shared/Services/PriceService.swift similarity index 100% rename from Shared/Services/PriceService.swift rename to Balance Shared/Services/PriceService.swift diff --git a/Shared/Services/ReviewRequester.swift b/Balance Shared/Services/ReviewRequester.swift similarity index 100% rename from Shared/Services/ReviewRequester.swift rename to Balance Shared/Services/ReviewRequester.swift diff --git a/Shared/Services/SessionStorage.swift b/Balance Shared/Services/SessionStorage.swift similarity index 100% rename from Shared/Services/SessionStorage.swift rename to Balance Shared/Services/SessionStorage.swift diff --git a/Shared/Strings.swift b/Balance Shared/Strings.swift similarity index 100% rename from Shared/Strings.swift rename to Balance Shared/Strings.swift diff --git a/Balance iOS/Data/FlagsExtension.swift b/Balance iOS/Data/FlagsExtension.swift index 80d199183..702f9c764 100644 --- a/Balance iOS/Data/FlagsExtension.swift +++ b/Balance iOS/Data/FlagsExtension.swift @@ -20,7 +20,7 @@ extension Flags { static var last_selected_network: EthereumChain { get { - guard let id = UserDefaults.standard.value(forKey: "last_selected_ethereum_chain") as? Int else { return EthereumChain.ethereum } + guard let id = UserDefaults.standard.value(forKey: "last_selected_ethereum_chain") as? UInt else { return EthereumChain.ethereum } return EthereumChain(rawValue: id) ?? .ethereum } set { UserDefaults.standard.set(newValue.rawValue, forKey: "last_selected_ethereum_chain") } diff --git a/Balance iOS/Resources/Entitlements.entitlements b/Balance iOS/Resources/Entitlements.entitlements index ff2a550bc..81dd2cff4 100644 --- a/Balance iOS/Resources/Entitlements.entitlements +++ b/Balance iOS/Resources/Entitlements.entitlements @@ -6,5 +6,9 @@ group.io.balance + keychain-access-groups + + $(AppIdentifierPrefix)io.balance + diff --git a/Balance iOS/Services/ExtensionService.swift b/Balance iOS/Services/ExtensionService.swift index 9635bbe2e..d1b45a001 100644 --- a/Balance iOS/Services/ExtensionService.swift +++ b/Balance iOS/Services/ExtensionService.swift @@ -24,6 +24,11 @@ enum ExtensionService { self.showErrorAlert("Can't get ETH Address") return } + guard let host = request.host else { + self.showErrorAlert("Can't get host") + return + } + Approvals.approve(account: address, on: host) let response = ResponseToExtension(id: request.id, name: request.name, results: [address], chainId: chain.hexStringId, rpcURL: chain.nodeURLString) self.respondTo(request: request, response: response, on: controller) }, on: controller) diff --git a/Balance iOS/Services/WalletsManagerExtension.swift b/Balance iOS/Services/WalletsManagerExtension.swift index dd570bb14..cf6a74cde 100644 --- a/Balance iOS/Services/WalletsManagerExtension.swift +++ b/Balance iOS/Services/WalletsManagerExtension.swift @@ -31,5 +31,6 @@ extension WalletsManager { Flags.show_safari_extension_advice = true AppDelegate.migration() NotificationCenter.default.post(name: .walletsUpdated, object: nil) + Approvals.destroy() } } diff --git a/Balance.xcodeproj/project.pbxproj b/Balance.xcodeproj/project.pbxproj index 9eefc2a0e..524b5ed93 100644 --- a/Balance.xcodeproj/project.pbxproj +++ b/Balance.xcodeproj/project.pbxproj @@ -48,8 +48,6 @@ 2C6B964F26B9D98C00D2C819 /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C6B964E26B9D98C00D2C819 /* Colors.xcassets */; }; 2C773F5C2742D483007B04E7 /* SafariRequest+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F5B2742D483007B04E7 /* SafariRequest+Helpers.swift */; }; 2C773F5E27450B97007B04E7 /* ExtensionBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F5D27450B97007B04E7 /* ExtensionBridge.swift */; }; - 2C773F5F27450FBD007B04E7 /* ExtensionBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F5D27450B97007B04E7 /* ExtensionBridge.swift */; }; - 2C773F62274523DC007B04E7 /* ResponseToExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F61274523DC007B04E7 /* ResponseToExtension.swift */; }; 2C773F63274523DC007B04E7 /* ResponseToExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F61274523DC007B04E7 /* ResponseToExtension.swift */; }; 2C78F8282683BDCC00C10670 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C78F8272683BDCC00C10670 /* Alert.swift */; }; 2C797E7E267BB88800F2CE2D /* WelcomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C797E7D267BB88800F2CE2D /* WelcomeViewController.swift */; }; @@ -97,8 +95,6 @@ 2CC8C5A7276A54DA0083FB1B /* macos-specific-background.js in Resources */ = {isa = PBXBuildFile; fileRef = 2CC8C5A6276A54DA0083FB1B /* macos-specific-background.js */; }; 2CC8C5AC276A7EF70083FB1B /* EthereumChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9F0B6726BDCB2E008FA3D6 /* EthereumChain.swift */; }; 2CC8C5AD276A7EF80083FB1B /* EthereumChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9F0B6726BDCB2E008FA3D6 /* EthereumChain.swift */; }; - 2CC8C5AF276A7F310083FB1B /* SafariRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC8C5AE276A7F310083FB1B /* SafariRequest.swift */; }; - 2CC8C5B0276A7F310083FB1B /* SafariRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC8C5AE276A7F310083FB1B /* SafariRequest.swift */; }; 2CC8C5B1276A7F310083FB1B /* SafariRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC8C5AE276A7F310083FB1B /* SafariRequest.swift */; }; 2CC8C5B2276A7F310083FB1B /* SafariRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC8C5AE276A7F310083FB1B /* SafariRequest.swift */; }; 2CC8C5B4276A96760083FB1B /* Haptic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC8C5B3276A96760083FB1B /* Haptic.swift */; }; @@ -116,11 +112,8 @@ 2CE0594127640E8E0042D844 /* content.js in Resources */ = {isa = PBXBuildFile; fileRef = 2C09CBAC273979C1009AD39B /* content.js */; }; 2CE0594227640E8E0042D844 /* inpage.js in Resources */ = {isa = PBXBuildFile; fileRef = 2CEFEB15274D5DC900CE23BD /* inpage.js */; }; 2CE0594327640EAB0042D844 /* ExtensionBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F5D27450B97007B04E7 /* ExtensionBridge.swift */; }; - 2CE0594427640EB40042D844 /* ExtensionBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F5D27450B97007B04E7 /* ExtensionBridge.swift */; }; 2CE0594527640EF10042D844 /* ResponseToExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F61274523DC007B04E7 /* ResponseToExtension.swift */; }; 2CE0594627640F470042D844 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC89470269A334A00879245 /* UserDefaults.swift */; }; - 2CE059492764D69D0042D844 /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C09CBA1273979C1009AD39B /* SafariWebExtensionHandler.swift */; }; - 2CE0594A2764D69D0042D844 /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C09CBA1273979C1009AD39B /* SafariWebExtensionHandler.swift */; }; 2CE3D012267F73C00032A62E /* Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE3D011267F73C00032A62E /* Transaction.swift */; }; 2CEFEB16274D5DCA00CE23BD /* inpage.js in Resources */ = {isa = PBXBuildFile; fileRef = 2CEFEB15274D5DC900CE23BD /* inpage.js */; }; 2CF25597275A46D300AE54B9 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C528A15267FA8EB00CA3ADD /* Defaults.swift */; }; @@ -145,7 +138,6 @@ 2CF255AC275A48CF00AE54B9 /* EthereumNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9F0B6426BDC9AF008FA3D6 /* EthereumNetwork.swift */; }; 2CF255AD275A48CF00AE54B9 /* EthereumChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9F0B6726BDCB2E008FA3D6 /* EthereumChain.swift */; }; 2CF255AE275A48CF00AE54B9 /* Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE3D011267F73C00032A62E /* Transaction.swift */; }; - 2CF255B1275A4A1800AE54B9 /* ResponseToExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F61274523DC007B04E7 /* ResponseToExtension.swift */; }; 2CF255B2275A4A7200AE54B9 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC89470269A334A00879245 /* UserDefaults.swift */; }; 2CF255B4275A744000AE54B9 /* PasswordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CF255B3275A744000AE54B9 /* PasswordViewController.swift */; }; 2CF255B6275A746000AE54B9 /* AccountsListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CF255B5275A746000AE54B9 /* AccountsListViewController.swift */; }; @@ -154,6 +146,32 @@ 2CFDDF4C2765416F00F89019 /* macos-specific-content.js in Resources */ = {isa = PBXBuildFile; fileRef = 2CFDDF4B2765416F00F89019 /* macos-specific-content.js */; }; 2CFDDF4E2765417E00F89019 /* ios-specific-content.js in Resources */ = {isa = PBXBuildFile; fileRef = 2CFDDF4D2765417D00F89019 /* ios-specific-content.js */; }; 6EAC8FE927B2D60900F7E4DE /* BlockiesAddressTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EAC8FE827B2D60900F7E4DE /* BlockiesAddressTableViewCell.swift */; }; + 6EAC8FEC27B6626800F7E4DE /* Approvals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EAC8FEB27B6626800F7E4DE /* Approvals.swift */; }; + 6EAC8FED27B6626800F7E4DE /* Approvals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EAC8FEB27B6626800F7E4DE /* Approvals.swift */; }; + 6EAC8FEE27B6626800F7E4DE /* Approvals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EAC8FEB27B6626800F7E4DE /* Approvals.swift */; }; + 6EAC8FEF27B6626800F7E4DE /* Approvals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EAC8FEB27B6626800F7E4DE /* Approvals.swift */; }; + 6EAC8FF027B664CB00F7E4DE /* SafariRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC8C5AE276A7F310083FB1B /* SafariRequest.swift */; }; + 6EAC8FF127B664CB00F7E4DE /* SafariRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC8C5AE276A7F310083FB1B /* SafariRequest.swift */; }; + 6EAC8FF227B664CB00F7E4DE /* ResponseToExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F61274523DC007B04E7 /* ResponseToExtension.swift */; }; + 6EAC8FF327B664CB00F7E4DE /* ResponseToExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F61274523DC007B04E7 /* ResponseToExtension.swift */; }; + 6EAC8FF427B664E700F7E4DE /* ExtensionBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F5D27450B97007B04E7 /* ExtensionBridge.swift */; }; + 6EAC8FF527B664E800F7E4DE /* ExtensionBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C773F5D27450B97007B04E7 /* ExtensionBridge.swift */; }; + 6EAC8FF927B6996F00F7E4DE /* TokenaryWallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD0668B26B2142000728C20 /* TokenaryWallet.swift */; }; + 6EAC8FFA27B6996F00F7E4DE /* WalletsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD0668926B213E500728C20 /* WalletsManager.swift */; }; + 6EAC8FFB27B6997000F7E4DE /* TokenaryWallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD0668B26B2142000728C20 /* TokenaryWallet.swift */; }; + 6EAC8FFC27B6997000F7E4DE /* WalletsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD0668926B213E500728C20 /* WalletsManager.swift */; }; + 6EAC8FFE27B69F0900F7E4DE /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C917428267D2A6E00049075 /* Keychain.swift */; }; + 6EAC8FFF27B69F0A00F7E4DE /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C917428267D2A6E00049075 /* Keychain.swift */; }; + 6EAC900027B69F4100F7E4DE /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6706A4267A6BFE006AAEF2 /* Bundle.swift */; }; + 6EAC900127B69F4100F7E4DE /* URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C96D39727623EC600687301 /* URL.swift */; }; + 6EAC900227B69F4100F7E4DE /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C03D1D4269B428C00EF10EA /* Notification.swift */; }; + 6EAC900327B69F4100F7E4DE /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C603D0126B6E13F00956955 /* String.swift */; }; + 6EAC900427B69F4100F7E4DE /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6706A4267A6BFE006AAEF2 /* Bundle.swift */; }; + 6EAC900527B69F4100F7E4DE /* URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C96D39727623EC600687301 /* URL.swift */; }; + 6EAC900627B69F4100F7E4DE /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C03D1D4269B428C00EF10EA /* Notification.swift */; }; + 6EAC900727B69F4100F7E4DE /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C603D0126B6E13F00956955 /* String.swift */; }; + 6EAC900827B69F9700F7E4DE /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = F468F02327A025AB007DD803 /* Notifications.swift */; }; + 98870B0CF598B9ED35EB432A /* Pods_Safari_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA70465E4A8AD5C405A76C02 /* Pods_Safari_iOS.framework */; }; DFC5A10D00631755121FCBE6 /* Pods_Balance_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29A83FE96A68BB9F154134EF /* Pods_Balance_iOS.framework */; }; F40432D527AAA082001E8F1D /* WalletExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F40432D427AAA082001E8F1D /* WalletExtension.swift */; }; F42D390727A9657A006DCF5B /* ExtensionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F42D390627A9657A006DCF5B /* ExtensionService.swift */; }; @@ -404,10 +422,14 @@ 2CFDDF4B2765416F00F89019 /* macos-specific-content.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "macos-specific-content.js"; sourceTree = ""; }; 2CFDDF4D2765417D00F89019 /* ios-specific-content.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "ios-specific-content.js"; sourceTree = ""; }; 4A2B4FCB9C257ECA0630805D /* Pods_Balance.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Balance.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5D0CBF6DF2B94AFADB417539 /* Pods-Safari iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Safari iOS.debug.xcconfig"; path = "Target Support Files/Pods-Safari iOS/Pods-Safari iOS.debug.xcconfig"; sourceTree = ""; }; 6EAC8FE827B2D60900F7E4DE /* BlockiesAddressTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockiesAddressTableViewCell.swift; sourceTree = ""; }; + 6EAC8FEB27B6626800F7E4DE /* Approvals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Approvals.swift; sourceTree = ""; }; 97732C86E51B06E7896F9030 /* Pods-Balance iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Balance iOS.release.xcconfig"; path = "Target Support Files/Pods-Balance iOS/Pods-Balance iOS.release.xcconfig"; sourceTree = ""; }; B0F99598E16ED4AD726860D3 /* Pods-Balance.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Balance.release.xcconfig"; path = "Target Support Files/Pods-Balance/Pods-Balance.release.xcconfig"; sourceTree = ""; }; C289F6A7A78D99CF20B75732 /* Pods-Balance.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Balance.debug.xcconfig"; path = "Target Support Files/Pods-Balance/Pods-Balance.debug.xcconfig"; sourceTree = ""; }; + EA70465E4A8AD5C405A76C02 /* Pods_Safari_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Safari_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EF3A81E9809BA8605D9E6E27 /* Pods-Safari iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Safari iOS.release.xcconfig"; path = "Target Support Files/Pods-Safari iOS/Pods-Safari iOS.release.xcconfig"; sourceTree = ""; }; F3B5261B155EF9E06AAD7D4C /* Pods-Balance iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Balance iOS.debug.xcconfig"; path = "Target Support Files/Pods-Balance iOS/Pods-Balance iOS.debug.xcconfig"; sourceTree = ""; }; F40432D427AAA082001E8F1D /* WalletExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletExtension.swift; sourceTree = ""; }; F42D390627A9657A006DCF5B /* ExtensionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionService.swift; sourceTree = ""; }; @@ -527,6 +549,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 98870B0CF598B9ED35EB432A /* Pods_Safari_iOS.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -554,6 +577,7 @@ children = ( 4A2B4FCB9C257ECA0630805D /* Pods_Balance.framework */, 29A83FE96A68BB9F154134EF /* Pods_Balance_iOS.framework */, + EA70465E4A8AD5C405A76C02 /* Pods_Safari_iOS.framework */, ); name = Frameworks; sourceTree = ""; @@ -584,7 +608,8 @@ F468EFC527A00EAB007DD803 /* Constants */, F468EFC427A00EAA007DD803 /* ExtensionImport */, F468EFC327A00E84007DD803 /* AppImport */, - 2CCEB7A127592A1F00768473 /* Shared */, + 6EAC8FEA27B6625400F7E4DE /* Shared */, + 2CCEB7A127592A1F00768473 /* Balance Shared */, 2C5FF97026C84F7B00B32ACC /* Balance iOS */, 2C19953E2674C4B900A8E370 /* Balance macOS */, 2CCEB7A227592A3800768473 /* Safari-Shared */, @@ -693,7 +718,6 @@ children = ( 2C1995552674D0F300A8E370 /* Ethereum.swift */, 2C9F0B6426BDC9AF008FA3D6 /* EthereumNetwork.swift */, - 2C9F0B6726BDCB2E008FA3D6 /* EthereumChain.swift */, 2CE3D011267F73C00032A62E /* Transaction.swift */, ); path = Ethereum; @@ -794,19 +818,16 @@ path = Extensions; sourceTree = ""; }; - 2CCEB7A127592A1F00768473 /* Shared */ = { + 2CCEB7A127592A1F00768473 /* Balance Shared */ = { isa = PBXGroup; children = ( - 0A0C549627AB29E0004510F4 /* Supporting Files */, 2C901C492689F01700D0926A /* Strings.swift */, 2C528A15267FA8EB00CA3ADD /* Defaults.swift */, 2C8A09C2267513A700993638 /* Ethereum */, 2CF255A4275A483600AE54B9 /* Services */, - 2CF2559F275A47B600AE54B9 /* Extension */, - 2CD0668826B213BB00728C20 /* Wallets */, 2CF25596275A468B00AE54B9 /* Models */, ); - path = Shared; + path = "Balance Shared"; sourceTree = ""; }; 2CCEB7A227592A3800768473 /* Safari-Shared */ = { @@ -815,9 +836,6 @@ 2CB3844227654BD500A189B9 /* web3-provider */, 2CB3844027654A0D00A189B9 /* Resources */, 2C09CBA1273979C1009AD39B /* SafariWebExtensionHandler.swift */, - 2C773F5D27450B97007B04E7 /* ExtensionBridge.swift */, - 2CC8C5AE276A7F310083FB1B /* SafariRequest.swift */, - 2C773F61274523DC007B04E7 /* ResponseToExtension.swift */, ); path = "Safari-Shared"; sourceTree = ""; @@ -850,6 +868,7 @@ 2CD0668826B213BB00728C20 /* Wallets */ = { isa = PBXGroup; children = ( + 6EAC8FEB27B6626800F7E4DE /* Approvals.swift */, 2CD0668926B213E500728C20 /* WalletsManager.swift */, 2CD0668B26B2142000728C20 /* TokenaryWallet.swift */, ); @@ -870,6 +889,7 @@ 2CF2559F275A47B600AE54B9 /* Extension */ = { isa = PBXGroup; children = ( + F468F02327A025AB007DD803 /* Notifications.swift */, 2CC89470269A334A00879245 /* UserDefaults.swift */, 2C6706A4267A6BFE006AAEF2 /* Bundle.swift */, 2C96D39727623EC600687301 /* URL.swift */, @@ -887,7 +907,6 @@ 2C901C4C268A033100D0926A /* GasService.swift */, 2CC0CDBD2692027E0072922A /* PriceService.swift */, 2CC8946E269A2E8C00879245 /* SessionStorage.swift */, - 2C917428267D2A6E00049075 /* Keychain.swift */, ); path = Services; sourceTree = ""; @@ -903,6 +922,29 @@ path = Screens; sourceTree = ""; }; + 6EAC8FEA27B6625400F7E4DE /* Shared */ = { + isa = PBXGroup; + children = ( + 2CC8C5AE276A7F310083FB1B /* SafariRequest.swift */, + 2C773F61274523DC007B04E7 /* ResponseToExtension.swift */, + 2C773F5D27450B97007B04E7 /* ExtensionBridge.swift */, + 2C9F0B6726BDCB2E008FA3D6 /* EthereumChain.swift */, + 2CF2559F275A47B600AE54B9 /* Extension */, + 6EAC8FFD27B69EE000F7E4DE /* Services */, + 2CD0668826B213BB00728C20 /* Wallets */, + 0A0C549627AB29E0004510F4 /* Supporting Files */, + ); + path = Shared; + sourceTree = ""; + }; + 6EAC8FFD27B69EE000F7E4DE /* Services */ = { + isa = PBXGroup; + children = ( + 2C917428267D2A6E00049075 /* Keychain.swift */, + ); + path = Services; + sourceTree = ""; + }; F43F0A7927AD40720099C2C7 /* Localisations */ = { isa = PBXGroup; children = ( @@ -947,7 +989,6 @@ F468EFCD27A00EEE007DD803 /* Scenes */, F468EFD127A00EEE007DD803 /* UISceneConfiguration+Scene.swift */, F468EFD227A00EEE007DD803 /* SceneUserActivity.swift */, - F468F02327A025AB007DD803 /* Notifications.swift */, ); path = App; sourceTree = ""; @@ -1214,6 +1255,8 @@ B0F99598E16ED4AD726860D3 /* Pods-Balance.release.xcconfig */, F3B5261B155EF9E06AAD7D4C /* Pods-Balance iOS.debug.xcconfig */, 97732C86E51B06E7896F9030 /* Pods-Balance iOS.release.xcconfig */, + 5D0CBF6DF2B94AFADB417539 /* Pods-Safari iOS.debug.xcconfig */, + EF3A81E9809BA8605D9E6E27 /* Pods-Safari iOS.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -1319,6 +1362,7 @@ isa = PBXNativeTarget; buildConfigurationList = 2CCEB84927594E2A00768473 /* Build configuration list for PBXNativeTarget "Safari iOS" */; buildPhases = ( + BFEADAB775F99A4944B92A65 /* [CP] Check Pods Manifest.lock */, 2CB3844927654C8D00A189B9 /* ShellScript */, 2CCEB82927594E2A00768473 /* Sources */, 2CCEB82A27594E2A00768473 /* Frameworks */, @@ -1587,6 +1631,28 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + BFEADAB775F99A4944B92A65 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Safari iOS-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; F59181777D33C21BD946A400 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1612,11 +1678,19 @@ buildActionMask = 2147483647; files = ( 2CF255B2275A4A7200AE54B9 /* UserDefaults.swift in Sources */, + 6EAC900427B69F4100F7E4DE /* Bundle.swift in Sources */, 2C773F5E27450B97007B04E7 /* ExtensionBridge.swift in Sources */, + 6EAC8FEE27B6626800F7E4DE /* Approvals.swift in Sources */, F4AD4A0127ABD64B00F613AF /* Secrets.swift in Sources */, + 6EAC900527B69F4100F7E4DE /* URL.swift in Sources */, 2CC8C5AC276A7EF70083FB1B /* EthereumChain.swift in Sources */, + 6EAC8FFE27B69F0900F7E4DE /* Keychain.swift in Sources */, 2CC8C5B1276A7F310083FB1B /* SafariRequest.swift in Sources */, + 6EAC8FF927B6996F00F7E4DE /* TokenaryWallet.swift in Sources */, + 6EAC900627B69F4100F7E4DE /* Notification.swift in Sources */, 2C09CBA2273979C1009AD39B /* SafariWebExtensionHandler.swift in Sources */, + 6EAC900727B69F4100F7E4DE /* String.swift in Sources */, + 6EAC8FFA27B6996F00F7E4DE /* WalletsManager.swift in Sources */, 2C773F63274523DC007B04E7 /* ResponseToExtension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1632,19 +1706,20 @@ 2C8A09C6267513FC00993638 /* Agent.swift in Sources */, 2C8A09D42675184700993638 /* Window.swift in Sources */, 2C9F0B6526BDC9AF008FA3D6 /* EthereumNetwork.swift in Sources */, - 2C773F62274523DC007B04E7 /* ResponseToExtension.swift in Sources */, - 2CE0594A2764D69D0042D844 /* SafariWebExtensionHandler.swift in Sources */, 2CC8946F269A2E8C00879245 /* SessionStorage.swift in Sources */, 0DC850E726B73A5900809E82 /* AuthenticationReason.swift in Sources */, 2CAA412526C7CD93009F3535 /* ReviewRequester.swift in Sources */, + 6EAC8FF227B664CB00F7E4DE /* ResponseToExtension.swift in Sources */, 2CD0669126B5537B00728C20 /* TokenaryWallet.swift in Sources */, 2C0EE4022753874D00AC2AFA /* PeerMeta.swift in Sources */, 2C3B7F022756A08600931264 /* Identifiers.swift in Sources */, 2C8A09D726751A0C00993638 /* WalletConnect.swift in Sources */, 2C9F0B6826BDCB2E008FA3D6 /* EthereumChain.swift in Sources */, 2C03D1D2269B407900EF10EA /* NetworkMonitor.swift in Sources */, + 6EAC8FEC27B6626800F7E4DE /* Approvals.swift in Sources */, 2C8A09E326757FC000993638 /* AccountCellView.swift in Sources */, 2C6B964C26B9D92500D2C819 /* NSColor.swift in Sources */, + 6EAC8FF027B664CB00F7E4DE /* SafariRequest.swift in Sources */, 2C603D0226B6E13F00956955 /* String.swift in Sources */, 2C773F5C2742D483007B04E7 /* SafariRequest+Helpers.swift in Sources */, 2C134BA627553EC500DAFBDB /* Browser.swift in Sources */, @@ -1658,7 +1733,6 @@ 0D059AD226C2796200EE3023 /* ApprovalSubject.swift in Sources */, 2C1995422674C4B900A8E370 /* ImportViewController.swift in Sources */, 2C8E47A326A322E8007B8354 /* RightClickTableView.swift in Sources */, - 2C773F5F27450FBD007B04E7 /* ExtensionBridge.swift in Sources */, 2C96D39927623ECE00687301 /* URL.swift in Sources */, 2C901C472689E6D400D0926A /* ApproveTransactionViewController.swift in Sources */, 2CDAB3722675B3F0009F8B97 /* PasswordViewController.swift in Sources */, @@ -1667,10 +1741,10 @@ 2C528A16267FA8EB00CA3ADD /* Defaults.swift in Sources */, 2CD0B3F526A0DAA900488D92 /* NSPasteboard.swift in Sources */, 2CE3D012267F73C00032A62E /* Transaction.swift in Sources */, + 6EAC8FF527B664E800F7E4DE /* ExtensionBridge.swift in Sources */, 2C8A09EB2675964700993638 /* ApproveViewController.swift in Sources */, 2C03D1D5269B428C00EF10EA /* Notification.swift in Sources */, 2C1995562674D0F300A8E370 /* Ethereum.swift in Sources */, - 2CC8C5AF276A7F310083FB1B /* SafariRequest.swift in Sources */, 2C8A09DF267579EA00993638 /* AccountsListViewController.swift in Sources */, 2C917429267D2A6E00049075 /* Keychain.swift in Sources */, ); @@ -1727,8 +1801,8 @@ F468F00327A00EEE007DD803 /* Controllers.swift in Sources */, F4AD4A0027ABD64B00F613AF /* Secrets.swift in Sources */, F478A37027A1541200D1398B /* PhraceCollectionViewCell.swift in Sources */, - 2CE059492764D69D0042D844 /* SafariWebExtensionHandler.swift in Sources */, 2CF2559A275A46E400AE54B9 /* SafariRequest+Helpers.swift in Sources */, + 6EAC8FF427B664E700F7E4DE /* ExtensionBridge.swift in Sources */, F468B96627A70D0B00314201 /* WalletsManagerExtension.swift in Sources */, 2CC8C5A22767D3B30083FB1B /* GasPriceSliderTableViewCell.swift in Sources */, F478A36027A149AB00D1398B /* WalletOnboardingController.swift in Sources */, @@ -1740,6 +1814,7 @@ 2CC6EF0D275E64810040CC62 /* UIViewController.swift in Sources */, F4B4CD9327A29B9100300582 /* PasswordController.swift in Sources */, 2CF255A9275A48BB00AE54B9 /* Keychain.swift in Sources */, + 6EAC8FED27B6626800F7E4DE /* Approvals.swift in Sources */, 2CF255A7275A48BB00AE54B9 /* PriceService.swift in Sources */, F4B4CD9C27A2A54F00300582 /* SetPasswrodOnboardingController.swift in Sources */, 2CF25598275A46D600AE54B9 /* Strings.swift in Sources */, @@ -1748,7 +1823,6 @@ 2C96D38F2762317300687301 /* AccountTableViewCell.swift in Sources */, 2CF255A1275A47DD00AE54B9 /* Notification.swift in Sources */, F468F02827A0292E007DD803 /* WalletController.swift in Sources */, - 2CC8C5B0276A7F310083FB1B /* SafariRequest.swift in Sources */, F4B4CD9E27A2A8BF00300582 /* SafariTableViewCell.swift in Sources */, F4B4CD9A27A2A4A200300582 /* ChangePassword.swift in Sources */, F478A36927A14A2D00D1398B /* BaseOnboardingController.swift in Sources */, @@ -1771,8 +1845,6 @@ 2CF255AD275A48CF00AE54B9 /* EthereumChain.swift in Sources */, 2CF2559C275A477F00AE54B9 /* ApprovalSubject.swift in Sources */, F468F01827A019E4007DD803 /* FlagsExtension.swift in Sources */, - 2CE0594427640EB40042D844 /* ExtensionBridge.swift in Sources */, - 2CF255B1275A4A1800AE54B9 /* ResponseToExtension.swift in Sources */, 2CF2559B275A46E700AE54B9 /* AuthenticationReason.swift in Sources */, 2C96D3A92763D13400687301 /* DataStateView.swift in Sources */, F4FB72E727A439B1008AFFF3 /* InterfaceAppearance.swift in Sources */, @@ -1782,6 +1854,7 @@ F478A37827A16E9800D1398B /* WalletPhracesActionsController.swift in Sources */, F468EFF327A00EEE007DD803 /* UISceneConfiguration+Scene.swift in Sources */, 2CF255B8275A748300AE54B9 /* ApproveTransactionViewController.swift in Sources */, + 6EAC8FF127B664CB00F7E4DE /* SafariRequest.swift in Sources */, F468F02E27A03077007DD803 /* WalletsController.swift in Sources */, F468EFF227A00EEE007DD803 /* SettingsSceneDelegate.swift in Sources */, F4FB72DF27A4351E008AFFF3 /* OnboardingBenefitsController.swift in Sources */, @@ -1805,6 +1878,7 @@ 2CF2559E275A479800AE54B9 /* WalletsManager.swift in Sources */, F42D390727A9657A006DCF5B /* ExtensionService.swift in Sources */, F478A37227A15BF600D1398B /* AuthService.swift in Sources */, + 6EAC8FF327B664CB00F7E4DE /* ResponseToExtension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1822,11 +1896,20 @@ buildActionMask = 2147483647; files = ( 2CE0594627640F470042D844 /* UserDefaults.swift in Sources */, + 6EAC900027B69F4100F7E4DE /* Bundle.swift in Sources */, 2CE0594327640EAB0042D844 /* ExtensionBridge.swift in Sources */, + 6EAC8FEF27B6626800F7E4DE /* Approvals.swift in Sources */, F4AD4A0227ABD64B00F613AF /* Secrets.swift in Sources */, + 6EAC900127B69F4100F7E4DE /* URL.swift in Sources */, 2CC8C5AD276A7EF80083FB1B /* EthereumChain.swift in Sources */, + 6EAC8FFF27B69F0A00F7E4DE /* Keychain.swift in Sources */, + 6EAC900827B69F9700F7E4DE /* Notifications.swift in Sources */, 2CC8C5B2276A7F310083FB1B /* SafariRequest.swift in Sources */, + 6EAC8FFB27B6997000F7E4DE /* TokenaryWallet.swift in Sources */, + 6EAC900227B69F4100F7E4DE /* Notification.swift in Sources */, 2CE0593F27640E300042D844 /* SafariWebExtensionHandler.swift in Sources */, + 6EAC900327B69F4100F7E4DE /* String.swift in Sources */, + 6EAC8FFC27B6997000F7E4DE /* WalletsManager.swift in Sources */, 2CE0594527640EF10042D844 /* ResponseToExtension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2212,6 +2295,7 @@ }; 2CCEB84727594E2A00768473 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 5D0CBF6DF2B94AFADB417539 /* Pods-Safari iOS.debug.xcconfig */; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CODE_SIGN_ENTITLEMENTS = "Safari iOS/Safari iOS.entitlements"; @@ -2245,6 +2329,7 @@ }; 2CCEB84827594E2A00768473 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = EF3A81E9809BA8605D9E6E27 /* Pods-Safari iOS.release.xcconfig */; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CODE_SIGN_ENTITLEMENTS = "Safari iOS/Safari iOS.entitlements"; diff --git a/Podfile b/Podfile index 89ba34332..c4920e9c9 100644 --- a/Podfile +++ b/Podfile @@ -18,3 +18,8 @@ target 'Balance iOS' do platform :ios, '15.0' shared_pods end + +target 'Safari iOS' do + platform :ios, '15.0' + shared_pods +end diff --git a/Podfile.lock b/Podfile.lock index 8b60e5ddb..e6b31ecde 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -82,6 +82,6 @@ SPEC CHECKSUMS: WalletConnect: 1df75d4355b1cacfc27d7ef2416fae43862d0eb4 Web3Swift.io: 18fd06aed9d56df9c704f9c6f87b06675bb05b53 -PODFILE CHECKSUM: 6773ec1c4d4258d4c280c95fc82c4059cc57c2ea +PODFILE CHECKSUM: e039b8dda181cd1d25c39acddcf79565c6a216e0 COCOAPODS: 1.11.2 diff --git a/Safari iOS/Resources/popup.js b/Safari iOS/Resources/popup.js index 04b3d379b..6942aacba 100644 --- a/Safari iOS/Resources/popup.js +++ b/Safari iOS/Resources/popup.js @@ -125,7 +125,7 @@ const $ = (query) => const render = (query, view) => $(query).innerHTML = view(); // todo sanitize? -document.addEventListener(`DOMContentLoaded`, () => { +document.addEventListener(`DOMContentLoaded`, async () => { browser.runtime.onMessage.addListener((request, sender, sendResponse) => { if (typeof request.message.address !== `undefined` && typeof request.message.balance !== `undefined` && typeof request.message.chainId !== `undefined` && typeof request.message.connected !== `undefined`) { if (request.message.connected === true) { @@ -156,4 +156,18 @@ document.addEventListener(`DOMContentLoaded`, () => { message: `get_state`, }, }); + + + + const result = await browser.runtime.sendNativeMessage("io.balance", {id: 1, subject: "getAccounts"}); + const log = document.createElement('div') + log.style.color = "black" + log.textContent = JSON.stringify(result) + document.body.appendChild(log) + + const chains = await browser.runtime.sendNativeMessage("io.balance", {id: 1, subject: "getChains"}); + const log2 = document.createElement('div') + log2.style.color = "black" + log2.textContent = JSON.stringify(chains) + document.body.appendChild(log2) }); diff --git a/Safari iOS/Safari iOS.entitlements b/Safari iOS/Safari iOS.entitlements index ff2a550bc..81dd2cff4 100644 --- a/Safari iOS/Safari iOS.entitlements +++ b/Safari iOS/Safari iOS.entitlements @@ -6,5 +6,9 @@ group.io.balance + keychain-access-groups + + $(AppIdentifierPrefix)io.balance + diff --git a/Safari-Shared/Resources/content.js b/Safari-Shared/Resources/content.js index 947942c2a..d3723834e 100644 --- a/Safari-Shared/Resources/content.js +++ b/Safari-Shared/Resources/content.js @@ -85,19 +85,27 @@ if (shouldInjectProvider()) { getLatestConfiguration(); } -function getLatestConfiguration() { - const storageItem = browser.storage.local.get(window.location.host); - storageItem.then((storage) => { - const latest = storage[window.location.host]; - var response = { results: [], chainId: "", name: "didLoadLatestConfiguration", rpcURL: "" }; - if (typeof latest !== "undefined" && "results" in latest && latest.results.length > 0 && latest.rpcURL.length > 0) { - response.results = latest.results; - response.chainId = latest.chainId; - response.rpcURL = latest.rpcURL; - } - const id = new Date().getTime() + Math.floor(Math.random() * 1000); - window.postMessage({ direction: "from-content-script", response: response, id: id }, "*"); - }); +async function getLatestConfiguration() { + const id = new Date().getTime() + Math.floor(Math.random() * 1000); + const approvalsResponse = await browser.runtime.sendMessage({ subject: "process-inpage-message", message: { id, subject: "getApprovals", host: window.location.host } }); + const approvals = JSON.parse(approvalsResponse.result); + const storageItem = await browser.storage.local.get(window.location.host); + const latest = storageItem[window.location.host]; + var response = { results: [], chainId: "", name: "didLoadLatestConfiguration", rpcURL: "" }; + if ( + typeof latest === "object" && + Array.isArray(latest.results) && + latest.results.length > 0 && + typeof latest.results[0] === "string" && + Array.isArray(approvals) && + approvals.includes(latest.results[0].toLowerCase()) && + latest.rpcURL.length > 0 + ) { + response.results = latest.results; + response.chainId = latest.chainId; + response.rpcURL = latest.rpcURL; + } + window.postMessage({ direction: "from-content-script", response, id }, "*"); } function storeConfigurationIfNeeded(request) { diff --git a/Safari-Shared/SafariWebExtensionHandler.swift b/Safari-Shared/SafariWebExtensionHandler.swift index 5966e9745..30b665cd3 100644 --- a/Safari-Shared/SafariWebExtensionHandler.swift +++ b/Safari-Shared/SafariWebExtensionHandler.swift @@ -4,22 +4,69 @@ import SafariServices let SFExtensionMessageKey = "message" +fileprivate func toJSON(from object:Any) throws -> String { + guard let result = String(data: try JSONSerialization.data(withJSONObject: object, options: []), encoding: .utf8) else { + throw "Failed to serialize JSON" + } + return result +} + class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { - private var context: NSExtensionContext? private let queue = DispatchQueue(label: "SafariWebExtensionHandler", qos: .default) func beginRequest(with context: NSExtensionContext) { guard let item = context.inputItems[0] as? NSExtensionItem, - let message = item.userInfo?[SFExtensionMessageKey], - let id = (message as? [String: Any])?["id"] as? Int else { return } + let message = item.userInfo?[SFExtensionMessageKey] as? [String: Any], + let id = message["id"] as? Int else { return } - let subject = (message as? [String: Any])?["subject"] as? String - if subject == "getResponse" { + let subject = message["subject"] as? String + if subject == "getAccounts" { + let manager = WalletsManager() + do { + try manager.start() + let addresses = try manager.wallets.map { wallet -> String in + guard let address = wallet.ethereumAddress else { throw "Failed retreiving Ethereum address" } + return address + } + let json = try toJSON(from: addresses) + context.respond(with: .init(id: id, name: "getAccounts", result: json)) + } catch { + context.respond(with: .init(id: id, name: "getAccounts", error: "An error occurred when fetching accounts: \(error.localizedDescription)")) + } + } else if subject == "getChains" { + do { + let mainnets = EthereumChain.allMainnets.reduce(into: [String: [String: Any]]()) { + $0[String($1.id)] = ["name": $1.name, "symbol": $1.symbol, "rpc": $1.nodeURLString, "isTestnet": false] + } + let chains = EthereumChain.allTestnets.reduce(into: mainnets) { + $0[String($1.id)] = ["name": $1.name, "symbol": $1.symbol, "rpc": $1.nodeURLString, "isTestnet": true] + } + context.respond(with: .init(id: id, name: "getChains", result: try toJSON(from: chains))) + } catch { + context.respond(with: .init(id: id, name: "getChains", error: "An error occurred when fetching accounts: \(error.localizedDescription)")) + } + } else if subject == "getApprovals" { + do { + guard let host = message["host"] as? String, host.count > 0 else { throw "`host` was invalid" } + context.respond(with: .init(id: id, name: "getApprovals", result: try toJSON(from: Approvals.getApprovals(for: host)))) + } catch { + context.respond(with: .init(id: id, name: "getApprovals", error: "An error occurred when fetching accounts: \(error.localizedDescription)")) + } + } else if subject == "approve" { + do { + // TODO: Actually validate address + guard let account = message["account"] as? String, account.count == 42 else { throw "`account` was invalid" } + guard let host = message["host"] as? String, host.count > 0 else { throw "`host` was invalid" } + Approvals.approve(account: account, on: host) + context.respond(with: .init(id: id, name: "getChains", result: "true")) + } catch { + context.respond(with: .init(id: id, name: "getChains", error: "An error occurred when fetching accounts: \(error.localizedDescription)")) + } + } else if subject == "getResponse" { #if !os(macOS) if let response = ExtensionBridge.getResponse(id: id) { - self.context = context - respond(with: response) + context.respond(with: response) ExtensionBridge.removeResponse(id: id) } #endif @@ -29,7 +76,6 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { let query = String(data: data, encoding: .utf8)?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let request = SafariRequest(query: query), let url = URL(string: "balance://safari?request=\(query)") { - self.context = context if request.method == .switchEthereumChain || request.method == .addEthereumChain { if let chain = request.switchToChain { let response = ResponseToExtension(id: request.id, @@ -37,39 +83,44 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { results: [request.address], chainId: chain.hexStringId, rpcURL: chain.nodeURLString) - respond(with: response) + context.respond(with: response) } else { let response = ResponseToExtension(id: request.id, name: request.name, error: "Failed to switch chain") - respond(with: response) + context.respond(with: response) } } else { ExtensionBridge.makeRequest(id: id) #if os(macOS) NSWorkspace.shared.open(url) #endif - poll(id: id) + poll(id: id, context: context) } } } - private func poll(id: Int) { + private func poll(id: Int, context: NSExtensionContext) { if let response = ExtensionBridge.getResponse(id: id) { - respond(with: response) + context.respond(with: response) #if os(macOS) ExtensionBridge.removeResponse(id: id) #endif } else { queue.asyncAfter(deadline: .now() + .milliseconds(500)) { [weak self] in - self?.poll(id: id) + self?.poll(id: id, context: context) } } } - private func respond(with response: ResponseToExtension) { +} + +extension NSExtensionContext { + func respond(with response: ResponseToExtension) { let item = NSExtensionItem() item.userInfo = [SFExtensionMessageKey: response.json] - context?.completeRequest(returningItems: [item], completionHandler: nil) - context = nil + self.completeRequest(returningItems: [item], completionHandler: nil) } - +} + +extension String: LocalizedError { + public var errorDescription: String? { return self } } diff --git a/Shared/Ethereum/EthereumChain.swift b/Shared/EthereumChain.swift similarity index 98% rename from Shared/Ethereum/EthereumChain.swift rename to Shared/EthereumChain.swift index 4f7f8aa14..d5e7779ec 100644 --- a/Shared/Ethereum/EthereumChain.swift +++ b/Shared/EthereumChain.swift @@ -2,7 +2,7 @@ import Foundation -enum EthereumChain: Int { +enum EthereumChain: UInt { case ethereum = 1 case arbitrum = 42161 case polygon = 137 @@ -22,7 +22,7 @@ enum EthereumChain: Int { case binanceTestnet = 97 case avalancheFuji = 43113 - var id: Int { + var id: UInt { return rawValue } diff --git a/Balance iOS/App/Notifications.swift b/Shared/Extension/Notifications.swift similarity index 100% rename from Balance iOS/App/Notifications.swift rename to Shared/Extension/Notifications.swift diff --git a/Safari-Shared/ExtensionBridge.swift b/Shared/ExtensionBridge.swift similarity index 100% rename from Safari-Shared/ExtensionBridge.swift rename to Shared/ExtensionBridge.swift diff --git a/Safari-Shared/ResponseToExtension.swift b/Shared/ResponseToExtension.swift similarity index 100% rename from Safari-Shared/ResponseToExtension.swift rename to Shared/ResponseToExtension.swift diff --git a/Safari-Shared/SafariRequest.swift b/Shared/SafariRequest.swift similarity index 97% rename from Safari-Shared/SafariRequest.swift rename to Shared/SafariRequest.swift index 7a143ea1b..a01269f29 100644 --- a/Safari-Shared/SafariRequest.swift +++ b/Shared/SafariRequest.swift @@ -64,7 +64,7 @@ struct SafariRequest { } var chain: EthereumChain? { - if let network = json["networkId"] as? String, let networkId = Int(network) { + if let network = json["networkId"] as? String, let networkId = UInt(network) { return EthereumChain(rawValue: networkId) } else { return nil @@ -83,7 +83,7 @@ struct SafariRequest { var switchToChain: EthereumChain? { if let chainId = (parameters?["chainId"] as? String)?.dropFirst(2), - let networkId = Int(chainId, radix: 16), + let networkId = UInt(chainId, radix: 16), let chain = EthereumChain(rawValue: networkId) { return chain } else { diff --git a/Shared/Wallets/Approvals.swift b/Shared/Wallets/Approvals.swift new file mode 100644 index 000000000..246c1e5bd --- /dev/null +++ b/Shared/Wallets/Approvals.swift @@ -0,0 +1,48 @@ +import Foundation + +fileprivate typealias ApprovalsDictionary = [String: [String]] + +enum Approvals { + + private static let key = "approvals" + + private static let defaults = UserDefaults(suiteName: "group.io.balance")! + + private static var dictionary: ApprovalsDictionary { + get { + defaults.dictionary(forKey: key) as? ApprovalsDictionary ?? [:] + } + set { + defaults.set(newValue, forKey: key) + } + } + + static func approve(account: String, on host: String) { + var approvals = getApprovals(for: host) + approvals.append(account.lowercased()) + dictionary[host] = approvals + } + + static func getApprovals(for host: String) -> [String] { + return dictionary[host] ?? [] + } + + static func removeApproval(for account: String, on host: String) { + dictionary[host] = getApprovals(for: host).filter { $0 != account.lowercased() } + } + + static func clearAllApprovals(for account: String) { + var dictionary = dictionary + for key in dictionary.keys { + guard var array = dictionary[key], let index = array.firstIndex(of: account.lowercased()) else { continue } + array.remove(at: index) + dictionary[key] = array + } + self.dictionary = dictionary + } + + static func destroy() { + self.dictionary = [:] + } + +} diff --git a/Shared/Wallets/WalletsManager.swift b/Shared/Wallets/WalletsManager.swift index c09fcc652..df127151c 100644 --- a/Shared/Wallets/WalletsManager.swift +++ b/Shared/Wallets/WalletsManager.swift @@ -19,8 +19,6 @@ final class WalletsManager { private let keychain = Keychain.shared private(set) var wallets = [TokenaryWallet]() - private init() {} - func start() throws { try load() } @@ -155,6 +153,9 @@ final class WalletsManager { defer { privateKey.resetBytes(in: 0..