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:
Morgan Pretty 2022-12-08 18:07:02 +11:00
parent f1e9412c7a
commit 174725c7fd
40 changed files with 381 additions and 549 deletions

View File

@ -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'

View File

@ -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

View File

@ -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 */,

View File

@ -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 {

View File

@ -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
)

View File

@ -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
}

View File

@ -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
)
}
}

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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()
}()

View File

@ -2,7 +2,6 @@
import Foundation
import GRDB
import Curve25519Kit
import SessionUtilitiesKit
import SessionSnodeKit

View File

@ -4,7 +4,6 @@ import Foundation
import AVKit
import GRDB
import YapDatabase
import Curve25519Kit
import SessionUtilitiesKit
import SessionSnodeKit

View File

@ -2,7 +2,6 @@
import Foundation
import GRDB
import Curve25519Kit
import SessionUtilitiesKit
import SessionSnodeKit

View File

@ -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
)
}
}
}

View File

@ -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)
}
}

View File

@ -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: "")
}
}

View File

@ -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

View File

@ -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

View File

@ -3,8 +3,6 @@
import Foundation
import GRDB
import Sodium
import CryptoSwift
import Curve25519Kit
import SessionUtilitiesKit
extension MessageReceiver {

View File

@ -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: [:]

View File

@ -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()
}

View File

@ -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 {

View File

@ -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?)

View File

@ -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(

View File

@ -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) }
)
)
}

View File

@ -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(

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -1,3 +1,5 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
public extension Data {

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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)
}
}
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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`

View File

@ -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)
}
}

View File

@ -2,7 +2,6 @@
import Foundation
import GRDB
import Curve25519Kit
public protocol GeneralCacheType {
var encodedPublicKey: String? { get set }

View File

@ -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

View File

@ -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).")