From 049705c9cb3d1d3ea34f1dc71b65a4d70b117edc Mon Sep 17 00:00:00 2001 From: Dirk Zimmermann Date: Thu, 6 Aug 2020 16:55:17 +0200 Subject: [PATCH] IOSAD-180 Own PEPPassphraseUtil --- pEpObjCAdapter.xcodeproj/project.pbxproj | 6 ++ pEpObjCAdapter/PEPPassphraseUtil.h | 28 +++++ pEpObjCAdapter/PEPPassphraseUtil.m | 129 +++++++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 pEpObjCAdapter/PEPPassphraseUtil.h create mode 100644 pEpObjCAdapter/PEPPassphraseUtil.m diff --git a/pEpObjCAdapter.xcodeproj/project.pbxproj b/pEpObjCAdapter.xcodeproj/project.pbxproj index a1501d3..a50039f 100644 --- a/pEpObjCAdapter.xcodeproj/project.pbxproj +++ b/pEpObjCAdapter.xcodeproj/project.pbxproj @@ -70,6 +70,7 @@ 435F519022204A67006EB11F /* PEPSessionProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 435F518F22204A67006EB11F /* PEPSessionProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4360AA0E2227F22900E62E5A /* PEPObjCAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = 43209B2F1ECC2ACD007E7E2E /* PEPObjCAdapter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 43676B661C57EA1A00233933 /* B623F674_sec.asc in Resources */ = {isa = PBXBuildFile; fileRef = 43676B641C57EA1A00233933 /* B623F674_sec.asc */; }; + 436C9A3324DC48B600007A3D /* PEPPassphraseUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 436C9A3224DC48B600007A3D /* PEPPassphraseUtil.m */; }; 436E916E24B65805000296FF /* PEPPassphraseProviderProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 436E916D24B65805000296FF /* PEPPassphraseProviderProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; 436E917224B714A2000296FF /* Rick Deckard (43F270EC) – Secret.asc in Resources */ = {isa = PBXBuildFile; fileRef = 436E917124B714A1000296FF /* Rick Deckard (43F270EC) – Secret.asc */; }; 436E917724B71E12000296FF /* PEPPassphraseProviderMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 436E917624B71E12000296FF /* PEPPassphraseProviderMock.m */; }; @@ -215,6 +216,8 @@ 4360A9FE2227EBB200E62E5A /* NSNumber+PEPRating+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSNumber+PEPRating+Internal.h"; sourceTree = ""; }; 43676B631C57EA1A00233933 /* 0xB623F674.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = 0xB623F674.asc; sourceTree = ""; }; 43676B641C57EA1A00233933 /* B623F674_sec.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = B623F674_sec.asc; sourceTree = ""; }; + 436C9A3124DC48B600007A3D /* PEPPassphraseUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PEPPassphraseUtil.h; sourceTree = ""; }; + 436C9A3224DC48B600007A3D /* PEPPassphraseUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PEPPassphraseUtil.m; sourceTree = ""; }; 436E916D24B65805000296FF /* PEPPassphraseProviderProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PEPPassphraseProviderProtocol.h; sourceTree = ""; }; 436E917124B714A1000296FF /* Rick Deckard (43F270EC) – Secret.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Rick Deckard (43F270EC) – Secret.asc"; sourceTree = ""; }; 436E917524B71E12000296FF /* PEPPassphraseProviderMock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PEPPassphraseProviderMock.h; sourceTree = ""; }; @@ -405,6 +408,8 @@ 4349CD6D24AC73FC00A22A13 /* NSString+NormalizePassphrase.h */, 4349CD6E24AC73FC00A22A13 /* NSString+NormalizePassphrase.m */, 434707F524C210CA00E05485 /* PEPAsyncSession.m */, + 436C9A3124DC48B600007A3D /* PEPPassphraseUtil.h */, + 436C9A3224DC48B600007A3D /* PEPPassphraseUtil.m */, ); path = pEpObjCAdapter; sourceTree = ""; @@ -716,6 +721,7 @@ 4396CECB2187220200FDD398 /* PEPSessionTestSendMessageDelegate.m in Sources */, 152D58EF201B6DB200036219 /* PEPMessageUtilTest.m in Sources */, 434707F924C30E9700E05485 /* PEPAsyncSessionTest.m in Sources */, + 436C9A3324DC48B600007A3D /* PEPPassphraseUtil.m in Sources */, 152A9C472010F50400F962ED /* PEPSessionTest.m in Sources */, 434226811D4F60000083ED79 /* PepTests.m in Sources */, 4336853F203D5CE60069A451 /* PEPTestUtils.m in Sources */, diff --git a/pEpObjCAdapter/PEPPassphraseUtil.h b/pEpObjCAdapter/PEPPassphraseUtil.h new file mode 100644 index 0000000..10a6eec --- /dev/null +++ b/pEpObjCAdapter/PEPPassphraseUtil.h @@ -0,0 +1,28 @@ +// +// PEPPassphraseUtil.h +// pEpObjCAdapterTests +// +// Created by Dirk Zimmermann on 06.08.20. +// Copyright © 2020 p≡p. All rights reserved. +// + +#import + +#import "pEpEngine.h" + +#import "PEPEngineTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PEPPassphraseUtil : NSObject + +/// Gets the currently cached passwords, +/// and executes the given block after setting each password in turn +/// until it returns something else other than PEP_PASSPHRASE_REQUIRED +/// or PEP_WRONG_PASSPHRASE, or there are no passwords anymore. +/// @param block The status-returning block to execute against different passwords ++ (PEPStatus)runWithPasswordsSession:(PEP_SESSION)session + block:(PEP_STATUS (^)(PEP_SESSION session))block; +@end + +NS_ASSUME_NONNULL_END diff --git a/pEpObjCAdapter/PEPPassphraseUtil.m b/pEpObjCAdapter/PEPPassphraseUtil.m new file mode 100644 index 0000000..f1c8ff6 --- /dev/null +++ b/pEpObjCAdapter/PEPPassphraseUtil.m @@ -0,0 +1,129 @@ +// +// PEPPassphraseUtil.m +// pEpObjCAdapterTests +// +// Created by Dirk Zimmermann on 06.08.20. +// Copyright © 2020 p≡p. All rights reserved. +// + +#import "PEPPassphraseUtil.h" + +#import "pEpEngine.h" + +#import "PEPPassphraseCache.h" +#import "PEPObjCAdapter+Internal.h" +#import "NSString+NormalizePassphrase.h" + +@implementation PEPPassphraseUtil + ++ (PEPStatus)runWithPasswordsSession:(PEP_SESSION)session + block:(PEP_STATUS (^)(PEP_SESSION session))block +{ + PEP_STATUS lastStatus = PEP_UNKNOWN_ERROR; + + NSMutableArray *passphrases = [NSMutableArray + arrayWithArray:[[PEPPassphraseCache passphraseCache] passphrases]]; + [passphrases insertObject:@"" atIndex:0]; + + if ([[PEPPassphraseCache passphraseCache] storedPassphrase]) { + [passphrases insertObject:[[PEPPassphraseCache passphraseCache] storedPassphrase] atIndex:1]; + } + + for (NSString *passphrase in passphrases) { + PEP_STATUS status = config_passphrase(session, [passphrase UTF8String]); + + if (status != PEPStatusOK) { + return (PEPStatus) status; + } + + lastStatus = block(session); + + if (lastStatus != PEP_PASSPHRASE_REQUIRED && lastStatus != PEP_WRONG_PASSPHRASE) { + // The passphrase worked, so reset its timeout + [[PEPPassphraseCache passphraseCache] resetTimeoutForPassphrase:passphrase]; + + return (PEPStatus) lastStatus; + } + } + + // If execution lands here, it means we ran out of passwords to set while + // receiving password-related error codes. + return [self tryPassphraseProviderSession:session + lastStatus:lastStatus block:block]; +} + +#pragma mark - Private + +/// Invokes the given block while setting passphrases requested from the +/// passphrase provider, if set. ++ (PEPStatus)tryPassphraseProviderSession:(PEP_SESSION)session + lastStatus:(PEP_STATUS)lastStatus + block:(PEP_STATUS (^)(PEP_SESSION session))block +{ + id passphraseProvider = [PEPObjCAdapter passphraseProvider]; + if (passphraseProvider) { + dispatch_group_t group = dispatch_group_create(); + + __block PEP_STATUS lastPassphraseProviderStatus = lastStatus; + __block NSString *lastPassphrase = nil; + + PEPPassphraseProviderCallback passphraseCallback = ^(NSString * _Nullable passphrase) { + lastPassphrase = passphrase; + dispatch_group_leave(group); + }; + + while (YES) { + if (lastPassphraseProviderStatus == PEP_PASSPHRASE_REQUIRED) { + dispatch_group_enter(group); + [passphraseProvider passphraseRequired:passphraseCallback]; + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + } else if (lastPassphraseProviderStatus == PEP_WRONG_PASSPHRASE) { + dispatch_group_enter(group); + [passphraseProvider wrongPassphrase:passphraseCallback]; + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + } + + if (lastPassphrase == nil) { + return (PEPStatus) lastPassphraseProviderStatus; + } + + NSString *normalizedPassphrase = [lastPassphrase normalizedPassphraseWithError:nil]; + + //Add the new passphrase to our cache to not having to bother the client again. + [[PEPPassphraseCache passphraseCache] addPassphrase:normalizedPassphrase]; + + if (normalizedPassphrase == nil) { + // Assume excessively long passphrase means PEP_WRONG_PASSPHRASE + lastPassphraseProviderStatus = PEP_WRONG_PASSPHRASE; + + dispatch_group_enter(group); + [passphraseProvider passphraseTooLong:passphraseCallback]; + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + continue; + } + + lastPassphraseProviderStatus = config_passphrase(session, + [lastPassphrase UTF8String]); + if (lastPassphraseProviderStatus != PEPStatusOK) { + return (PEPStatus) lastPassphraseProviderStatus; + } + + lastPassphraseProviderStatus = block(session); + + if (lastPassphraseProviderStatus != PEP_PASSPHRASE_REQUIRED && + lastPassphraseProviderStatus != PEP_WRONG_PASSPHRASE) { + // The passphrase worked, so reset its timeout + [[PEPPassphraseCache passphraseCache] resetTimeoutForPassphrase:lastPassphrase]; + + return (PEPStatus) lastPassphraseProviderStatus; + } + } + + return (PEPStatus) lastPassphraseProviderStatus; + } else { + // no passphrase provider + return (PEPStatus) lastStatus; + } +} + +@end