diff --git a/Encrypted Ink.xcodeproj/project.pbxproj b/Encrypted Ink.xcodeproj/project.pbxproj index 6058a786..ab2f50ce 100644 --- a/Encrypted Ink.xcodeproj/project.pbxproj +++ b/Encrypted Ink.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ 2C09CBAD273979C1009AD39B /* content.js in Resources */ = {isa = PBXBuildFile; fileRef = 2C09CBAC273979C1009AD39B /* content.js */; }; 2C09CBB9273979C1009AD39B /* Safari.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 2C09CB9F273979C1009AD39B /* Safari.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 2C0EE4022753874D00AC2AFA /* PeerMeta.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0EE4012753874D00AC2AFA /* PeerMeta.swift */; }; + 2C134BA627553EC500DAFBDB /* Browser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C134BA527553EC500DAFBDB /* Browser.swift */; }; 2C1995402674C4B900A8E370 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C19953F2674C4B900A8E370 /* AppDelegate.swift */; }; 2C1995422674C4B900A8E370 /* ImportViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C1995412674C4B900A8E370 /* ImportViewController.swift */; }; 2C1995442674C4BA00A8E370 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C1995432674C4BA00A8E370 /* Assets.xcassets */; }; @@ -115,6 +116,7 @@ 2C09CBB4273979C1009AD39B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2C09CBB5273979C1009AD39B /* Safari.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Safari.entitlements; sourceTree = ""; }; 2C0EE4012753874D00AC2AFA /* PeerMeta.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerMeta.swift; sourceTree = ""; }; + 2C134BA527553EC500DAFBDB /* Browser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Browser.swift; sourceTree = ""; }; 2C19953C2674C4B900A8E370 /* Encrypted Ink.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Encrypted Ink.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 2C19953F2674C4B900A8E370 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 2C1995412674C4B900A8E370 /* ImportViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportViewController.swift; sourceTree = ""; }; @@ -222,6 +224,7 @@ children = ( 0DC850E626B73A5900809E82 /* AuthenticationReason.swift */, 0D059AD126C2796200EE3023 /* ApprovalSubject.swift */, + 2C134BA527553EC500DAFBDB /* Browser.swift */, 2C0EE4012753874D00AC2AFA /* PeerMeta.swift */, 2C773F5B2742D483007B04E7 /* SafariRequest.swift */, ); @@ -729,6 +732,7 @@ 2C6B964C26B9D92500D2C819 /* NSColor.swift in Sources */, 2C603D0226B6E13F00956955 /* String.swift in Sources */, 2C773F5C2742D483007B04E7 /* SafariRequest.swift in Sources */, + 2C134BA627553EC500DAFBDB /* Browser.swift in Sources */, 2CC89471269A334A00879245 /* UserDefaults.swift in Sources */, 2C78F8282683BDCC00C10670 /* Alert.swift in Sources */, 2C8A09EE2675965F00993638 /* WaitingViewController.swift in Sources */, diff --git a/Encrypted Ink/Agent.swift b/Encrypted Ink/Agent.swift index e07b3a8d..6f419f61 100644 --- a/Encrypted Ink/Agent.swift +++ b/Encrypted Ink/Agent.swift @@ -88,32 +88,32 @@ class Agent: NSObject { } } - func showApprove(transaction: Transaction, chain: EthereumChain, peerMeta: PeerMeta?, completion: @escaping (Transaction?) -> Void) { + func showApprove(transaction: Transaction, chain: EthereumChain, peerMeta: PeerMeta?, browser: Browser?, completion: @escaping (Transaction?) -> Void) { let windowController = Window.showNew() let approveViewController = ApproveTransactionViewController.with(transaction: transaction, chain: chain, peerMeta: peerMeta) { [weak self] transaction in if transaction != nil { self?.askAuthentication(on: windowController.window, onStart: false, reason: .sendTransaction) { success in completion(success ? transaction : nil) - Window.closeAllAndActivateBrowser() + Window.closeAllAndActivateBrowser(force: browser) } } else { - Window.closeAllAndActivateBrowser() + Window.closeAllAndActivateBrowser(force: browser) completion(nil) } } windowController.contentViewController = approveViewController } - func showApprove(subject: ApprovalSubject, meta: String, peerMeta: PeerMeta?, completion: @escaping (Bool) -> Void) { + func showApprove(subject: ApprovalSubject, meta: String, peerMeta: PeerMeta?, browser: Browser?, completion: @escaping (Bool) -> Void) { let windowController = Window.showNew() let approveViewController = ApproveViewController.with(subject: subject, meta: meta, peerMeta: peerMeta) { [weak self] result in if result { self?.askAuthentication(on: windowController.window, onStart: false, reason: subject.asAuthenticationReason) { success in completion(success) - Window.closeAllAndActivateBrowser() + Window.closeAllAndActivateBrowser(force: browser) } } else { - Window.closeAllAndActivateBrowser() + Window.closeAllAndActivateBrowser(force: browser) completion(result) } } @@ -301,7 +301,7 @@ class Agent: NSObject { walletConnect.connect(session: session, chainId: chainId, walletId: wallet.id) { [weak window] _ in if window?.isVisible == true { - Window.closeAllAndActivateBrowser() + Window.closeAllAndActivateBrowser(force: nil) } } } @@ -318,12 +318,12 @@ class Agent: NSObject { } else { // TODO: respond with error } - Window.closeAllAndActivateBrowser() + Window.closeAllAndActivateBrowser(force: .safari) case .signPersonalMessage: guard let data = safariRequest.message else { return }// TODO: respond with error let text = String(data: data, encoding: .utf8) ?? data.hexString // TODO: display meta and peerMeta - showApprove(subject: .signPersonalMessage, meta: text, peerMeta: peerMeta) { [weak self] approved in + showApprove(subject: .signPersonalMessage, meta: text, peerMeta: peerMeta, browser: .safari) { [weak self] approved in if approved { self?.signPersonalMessage(address: safariRequest.address, data: data, request: safariRequest) // TODO: sign and respond @@ -345,7 +345,7 @@ class Agent: NSObject { } else { ExtensionBridge.respond(id: safariRequest.id, response: ResponseToExtension(name: safariRequest.name, error: "Canceled")) } - Window.closeAllAndActivateBrowser() + Window.closeAllAndActivateBrowser(force: .safari) } // TODO: pass cancel as well @@ -356,7 +356,7 @@ class Agent: NSObject { } // TODO: display meta and peerMeta - showApprove(subject: .signMessage, meta: data.hexString, peerMeta: peerMeta) { [weak self] approved in + showApprove(subject: .signMessage, meta: data.hexString, peerMeta: peerMeta, browser: .safari) { [weak self] approved in if approved { self?.signMessage(address: safariRequest.address, data: data, request: safariRequest) // TODO: sign and respond @@ -368,7 +368,7 @@ class Agent: NSObject { guard let raw = safariRequest.raw else { return } // TODO: respond with error // TODO: display meta and peerMeta - showApprove(subject: .signTypedData, meta: raw, peerMeta: peerMeta) { [weak self] approved in + showApprove(subject: .signTypedData, meta: raw, peerMeta: peerMeta, browser: .safari) { [weak self] approved in if approved { self?.signTypedData(address: safariRequest.address, raw: raw, request: safariRequest) // TODO: sign and respond @@ -380,7 +380,7 @@ class Agent: NSObject { guard let transaction = safariRequest.transaction, let chain = safariRequest.chain else { return // TODO: respond with error } - showApprove(transaction: transaction, chain: chain, peerMeta: peerMeta) { [weak self] transaction in + showApprove(transaction: transaction, chain: chain, peerMeta: peerMeta, browser: .safari) { [weak self] transaction in if let transaction = transaction { self?.sendTransaction(transaction, address: safariRequest.address, chain: chain, request: safariRequest) // TODO: show some kind of spinner @@ -397,10 +397,10 @@ class Agent: NSObject { } else { ExtensionBridge.respond(id: safariRequest.id, response: ResponseToExtension(name: safariRequest.name, error: "Failed to verify")) } - Window.closeAllAndActivateBrowser() + Window.closeAllAndActivateBrowser(force: .safari) default: // TODO: implement all cases - Window.closeAllAndActivateBrowser() + Window.closeAllAndActivateBrowser(force: .safari) } } diff --git a/Encrypted Ink/Models/Browser.swift b/Encrypted Ink/Models/Browser.swift new file mode 100644 index 00000000..c599ab02 --- /dev/null +++ b/Encrypted Ink/Models/Browser.swift @@ -0,0 +1,17 @@ +// Copyright © 2021 Encrypted Ink. All rights reserved. + +import Foundation + +enum Browser: String, CaseIterable { + case safari = "com.apple.Safari" + case chrome = "com.google.Chrome" + case tor = "org.torproject.torbrowser" + case opera = "com.operasoftware.Opera" + case edge = "com.microsoft.edgemac" + case brave = "com.brave.Browser" + case firefox = "org.mozilla.firefox" + case vivaldi = "com.vivaldi.Vivaldi" + case yandex = "ru.yandex.desktop.yandex-browser" + + static let allBundleIds = Set(Browser.allCases.map { $0.rawValue }) +} diff --git a/Encrypted Ink/Screens/ErrorViewController.swift b/Encrypted Ink/Screens/ErrorViewController.swift index b73be4b8..e568785d 100644 --- a/Encrypted Ink/Screens/ErrorViewController.swift +++ b/Encrypted Ink/Screens/ErrorViewController.swift @@ -21,7 +21,7 @@ class ErrorViewController: NSViewController { } @IBAction func actionButtonTapped(_ sender: Any) { - Window.closeAllAndActivateBrowser() + Window.closeAllAndActivateBrowser(force: nil) } } diff --git a/Encrypted Ink/WalletConnect.swift b/Encrypted Ink/WalletConnect.swift index 48a8561a..34b729a3 100644 --- a/Encrypted Ink/WalletConnect.swift +++ b/Encrypted Ink/WalletConnect.swift @@ -132,7 +132,7 @@ class WalletConnect { let peer = PeerMeta(wcPeerMeta: getPeerOfInteractor(interactor)) let transaction = Transaction(from: wct.from, to: to, nonce: wct.nonce, gasPrice: wct.gasPrice, gas: wct.gas, value: wct.value, data: wct.data) - Agent.shared.showApprove(transaction: transaction, chain: chain, peerMeta: peer) { [weak self, weak interactor] transaction in + Agent.shared.showApprove(transaction: transaction, chain: chain, peerMeta: peer, browser: nil) { [weak self, weak interactor] transaction in if let transaction = transaction { self?.sendTransaction(transaction, walletId: walletId, chainId: chainId, requestId: id, interactor: interactor) } else { @@ -159,7 +159,7 @@ class WalletConnect { } let peer = PeerMeta(wcPeerMeta: getPeerOfInteractor(interactor)) - Agent.shared.showApprove(subject: approvalSubject, meta: message ?? "", peerMeta: peer) { [weak self, weak interactor] approved in + Agent.shared.showApprove(subject: approvalSubject, meta: message ?? "", peerMeta: peer, browser: nil) { [weak self, weak interactor] approved in if approved { self?.sign(id: id, payload: payload, walletId: walletId, interactor: interactor) } else { diff --git a/Encrypted Ink/Window.swift b/Encrypted Ink/Window.swift index 43c377c4..28aa521b 100644 --- a/Encrypted Ink/Window.swift +++ b/Encrypted Ink/Window.swift @@ -4,18 +4,6 @@ import Cocoa struct Window { - private static let browsersBundleIds = Set([ - "com.apple.Safari", - "com.google.Chrome", - "org.torproject.torbrowser", - "com.operasoftware.Opera", - "com.microsoft.edgemac", - "com.brave.Browser", - "org.mozilla.firefox", - "com.vivaldi.Vivaldi", - "ru.yandex.desktop.yandex-browser" - ]) - static func showNew() -> NSWindowController { closeAll() let windowController = new @@ -33,9 +21,9 @@ struct Window { window?.makeKeyAndOrderFront(nil) } - static func closeAllAndActivateBrowser() { + static func closeAllAndActivateBrowser(force browser: Browser?) { closeAll() - activateBrowser() + activateBrowser(force: browser) } static func closeAll(updateStatusBarItem: Bool = true) { @@ -45,10 +33,15 @@ struct Window { } } - static func activateBrowser() { + static func activateBrowser(force browser: Browser?) { + if let browser = browser { + activateBrowser(browser) + return + } + let browsers = NSWorkspace.shared.runningApplications.filter { app in if let bundleId = app.bundleIdentifier { - return browsersBundleIds.contains(bundleId) + return Browser.allBundleIds.contains(bundleId) } else { return false } @@ -67,6 +60,10 @@ struct Window { } } + private static func activateBrowser(_ browser: Browser) { + NSWorkspace.shared.runningApplications.first(where: { $0.bundleIdentifier == browser.rawValue })?.activate(options: .activateIgnoringOtherApps) + } + static var current: NSWindowController? { return NSApplication.shared.windows.first?.windowController }