secd-210-keyinterest.m   [plain text]

//
// secd-210-keyinterest.m
// Security
//
// Created by Mitch Adler on 10/31/16.
//
//

#import <Foundation/Foundation.h>

#include "secd_regressions.h"

#import "CKDStore.h"
#import "CKDKVSProxy.h"
#import "CKDSimulatedStore.h"
#import "CKDSimulatedAccount.h"
#import "CKDAKSLockMonitor.h"
#include "SOSCloudKeychainConstants.h"
#include "SOSAccountTesting.h"

#if SOS_ENABLED

@interface CKDSimulatedLockMonitor : NSObject<CKDLockMonitor>

@property (readwrite) BOOL unlockedSinceBoot;
@property (readwrite) BOOL locked;

@property (weak) NSObject<CKDLockListener>* listener;

+ (instancetype) monitor;

- (instancetype) init;

- (void) recheck;

- (void) notifyListener;
- (void) connectTo: (NSObject<CKDLockListener>*) listener;

- (void) lock;
- (void) unlock;

@end

@implementation CKDSimulatedLockMonitor

+ (instancetype) monitor {
return [[CKDSimulatedLockMonitor alloc] init];
}

- (instancetype) init {
if ((self = [super init])) {
_locked = true;
_unlockedSinceBoot = false;
}

[self notifyListener];

return self;
}

- (void) recheck {
}

- (void) notifyListener {
// Take a strong reference:
__strong __typeof(self.listener) listener = self.listener;

if (listener) {
if (self.locked) {
[listener locked];
} else {
[listener unlocked];
}
}
}

- (void) connectTo: (NSObject<CKDLockListener>*) listener {
self.listener = listener;
[self notifyListener];
}

- (void) lock {
self.locked = true;
[self notifyListener];
}
- (void) unlock {
self.locked = false;
self.unlockedSinceBoot = true;
[self notifyListener];
}

@end

@interface UbiqitousKVSProxy (Testing)
- (void) flush;
@end

@implementation UbiqitousKVSProxy (Testing)
- (void) flush {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);

[self doAfterFlush:^{
dispatch_semaphore_signal(sema);
}];

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
@end

static void tests(void) {
CKDSimulatedStore* store = [CKDSimulatedStore simulatedInterface];
CKDSimulatedAccount* account = [[CKDSimulatedAccount alloc] init];
CKDSimulatedLockMonitor* monitor = [CKDSimulatedLockMonitor monitor];

NSString * testKey = @"TestKey";

UbiqitousKVSProxy * proxy = [UbiqitousKVSProxy withAccount:account
store:store
lockMonitor:monitor
persistence:[NSURL fileURLWithPath:@"/tmp/kvsPersistenceTestFile"]];

NSDictionary* interests = @{ [NSString stringWithUTF8String:kMessageKeyParameter]:@{ @"UnlockedKeys":@[ testKey ] } };
NSString* accountID = @"Account1";

dispatch_sync([proxy ckdkvsproxy_queue], ^{
[proxy registerKeys:interests forAccount:accountID];
});

is([[account extractKeyChanges] count], (NSUInteger)0, "No changes yet");

[store remoteSetObject:@1 forKey:testKey];
[proxy flush];

is([[account extractKeyChanges] count], (NSUInteger)0, "Still none while locked");

[monitor unlock];
[proxy flush];

is([[account extractKeyChanges] count], (NSUInteger)1, "Notified after unlock");

[monitor lock];
[monitor unlock];
[proxy flush];

is([[account extractKeyChanges] count], (NSUInteger)0, "lock unlock and nothing changes");

[store remoteSetObject:@2 forKey:testKey];
[proxy flush];

{
NSDictionary<NSString*, NSObject*> *changes = [account extractKeyChanges];
is([changes count], (NSUInteger)1, "lock, nothing changes");
is(changes[testKey], @2, "Sent second value");
}

[monitor lock];
[store remoteSetObject:@3 forKey:testKey];
[proxy flush];

is([[account extractKeyChanges] count], (NSUInteger)0, "Changes to Unlocked not when locked");

[monitor unlock];
[proxy flush];

{
NSDictionary<NSString*, NSObject*> *changes = [account extractKeyChanges];
is([changes count], (NSUInteger)1, "Change defered to after unlock");
is(changes[testKey], @3, "Correct value");
}

dispatch_sync([proxy ckdkvsproxy_queue], ^{
[proxy registerKeys:interests forAccount:accountID];
});
[proxy flush];

is([[account extractKeyChanges] count], (NSUInteger)0, "Same interests, no new data");

dispatch_sync([proxy ckdkvsproxy_queue], ^{
[proxy registerKeys:interests forAccount:@"different"];
});
[proxy flush];

{
NSDictionary<NSString*, NSObject*> *changes = [account extractKeyChanges];
is([changes count], (NSUInteger)1, "New account, same interests, new data");
is(changes[testKey], @3, "Latest value for new data");
}

}

#endif

int secd_210_keyinterest(int argc, char *const *argv)
{
#if SOS_ENABLED
plan_tests(12);
tests();
#else
plan_tests(0);
#endif
return 0;
}