Removed unneeded imports of libraries to understand usage
Refactored some 3rd-part standard encryption to use CryptoKit Removed the PromiseKit pod Fixed the broken tests
This commit is contained in:
parent
f1e9412c7a
commit
174725c7fd
1
Podfile
1
Podfile
|
@ -6,7 +6,6 @@ inhibit_all_warnings!
|
|||
|
||||
# Dependencies to be included in the app and all extensions/frameworks
|
||||
abstract_target 'GlobalDependencies' do
|
||||
pod 'PromiseKit'
|
||||
pod 'CryptoSwift'
|
||||
# FIXME: If https://github.com/jedisct1/swift-sodium/pull/249 gets resolved then revert this back to the standard pod
|
||||
pod 'Sodium', :git => 'https://github.com/oxen-io/session-ios-swift-sodium.git', branch: 'session-build'
|
||||
|
|
14
Podfile.lock
14
Podfile.lock
|
@ -28,15 +28,6 @@ PODS:
|
|||
- NVActivityIndicatorView/Base (= 5.1.1)
|
||||
- NVActivityIndicatorView/Base (5.1.1)
|
||||
- OpenSSL-Universal (1.1.1300)
|
||||
- PromiseKit (6.18.1):
|
||||
- PromiseKit/CorePromise (= 6.18.1)
|
||||
- PromiseKit/Foundation (= 6.18.1)
|
||||
- PromiseKit/UIKit (= 6.18.1)
|
||||
- PromiseKit/CorePromise (6.18.1)
|
||||
- PromiseKit/Foundation (6.18.1):
|
||||
- PromiseKit/CorePromise
|
||||
- PromiseKit/UIKit (6.18.1):
|
||||
- PromiseKit/CorePromise
|
||||
- PureLayout (3.1.9)
|
||||
- Quick (5.0.1)
|
||||
- Reachability (3.2)
|
||||
|
@ -130,7 +121,6 @@ DEPENDENCIES:
|
|||
- GRDB.swift/SQLCipher
|
||||
- Nimble
|
||||
- NVActivityIndicatorView
|
||||
- PromiseKit
|
||||
- PureLayout (~> 3.1.8)
|
||||
- Quick
|
||||
- Reachability
|
||||
|
@ -155,7 +145,6 @@ SPEC REPOS:
|
|||
- Nimble
|
||||
- NVActivityIndicatorView
|
||||
- OpenSSL-Universal
|
||||
- PromiseKit
|
||||
- PureLayout
|
||||
- Quick
|
||||
- Reachability
|
||||
|
@ -209,7 +198,6 @@ SPEC CHECKSUMS:
|
|||
Nimble: 5316ef81a170ce87baf72dd961f22f89a602ff84
|
||||
NVActivityIndicatorView: 1f6c5687f1171810aa27a3296814dc2d7dec3667
|
||||
OpenSSL-Universal: e7311447fd2419f57420c79524b641537387eff2
|
||||
PromiseKit: 49d70c53d5d20e346beaea4b276b5dd2ab446bb4
|
||||
PureLayout: 5fb5e5429519627d60d079ccb1eaa7265ce7cf88
|
||||
Quick: 749aa754fd1e7d984f2000fe051e18a3a9809179
|
||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||
|
@ -224,6 +212,6 @@ SPEC CHECKSUMS:
|
|||
YYImage: f1ddd15ac032a58b78bbed1e012b50302d318331
|
||||
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
|
||||
|
||||
PODFILE CHECKSUM: ce9209e5c7ea252b767ee08075d4e4f8b49e487b
|
||||
PODFILE CHECKSUM: 6ee08fc446436a2534ec34c041c3b9bc39801870
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
|
|
|
@ -278,7 +278,6 @@
|
|||
C32C598A256D0664003C73A2 /* SNProtoEnvelope+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */; };
|
||||
C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */; };
|
||||
C32C5A24256DB7DB003C73A2 /* SNUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* SNUserDefaults.swift */; };
|
||||
C32C5A47256DB8F0003C73A2 /* ECKeyPair+Hexadecimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */; };
|
||||
C32C5A48256DB8F0003C73A2 /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */; };
|
||||
C32C5A88256DBCF9003C73A2 /* MessageReceiver+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = C32C5A87256DBCF9003C73A2 /* MessageReceiver+ClosedGroups.swift */; };
|
||||
C32C5B48256DC211003C73A2 /* NSNotificationCenter+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6C255A580F00E217F9 /* NSNotificationCenter+OWS.m */; };
|
||||
|
@ -344,7 +343,6 @@
|
|||
C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC16255A581E00E217F9 /* FunctionalUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3402FE52559036600EA6424 /* SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C331FF1B2558F9D300070591 /* SessionUIKit.framework */; };
|
||||
C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */; };
|
||||
C3471ED42555386B00297E91 /* AESGCM.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D72553860B00C340D1 /* AESGCM.swift */; };
|
||||
C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3471F4B25553AB000297E91 /* MessageReceiver+Decryption.swift */; };
|
||||
C34C8F7423A7830B00D82669 /* SpaceMono-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C34C8F7323A7830A00D82669 /* SpaceMono-Bold.ttf */; };
|
||||
C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A2FE25574B6300338F3E /* MessageSendJob.swift */; };
|
||||
|
@ -427,7 +425,6 @@
|
|||
C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D1C25589AC30043A11F /* WebSocketProto.swift */; };
|
||||
C3A71D1F25589AC30043A11F /* WebSocketResources.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D1D25589AC30043A11F /* WebSocketResources.pb.swift */; };
|
||||
C3A71F892558BA9F0043A11F /* Mnemonic.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71F882558BA9F0043A11F /* Mnemonic.swift */; };
|
||||
C3A7211A2558BCA10043A11F /* DiffieHellman.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D662558A0170043A11F /* DiffieHellman.swift */; };
|
||||
C3AAFFF225AE99710089E6DD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3AAFFF125AE99710089E6DD /* AppDelegate.swift */; };
|
||||
C3ADC66126426688005F1414 /* ShareNavController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ADC66026426688005F1414 /* ShareNavController.swift */; };
|
||||
C3BBE0A82554D4DE0050F1E3 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D92553860B00C340D1 /* JSON.swift */; };
|
||||
|
@ -655,7 +652,7 @@
|
|||
FD705A92278D051200F16121 /* ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A91278D051200F16121 /* ReusableView.swift */; };
|
||||
FD7115EB28C5D78E00B47552 /* ThreadSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7115EA28C5D78E00B47552 /* ThreadSettingsViewModel.swift */; };
|
||||
FD7115F228C6CB3900B47552 /* _010_AddThreadIdToFTS.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7115F128C6CB3900B47552 /* _010_AddThreadIdToFTS.swift */; };
|
||||
FD7115F428C71EB200B47552 /* ThreadDisappearingMessagesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7115F328C71EB200B47552 /* ThreadDisappearingMessagesViewModel.swift */; };
|
||||
FD7115F428C71EB200B47552 /* ThreadDisappearingMessagesSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7115F328C71EB200B47552 /* ThreadDisappearingMessagesSettingsViewModel.swift */; };
|
||||
FD7115F828C8151C00B47552 /* DisposableBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7115F728C8151C00B47552 /* DisposableBarButtonItem.swift */; };
|
||||
FD7115FA28C8153400B47552 /* UIBarButtonItem+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7115F928C8153400B47552 /* UIBarButtonItem+Combine.swift */; };
|
||||
FD7115FC28C8155800B47552 /* Publisher+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7115FB28C8155800B47552 /* Publisher+Utilities.swift */; };
|
||||
|
@ -801,6 +798,8 @@
|
|||
FDD2506E283711D600198BDA /* DifferenceKit+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD2506D283711D600198BDA /* DifferenceKit+Utilities.swift */; };
|
||||
FDD250702837199200198BDA /* GarbageCollectionJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD2506F2837199200198BDA /* GarbageCollectionJob.swift */; };
|
||||
FDD250722837234B00198BDA /* MediaGalleryNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD250712837234B00198BDA /* MediaGalleryNavigationController.swift */; };
|
||||
FDE658A129418C7900A33BC1 /* CryptoKit+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE658A029418C7900A33BC1 /* CryptoKit+Utilities.swift */; };
|
||||
FDE658A329418E2F00A33BC1 /* KeyPair.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE658A229418E2F00A33BC1 /* KeyPair.swift */; };
|
||||
FDE77F6B280FEB28002CFC5D /* ControlMessageProcessRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE77F6A280FEB28002CFC5D /* ControlMessageProcessRecord.swift */; };
|
||||
FDED2E3C282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDED2E3B282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift */; };
|
||||
FDF0B73C27FFD3D6004C14C5 /* LinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B73B27FFD3D6004C14C5 /* LinkPreview.swift */; };
|
||||
|
@ -1405,7 +1404,6 @@
|
|||
C33FD9AD255A548A00E217F9 /* SignalUtilitiesKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SignalUtilitiesKit.h; sourceTree = "<group>"; };
|
||||
C33FD9AE255A548A00E217F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReachabilityManager.swift; sourceTree = "<group>"; };
|
||||
C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ECKeyPair+Hexadecimal.swift"; sourceTree = "<group>"; };
|
||||
C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSRegularExpression+SSK.swift"; sourceTree = "<group>"; };
|
||||
C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicators.swift; sourceTree = "<group>"; };
|
||||
C33FDA8B255A57FD00E217F9 /* AppVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppVersion.m; sourceTree = "<group>"; };
|
||||
|
@ -1573,7 +1571,6 @@
|
|||
C3A71D0A2558989C0043A11F /* MessageWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageWrapper.swift; sourceTree = "<group>"; };
|
||||
C3A71D1C25589AC30043A11F /* WebSocketProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketProto.swift; sourceTree = "<group>"; };
|
||||
C3A71D1D25589AC30043A11F /* WebSocketResources.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketResources.pb.swift; sourceTree = "<group>"; };
|
||||
C3A71D662558A0170043A11F /* DiffieHellman.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiffieHellman.swift; sourceTree = "<group>"; };
|
||||
C3A71F882558BA9F0043A11F /* Mnemonic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mnemonic.swift; sourceTree = "<group>"; };
|
||||
C3A8AF752665B03900A467FE /* hi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hi; path = hi.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
C3A8AF762665F97A00A467FE /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
|
@ -1592,7 +1589,6 @@
|
|||
C3C2A5D22553860900C340D1 /* String+Trimming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Trimming.swift"; sourceTree = "<group>"; };
|
||||
C3C2A5D42553860A00C340D1 /* Threading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = "<group>"; };
|
||||
C3C2A5D52553860A00C340D1 /* Dictionary+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dictionary+Utilities.swift"; sourceTree = "<group>"; };
|
||||
C3C2A5D72553860B00C340D1 /* AESGCM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AESGCM.swift; sourceTree = "<group>"; };
|
||||
C3C2A5D82553860B00C340D1 /* Data+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Utilities.swift"; sourceTree = "<group>"; };
|
||||
C3C2A5D92553860B00C340D1 /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
|
||||
C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SessionUtilitiesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -1773,7 +1769,7 @@
|
|||
FD7115EA28C5D78E00B47552 /* ThreadSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadSettingsViewModel.swift; sourceTree = "<group>"; };
|
||||
FD7115EF28C5D7DE00B47552 /* SessionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionHeaderView.swift; sourceTree = "<group>"; };
|
||||
FD7115F128C6CB3900B47552 /* _010_AddThreadIdToFTS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _010_AddThreadIdToFTS.swift; sourceTree = "<group>"; };
|
||||
FD7115F328C71EB200B47552 /* ThreadDisappearingMessagesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadDisappearingMessagesViewModel.swift; sourceTree = "<group>"; };
|
||||
FD7115F328C71EB200B47552 /* ThreadDisappearingMessagesSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadDisappearingMessagesSettingsViewModel.swift; sourceTree = "<group>"; };
|
||||
FD7115F728C8151C00B47552 /* DisposableBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisposableBarButtonItem.swift; sourceTree = "<group>"; };
|
||||
FD7115F928C8153400B47552 /* UIBarButtonItem+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIBarButtonItem+Combine.swift"; sourceTree = "<group>"; };
|
||||
FD7115FB28C8155800B47552 /* Publisher+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Publisher+Utilities.swift"; sourceTree = "<group>"; };
|
||||
|
@ -1910,6 +1906,8 @@
|
|||
FDD2506D283711D600198BDA /* DifferenceKit+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DifferenceKit+Utilities.swift"; sourceTree = "<group>"; };
|
||||
FDD2506F2837199200198BDA /* GarbageCollectionJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarbageCollectionJob.swift; sourceTree = "<group>"; };
|
||||
FDD250712837234B00198BDA /* MediaGalleryNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaGalleryNavigationController.swift; sourceTree = "<group>"; };
|
||||
FDE658A029418C7900A33BC1 /* CryptoKit+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CryptoKit+Utilities.swift"; sourceTree = "<group>"; };
|
||||
FDE658A229418E2F00A33BC1 /* KeyPair.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyPair.swift; sourceTree = "<group>"; };
|
||||
FDE7214F287E50D50093DF33 /* ProtoWrappers.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = ProtoWrappers.py; sourceTree = "<group>"; };
|
||||
FDE72150287E50D50093DF33 /* LintLocalizableStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LintLocalizableStrings.swift; sourceTree = "<group>"; };
|
||||
FDE77F68280F9EDA002CFC5D /* JobRunnerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobRunnerError.swift; sourceTree = "<group>"; };
|
||||
|
@ -2506,11 +2504,10 @@
|
|||
B8A582AC258C653C00AFD84C /* Crypto */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C3C2A5D72553860B00C340D1 /* AESGCM.swift */,
|
||||
FDE658A029418C7900A33BC1 /* CryptoKit+Utilities.swift */,
|
||||
C3C2ABD12553C6C900C340D1 /* Data+SecureRandom.swift */,
|
||||
C3A71D662558A0170043A11F /* DiffieHellman.swift */,
|
||||
C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */,
|
||||
B88FA7FA26114EA70049422F /* Hex.swift */,
|
||||
FDE658A229418E2F00A33BC1 /* KeyPair.swift */,
|
||||
C3A71F882558BA9F0043A11F /* Mnemonic.swift */,
|
||||
);
|
||||
path = Crypto;
|
||||
|
@ -2741,7 +2738,7 @@
|
|||
3427C64120F500DE00EEC730 /* OWSMessageTimerView.h */,
|
||||
3427C64220F500DF00EEC730 /* OWSMessageTimerView.m */,
|
||||
FD7115EA28C5D78E00B47552 /* ThreadSettingsViewModel.swift */,
|
||||
FD7115F328C71EB200B47552 /* ThreadDisappearingMessagesViewModel.swift */,
|
||||
FD7115F328C71EB200B47552 /* ThreadDisappearingMessagesSettingsViewModel.swift */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
|
@ -5457,8 +5454,8 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FDE658A129418C7900A33BC1 /* CryptoKit+Utilities.swift in Sources */,
|
||||
FDFD645927F26C6800808CA1 /* Array+Utilities.swift in Sources */,
|
||||
C32C5A47256DB8F0003C73A2 /* ECKeyPair+Hexadecimal.swift in Sources */,
|
||||
7B1D74B027C365960030B423 /* Timer+MainThread.swift in Sources */,
|
||||
C32C5D83256DD5B6003C73A2 /* SSKKeychainStorage.swift in Sources */,
|
||||
FDF8488329405A12007DCAE5 /* BatchResponse.swift in Sources */,
|
||||
|
@ -5486,13 +5483,13 @@
|
|||
FD71160228C8255900B47552 /* UIControl+Combine.swift in Sources */,
|
||||
FD9004152818B46300ABAAF6 /* JobRunner.swift in Sources */,
|
||||
FDF8487929405906007DCAE5 /* HTTPQueryParam.swift in Sources */,
|
||||
C3A7211A2558BCA10043A11F /* DiffieHellman.swift in Sources */,
|
||||
FD17D7CA27F546D900122BE0 /* _001_InitialSetupMigration.swift in Sources */,
|
||||
C3D9E4D12567777D0040E4F3 /* OWSMediaUtils.swift in Sources */,
|
||||
C3BBE0AA2554D4DE0050F1E3 /* Dictionary+Utilities.swift in Sources */,
|
||||
FD37EA1128AB34B3003AE748 /* TypedTableAlteration.swift in Sources */,
|
||||
C3D9E4DA256778410040E4F3 /* UIImage+OWS.m in Sources */,
|
||||
C32C600F256E07F5003C73A2 /* NSUserDefaults+OWS.m in Sources */,
|
||||
FDE658A329418E2F00A33BC1 /* KeyPair.swift in Sources */,
|
||||
FD37E9FF28A5F2CD003AE748 /* Configuration.swift in Sources */,
|
||||
FDB7400B28EB99A70094D718 /* TimeInterval+Utilities.swift in Sources */,
|
||||
C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */,
|
||||
|
@ -5513,7 +5510,6 @@
|
|||
FD77289E284EF1C50018502F /* Sodium+Utilities.swift in Sources */,
|
||||
B8856DE6256F15F2001CE70E /* String+SSK.swift in Sources */,
|
||||
FDF2220F281B55E6000A4995 /* QueryInterfaceRequest+Utilities.swift in Sources */,
|
||||
C3471ED42555386B00297E91 /* AESGCM.swift in Sources */,
|
||||
FDF848EF294067E4007DCAE5 /* URLResponse+Utilities.swift in Sources */,
|
||||
FD848B9A28442CE6000E298B /* StorageError.swift in Sources */,
|
||||
FD17D7B827F51ECA00122BE0 /* Migration.swift in Sources */,
|
||||
|
@ -5875,7 +5871,7 @@
|
|||
45B5360E206DD8BB00D61655 /* UIResponder+OWS.swift in Sources */,
|
||||
7B9F71C928470667006DFE7B /* ReactionListSheet.swift in Sources */,
|
||||
7B7037452834BCC0000DCF35 /* ReactionView.swift in Sources */,
|
||||
FD7115F428C71EB200B47552 /* ThreadDisappearingMessagesViewModel.swift in Sources */,
|
||||
FD7115F428C71EB200B47552 /* ThreadDisappearingMessagesSettingsViewModel.swift in Sources */,
|
||||
B8D84ECF25E3108A005A043E /* ExpandingAttachmentsButton.swift in Sources */,
|
||||
7B7CB190270FB2150079FF93 /* MiniCallView.swift in Sources */,
|
||||
7B13E1E92810F01300BD4F64 /* SessionCallManager+Action.swift in Sources */,
|
||||
|
|
|
@ -8,7 +8,7 @@ import SessionUIKit
|
|||
import SessionMessagingKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
class ThreadDisappearingMessagesViewModel: SessionTableViewModel<ThreadDisappearingMessagesViewModel.NavButton, ThreadDisappearingMessagesViewModel.Section, ThreadDisappearingMessagesViewModel.Item> {
|
||||
class ThreadDisappearingMessagesSettingsViewModel: SessionTableViewModel<ThreadDisappearingMessagesSettingsViewModel.NavButton, ThreadDisappearingMessagesSettingsViewModel.Section, ThreadDisappearingMessagesSettingsViewModel.Item> {
|
||||
// MARK: - Config
|
||||
|
||||
enum NavButton: Equatable {
|
|
@ -83,8 +83,19 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
|
|||
// MARK: - Navigation
|
||||
|
||||
lazy var navState: AnyPublisher<NavState, Never> = {
|
||||
isEditing
|
||||
.map { isEditing in (isEditing ? .editing : .standard) }
|
||||
Publishers
|
||||
.CombineLatest(
|
||||
isEditing,
|
||||
textChanged
|
||||
.handleEvents(
|
||||
receiveOutput: { [weak self] value, _ in
|
||||
self?.editedDisplayName = value
|
||||
}
|
||||
)
|
||||
.filter { _ in false }
|
||||
.prepend((nil, .nickname))
|
||||
)
|
||||
.map { isEditing, _ -> NavState in (isEditing ? .editing : .standard) }
|
||||
.removeDuplicates()
|
||||
.prepend(.standard) // Initial value
|
||||
.shareReplay(1)
|
||||
|
@ -429,7 +440,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
|
|||
onTap: { [weak self] in
|
||||
self?.transitionToScreen(
|
||||
SessionTableViewController(
|
||||
viewModel: ThreadDisappearingMessagesViewModel(
|
||||
viewModel: ThreadDisappearingMessagesSettingsViewModel(
|
||||
threadId: threadId,
|
||||
config: disappearingMessagesConfig
|
||||
)
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import UIKit
|
||||
import AVFoundation
|
||||
import GRDB
|
||||
import Curve25519Kit
|
||||
import SessionUIKit
|
||||
import SessionMessagingKit
|
||||
import SessionUtilitiesKit
|
||||
|
@ -174,7 +173,7 @@ final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControlle
|
|||
fileprivate func startNewDMIfPossible(with onsNameOrPublicKey: String) {
|
||||
let maybeSessionId: SessionId? = SessionId(from: onsNameOrPublicKey)
|
||||
|
||||
if ECKeyPair.isValidHexEncodedPublicKey(candidate: onsNameOrPublicKey) && maybeSessionId?.prefix == .standard {
|
||||
if KeyPair.isValidHexEncodedPublicKey(candidate: onsNameOrPublicKey) && maybeSessionId?.prefix == .standard {
|
||||
startNewDM(with: onsNameOrPublicKey)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -623,27 +623,3 @@ public class MediaGalleryViewModel {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Objective-C Support
|
||||
|
||||
// FIXME: Remove when we can
|
||||
|
||||
@objc(SNMediaGallery)
|
||||
public class SNMediaGallery: NSObject {
|
||||
@objc(pushTileViewWithSliderEnabledForThreadId:isClosedGroup:isOpenGroup:fromNavController:)
|
||||
static func pushTileView(threadId: String, isClosedGroup: Bool, isOpenGroup: Bool, fromNavController: UINavigationController) {
|
||||
fromNavController.pushViewController(
|
||||
MediaGalleryViewModel.createAllMediaViewController(
|
||||
threadId: threadId,
|
||||
threadVariant: {
|
||||
if isClosedGroup { return .closedGroup }
|
||||
if isOpenGroup { return .openGroup }
|
||||
|
||||
return .contact
|
||||
}(),
|
||||
focusedAttachmentId: nil
|
||||
),
|
||||
animated: true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import Foundation
|
||||
import Sodium
|
||||
import GRDB
|
||||
import Curve25519Kit
|
||||
import SessionUtilitiesKit
|
||||
import SessionMessagingKit
|
||||
|
||||
|
@ -12,7 +11,7 @@ enum Onboarding {
|
|||
enum Flow {
|
||||
case register, recover, link
|
||||
|
||||
func preregister(with seed: Data, ed25519KeyPair: Sign.KeyPair, x25519KeyPair: ECKeyPair) {
|
||||
func preregister(with seed: Data, ed25519KeyPair: KeyPair, x25519KeyPair: KeyPair) {
|
||||
let userDefaults = UserDefaults.standard
|
||||
Identity.store(seed: seed, ed25519KeyPair: ed25519KeyPair, x25519KeyPair: x25519KeyPair)
|
||||
let x25519PublicKey = x25519KeyPair.hexEncodedPublicKey
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
|
||||
import UIKit
|
||||
import Sodium
|
||||
import Curve25519Kit
|
||||
import SessionUIKit
|
||||
import SignalUtilitiesKit
|
||||
|
||||
final class RegisterVC : BaseVC {
|
||||
private var seed: Data! { didSet { updateKeyPair() } }
|
||||
private var ed25519KeyPair: Sign.KeyPair!
|
||||
private var x25519KeyPair: ECKeyPair! { didSet { updatePublicKeyLabel() } }
|
||||
private var ed25519KeyPair: KeyPair!
|
||||
private var x25519KeyPair: KeyPair! { didSet { updatePublicKeyLabel() } }
|
||||
|
||||
// MARK: - Components
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import UIKit
|
||||
import AVFoundation
|
||||
import Curve25519Kit
|
||||
import SessionUIKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
|
@ -125,7 +124,7 @@ final class QRCodeVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControl
|
|||
}
|
||||
|
||||
fileprivate func startNewPrivateChatIfPossible(with hexEncodedPublicKey: String) {
|
||||
if !ECKeyPair.isValidHexEncodedPublicKey(candidate: hexEncodedPublicKey) {
|
||||
if !KeyPair.isValidHexEncodedPublicKey(candidate: hexEncodedPublicKey) {
|
||||
let modal: ConfirmationModal = ConfirmationModal(
|
||||
targetView: self.view,
|
||||
info: ConfirmationModal.Info(
|
||||
|
|
|
@ -97,8 +97,7 @@ class SettingsViewModel: SessionTableViewModel<SettingsViewModel.NavButton, Sett
|
|||
lazy var navState: AnyPublisher<NavState, Never> = {
|
||||
Publishers
|
||||
.CombineLatest(
|
||||
isEditing
|
||||
.map { isEditing in isEditing },
|
||||
isEditing,
|
||||
textChanged
|
||||
.handleEvents(
|
||||
receiveOutput: { [weak self] value, _ in
|
||||
|
@ -111,6 +110,7 @@ class SettingsViewModel: SessionTableViewModel<SettingsViewModel.NavButton, Sett
|
|||
.map { isEditing, _ -> NavState in (isEditing ? .editing : .standard) }
|
||||
.removeDuplicates()
|
||||
.prepend(.standard) // Initial value
|
||||
.shareReplay(1)
|
||||
.eraseToAnyPublisher()
|
||||
}()
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import Curve25519Kit
|
||||
import SessionUtilitiesKit
|
||||
import SessionSnodeKit
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import Foundation
|
|||
import AVKit
|
||||
import GRDB
|
||||
import YapDatabase
|
||||
import Curve25519Kit
|
||||
import SessionUtilitiesKit
|
||||
import SessionSnodeKit
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import Curve25519Kit
|
||||
import SessionUtilitiesKit
|
||||
import SessionSnodeKit
|
||||
|
||||
|
|
|
@ -125,100 +125,3 @@ extension DisappearingMessagesConfiguration {
|
|||
return (validDurationsSeconds.max() ?? 0)
|
||||
}()
|
||||
}
|
||||
|
||||
// MARK: - Objective-C Support
|
||||
|
||||
// TODO: Remove this when possible
|
||||
|
||||
@objc(SMKDisappearingMessagesConfiguration)
|
||||
public class SMKDisappearingMessagesConfiguration: NSObject {
|
||||
@objc public static var maxDurationSeconds: UInt = UInt(DisappearingMessagesConfiguration.maxDurationSeconds)
|
||||
|
||||
@objc public static var validDurationsSeconds: [UInt] = DisappearingMessagesConfiguration
|
||||
.validDurationsSeconds
|
||||
.map { UInt($0) }
|
||||
|
||||
@objc(isEnabledFor:)
|
||||
public static func isEnabled(for threadId: String) -> Bool {
|
||||
return Storage.shared
|
||||
.read { db in
|
||||
try DisappearingMessagesConfiguration
|
||||
.select(.isEnabled)
|
||||
.filter(id: threadId)
|
||||
.asRequest(of: Bool.self)
|
||||
.fetchOne(db)
|
||||
}
|
||||
.defaulting(to: false)
|
||||
}
|
||||
|
||||
@objc(durationIndexFor:)
|
||||
public static func durationIndex(for threadId: String) -> Int {
|
||||
let durationSeconds: TimeInterval = Storage.shared
|
||||
.read { db in
|
||||
try DisappearingMessagesConfiguration
|
||||
.select(.durationSeconds)
|
||||
.filter(id: threadId)
|
||||
.asRequest(of: TimeInterval.self)
|
||||
.fetchOne(db)
|
||||
}
|
||||
.defaulting(to: DisappearingMessagesConfiguration.defaultDuration)
|
||||
|
||||
return DisappearingMessagesConfiguration.validDurationsSeconds
|
||||
.firstIndex(of: durationSeconds)
|
||||
.defaulting(to: 0)
|
||||
}
|
||||
|
||||
@objc(durationStringFor:)
|
||||
public static func durationString(for index: Int) -> String {
|
||||
let durationSeconds: TimeInterval = (
|
||||
index >= 0 && index < DisappearingMessagesConfiguration.validDurationsSeconds.count ?
|
||||
DisappearingMessagesConfiguration.validDurationsSeconds[index] :
|
||||
DisappearingMessagesConfiguration.validDurationsSeconds[0]
|
||||
)
|
||||
|
||||
return floor(durationSeconds).formatted(format: .long)
|
||||
}
|
||||
|
||||
@objc(update:isEnabled:durationIndex:)
|
||||
public static func update(_ threadId: String, isEnabled: Bool, durationIndex: Int) {
|
||||
let durationSeconds: TimeInterval = (
|
||||
durationIndex >= 0 && durationIndex < DisappearingMessagesConfiguration.validDurationsSeconds.count ?
|
||||
DisappearingMessagesConfiguration.validDurationsSeconds[durationIndex] :
|
||||
DisappearingMessagesConfiguration.validDurationsSeconds[0]
|
||||
)
|
||||
|
||||
Storage.shared.write { db in
|
||||
guard let thread: SessionThread = try SessionThread.fetchOne(db, id: threadId) else {
|
||||
return
|
||||
}
|
||||
|
||||
let config: DisappearingMessagesConfiguration = try DisappearingMessagesConfiguration
|
||||
.fetchOne(db, id: threadId)
|
||||
.defaulting(to: DisappearingMessagesConfiguration.defaultWith(threadId))
|
||||
.with(
|
||||
isEnabled: isEnabled,
|
||||
durationSeconds: durationSeconds
|
||||
)
|
||||
.saved(db)
|
||||
|
||||
let interaction: Interaction = try Interaction(
|
||||
threadId: threadId,
|
||||
authorId: getUserHexEncodedPublicKey(db),
|
||||
variant: .infoDisappearingMessagesUpdate,
|
||||
body: config.messageInfoString(with: nil),
|
||||
timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000))
|
||||
)
|
||||
.inserted(db)
|
||||
|
||||
try MessageSender.send(
|
||||
db,
|
||||
message: ExpirationTimerUpdate(
|
||||
syncTarget: nil,
|
||||
duration: UInt32(floor(isEnabled ? durationSeconds : 0))
|
||||
),
|
||||
interactionId: interaction.id,
|
||||
in: thread
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,39 +60,3 @@ public struct GroupMember: Codable, Equatable, FetchableRecord, PersistableRecor
|
|||
self.isHidden = isHidden
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Objective-C Support
|
||||
|
||||
// FIXME: Remove when possible
|
||||
|
||||
@objc(SMKGroupMember)
|
||||
public class SMKGroupMember: NSObject {
|
||||
@objc(isCurrentUserMemberOf:)
|
||||
public static func isCurrentUserMember(of groupId: String) -> Bool {
|
||||
return Storage.shared.read { db in
|
||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||
let numEntries: Int = try GroupMember
|
||||
.filter(GroupMember.Columns.groupId == groupId)
|
||||
.filter(GroupMember.Columns.profileId == userPublicKey)
|
||||
.fetchCount(db)
|
||||
|
||||
return (numEntries > 0)
|
||||
}
|
||||
.defaulting(to: false)
|
||||
}
|
||||
|
||||
@objc(isCurrentUserAdminOf:)
|
||||
public static func isCurrentUserAdmin(of groupId: String) -> Bool {
|
||||
return Storage.shared.read { db in
|
||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||
let numEntries: Int = try GroupMember
|
||||
.filter(GroupMember.Columns.groupId == groupId)
|
||||
.filter(GroupMember.Columns.profileId == userPublicKey)
|
||||
.filter(GroupMember.Columns.role == GroupMember.Role.admin)
|
||||
.fetchCount(db)
|
||||
|
||||
return (numEntries > 0)
|
||||
}
|
||||
.defaulting(to: false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -351,33 +351,3 @@ public extension Profile {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Objective-C Support
|
||||
|
||||
// FIXME: Remove when possible
|
||||
|
||||
@objc(SMKProfile)
|
||||
public class SMKProfile: NSObject {
|
||||
@objc public static func displayName(id: String) -> String {
|
||||
return Profile.displayName(id: id)
|
||||
}
|
||||
|
||||
@objc public static func displayName(id: String, customFallback: String) -> String {
|
||||
return Profile.displayName(id: id, customFallback: customFallback)
|
||||
}
|
||||
|
||||
@objc(displayNameAfterSavingNickname:forProfileId:)
|
||||
public static func displayNameAfterSaving(nickname: String?, for profileId: String) -> String {
|
||||
return Storage.shared.write { db in
|
||||
let profile: Profile = Profile.fetchOrCreate(id: profileId)
|
||||
let targetNickname: String? = ((nickname ?? "").count > 0 ? nickname : nil)
|
||||
|
||||
try Profile
|
||||
.filter(id: profile.id)
|
||||
.updateAll(db, Profile.Columns.nickname.set(to: targetNickname))
|
||||
|
||||
return (targetNickname ?? profile.name)
|
||||
}
|
||||
.defaulting(to: "")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import Foundation
|
|||
import Combine
|
||||
import GRDB
|
||||
import Sodium
|
||||
import Curve25519Kit
|
||||
import SessionSnodeKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
|
@ -1300,24 +1299,24 @@ public enum OpenGroupAPI {
|
|||
guard let blindedKeyPair: Box.KeyPair = dependencies.sodium.blindedKeyPair(serverPublicKey: serverPublicKey, edKeyPair: userEdKeyPair, genericHash: dependencies.genericHash) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
guard let signatureResult: Bytes = dependencies.sodium.sogsSignature(message: messageBytes, secretKey: userEdKeyPair.secretKey, blindedSecretKey: blindedKeyPair.secretKey, blindedPublicKey: blindedKeyPair.publicKey) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
publicKey: SessionId(.blinded, publicKey: blindedKeyPair.publicKey).hexString,
|
||||
signature: signatureResult
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// Otherwise sign using the fallback type
|
||||
switch signingType {
|
||||
case .unblinded:
|
||||
guard let signatureResult: Bytes = dependencies.sign.signature(message: messageBytes, secretKey: userEdKeyPair.secretKey) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
publicKey: SessionId(.unblinded, publicKey: userEdKeyPair.publicKey).hexString,
|
||||
signature: signatureResult
|
||||
|
|
|
@ -19,9 +19,13 @@ extension MessageSender {
|
|||
var members: Set<String> = members
|
||||
|
||||
// Generate the group's public key
|
||||
let groupPublicKey = Curve25519.generateKeyPair().hexEncodedPublicKey // Includes the 'SessionId.Prefix.standard' prefix
|
||||
let groupKeyPair: ECKeyPair = Curve25519.generateKeyPair()
|
||||
let groupPublicKey: String = KeyPair(
|
||||
publicKey: groupKeyPair.publicKey.bytes,
|
||||
secretKey: groupKeyPair.privateKey.bytes
|
||||
).hexEncodedPublicKey // Includes the 'SessionId.Prefix.standard' prefix
|
||||
// Generate the key pair that'll be used for encryption and decryption
|
||||
let encryptionKeyPair = Curve25519.generateKeyPair()
|
||||
let encryptionKeyPair: ECKeyPair = Curve25519.generateKeyPair()
|
||||
|
||||
// Create the group
|
||||
members.insert(userPublicKey) // Ensure the current user is included in the member list
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import Sodium
|
||||
import CryptoSwift
|
||||
import Curve25519Kit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
extension MessageReceiver {
|
||||
|
|
|
@ -45,9 +45,13 @@ class TestOnionRequestAPI: OnionRequestAPIType {
|
|||
httpMethod: (request.httpMethod ?? "GET"),
|
||||
headers: (request.allHTTPHeaderFields ?? [:]),
|
||||
body: request.httpBody,
|
||||
server: server,
|
||||
version: .v4,
|
||||
publicKey: x25519PublicKey
|
||||
destination: OnionRequestAPIDestination.server(
|
||||
host: (request.url?.host ?? ""),
|
||||
target: OnionRequestAPIVersion.v4.rawValue,
|
||||
x25519PublicKey: x25519PublicKey,
|
||||
scheme: request.url!.scheme,
|
||||
port: request.url!.port.map { UInt16($0) }
|
||||
)
|
||||
),
|
||||
code: 200,
|
||||
headers: [:]
|
||||
|
@ -61,15 +65,11 @@ class TestOnionRequestAPI: OnionRequestAPIType {
|
|||
static func sendOnionRequest(_ payload: Data, to snode: Snode) -> AnyPublisher<(ResponseInfoType, Data?), Error> {
|
||||
let responseInfo: ResponseInfo = ResponseInfo(
|
||||
requestData: RequestData(
|
||||
urlString: nil,
|
||||
urlString: "\(snode.address):\(snode.port)/onion_req/v2",
|
||||
httpMethod: "POST",
|
||||
headers: [:],
|
||||
snodeMethod: nil,
|
||||
body: payload,
|
||||
|
||||
server: "",
|
||||
version: .v3,
|
||||
publicKey: snode.x25519PublicKey
|
||||
destination: OnionRequestAPIDestination.snode(snode)
|
||||
),
|
||||
code: 200,
|
||||
headers: [:]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import Combine
|
||||
import CryptoSwift
|
||||
import CryptoKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
internal extension OnionRequestAPI {
|
||||
|
@ -28,14 +28,14 @@ internal extension OnionRequestAPI {
|
|||
static func encrypt(
|
||||
_ payload: Data,
|
||||
for destination: OnionRequestAPIDestination
|
||||
) -> AnyPublisher<AESGCM.EncryptionResult, Error> {
|
||||
) -> AnyPublisher<AES.GCM.EncryptionResult, Error> {
|
||||
switch destination {
|
||||
case .snode(let snode):
|
||||
// Need to wrap the payload for snode requests
|
||||
return encode(ciphertext: payload, json: [ "headers" : "" ])
|
||||
.flatMap { data -> AnyPublisher<AESGCM.EncryptionResult, Error> in
|
||||
.flatMap { data -> AnyPublisher<AES.GCM.EncryptionResult, Error> in
|
||||
do {
|
||||
return Just(try AESGCM.encrypt(data, for: snode.x25519PublicKey))
|
||||
return Just(try AES.GCM.encrypt(data, for: snode.x25519PublicKey))
|
||||
.setFailureType(to: Error.self)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ internal extension OnionRequestAPI {
|
|||
|
||||
case .server(_, _, let serverX25519PublicKey, _, _):
|
||||
do {
|
||||
return Just(try AESGCM.encrypt(payload, for: serverX25519PublicKey))
|
||||
return Just(try AES.GCM.encrypt(payload, for: serverX25519PublicKey))
|
||||
.setFailureType(to: Error.self)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
@ -63,8 +63,8 @@ internal extension OnionRequestAPI {
|
|||
static func encryptHop(
|
||||
from lhs: OnionRequestAPIDestination,
|
||||
to rhs: OnionRequestAPIDestination,
|
||||
using previousEncryptionResult: AESGCM.EncryptionResult
|
||||
) -> AnyPublisher<AESGCM.EncryptionResult, Error> {
|
||||
using previousEncryptionResult: AES.GCM.EncryptionResult
|
||||
) -> AnyPublisher<AES.GCM.EncryptionResult, Error> {
|
||||
var parameters: JSON
|
||||
|
||||
switch rhs {
|
||||
|
@ -89,9 +89,9 @@ internal extension OnionRequestAPI {
|
|||
}()
|
||||
|
||||
return encode(ciphertext: previousEncryptionResult.ciphertext, json: parameters)
|
||||
.flatMap { data -> AnyPublisher<AESGCM.EncryptionResult, Error> in
|
||||
.flatMap { data -> AnyPublisher<AES.GCM.EncryptionResult, Error> in
|
||||
do {
|
||||
return Just(try AESGCM.encrypt(data, for: x25519PublicKey))
|
||||
return Just(try AES.GCM.encrypt(data, for: x25519PublicKey))
|
||||
.setFailureType(to: Error.self)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import Combine
|
||||
import CryptoSwift
|
||||
import CryptoKit
|
||||
import GRDB
|
||||
import SessionUtilitiesKit
|
||||
|
||||
|
@ -51,7 +51,7 @@ public enum OnionRequestAPI: OnionRequestAPIType {
|
|||
|
||||
// MARK: - Onion Building Result
|
||||
|
||||
private typealias OnionBuildingResult = (guardSnode: Snode, finalEncryptionResult: AESGCM.EncryptionResult, destinationSymmetricKey: Data)
|
||||
private typealias OnionBuildingResult = (guardSnode: Snode, finalEncryptionResult: AES.GCM.EncryptionResult, destinationSymmetricKey: Data)
|
||||
|
||||
// MARK: - Private API
|
||||
|
||||
|
@ -359,18 +359,18 @@ public enum OnionRequestAPI: OnionRequestAPIType {
|
|||
) -> AnyPublisher<OnionBuildingResult, Error> {
|
||||
var guardSnode: Snode!
|
||||
var targetSnodeSymmetricKey: Data! // Needed by invoke(_:on:with:) to decrypt the response sent back by the destination
|
||||
var encryptionResult: AESGCM.EncryptionResult!
|
||||
var encryptionResult: AES.GCM.EncryptionResult!
|
||||
var snodeToExclude: Snode?
|
||||
|
||||
if case .snode(let snode) = destination { snodeToExclude = snode }
|
||||
|
||||
return getPath(excluding: snodeToExclude)
|
||||
.flatMap { path -> AnyPublisher<AESGCM.EncryptionResult, Error> in
|
||||
.flatMap { path -> AnyPublisher<AES.GCM.EncryptionResult, Error> in
|
||||
guardSnode = path.first!
|
||||
|
||||
// Encrypt in reverse order, i.e. the destination first
|
||||
return encrypt(payload, for: destination)
|
||||
.flatMap { r -> AnyPublisher<AESGCM.EncryptionResult, Error> in
|
||||
.flatMap { r -> AnyPublisher<AES.GCM.EncryptionResult, Error> in
|
||||
targetSnodeSymmetricKey = r.symmetricKey
|
||||
|
||||
// Recursively encrypt the layers of the onion (again in reverse order)
|
||||
|
@ -378,7 +378,7 @@ public enum OnionRequestAPI: OnionRequestAPIType {
|
|||
var path = path
|
||||
var rhs = destination
|
||||
|
||||
func addLayer() -> AnyPublisher<AESGCM.EncryptionResult, Error> {
|
||||
func addLayer() -> AnyPublisher<AES.GCM.EncryptionResult, Error> {
|
||||
guard !path.isEmpty else {
|
||||
return Just(encryptionResult)
|
||||
.setFailureType(to: Error.self)
|
||||
|
@ -388,7 +388,7 @@ public enum OnionRequestAPI: OnionRequestAPIType {
|
|||
let lhs = OnionRequestAPIDestination.snode(path.removeLast())
|
||||
return OnionRequestAPI
|
||||
.encryptHop(from: lhs, to: rhs, using: encryptionResult)
|
||||
.flatMap { r -> AnyPublisher<AESGCM.EncryptionResult, Error> in
|
||||
.flatMap { r -> AnyPublisher<AES.GCM.EncryptionResult, Error> in
|
||||
encryptionResult = r
|
||||
rhs = lhs
|
||||
return addLayer()
|
||||
|
@ -644,13 +644,13 @@ public enum OnionRequestAPI: OnionRequestAPIType {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
guard let base64EncodedIVAndCiphertext = json["result"] as? String, let ivAndCiphertext = Data(base64Encoded: base64EncodedIVAndCiphertext), ivAndCiphertext.count >= AESGCM.ivSize else {
|
||||
guard let base64EncodedIVAndCiphertext = json["result"] as? String, let ivAndCiphertext = Data(base64Encoded: base64EncodedIVAndCiphertext), ivAndCiphertext.count >= AES.GCM.ivSize else {
|
||||
return Fail(error: HTTPError.invalidJSON)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
do {
|
||||
let data = try AESGCM.decrypt(ivAndCiphertext, with: destinationSymmetricKey)
|
||||
let data = try AES.GCM.decrypt(ivAndCiphertext, with: destinationSymmetricKey)
|
||||
|
||||
guard let json = try JSONSerialization.jsonObject(with: data, options: [ .fragmentsAllowed ]) as? JSON, let statusCode = json["status_code"] as? Int ?? json["status"] as? Int else {
|
||||
return Fail(error: HTTPError.invalidJSON)
|
||||
|
@ -725,13 +725,13 @@ public enum OnionRequestAPI: OnionRequestAPIType {
|
|||
|
||||
// V4 Onion Requests have a very different structure for responses
|
||||
case .v4:
|
||||
guard responseData.count >= AESGCM.ivSize else {
|
||||
guard responseData.count >= AES.GCM.ivSize else {
|
||||
return Fail(error: HTTPError.invalidResponse)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
do {
|
||||
let data: Data = try AESGCM.decrypt(responseData, with: destinationSymmetricKey)
|
||||
let data: Data = try AES.GCM.decrypt(responseData, with: destinationSymmetricKey)
|
||||
|
||||
// Process the bencoded response
|
||||
guard let processedResponse: (info: ResponseInfoType, body: Data?) = process(bencodedData: data) else {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
public enum OnionRequestAPIDestination: CustomStringConvertible {
|
||||
public enum OnionRequestAPIDestination: CustomStringConvertible, Codable {
|
||||
case snode(Snode)
|
||||
case server(host: String, target: String, x25519PublicKey: String, scheme: String?, port: UInt16?)
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ import Nimble
|
|||
|
||||
@testable import Session
|
||||
|
||||
class ThreadDisappearingMessagesViewModelSpec: QuickSpec {
|
||||
typealias ParentType = SessionTableViewModel<ThreadDisappearingMessagesViewModel.NavButton, ThreadDisappearingMessagesViewModel.Section, ThreadDisappearingMessagesViewModel.Item>
|
||||
class ThreadDisappearingMessagesSettingsViewModelSpec: QuickSpec {
|
||||
typealias ParentType = SessionTableViewModel<ThreadDisappearingMessagesSettingsViewModel.NavButton, ThreadDisappearingMessagesSettingsViewModel.Section, ThreadDisappearingMessagesSettingsViewModel.Item>
|
||||
|
||||
// MARK: - Spec
|
||||
|
||||
|
@ -16,9 +16,9 @@ class ThreadDisappearingMessagesViewModelSpec: QuickSpec {
|
|||
var mockStorage: Storage!
|
||||
var cancellables: [AnyCancellable] = []
|
||||
var dependencies: Dependencies!
|
||||
var viewModel: ThreadDisappearingMessagesViewModel!
|
||||
var viewModel: ThreadDisappearingMessagesSettingsViewModel!
|
||||
|
||||
describe("a ThreadDisappearingMessagesViewModel") {
|
||||
describe("a ThreadDisappearingMessagesSettingsViewModel") {
|
||||
// MARK: - Configuration
|
||||
|
||||
beforeEach {
|
||||
|
@ -41,17 +41,17 @@ class ThreadDisappearingMessagesViewModelSpec: QuickSpec {
|
|||
variant: .contact
|
||||
).insert(db)
|
||||
}
|
||||
viewModel = ThreadDisappearingMessagesViewModel(
|
||||
viewModel = ThreadDisappearingMessagesSettingsViewModel(
|
||||
dependencies: dependencies,
|
||||
threadId: "TestId",
|
||||
config: DisappearingMessagesConfiguration.defaultWith("TestId")
|
||||
)
|
||||
cancellables.append(
|
||||
viewModel.observableSettingsData
|
||||
viewModel.observableTableData
|
||||
.receiveOnMain(immediately: true)
|
||||
.sink(
|
||||
receiveCompletion: { _ in },
|
||||
receiveValue: { viewModel.updateSettings($0) }
|
||||
receiveValue: { viewModel.updateTableData($0.0) }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -72,18 +72,18 @@ class ThreadDisappearingMessagesViewModelSpec: QuickSpec {
|
|||
}
|
||||
|
||||
it("has the correct number of items") {
|
||||
expect(viewModel.settingsData.count)
|
||||
expect(viewModel.tableData.count)
|
||||
.to(equal(1))
|
||||
expect(viewModel.settingsData.first?.elements.count)
|
||||
expect(viewModel.tableData.first?.elements.count)
|
||||
.to(equal(12))
|
||||
}
|
||||
|
||||
it("has the correct default state") {
|
||||
expect(viewModel.settingsData.first?.elements.first)
|
||||
expect(viewModel.tableData.first?.elements.first)
|
||||
.to(
|
||||
equal(
|
||||
SessionCell.Info(
|
||||
id: ThreadDisappearingMessagesViewModel.Item(
|
||||
id: ThreadDisappearingMessagesSettingsViewModel.Item(
|
||||
title: "DISAPPEARING_MESSAGES_OFF".localized()
|
||||
),
|
||||
position: .top,
|
||||
|
@ -98,7 +98,7 @@ class ThreadDisappearingMessagesViewModelSpec: QuickSpec {
|
|||
let title: String = (DisappearingMessagesConfiguration.validDurationsSeconds.last?
|
||||
.formatted(format: .long))
|
||||
.defaulting(to: "")
|
||||
expect(viewModel.settingsData.first?.elements.last)
|
||||
expect(viewModel.tableData.first?.elements.last)
|
||||
.to(
|
||||
equal(
|
||||
SessionCell.Info(
|
||||
|
@ -123,25 +123,25 @@ class ThreadDisappearingMessagesViewModelSpec: QuickSpec {
|
|||
mockStorage.write { db in
|
||||
_ = try config.saved(db)
|
||||
}
|
||||
viewModel = ThreadDisappearingMessagesViewModel(
|
||||
viewModel = ThreadDisappearingMessagesSettingsViewModel(
|
||||
dependencies: dependencies,
|
||||
threadId: "TestId",
|
||||
config: config
|
||||
)
|
||||
cancellables.append(
|
||||
viewModel.observableSettingsData
|
||||
viewModel.observableTableData
|
||||
.receiveOnMain(immediately: true)
|
||||
.sink(
|
||||
receiveCompletion: { _ in },
|
||||
receiveValue: { viewModel.updateSettings($0) }
|
||||
receiveValue: { viewModel.updateTableData($0.0) }
|
||||
)
|
||||
)
|
||||
|
||||
expect(viewModel.settingsData.first?.elements.first)
|
||||
expect(viewModel.tableData.first?.elements.first)
|
||||
.to(
|
||||
equal(
|
||||
SessionCell.Info(
|
||||
id: ThreadDisappearingMessagesViewModel.Item(
|
||||
id: ThreadDisappearingMessagesSettingsViewModel.Item(
|
||||
title: "DISAPPEARING_MESSAGES_OFF".localized()
|
||||
),
|
||||
position: .top,
|
||||
|
@ -156,7 +156,7 @@ class ThreadDisappearingMessagesViewModelSpec: QuickSpec {
|
|||
let title: String = (DisappearingMessagesConfiguration.validDurationsSeconds.last?
|
||||
.formatted(format: .long))
|
||||
.defaulting(to: "")
|
||||
expect(viewModel.settingsData.first?.elements.last)
|
||||
expect(viewModel.tableData.first?.elements.last)
|
||||
.to(
|
||||
equal(
|
||||
SessionCell.Info(
|
||||
|
|
|
@ -69,10 +69,6 @@ class ThreadSettingsViewModelSpec: QuickSpec {
|
|||
didTriggerSearchCallbackTriggered = true
|
||||
}
|
||||
)
|
||||
setupStandardBinding()
|
||||
}
|
||||
|
||||
func setupStandardBinding() {
|
||||
disposables.append(
|
||||
viewModel.observableTableData
|
||||
.receiveOnMain(immediately: true)
|
||||
|
@ -81,14 +77,6 @@ class ThreadSettingsViewModelSpec: QuickSpec {
|
|||
receiveValue: { viewModel.updateTableData($0.0) }
|
||||
)
|
||||
)
|
||||
disposables.append(
|
||||
viewModel.transitionToScreen
|
||||
.receiveOnMain(immediately: true)
|
||||
.sink(
|
||||
receiveCompletion: { _ in },
|
||||
receiveValue: { transitionInfo = $0 }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
afterEach {
|
||||
|
@ -105,7 +93,7 @@ class ThreadSettingsViewModelSpec: QuickSpec {
|
|||
|
||||
context("with any conversation type") {
|
||||
it("triggers the search callback when tapping search") {
|
||||
viewModel.settingsData
|
||||
viewModel.tableData
|
||||
.first(where: { $0.model == .content })?
|
||||
.elements
|
||||
.first(where: { $0.id == .searchConversation })?
|
||||
|
@ -115,10 +103,10 @@ class ThreadSettingsViewModelSpec: QuickSpec {
|
|||
}
|
||||
|
||||
it("mutes a conversation") {
|
||||
viewModel.settingsData
|
||||
viewModel.tableData
|
||||
.first(where: { $0.model == .content })?
|
||||
.elements
|
||||
.first(where: { $0.id == .notifications })?
|
||||
.first(where: { $0.id == .notificationMute })?
|
||||
.onTap?()
|
||||
|
||||
expect(
|
||||
|
@ -145,11 +133,11 @@ class ThreadSettingsViewModelSpec: QuickSpec {
|
|||
)
|
||||
.toNot(beNil())
|
||||
|
||||
viewModel.settingsData
|
||||
viewModel.tableData
|
||||
.first(where: { $0.model == .content })?
|
||||
.elements
|
||||
.first(where: { $0.id == .notificationMute })?
|
||||
.onTap?(nil)
|
||||
.onTap?()
|
||||
|
||||
expect(
|
||||
mockStorage
|
||||
|
@ -179,12 +167,12 @@ class ThreadSettingsViewModelSpec: QuickSpec {
|
|||
didTriggerSearchCallbackTriggered = true
|
||||
}
|
||||
)
|
||||
cancellables.append(
|
||||
viewModel.observableSettingsData
|
||||
disposables.append(
|
||||
viewModel.observableTableData
|
||||
.receiveOnMain(immediately: true)
|
||||
.sink(
|
||||
receiveCompletion: { _ in },
|
||||
receiveValue: { viewModel.updateSettings($0) }
|
||||
receiveValue: { viewModel.updateTableData($0.0) }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -210,7 +198,7 @@ class ThreadSettingsViewModelSpec: QuickSpec {
|
|||
|
||||
it("has no mute button") {
|
||||
expect(
|
||||
viewModel.settingsData
|
||||
viewModel.tableData
|
||||
.first(where: { $0.model == .content })?
|
||||
.elements
|
||||
.first(where: { $0.id == .notificationMute })
|
||||
|
@ -233,7 +221,7 @@ class ThreadSettingsViewModelSpec: QuickSpec {
|
|||
ParentType.NavItem(
|
||||
id: .cancel,
|
||||
systemItem: .cancel,
|
||||
accessibilityIdentifier: "Cancel"
|
||||
accessibilityIdentifier: "Cancel button"
|
||||
)
|
||||
]))
|
||||
expect(viewModel.rightNavItems.firstValue())
|
||||
|
@ -453,12 +441,12 @@ class ThreadSettingsViewModelSpec: QuickSpec {
|
|||
didTriggerSearchCallbackTriggered = true
|
||||
}
|
||||
)
|
||||
cancellables.append(
|
||||
viewModel.observableSettingsData
|
||||
disposables.append(
|
||||
viewModel.observableTableData
|
||||
.receiveOnMain(immediately: true)
|
||||
.sink(
|
||||
receiveCompletion: { _ in },
|
||||
receiveValue: { viewModel.updateSettings($0) }
|
||||
receiveValue: { viewModel.updateTableData($0.0) }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -495,12 +483,12 @@ class ThreadSettingsViewModelSpec: QuickSpec {
|
|||
didTriggerSearchCallbackTriggered = true
|
||||
}
|
||||
)
|
||||
cancellables.append(
|
||||
viewModel.observableSettingsData
|
||||
disposables.append(
|
||||
viewModel.observableTableData
|
||||
.receiveOnMain(immediately: true)
|
||||
.sink(
|
||||
receiveCompletion: { _ in },
|
||||
receiveValue: { viewModel.updateSettings($0) }
|
||||
receiveValue: { viewModel.updateTableData($0.0) }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -30,11 +30,11 @@ class NotificationContentViewModelSpec: QuickSpec {
|
|||
]
|
||||
)
|
||||
viewModel = NotificationContentViewModel(storage: mockStorage, scheduling: .immediate)
|
||||
dataChangeCancellable = viewModel.observableSettingsData
|
||||
dataChangeCancellable = viewModel.observableTableData
|
||||
.receiveOnMain(immediately: true)
|
||||
.sink(
|
||||
receiveCompletion: { _ in },
|
||||
receiveValue: { viewModel.updateSettings($0) }
|
||||
receiveValue: { viewModel.updateTableData($0.0) }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -55,14 +55,14 @@ class NotificationContentViewModelSpec: QuickSpec {
|
|||
}
|
||||
|
||||
it("has the correct number of items") {
|
||||
expect(viewModel.settingsData.count)
|
||||
expect(viewModel.tableData.count)
|
||||
.to(equal(1))
|
||||
expect(viewModel.settingsData.first?.elements.count)
|
||||
expect(viewModel.tableData.first?.elements.count)
|
||||
.to(equal(3))
|
||||
}
|
||||
|
||||
it("has the correct default state") {
|
||||
expect(viewModel.settingsData.first?.elements)
|
||||
expect(viewModel.tableData.first?.elements)
|
||||
.to(
|
||||
equal([
|
||||
SessionCell.Info(
|
||||
|
@ -98,14 +98,14 @@ class NotificationContentViewModelSpec: QuickSpec {
|
|||
db[.preferencesNotificationPreviewType] = Preferences.NotificationPreviewType.nameNoPreview
|
||||
}
|
||||
viewModel = NotificationContentViewModel(storage: mockStorage, scheduling: .immediate)
|
||||
dataChangeCancellable = viewModel.observableSettingsData
|
||||
dataChangeCancellable = viewModel.observableTableData
|
||||
.receiveOnMain(immediately: true)
|
||||
.sink(
|
||||
receiveCompletion: { _ in },
|
||||
receiveValue: { viewModel.updateSettings($0) }
|
||||
receiveValue: { viewModel.updateTableData($0.0) }
|
||||
)
|
||||
|
||||
expect(viewModel.settingsData.first?.elements)
|
||||
expect(viewModel.tableData.first?.elements)
|
||||
.to(
|
||||
equal([
|
||||
SessionCell.Info(
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
import CryptoSwift
|
||||
import Curve25519Kit
|
||||
|
||||
public enum AESGCM {
|
||||
public static let gcmTagSize: UInt = 16
|
||||
public static let ivSize: UInt = 12
|
||||
|
||||
public struct EncryptionResult { public let ciphertext: Data, symmetricKey: Data, ephemeralPublicKey: Data }
|
||||
|
||||
public enum Error : LocalizedError {
|
||||
case keyPairGenerationFailed
|
||||
case sharedSecretGenerationFailed
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .keyPairGenerationFailed: return "Couldn't generate a key pair."
|
||||
case .sharedSecretGenerationFailed: return "Couldn't generate a shared secret."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// - Note: Sync. Don't call from the main thread.
|
||||
public static func generateSymmetricKey(x25519PublicKey: Data, x25519PrivateKey: Data) throws -> Data {
|
||||
if Thread.isMainThread {
|
||||
#if DEBUG
|
||||
preconditionFailure("It's illegal to call encrypt(_:forSnode:) from the main thread.")
|
||||
#endif
|
||||
}
|
||||
guard let sharedSecret = try? Curve25519.generateSharedSecret(fromPublicKey: x25519PublicKey, privateKey: x25519PrivateKey) else {
|
||||
throw Error.sharedSecretGenerationFailed
|
||||
}
|
||||
let salt = "LOKI"
|
||||
return try Data(HMAC(key: salt.bytes, variant: .sha256).authenticate(sharedSecret.bytes))
|
||||
}
|
||||
|
||||
/// - Note: Sync. Don't call from the main thread.
|
||||
public static func decrypt(_ ivAndCiphertext: Data, with symmetricKey: Data) throws -> Data {
|
||||
if Thread.isMainThread {
|
||||
#if DEBUG
|
||||
preconditionFailure("It's illegal to call decrypt(_:usingAESGCMWithSymmetricKey:) from the main thread.")
|
||||
#endif
|
||||
}
|
||||
let iv = ivAndCiphertext[0..<Int(ivSize)]
|
||||
let ciphertext = ivAndCiphertext[Int(ivSize)...]
|
||||
let gcm = GCM(iv: iv.bytes, tagLength: Int(gcmTagSize), mode: .combined)
|
||||
let aes = try AES(key: symmetricKey.bytes, blockMode: gcm, padding: .noPadding)
|
||||
return Data(try aes.decrypt(ciphertext.bytes))
|
||||
}
|
||||
|
||||
/// - Note: Sync. Don't call from the main thread.
|
||||
public static func encrypt(_ plaintext: Data, with symmetricKey: Data) throws -> Data {
|
||||
if Thread.isMainThread {
|
||||
#if DEBUG
|
||||
preconditionFailure("It's illegal to call encrypt(_:usingAESGCMWithSymmetricKey:) from the main thread.")
|
||||
#endif
|
||||
}
|
||||
let iv = Data.getSecureRandomData(ofSize: ivSize)!
|
||||
let gcm = GCM(iv: iv.bytes, tagLength: Int(gcmTagSize), mode: .combined)
|
||||
let aes = try AES(key: symmetricKey.bytes, blockMode: gcm, padding: .noPadding)
|
||||
let ciphertext = try aes.encrypt(plaintext.bytes)
|
||||
return iv + Data(ciphertext)
|
||||
}
|
||||
|
||||
/// - Note: Sync. Don't call from the main thread.
|
||||
public static func encrypt(_ plaintext: Data, for hexEncodedX25519PublicKey: String) throws -> EncryptionResult {
|
||||
if Thread.isMainThread {
|
||||
#if DEBUG
|
||||
preconditionFailure("It's illegal to call encrypt(_:forSnode:) from the main thread.")
|
||||
#endif
|
||||
}
|
||||
let x25519PublicKey = Data(hex: hexEncodedX25519PublicKey)
|
||||
let ephemeralKeyPair = Curve25519.generateKeyPair()
|
||||
let symmetricKey = try generateSymmetricKey(x25519PublicKey: x25519PublicKey, x25519PrivateKey: ephemeralKeyPair.privateKey)
|
||||
let ciphertext = try encrypt(plaintext, with: Data(symmetricKey))
|
||||
return EncryptionResult(ciphertext: ciphertext, symmetricKey: Data(symmetricKey), ephemeralPublicKey: ephemeralKeyPair.publicKey)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import CryptoKit
|
||||
import Curve25519Kit
|
||||
|
||||
public extension Digest {
|
||||
var bytes: [UInt8] { Array(makeIterator()) }
|
||||
var data: Data { Data(bytes) }
|
||||
|
||||
var hexString: String {
|
||||
bytes.map { String(format: "%02X", $0) }.joined()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - AES.GCM
|
||||
|
||||
public extension AES.GCM {
|
||||
static let ivSize: Int = 12
|
||||
|
||||
struct EncryptionResult {
|
||||
public let ciphertext: Data
|
||||
public let symmetricKey: Data
|
||||
public let ephemeralPublicKey: Data
|
||||
}
|
||||
|
||||
enum Error: LocalizedError {
|
||||
case keyPairGenerationFailed
|
||||
case sharedSecretGenerationFailed
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .keyPairGenerationFailed: return "Couldn't generate a key pair."
|
||||
case .sharedSecretGenerationFailed: return "Couldn't generate a shared secret."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// - Note: Sync. Don't call from the main thread.
|
||||
static func generateSymmetricKey(x25519PublicKey: Data, x25519PrivateKey: Data) throws -> Data {
|
||||
if Thread.isMainThread {
|
||||
#if DEBUG
|
||||
preconditionFailure("It's illegal to call encrypt(_:forSnode:) from the main thread.")
|
||||
#endif
|
||||
}
|
||||
guard let sharedSecret: Data = try? Curve25519.generateSharedSecret(fromPublicKey: x25519PublicKey, privateKey: x25519PrivateKey) else {
|
||||
throw Error.sharedSecretGenerationFailed
|
||||
}
|
||||
let salt = "LOKI"
|
||||
|
||||
return Data(
|
||||
HMAC<SHA256>.authenticationCode(
|
||||
for: sharedSecret,
|
||||
using: SymmetricKey(data: salt.bytes)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/// - Note: Sync. Don't call from the main thread.
|
||||
static func decrypt(_ nonceAndCiphertext: Data, with symmetricKey: Data) throws -> Data {
|
||||
if Thread.isMainThread {
|
||||
#if DEBUG
|
||||
preconditionFailure("It's illegal to call decrypt(_:usingAESGCMWithSymmetricKey:) from the main thread.")
|
||||
#endif
|
||||
}
|
||||
|
||||
return try AES.GCM.open(
|
||||
try AES.GCM.SealedBox(combined: nonceAndCiphertext),
|
||||
using: SymmetricKey(data: symmetricKey)
|
||||
)
|
||||
}
|
||||
|
||||
/// - Note: Sync. Don't call from the main thread.
|
||||
static func encrypt(_ plaintext: Data, with symmetricKey: Data) throws -> Data {
|
||||
if Thread.isMainThread {
|
||||
#if DEBUG
|
||||
preconditionFailure("It's illegal to call encrypt(_:usingAESGCMWithSymmetricKey:) from the main thread.")
|
||||
#endif
|
||||
}
|
||||
|
||||
let nonceData: Data = try Randomness.generateRandomBytes(numberBytes: ivSize)
|
||||
let sealedData: AES.GCM.SealedBox = try AES.GCM.seal(
|
||||
plaintext,
|
||||
using: SymmetricKey(data: symmetricKey),
|
||||
nonce: try AES.GCM.Nonce(data: nonceData)
|
||||
)
|
||||
|
||||
guard let cipherText: Data = sealedData.combined else {
|
||||
throw GeneralError.keyGenerationFailed
|
||||
}
|
||||
|
||||
return cipherText
|
||||
}
|
||||
|
||||
/// - Note: Sync. Don't call from the main thread.
|
||||
static func encrypt(_ plaintext: Data, for hexEncodedX25519PublicKey: String) throws -> EncryptionResult {
|
||||
if Thread.isMainThread {
|
||||
#if DEBUG
|
||||
preconditionFailure("It's illegal to call encrypt(_:forSnode:) from the main thread.")
|
||||
#endif
|
||||
}
|
||||
let x25519PublicKey = Data(hex: hexEncodedX25519PublicKey)
|
||||
let ephemeralKeyPair = Curve25519.generateKeyPair()
|
||||
let symmetricKey = try generateSymmetricKey(x25519PublicKey: x25519PublicKey, x25519PrivateKey: ephemeralKeyPair.privateKey)
|
||||
let ciphertext = try encrypt(plaintext, with: Data(symmetricKey))
|
||||
|
||||
return EncryptionResult(ciphertext: ciphertext, symmetricKey: Data(symmetricKey), ephemeralPublicKey: ephemeralKeyPair.publicKey)
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension Data {
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
import CryptoSwift
|
||||
import Curve25519Kit
|
||||
|
||||
public final class DiffieHellman : NSObject {
|
||||
public static let ivSize: UInt = 16
|
||||
|
||||
public enum Error : LocalizedError {
|
||||
case decryptionFailed
|
||||
case sharedSecretGenerationFailed
|
||||
|
||||
public var errorDescription: String {
|
||||
switch self {
|
||||
case .decryptionFailed: return "Couldn't decrypt data"
|
||||
case .sharedSecretGenerationFailed: return "Couldn't generate a shared secret."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private override init() { }
|
||||
|
||||
public static func encrypt(_ plaintext: Data, using symmetricKey: Data) throws -> Data {
|
||||
let iv = Data.getSecureRandomData(ofSize: ivSize)!
|
||||
let cbc = CBC(iv: iv.bytes)
|
||||
let aes = try AES(key: symmetricKey.bytes, blockMode: cbc)
|
||||
let ciphertext = try aes.encrypt(plaintext.bytes)
|
||||
let ivAndCiphertext = iv.bytes + ciphertext
|
||||
return Data(ivAndCiphertext)
|
||||
}
|
||||
|
||||
public static func encrypt(_ plaintext: Data, publicKey: Data, privateKey: Data) throws -> Data {
|
||||
guard let symmetricKey = try? Curve25519.generateSharedSecret(fromPublicKey: publicKey, privateKey: privateKey) else { throw Error.sharedSecretGenerationFailed }
|
||||
return try encrypt(plaintext, using: symmetricKey)
|
||||
}
|
||||
|
||||
public static func decrypt(_ ivAndCiphertext: Data, using symmetricKey: Data) throws -> Data {
|
||||
guard ivAndCiphertext.count >= ivSize else { throw Error.decryptionFailed }
|
||||
let iv = ivAndCiphertext[..<ivSize]
|
||||
let ciphertext = ivAndCiphertext[ivSize...]
|
||||
let cbc = CBC(iv: iv.bytes)
|
||||
let aes = try AES(key: symmetricKey.bytes, blockMode: cbc)
|
||||
let plaintext = try aes.decrypt(ciphertext.bytes)
|
||||
return Data(plaintext)
|
||||
}
|
||||
|
||||
public static func decrypt(_ ivAndCiphertext: Data, publicKey: Data, privateKey: Data) throws -> Data {
|
||||
guard let symmetricKey = try? Curve25519.generateSharedSecret(fromPublicKey: publicKey, privateKey: privateKey) else { throw Error.sharedSecretGenerationFailed }
|
||||
return try decrypt(ivAndCiphertext, using: symmetricKey)
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
import Curve25519Kit
|
||||
|
||||
public extension ECKeyPair {
|
||||
|
||||
@objc var hexEncodedPrivateKey: String {
|
||||
return privateKey.map { String(format: "%02hhx", $0) }.joined()
|
||||
}
|
||||
|
||||
@objc var hexEncodedPublicKey: String {
|
||||
// Prefixing with 'SessionId.Prefix.standard' is necessary for what seems to be a sort of Signal public key versioning system
|
||||
return SessionId(.standard, publicKey: publicKey.bytes).hexString
|
||||
}
|
||||
|
||||
@objc static func isValidHexEncodedPublicKey(candidate: String) -> Bool {
|
||||
// Note: If the logic in here changes ensure it doesn't break `SessionId.Prefix(from:)`
|
||||
// Check that it's a valid hexadecimal encoding
|
||||
guard Hex.isValid(candidate) else { return false }
|
||||
// Check that it has length 66 and a valid prefix
|
||||
guard candidate.count == 66 && SessionId.Prefix.allCases.first(where: { candidate.hasPrefix($0.rawValue) }) != nil else {
|
||||
return false
|
||||
}
|
||||
|
||||
// It appears to be a valid public key
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -1,8 +1,74 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum Hex {
|
||||
|
||||
public static func isValid(_ string: String) -> Bool {
|
||||
let allowedCharacters = CharacterSet(charactersIn: "0123456789ABCDEF")
|
||||
|
||||
return string.uppercased().unicodeScalars.allSatisfy { allowedCharacters.contains($0) }
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Data
|
||||
|
||||
public extension Data {
|
||||
var bytes: [UInt8] { return Array(self) }
|
||||
|
||||
func toHexString() -> String {
|
||||
return bytes.map { String(format: "%02x", $0) }.joined()
|
||||
}
|
||||
|
||||
init(hex: String) {
|
||||
self.init(Array<UInt8>(hex: hex))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Array
|
||||
|
||||
public extension Array where Element == UInt8 {
|
||||
init(hex: String) {
|
||||
self = Array<Element>()
|
||||
self.reserveCapacity(hex.unicodeScalars.lazy.underestimatedCount)
|
||||
|
||||
var buffer: UInt8?
|
||||
var skip = (hex.hasPrefix("0x") ? 2 : 0)
|
||||
|
||||
for char in hex.unicodeScalars.lazy {
|
||||
guard skip == 0 else {
|
||||
skip -= 1
|
||||
continue
|
||||
}
|
||||
|
||||
guard char.value >= 48 && char.value <= 102 else {
|
||||
removeAll()
|
||||
return
|
||||
}
|
||||
|
||||
let v: UInt8
|
||||
let c: UInt8 = UInt8(char.value)
|
||||
|
||||
switch c {
|
||||
case let c where c <= 57: v = c - 48
|
||||
case let c where c >= 65 && c <= 70: v = c - 55
|
||||
case let c where c >= 97: v = c - 87
|
||||
|
||||
default:
|
||||
removeAll()
|
||||
return
|
||||
}
|
||||
|
||||
if let b = buffer {
|
||||
append(b << 4 | v)
|
||||
buffer = nil
|
||||
}
|
||||
else {
|
||||
buffer = v
|
||||
}
|
||||
}
|
||||
|
||||
if let b = buffer {
|
||||
append(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct KeyPair {
|
||||
public let publicKey: [UInt8]
|
||||
public let secretKey: [UInt8]
|
||||
|
||||
public var hexEncodedPublicKey: String {
|
||||
return SessionId(.standard, publicKey: publicKey).hexString
|
||||
}
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
public init(publicKey: [UInt8], secretKey: [UInt8]) {
|
||||
self.publicKey = publicKey
|
||||
self.secretKey = secretKey
|
||||
}
|
||||
|
||||
// MARK: - Functions
|
||||
|
||||
public static func isValidHexEncodedPublicKey(candidate: String) -> Bool {
|
||||
// Note: If the logic in here changes ensure it doesn't break `SessionId.Prefix(from:)`
|
||||
// Check that it's a valid hexadecimal encoding
|
||||
guard Hex.isValid(candidate) else { return false }
|
||||
|
||||
// Check that it has length 66 and a valid prefix
|
||||
guard candidate.count == 66 && SessionId.Prefix.allCases.first(where: { candidate.hasPrefix($0.rawValue) }) != nil else {
|
||||
return false
|
||||
}
|
||||
|
||||
// It appears to be a valid public key
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import CryptoSwift
|
||||
|
||||
/// Based on [mnemonic.js](https://github.com/loki-project/loki-messenger/blob/development/libloki/modules/mnemonic.js) .
|
||||
public enum Mnemonic {
|
||||
|
||||
public struct Language : Hashable {
|
||||
public struct Language: Hashable {
|
||||
fileprivate let filename: String
|
||||
fileprivate let prefixLength: UInt
|
||||
|
||||
|
@ -12,8 +14,8 @@ public enum Mnemonic {
|
|||
public static let portuguese = Language(filename: "portuguese", prefixLength: 4)
|
||||
public static let spanish = Language(filename: "spanish", prefixLength: 4)
|
||||
|
||||
private static var wordSetCache: [Language:[String]] = [:]
|
||||
private static var truncatedWordSetCache: [Language:[String]] = [:]
|
||||
private static var wordSetCache: [Language: [String]] = [:]
|
||||
private static var truncatedWordSetCache: [Language: [String]] = [:]
|
||||
|
||||
private init(filename: String, prefixLength: UInt) {
|
||||
self.filename = filename
|
||||
|
@ -23,23 +25,25 @@ public enum Mnemonic {
|
|||
fileprivate func loadWordSet() -> [String] {
|
||||
if let cachedResult = Language.wordSetCache[self] {
|
||||
return cachedResult
|
||||
} else {
|
||||
let url = Bundle.main.url(forResource: filename, withExtension: "txt")!
|
||||
let contents = try! String(contentsOf: url)
|
||||
let result = contents.split(separator: ",").map { String($0) }
|
||||
Language.wordSetCache[self] = result
|
||||
return result
|
||||
}
|
||||
|
||||
let url = Bundle.main.url(forResource: filename, withExtension: "txt")!
|
||||
let contents = try! String(contentsOf: url)
|
||||
let result = contents.split(separator: ",").map { String($0) }
|
||||
Language.wordSetCache[self] = result
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fileprivate func loadTruncatedWordSet() -> [String] {
|
||||
if let cachedResult = Language.truncatedWordSetCache[self] {
|
||||
return cachedResult
|
||||
} else {
|
||||
let result = loadWordSet().map { $0.prefix(length: prefixLength) }
|
||||
Language.truncatedWordSetCache[self] = result
|
||||
return result
|
||||
}
|
||||
|
||||
let result = loadWordSet().map { $0.prefix(length: prefixLength) }
|
||||
Language.truncatedWordSetCache[self] = result
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,6 +72,7 @@ public enum Mnemonic {
|
|||
var result: [String] = []
|
||||
let n = wordSet.count
|
||||
let characterCount = string.indices.count // Safe for this particular case
|
||||
|
||||
for chunkStartIndexAsInt in stride(from: 0, to: characterCount, by: 8) {
|
||||
let chunkStartIndex = string.index(string.startIndex, offsetBy: chunkStartIndexAsInt)
|
||||
let chunkEndIndex = string.index(chunkStartIndex, offsetBy: 8)
|
||||
|
@ -76,6 +81,7 @@ public enum Mnemonic {
|
|||
let p3 = string[chunkEndIndex..<string.endIndex]
|
||||
string = String(p1 + p2 + p3)
|
||||
}
|
||||
|
||||
for chunkStartIndexAsInt in stride(from: 0, to: characterCount, by: 8) {
|
||||
let chunkStartIndex = string.index(string.startIndex, offsetBy: chunkStartIndexAsInt)
|
||||
let chunkEndIndex = string.index(chunkStartIndex, offsetBy: 8)
|
||||
|
@ -85,9 +91,11 @@ public enum Mnemonic {
|
|||
let w3 = (((x / n) / n) + w2) % n
|
||||
result += [ wordSet[w1], wordSet[w2], wordSet[w3] ]
|
||||
}
|
||||
|
||||
let checksumIndex = determineChecksumIndex(for: result, prefixLength: prefixLength)
|
||||
let checksumWord = result[checksumIndex]
|
||||
result.append(checksumWord)
|
||||
|
||||
return result.joined(separator: " ")
|
||||
}
|
||||
|
||||
|
@ -97,11 +105,14 @@ public enum Mnemonic {
|
|||
let prefixLength = language.prefixLength
|
||||
var result = ""
|
||||
let n = truncatedWordSet.count
|
||||
|
||||
// Check preconditions
|
||||
guard words.count >= 12 else { throw DecodingError.inputTooShort }
|
||||
guard !words.count.isMultiple(of: 3) else { throw DecodingError.missingLastWord }
|
||||
|
||||
// Get checksum word
|
||||
let checksumWord = words.popLast()!
|
||||
|
||||
// Decode
|
||||
for chunkStartIndex in stride(from: 0, to: words.count, by: 3) {
|
||||
guard let w1 = truncatedWordSet.firstIndex(of: words[chunkStartIndex].prefix(length: prefixLength)),
|
||||
|
@ -112,10 +123,12 @@ public enum Mnemonic {
|
|||
let string = "0000000" + String(x, radix: 16)
|
||||
result += swap(String(string[string.index(string.endIndex, offsetBy: -8)..<string.endIndex]))
|
||||
}
|
||||
|
||||
// Verify checksum
|
||||
let checksumIndex = determineChecksumIndex(for: words, prefixLength: prefixLength)
|
||||
let expectedChecksumWord = words[checksumIndex]
|
||||
guard expectedChecksumWord.prefix(length: prefixLength) == checksumWord.prefix(length: prefixLength) else { throw DecodingError.verificationFailed }
|
||||
|
||||
// Return
|
||||
return result
|
||||
}
|
||||
|
@ -124,38 +137,24 @@ public enum Mnemonic {
|
|||
func toStringIndex(_ indexAsInt: Int) -> String.Index {
|
||||
return x.index(x.startIndex, offsetBy: indexAsInt)
|
||||
}
|
||||
|
||||
let p1 = x[toStringIndex(6)..<toStringIndex(8)]
|
||||
let p2 = x[toStringIndex(4)..<toStringIndex(6)]
|
||||
let p3 = x[toStringIndex(2)..<toStringIndex(4)]
|
||||
let p4 = x[toStringIndex(0)..<toStringIndex(2)]
|
||||
|
||||
return String(p1 + p2 + p3 + p4)
|
||||
}
|
||||
|
||||
private static func determineChecksumIndex(for x: [String], prefixLength: UInt) -> Int {
|
||||
let checksum = Array(x.map { $0.prefix(length: prefixLength) }.joined().utf8).crc32()
|
||||
|
||||
return Int(checksum) % x.count
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
|
||||
func prefix(length: UInt) -> String {
|
||||
return String(self[startIndex..<index(startIndex, offsetBy: Int(length))])
|
||||
}
|
||||
}
|
||||
|
||||
@objc(SNMnemonic)
|
||||
public final class ObjCMnemonic : NSObject {
|
||||
|
||||
override private init() { }
|
||||
|
||||
@objc(hashHexEncodedString:)
|
||||
public static func hash(hexEncodedString string: String) -> String {
|
||||
return Mnemonic.hash(hexEncodedString: string)
|
||||
}
|
||||
|
||||
@objc(encodeHexEncodedString:)
|
||||
public static func encode(hexEncodedString string: String) -> String {
|
||||
return Mnemonic.encode(hexEncodedString: string)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import Curve25519Kit
|
||||
|
||||
/// This migration sets up the standard jobs, since we want these jobs to run before any "once-off" jobs we do this migration
|
||||
/// before running the `YDBToGRDBMigration`
|
||||
|
|
|
@ -4,7 +4,6 @@ import Foundation
|
|||
import GRDB
|
||||
import Sodium
|
||||
import Curve25519Kit
|
||||
import CryptoSwift
|
||||
|
||||
public struct Identity: Codable, Identifiable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible {
|
||||
public static var databaseTableName: String { "identity" }
|
||||
|
@ -39,20 +38,10 @@ public struct Identity: Codable, Identifiable, FetchableRecord, PersistableRecor
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Convenience
|
||||
|
||||
extension ECKeyPair {
|
||||
func toData() -> Data {
|
||||
var targetValue: ECKeyPair = self
|
||||
|
||||
return Data(bytes: &targetValue, count: MemoryLayout.size(ofValue: targetValue))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - GRDB Interactions
|
||||
|
||||
public extension Identity {
|
||||
static func generate(from seed: Data) throws -> (ed25519KeyPair: Sign.KeyPair, x25519KeyPair: ECKeyPair) {
|
||||
static func generate(from seed: Data) throws -> (ed25519KeyPair: KeyPair, x25519KeyPair: KeyPair) {
|
||||
assert(seed.count == 16)
|
||||
let padding = Data(repeating: 0, count: 16)
|
||||
|
||||
|
@ -64,18 +53,25 @@ public extension Identity {
|
|||
throw GeneralError.keyGenerationFailed
|
||||
}
|
||||
|
||||
let x25519KeyPair = try ECKeyPair(publicKeyData: Data(x25519PublicKey), privateKeyData: Data(x25519SecretKey))
|
||||
|
||||
return (ed25519KeyPair: ed25519KeyPair, x25519KeyPair: x25519KeyPair)
|
||||
return (
|
||||
ed25519KeyPair: KeyPair(
|
||||
publicKey: ed25519KeyPair.publicKey,
|
||||
secretKey: ed25519KeyPair.secretKey
|
||||
),
|
||||
x25519KeyPair: KeyPair(
|
||||
publicKey: x25519PublicKey,
|
||||
secretKey: x25519SecretKey
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
static func store(seed: Data, ed25519KeyPair: Sign.KeyPair, x25519KeyPair: ECKeyPair) {
|
||||
static func store(seed: Data, ed25519KeyPair: KeyPair, x25519KeyPair: KeyPair) {
|
||||
Storage.shared.write { db in
|
||||
try Identity(variant: .seed, data: seed).save(db)
|
||||
try Identity(variant: .ed25519SecretKey, data: Data(ed25519KeyPair.secretKey)).save(db)
|
||||
try Identity(variant: .ed25519PublicKey, data: Data(ed25519KeyPair.publicKey)).save(db)
|
||||
try Identity(variant: .x25519PrivateKey, data: x25519KeyPair.privateKey).save(db)
|
||||
try Identity(variant: .x25519PublicKey, data: x25519KeyPair.publicKey).save(db)
|
||||
try Identity(variant: .x25519PrivateKey, data: Data(x25519KeyPair.secretKey)).save(db)
|
||||
try Identity(variant: .x25519PublicKey, data: Data(x25519KeyPair.publicKey)).save(db)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,16 +149,3 @@ public extension Identity {
|
|||
NotificationCenter.default.post(name: .registrationStateDidChange, object: nil, userInfo: nil)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Objective-C Support
|
||||
|
||||
// TODO: Remove this when possible
|
||||
@objc(SUKIdentity)
|
||||
public class SUKIdentity: NSObject {
|
||||
@objc(userExists)
|
||||
public static func userExists() -> Bool {
|
||||
return Storage.shared
|
||||
.read { db in Identity.userExists(db) }
|
||||
.defaulting(to: false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import Curve25519Kit
|
||||
|
||||
public protocol GeneralCacheType {
|
||||
var encodedPublicKey: String? { get set }
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import Foundation
|
||||
import Sodium
|
||||
import Curve25519Kit
|
||||
|
||||
public struct SessionId {
|
||||
public static let byteCount: Int = 33
|
||||
|
@ -21,7 +20,7 @@ public struct SessionId {
|
|||
return
|
||||
}
|
||||
|
||||
guard ECKeyPair.isValidHexEncodedPublicKey(candidate: stringValue) else { return nil }
|
||||
guard KeyPair.isValidHexEncodedPublicKey(candidate: stringValue) else { return nil }
|
||||
guard let targetPrefix: Prefix = Prefix(rawValue: String(stringValue.prefix(2))) else { return nil }
|
||||
|
||||
self = targetPrefix
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
import CryptoSwift
|
||||
import CryptoKit
|
||||
import SessionUIKit
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public class PlaceholderIcon {
|
||||
private let seed: Int
|
||||
|
@ -19,7 +20,10 @@ public class PlaceholderIcon {
|
|||
convenience init(seed: String, colors: [UIColor]? = nil) {
|
||||
// Ensure we have a correct hash
|
||||
var hash = seed
|
||||
if (hash.matches("^[0-9A-Fa-f]+$") && hash.count >= 12) { hash = seed.sha512() }
|
||||
|
||||
if (hash.matches("^[0-9A-Fa-f]+$") && hash.count >= 12) {
|
||||
hash = SHA512.hash(data: Data(seed.bytes)).hexString
|
||||
}
|
||||
|
||||
guard let number = Int(hash.substring(to: 12), radix: 16) else {
|
||||
owsFailDebug("Failed to generate number from seed string: \(seed).")
|
||||
|
|
Loading…
Reference in New Issue