You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

345 lines
10 KiB

//
// pEpObjCAdapter.m
// pEpObjCAdapter
//
// Created by Volker Birk on 28.04.15.
// Copyright (c) 2015 p≡p. All rights reserved.
//
#import <Foundation/Foundation.h>
#ifdef IS_IOS_BUILD
#import <pEp4iosIntern/pEp4iosIntern.h>
#endif
#import "PEPObjCAdapter.h"
#import "PEPObjCAdapter+Internal.h"
#import "NSString+NormalizePassphrase.h"
#import "PEPInternalSession.h"
#import "PEPPassphraseCache.h"
#import "Logger.h"
#import "keymanagement.h"
#import "mime.h"
#import "message.h"
#import "message_api.h"
const PEP_decrypt_flags PEP_decrypt_flag_none = 0x0;
/**
The pEp part of the home directory (where pEp is supposed to store data).
*/
static NSString * const s_pEpHomeComponent = @"pEp_home";
const char* _Nullable perMachineDirectory = NULL;
NSURL *s_homeURL;
static BOOL s_unEncryptedSubjectEnabled = NO;
static BOOL s_passiveModeEnabled = NO;
static NSString *s_passphraseForNewKeys = nil;
static id<PEPPassphraseProviderProtocol> s_passphraseProvider = nil;
@implementation PEPObjCAdapter
#pragma mark - SUBJECT PROTECTION
+ (BOOL)unEncryptedSubjectEnabled;
{
return s_unEncryptedSubjectEnabled;
}
+ (void)setUnEncryptedSubjectEnabled:(BOOL)enabled;
{
s_unEncryptedSubjectEnabled = enabled;
}
#pragma mark - Passive Mode
+ (BOOL)passiveModeEnabled
{
return s_passiveModeEnabled;
}
+ (void)setPassiveModeEnabled:(BOOL)enabled
{
s_passiveModeEnabled = enabled;
}
#pragma mark - Passphrase for own keys
+ (BOOL)configurePassphraseForNewKeys:(NSString * _Nullable)passphrase
error:(NSError * _Nullable * _Nullable)error
{
if (passphrase == nil) {
s_passphraseForNewKeys = nil;
[[PEPPassphraseCache sharedInstance] setStoredPassphrase:passphrase];
return YES;
} else {
NSString *normalizedPassphrase = [passphrase normalizedPassphraseWithError:error];
if (normalizedPassphrase == nil) {
return NO;
}
s_passphraseForNewKeys = normalizedPassphrase;
[[PEPPassphraseCache sharedInstance] setStoredPassphrase:passphrase];
return YES;
}
}
+ (NSString * _Nullable)passphraseForNewKeys
{
return s_passphraseForNewKeys;
}
#pragma mark - Passphrase Provider
+ (void)setPassphraseProvider:(id<PEPPassphraseProviderProtocol> _Nullable)passphraseProvider
{
s_passphraseProvider = passphraseProvider;
}
+ (id<PEPPassphraseProviderProtocol> _Nullable)passphraseProvider
{
return s_passphraseProvider;
}
#pragma mark - DB PATHS
+ (void)initialize
{
[self setupPerUserDirectory];
[self setupPerMachineDirectory];
}
+ (NSURL *)homeURL
{
return s_homeURL;
}
+ (void)setupPerUserDirectory {
// The Engine uses the HOME env as per-user-directory. We hijack that on iOS,
// or when running XCTests on macOS.
#if TARGET_OS_MAC
#if TARGET_OS_IPHONE
s_homeURL = [self createApplicationDirectory];
setenv("HOME", [[s_homeURL path] cStringUsingEncoding:NSUTF8StringEncoding], 1);
return;
#elif TARGET_OS_OSX
if ([self isXCTestRunning] || [self isRunningInDevelopmentEnvironment]) {
s_homeURL = [self createTestDataDirectoryMacOS];
setenv("HOME", [[s_homeURL path] cStringUsingEncoding:NSUTF8StringEncoding], 1);
}
return;
#endif
#else
// Neither macOS nor iOS. The engine will use $HOME.
#endif
}
+ (void)setupPerMachineDirectory {
#if TARGET_OS_IPHONE
[self setPerMachineDirectory:[self homeURL]];
#else
// For macOS there is nothing toDo. The defaults in Engine platform_unix.h should do.
#endif
}
/**
Looks up the shared directory for pEp apps under iOS and makes sure it exists.
@return A URL pointing a pEp directory in the app container.
*/
#ifdef IS_IOS_BUILD
+ (NSURL *)createApplicationDirectoryiOS
{
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *containerUrl = [fm containerURLForSecurityApplicationGroupIdentifier:kAppGroupIdentifier];
LogInfo(@"containerUrl '%@'", containerUrl);
if (containerUrl == nil) {
// Will happen when running tests, so fall back.
NSArray *appSupportDir = [fm URLsForDirectory:NSApplicationSupportDirectory
inDomains:NSUserDomainMask];
containerUrl = [appSupportDir lastObject];
}
if (containerUrl == nil) {
LogErrorAndCrash(@"No app container, no application support directory.");
}
NSURL *dirPath = [containerUrl URLByAppendingPathComponent:s_pEpHomeComponent];
// If the directory does not exist, this method creates it.
NSError *theError = nil;
if (![fm createDirectoryAtURL:dirPath withIntermediateDirectories:YES
attributes:nil error:&theError]) {
LogErrorAndCrash(@"Could not create pEp home directory, directly writing to app container instead.");
}
return dirPath;
}
#endif
/**
Looks up the shared directory for pEp apps under iOS and makes sure it exists.
Derived settings:
* $HOME (the engine uses that).
* The engine's per_user_directory (which is placed under $HOME).
* The engine's per_machine_directory (see [PEPObjCAdapter setPerMachineDirectory:]).
@return A URL pointing to as app-specific directory under the OS defined
application support directory for the current user.
*/
#ifdef IS_IOS_BUILD
+ (NSURL *)createApplicationDirectory
{
return [self createApplicationDirectoryiOS];
}
#endif
/**
Sets the directory that will be fed into the engine's per_machine_directory.
Does not handle macOS. For macOS, either PER_MACHINE_DIRECTORY has to be defined
(if constant), or this method has to be extended to handle it.
@param perMachineDir The url to use as the per_machine_directory directory.
*/
+ (void)setPerMachineDirectory:(NSURL *)perMachineDir
{
if (perMachineDirectory) {
free((void *) perMachineDirectory); //BUFF: DIRK??
}
perMachineDirectory = strdup([perMachineDir path].UTF8String);
}
+ (void)copyAssetsIntoDocumentsDirectory:(NSBundle *)srcBundle
fileName:(NSString *)fileName {
#ifdef IS_IOS_BUILD
NSString *systemDir = [NSString stringWithUTF8String:perMachineDirectory];
if(!(srcBundle && systemDir && fileName)) {
return;
}
// Check if the database file exists in the documents directory.
NSString *destinationPath = [systemDir stringByAppendingPathComponent:fileName];
if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
// The file does not exist in the documents directory, so copy it from bundle now.
NSString *sourcePath =[[srcBundle resourcePath] stringByAppendingPathComponent: fileName];
NSError *error;
[[NSFileManager defaultManager]
copyItemAtPath:sourcePath toPath:destinationPath error:&error];
// Check if any error occurred during copying and display it.
if (error != nil) {
LogInfo(@"%@", [error localizedDescription]);
}
}
#endif
}
+ (void)setupTrustWordsDB:(NSBundle *)rootBundle {
#if TARGET_OS_IPHONE
[PEPObjCAdapter copyAssetsIntoDocumentsDirectory:rootBundle
fileName:@"system.db"];
#else
// On macOS the installer must put that in place.
#endif
}
+ (void)setupTrustWordsDB
{
[PEPObjCAdapter setupTrustWordsDB:[NSBundle mainBundle]];
}
+ (NSString * _Nonnull)perUserDirectoryString
{
return [NSString stringWithCString:per_user_directory() encoding:NSUTF8StringEncoding];
}
+ (NSString * _Nonnull)perMachineDirectoryString
{
return [NSString stringWithCString:per_machine_directory() encoding:NSUTF8StringEncoding];
}
#pragma mark - DB PATHS Helpers for macOS
/// Determines whether the adapter is running under a XCTest.
///
/// Uses `NSClassFromString`, `[NSObject valueForKey]` and `[NSProcessInfo processInfo]` and should therefore
/// compile on most GNUstep platforms an macOS.
///
/// This is only used under macOS, although it should work on iOS as well.
+ (BOOL)isXCTestRunning
{
BOOL isTesting = NO;
Class testProbeClass = NSClassFromString(@"XCTestProbe");
if (testProbeClass) {
NSNumber *numberValue = [testProbeClass valueForKey:@"isTesting"];
isTesting = [numberValue boolValue];
}
id configFp = [[[NSProcessInfo processInfo] environment]
valueForKey:@"XCTestConfigurationFilePath"];
return isTesting || configFp != nil;
}
/// Checks the environment for a variable that hints at development.
///
/// In a development environment, the engine should never read from or write to production data.
///
/// @note While this kind of check is feasible on all kinds of OSs, it should be used only on macOS,
/// because there is a strict separation between a shell environment (used by developers) and the
/// environment used by apps and background tasks.
/// E.g., see https://support.apple.com/guide/terminal/use-environment-variables-apd382cc5fa-4f58-4449-b20a-41c53c006f8f/2.11/mac/11.0
/// @return `YES` when the `PEP_TEST` environment variable is set.
+ (BOOL)isRunningInDevelopmentEnvironment
{
id pEpTest = [[[NSProcessInfo processInfo] environment] valueForKey:@"PEP_TEST"];
return pEpTest != nil;
}
#if TARGET_OS_OSX
/// Creates a pEp directory for use by the engine that doesn't affect production data,
/// e.g. for use by XCTests or when running in a development environment.
///
/// Uses `[NSFileManager URLsForDirectory:inDomains:]`, so not safe for other platforms besides macOS.
+ (NSURL *)createTestDataDirectoryMacOS
{
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *appSupportDir = [fm URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
NSURL *containerUrl = containerUrl = [appSupportDir lastObject];
if (containerUrl == nil) {
LogErrorAndCrash(@"No app container, no application support directory.");
}
NSURL *dirPath = [containerUrl URLByAppendingPathComponent:s_pEpHomeComponent];
// If the directory does not exist, this method creates it.
NSError *theError = nil;
if (![fm createDirectoryAtURL:dirPath withIntermediateDirectories:YES
attributes:nil error:&theError]) {
LogErrorAndCrash(@"Could not create pEp home directory, directly writing to app container instead.");
}
return dirPath;
}
#endif
@end