diff --git a/macos/CakeWallet/decrypt.swift b/macos/CakeWallet/decrypt.swift new file mode 100644 index 000000000..5f24ad3fb --- /dev/null +++ b/macos/CakeWallet/decrypt.swift @@ -0,0 +1,16 @@ +import Foundation +import CryptoSwift + +func decrypt(data: Data, key: String, salt: String) -> String? { + let keyBytes = key.data(using: .utf8)?.bytes ?? [] + let saltBytes = salt.data(using: .utf8)?.bytes ?? [] + + guard let PBKDF2key = try? PKCS5.PBKDF2(password: keyBytes, salt: saltBytes, iterations: 4096, variant: .sha256).calculate(), + let cipher = try? Blowfish(key: PBKDF2key, padding: .pkcs7), + let decryptedBytes = try? cipher.decrypt(data.bytes) else { + return nil + } + + let decryptedData = Data(decryptedBytes) + return String(data: decryptedData, encoding: .utf8) +} diff --git a/macos/CakeWallet/secRandom.swift b/macos/CakeWallet/secRandom.swift new file mode 100644 index 000000000..c9b2e3593 --- /dev/null +++ b/macos/CakeWallet/secRandom.swift @@ -0,0 +1,12 @@ +import Foundation + +func secRandom(count: Int) -> Data? { + var bytes = [Int8](repeating: 0, count: count) + let status = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes) + + if status == errSecSuccess { + return Data(bytes: bytes, count: bytes.count) + } + + return nil +} diff --git a/macos/Podfile b/macos/Podfile index dade8dfad..8261d92c2 100644 --- a/macos/Podfile +++ b/macos/Podfile @@ -31,6 +31,11 @@ target 'Runner' do use_modular_headers! flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + + # Cake Wallet (Legacy) + pod 'CryptoSwift' +# Not supported on macos +# pod 'UnstoppableDomainsResolution', '~> 5.0.0' end post_install do |installer| diff --git a/macos/Podfile.lock b/macos/Podfile.lock index a232a07e6..251e96725 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -2,6 +2,7 @@ PODS: - connectivity_macos (0.0.1): - FlutterMacOS - Reachability + - CryptoSwift (1.3.1) - cw_monero (0.0.1): - cw_monero/Boost (= 0.0.1) - cw_monero/Monero (= 0.0.1) @@ -43,6 +44,7 @@ PODS: DEPENDENCIES: - connectivity_macos (from `Flutter/ephemeral/.symlinks/plugins/connectivity_macos/macos`) + - CryptoSwift - cw_monero (from `Flutter/ephemeral/.symlinks/plugins/cw_monero/macos`) - devicelocale (from `Flutter/ephemeral/.symlinks/plugins/devicelocale/macos`) - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) @@ -57,6 +59,7 @@ DEPENDENCIES: SPEC REPOS: trunk: + - CryptoSwift - Reachability EXTERNAL SOURCES: @@ -87,6 +90,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: connectivity_macos: 5dae6ee11d320fac7c05f0d08bd08fc32b5514d9 + CryptoSwift: f12f037f6d0fcd6d48c96db0071b653de64e6c4d cw_monero: f8b7f104508efba2591548e76b5c058d05cba3f0 devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225 flutter_secure_storage_macos: 6ceee8fbc7f484553ad17f79361b556259df89aa @@ -100,6 +104,6 @@ SPEC CHECKSUMS: shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca url_launcher_macos: c04e4fa86382d4f94f6b38f14625708be3ae52e2 -PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c +PODFILE CHECKSUM: 95c2abf1742d9564d190610743847d385992e6cc COCOAPODS: 1.11.3 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index c828bb927..f8a688f2c 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 9F3F7550298098120030A1D7 /* secRandom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3F754D298098120030A1D7 /* secRandom.swift */; }; + 9F3F7551298098120030A1D7 /* decrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3F754E298098120030A1D7 /* decrypt.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -72,6 +74,8 @@ 359F2F22842E234537DED5E3 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 9F3F754D298098120030A1D7 /* secRandom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = secRandom.swift; path = CakeWallet/secRandom.swift; sourceTree = ""; }; + 9F3F754E298098120030A1D7 /* decrypt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = decrypt.swift; path = CakeWallet/decrypt.swift; sourceTree = ""; }; C84AA35EA80D710889C68D81 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FF499CFF131B036E3C5638D0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -102,6 +106,8 @@ 33CC10E42044A3C60003C045 = { isa = PBXGroup; children = ( + 9F3F754E298098120030A1D7 /* decrypt.swift */, + 9F3F754D298098120030A1D7 /* secRandom.swift */, 33FAB671232836740065AC1E /* Runner */, 33CEB47122A05771004F2AC0 /* Flutter */, 33CC10EE2044A3C60003C045 /* Products */, @@ -338,6 +344,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9F3F7550298098120030A1D7 /* secRandom.swift in Sources */, + 9F3F7551298098120030A1D7 /* decrypt.swift in Sources */, 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index d53ef6437..def2979dd 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -1,9 +1,101 @@ import Cocoa import FlutterMacOS +import IOKit.pwr_mgt @NSApplicationMain class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + var assertionID: IOPMAssertionID = 0 + + override func applicationDidFinishLaunching(_ notification: Notification) { + let controller : FlutterViewController = mainFlutterWindow?.contentViewController as! FlutterViewController + let legacyMigrationChannel = FlutterMethodChannel( + name: "com.cakewallet.cakewallet/legacy_wallet_migration", + binaryMessenger: controller.engine.binaryMessenger) + legacyMigrationChannel.setMethodCallHandler({ + (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + + switch call.method { + case "decrypt": + guard let args = call.arguments as? Dictionary, + let data = args["bytes"] as? FlutterStandardTypedData, + let key = args["key"] as? String, + let salt = args["salt"] as? String else { + result(nil) + return + } + + let content = decrypt(data: data.data, key: key, salt: salt) + result(content) + case "read_user_defaults": + guard let args = call.arguments as? Dictionary, + let key = args["key"] as? String, + let type = args["type"] as? String else { + result(nil) + return + } + + var value: Any? + + switch (type) { + case "string": + value = UserDefaults.standard.string(forKey: key) + case "int": + value = UserDefaults.standard.integer(forKey: key) + case "bool": + value = UserDefaults.standard.bool(forKey: key) + default: + break + } + + result(value) + default: + result(FlutterMethodNotImplemented) + } + }) + + let utilsChannel = FlutterMethodChannel( + name: "com.cake_wallet/native_utils", + binaryMessenger: controller.engine.binaryMessenger) + utilsChannel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + switch call.method { + case "sec_random": + guard let args = call.arguments as? Dictionary, + let count = args["count"] as? Int else { + result(nil) + return + } + + result(secRandom(count: count)) + case "getUnstoppableDomainAddress": + // Not supported on macos + result(nil) + case "enableWakeScreen": + result(self?.enableWakeScreen()) + + case "disableWakeScreen": + result(self?.disableWakeScreen()) + + default: + result(FlutterMethodNotImplemented) + } + }) + } + + + func enableWakeScreen(reason: String = "Disabling display sleep") -> Bool{ + return IOPMAssertionCreateWithName( kIOPMAssertionTypeNoDisplaySleep as CFString, + IOPMAssertionLevel(kIOPMAssertionLevelOn), + reason as CFString, + &assertionID) == kIOReturnSuccess + } + + func disableWakeScreen() -> Bool{ + IOPMAssertionRelease(assertionID) + + return true + } }