diff --git a/mobile/ios/LessPass-Bridging-Header.h b/mobile/ios/LessPass-Bridging-Header.h new file mode 100644 index 0000000..95aabb9 --- /dev/null +++ b/mobile/ios/LessPass-Bridging-Header.h @@ -0,0 +1,2 @@ +#import "React/RCTBridgeModule.h" +#import diff --git a/mobile/ios/LessPass.xcodeproj/project.pbxproj b/mobile/ios/LessPass.xcodeproj/project.pbxproj index d5430f1..6c273e3 100644 --- a/mobile/ios/LessPass.xcodeproj/project.pbxproj +++ b/mobile/ios/LessPass.xcodeproj/project.pbxproj @@ -19,6 +19,8 @@ 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 2DCD954D1E0B4F2C00145EB5 /* LessPassTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* LessPassTests.m */; }; + F08AE89A24CCC1AC00473F32 /* LessPassModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = F08AE89924CCC1AC00473F32 /* LessPassModule.swift */; }; + F08AE89C24CCC24600473F32 /* LessPassModule.m in Sources */ = {isa = PBXBuildFile; fileRef = F08AE89B24CCC24600473F32 /* LessPassModule.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -50,7 +52,7 @@ 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = LessPass/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = LessPass/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = LessPass/main.m; sourceTree = ""; }; - 2A7E546E77E74EF3A37A6A77 /* Hack.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = Hack.ttf; path = ../assets/fonts/Hack.ttf; sourceTree = ""; }; + 2A7E546E77E74EF3A37A6A77 /* Hack.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Hack.ttf; path = ../assets/fonts/Hack.ttf; sourceTree = ""; }; 2D02E47B1E0B4A5D006451C7 /* LessPass-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "LessPass-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 2D02E4901E0B4A5D006451C7 /* LessPass-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "LessPass-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 3178A2A0D39C6D11D24D04D5 /* libPods-LessPass.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LessPass.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -60,6 +62,9 @@ 866EE194EF41CD9D16C23CCB /* libPods-LessPass-LessPassTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LessPass-LessPassTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; }; + F08AE89824CCC1AB00473F32 /* LessPass-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LessPass-Bridging-Header.h"; sourceTree = ""; }; + F08AE89924CCC1AC00473F32 /* LessPassModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LessPassModule.swift; sourceTree = ""; }; + F08AE89B24CCC24600473F32 /* LessPassModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LessPassModule.m; sourceTree = ""; }; F91388109829B5726913CF33 /* Pods-LessPass.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LessPass.debug.xcconfig"; path = "Target Support Files/Pods-LessPass/Pods-LessPass.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -120,7 +125,6 @@ 2A7E546E77E74EF3A37A6A77 /* Hack.ttf */, ); name = Resources; - path = ""; sourceTree = ""; }; 13B07FAE1A68108700A75B9A /* LessPass */ = { @@ -133,6 +137,9 @@ 13B07FB61A68108700A75B9A /* Info.plist */, 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, 13B07FB71A68108700A75B9A /* main.m */, + F08AE89924CCC1AC00473F32 /* LessPassModule.swift */, + F08AE89824CCC1AB00473F32 /* LessPass-Bridging-Header.h */, + F08AE89B24CCC24600473F32 /* LessPassModule.m */, ); name = LessPass; sourceTree = ""; @@ -190,7 +197,6 @@ 5968C1F79B18BEE09EA7A8EF /* Pods-LessPass-LessPassTests.debug.xcconfig */, 732DAC9D38E5682E3CF6EDE8 /* Pods-LessPass-LessPassTests.release.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -288,7 +294,7 @@ TestTargetID = 13B07F861A680F5B00A75B9A; }; 13B07F861A680F5B00A75B9A = { - LastSwiftMigration = 1120; + LastSwiftMigration = 1160; }; 2D02E47A1E0B4A5D006451C7 = { CreatedOnToolsVersion = 8.2.1; @@ -580,7 +586,9 @@ buildActionMask = 2147483647; files = ( 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, + F08AE89A24CCC1AC00473F32 /* LessPassModule.swift in Sources */, 13B07FC11A68108700A75B9A /* main.m in Sources */, + F08AE89C24CCC24600473F32 /* LessPassModule.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -633,6 +641,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 5968C1F79B18BEE09EA7A8EF /* Pods-LessPass-LessPassTests.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -656,6 +665,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 732DAC9D38E5682E3CF6EDE8 /* Pods-LessPass-LessPassTests.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; INFOPLIST_FILE = LessPassTests/Info.plist; @@ -693,6 +703,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = LessPass; + SWIFT_OBJC_BRIDGING_HEADER = "LessPass-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -715,6 +726,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = LessPass; + SWIFT_OBJC_BRIDGING_HEADER = "LessPass-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; diff --git a/mobile/ios/LessPassModule.m b/mobile/ios/LessPassModule.m new file mode 100644 index 0000000..9e606b3 --- /dev/null +++ b/mobile/ios/LessPassModule.m @@ -0,0 +1,9 @@ +#import "React/RCTBridgeModule.h" + +@interface RCT_EXTERN_REMAP_MODULE(LessPass, LessPassModule, NSObject) + + RCT_EXTERN_METHOD(createFingerprint:(NSString *) masterPassword + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +@end diff --git a/mobile/ios/LessPassModule.swift b/mobile/ios/LessPassModule.swift new file mode 100644 index 0000000..65cc9d0 --- /dev/null +++ b/mobile/ios/LessPassModule.swift @@ -0,0 +1,75 @@ +import Foundation + +enum HMACAlgorithm { + case MD5, SHA1, SHA224, SHA256, SHA384, SHA512 + + func toCCHmacAlgorithm() -> CCHmacAlgorithm { + var result: Int = 0 + switch self { + case .MD5: + result = kCCHmacAlgMD5 + case .SHA1: + result = kCCHmacAlgSHA1 + case .SHA224: + result = kCCHmacAlgSHA224 + case .SHA256: + result = kCCHmacAlgSHA256 + case .SHA384: + result = kCCHmacAlgSHA384 + case .SHA512: + result = kCCHmacAlgSHA512 + } + return CCHmacAlgorithm(result) + } + + func digestLength() -> Int { + var result: CInt = 0 + switch self { + case .MD5: + result = CC_MD5_DIGEST_LENGTH + case .SHA1: + result = CC_SHA1_DIGEST_LENGTH + case .SHA224: + result = CC_SHA224_DIGEST_LENGTH + case .SHA256: + result = CC_SHA256_DIGEST_LENGTH + case .SHA384: + result = CC_SHA384_DIGEST_LENGTH + case .SHA512: + result = CC_SHA512_DIGEST_LENGTH + } + return Int(result) + } +} + +extension String { + func hmac(algorithm: HMACAlgorithm, key: String) -> String { + let cKey = key.cString(using: String.Encoding.utf8) + let cData = self.cString(using: String.Encoding.utf8) + var result = [CUnsignedChar](repeating: 0, count: Int(algorithm.digestLength())) + CCHmac(algorithm.toCCHmacAlgorithm(), cKey!, Int(strlen(cKey!)), cData!, Int(strlen(cData!)), &result) + let hmacData:NSData = NSData(bytes: result, length: (Int(algorithm.digestLength()))) + var bytes = [UInt8](repeating:0, count: hmacData.length) + hmacData.getBytes(&bytes, length: hmacData.length) + var hexString = "" + for byte in bytes { + hexString += String(format:"%02hhx", UInt8(byte)) + } + return hexString + } +} + +@objc(LessPassModule) +class LessPassModule: NSObject { + @objc(createFingerprint:resolver:rejecter:) + func createFingerprint(_ masterPassword: String, + resolver resolve: RCTPromiseResolveBlock, + rejecter reject:RCTPromiseRejectBlock) -> Void { + resolve("".hmac(algorithm: HMACAlgorithm.SHA256, key: masterPassword)) + } + + @objc + static func requiresMainQueueSetup() -> Bool { + return false + } +}