Skip to content

Commit

Permalink
Use server-based default ACL
Browse files Browse the repository at this point in the history
  • Loading branch information
cheungpat authored Apr 7, 2017
2 parents 6761eb3 + 124416a commit d3d19bd
Show file tree
Hide file tree
Showing 12 changed files with 352 additions and 109 deletions.
4 changes: 4 additions & 0 deletions Example/SKYKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
CD98A8A41A9F28030056420F /* SKYRecordDeserializerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD98A8A31A9F28030056420F /* SKYRecordDeserializerTests.m */; };
CD98A8A61A9F34390056420F /* SKYFetchRecordsOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD98A8A51A9F34390056420F /* SKYFetchRecordsOperationTests.m */; };
CDF571031AB4825700091DB3 /* SKYQuerySerializerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CDF571021AB4825700091DB3 /* SKYQuerySerializerTests.m */; };
CF234C631E8AB08600BF4E0F /* SKYDefineDefaultAccessOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CF234C621E8AB08600BF4E0F /* SKYDefineDefaultAccessOperationTests.m */; };
DF862921DB633F3364419993 /* Pods_Swift_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA35E28666BD02136512A2B5 /* Pods_Swift_Example.framework */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -208,6 +209,7 @@
CD98A8A31A9F28030056420F /* SKYRecordDeserializerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SKYRecordDeserializerTests.m; sourceTree = "<group>"; };
CD98A8A51A9F34390056420F /* SKYFetchRecordsOperationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SKYFetchRecordsOperationTests.m; sourceTree = "<group>"; };
CDF571021AB4825700091DB3 /* SKYQuerySerializerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SKYQuerySerializerTests.m; sourceTree = "<group>"; };
CF234C621E8AB08600BF4E0F /* SKYDefineDefaultAccessOperationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SKYDefineDefaultAccessOperationTests.m; sourceTree = "<group>"; };
DA35E28666BD02136512A2B5 /* Pods_Swift_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Swift_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E14141B974E77B52FC7F22EF /* Pods-SKYKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SKYKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-SKYKit/Pods-SKYKit.release.xcconfig"; sourceTree = "<group>"; };
E61967EA35930CACEBEC4FC6 /* Pods-Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.release.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -362,6 +364,7 @@
CD395D0C1AA0273F00A97B16 /* SKYDatabaseTest.m */,
604A899A1C7C05A20013E114 /* SKYDefineAdminRolesOperationTests.m */,
60B47C621C8423D80091A7C3 /* SKYDefineCreationAccessOperationTests.m */,
CF234C621E8AB08600BF4E0F /* SKYDefineDefaultAccessOperationTests.m */,
CD42FE0B1AA2DAA20079B3DA /* SKYDeleteRecordsOperationTests.m */,
374575591B08C682004539C3 /* SKYDeleteSubscriptionsOperationTests.m */,
37CDD6061B4C040F007B9FE1 /* SKYDownloadAssetOperationTests.m */,
Expand Down Expand Up @@ -949,6 +952,7 @@
3785584A1AE63FEC00685319 /* SKYSubscriptionSerializerTests.m in Sources */,
CD48CE0F1AA06C7900A1CD04 /* SKYModifyRecordsOperationTests.m in Sources */,
38A115351B02EC4E00D3BAFB /* SKYRecordSynchronizerTests.m in Sources */,
CF234C631E8AB08600BF4E0F /* SKYDefineDefaultAccessOperationTests.m in Sources */,
CD7FE2721A9EDD5B002C076E /* SKYSignupUserOperationTests.m in Sources */,
CD56972A1AAC7D3700AE596B /* SKYRecordIDTests.m in Sources */,
372FD24E1AF79F59008128EC /* SKYHexer.m in Sources */,
Expand Down
53 changes: 0 additions & 53 deletions Example/Tests/SKYAccessControlTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -221,59 +221,6 @@
});
});

describe(@"Default Access Control", ^{
beforeEach(^{
[SKYAccessControl setDefaultAccessControl:nil];
});

it(@"should be public readable ACL by default", ^{
SKYAccessControl *acl = [SKYAccessControl defaultAccessControl];

expect(acl.entries).to.haveACountOf(1);

SKYAccessControlEntry *firstEntry = acl.entries[0];
expect(firstEntry.accessLevel).to.equal(SKYAccessControlEntryLevelRead);
expect(firstEntry.entryType).to.equal(SKYAccessControlEntryTypePublic);
});

it(@"should be able to set default ACL", ^{
SKYRole *developerRole = [SKYRole roleWithName:@"Developer"];
SKYUser *user0 = [SKYUser userWithUserID:@"20A4F099-A9B1-490F-857D-2E9A5B128B16"];
SKYRelation *friendRelation = [SKYRelation friendRelation];

SKYAccessControl *defaultACL = [SKYAccessControl defaultAccessControl];
// Should be public readable
expect([defaultACL hasReadAccessForRole:developerRole]).to.equal(YES);
expect([defaultACL hasReadAccessForUser:user0]).to.equal(YES);
expect([defaultACL hasReadAccessForRelation:friendRelation]).to.equal(YES);

// Should be public NOT writable
expect([defaultACL hasWriteAccessForRole:developerRole]).to.equal(NO);
expect([defaultACL hasWriteAccessForUser:user0]).to.equal(NO);
expect([defaultACL hasWriteAccessForRelation:friendRelation]).to.equal(NO);

SKYAccessControl *acl = [SKYAccessControl accessControlWithEntries:@[
[SKYAccessControlEntry readEntryForRole:developerRole],
[SKYAccessControlEntry writeEntryForRole:developerRole],
[SKYAccessControlEntry readEntryForUser:user0],
[SKYAccessControlEntry readEntryForRelation:friendRelation]
]];
[SKYAccessControl setDefaultAccessControl:acl];

defaultACL = [SKYAccessControl defaultAccessControl];
expect([defaultACL hasReadAccessForRole:developerRole]).to.equal(YES);
expect([defaultACL hasWriteAccessForRole:developerRole]).to.equal(YES);
expect([defaultACL hasReadAccessForUser:user0]).to.equal(YES);
expect([defaultACL hasWriteAccessForUser:user0]).to.equal(NO);
expect([defaultACL hasReadAccessForRelation:friendRelation]).to.equal(YES);
expect([defaultACL hasWriteAccessForRelation:friendRelation]).to.equal(NO);
});

afterEach(^{
[SKYAccessControl setDefaultAccessControl:nil];
});
});

describe(@"Access Control Entry", ^{
SKYRole *humanRole = [SKYRole roleWithName:@"Human"];
SKYRole *godRole = [SKYRole roleWithName:@"God"];
Expand Down
58 changes: 58 additions & 0 deletions Example/Tests/SKYContainerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#import "SKYHexer.h"

#import "SKYAccessControl_Private.h"
#import "SKYContainer_Private.h"
#import "SKYNotification_Private.h"

Expand Down Expand Up @@ -969,4 +970,61 @@ __block void (^assertLoggedIn)(NSString *, NSError *) =
});
});

describe(@"record default access", ^{
NSString *apiKey = @"CORRECT_KEY";
NSString *currentUserId = @"CORRECT_USER_ID";
NSString *token = @"CORRECT_TOKEN";

NSString *painterRoleName = @"Painter";
NSString *paintingRecordType = @"Painting";

SKYRole *painterRole = [SKYRole roleWithName:painterRoleName];

__block SKYContainer *container = nil;

beforeEach(^{
container = [[SKYContainer alloc] init];
[container configureWithAPIKey:apiKey];
[container updateWithUserRecordID:currentUserId
accessToken:[[SKYAccessToken alloc] initWithTokenString:token]];
});

it(@"can define default access of record", ^{
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
return YES;
}
withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
NSDictionary *response = @{
@"result" : @{
@"type" : paintingRecordType,
@"default_access" : @[
@{@"public" : @1, @"level" : @"read"},
@{@"role" : @"Painter", @"level" : @"write"}
]
}
};
return [OHHTTPStubsResponse responseWithJSONObject:response
statusCode:200
headers:nil];
}];

waitUntil(^(DoneCallback done) {
SKYAccessControl *acl = [SKYAccessControl accessControlWithEntries:@[
[SKYAccessControlEntry readEntryForRole:painterRole],
[SKYAccessControlEntry readEntryForPublic]
]];
[container defineDefaultAccessWithRecordType:paintingRecordType
access:acl
completion:^(NSError *error) {
expect(error).to.beNil();
done();
}];
});
});

afterEach(^{
[OHHTTPStubs removeAllStubs];
});
});

SpecEnd
124 changes: 124 additions & 0 deletions Example/Tests/SKYDefineDefaultAccessOperationTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//
// SKYDefineCreationAccessOperationTests.m
// SKYKit
//
// Copyright 2015 Oursky Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#import "SKYAccessControl_Private.h"
#import <Foundation/Foundation.h>
#import <SKYKit/SKYKit.h>

SpecBegin(SKYDefineDefaultAccessOperation)

describe(@"Define Default Access Operation", ^{
NSString *apiKey = @"CORRECT_KEY";
NSString *currentUserID = @"CORRECT_USER_ID";
NSString *token = @"CORRECT_TOKEN";

NSString *developerRoleName = @"Developer";
NSString *testerRoleName = @"Tester";

NSString *sourceCodeRecordType = @"SourceCode";

SKYRole *developerRole = [SKYRole roleWithName:developerRoleName];
SKYRole *testerRole = [SKYRole roleWithName:testerRoleName];

SKYAccessControl *acl = [SKYAccessControl accessControlWithEntries:@[
[SKYAccessControlEntry writeEntryForRole:developerRole],
[SKYAccessControlEntry readEntryForRole:testerRole]
]];

__block SKYContainer *container;

beforeEach(^{
container = [[SKYContainer alloc] init];
[container configureWithAPIKey:apiKey];
[container updateWithUserRecordID:currentUserID
accessToken:[[SKYAccessToken alloc] initWithTokenString:token]];
});

it(@"should create SKYRequest correctly", ^{
SKYDefineDefaultAccessOperation *operation =
[SKYDefineDefaultAccessOperation operationWithRecordType:sourceCodeRecordType
accessControl:acl];
[operation setContainer:container];
[operation prepareForRequest];

SKYRequest *request = operation.request;
expect(request.action).to.equal(@"schema:default_access");
expect(request.accessToken.tokenString).to.equal(token);

NSString *recordTypePayload = [request.payload objectForKey:@"type"];
NSArray<NSString *> *accessRolesPayload =
[request.payload objectForKey:@"default_access"];

expect(recordTypePayload).to.equal(sourceCodeRecordType);
expect(accessRolesPayload).to.haveACountOf(2);
expect(accessRolesPayload).to.contain((@{
@"role" : @"Developer",
@"level" : @"write"
}));
expect(accessRolesPayload).to.contain((@{ @"role" : @"Tester", @"level" : @"read" }));
});

it(@"should handle success response correctly", ^{
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
return YES;
}
withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
NSDictionary *response = @{
@"result" : @{
@"type" : sourceCodeRecordType,
@"default_access" : @[
@{@"public" : @1, @"level" : @"read"},
@{@"role" : @"Painter", @"level" : @"write"}
]
}
};
return [OHHTTPStubsResponse responseWithJSONObject:response
statusCode:200
headers:nil];
}];

SKYDefineDefaultAccessOperation *operation =
[SKYDefineDefaultAccessOperation operationWithRecordType:sourceCodeRecordType
accessControl:acl];
[operation setContainer:container];

waitUntil(^(DoneCallback done) {
operation.defineDefaultAccessCompletionBlock =
^(NSString *recordType, SKYAccessControl *access, NSError *error) {
expect(recordType).to.equal(sourceCodeRecordType);
expect(access.entries).to.haveACountOf(2);

NSArray *roles = [[access.entries array] valueForKey:@"role"];
expect(roles).to.contain(developerRole);
expect(roles).to.contain(testerRole);
expect(error).to.beNil();

done();
};

[container addOperation:operation];
});
});

afterEach(^{
[OHHTTPStubs removeAllStubs];
});
});

SpecEnd
38 changes: 0 additions & 38 deletions Pod/Classes/SKYAccessControl.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,44 +36,6 @@ + (instancetype)accessControlWithEntries:(NSArray<SKYAccessControlEntry *> *)ent
return [[self alloc] initWithEntries:entries];
}

+ (instancetype)defaultAccessControl
{
static SKYAccessControlDeserializer *deserializer;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
deserializer = [SKYAccessControlDeserializer deserializer];
});

NSArray *aclData =
[[NSUserDefaults standardUserDefaults] objectForKey:@"SKYAccessControlDefault"];

if (aclData) {
return [deserializer accessControlWithArray:aclData];
} else {
return [SKYAccessControl publicReadableAccessControl];
}
}

+ (void)setDefaultAccessControl:(SKYAccessControl *)defaultAccessControl
{
static SKYAccessControlSerializer *serializer;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
serializer = [SKYAccessControlSerializer serializer];
});

NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];

if (!defaultAccessControl) {
[userDefault removeObjectForKey:@"SKYAccessControlDefault"];
} else {
NSArray *aclData = [serializer arrayWithAccessControl:defaultAccessControl];
[userDefault setObject:aclData forKey:@"SKYAccessControlDefault"];
}

[userDefault synchronize];
}

- (instancetype)initWithPublicReadableAccessControl
{
return [self initWithEntries:@[ [SKYAccessControlEntry readEntryForPublic] ]];
Expand Down
3 changes: 0 additions & 3 deletions Pod/Classes/SKYAccessControl_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@
+ (instancetype)publicReadableAccessControl;
+ (instancetype)accessControlWithEntries:(NSArray<SKYAccessControlEntry *> *)entries;

+ (instancetype)defaultAccessControl;
+ (void)setDefaultAccessControl:(SKYAccessControl *)defaultAccessControl;

- (instancetype)initWithPublicReadableAccessControl;
- (instancetype)initWithEntries:(NSArray<SKYAccessControlEntry *> *)entries
NS_DESIGNATED_INITIALIZER;
Expand Down
15 changes: 12 additions & 3 deletions Pod/Classes/SKYContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,6 @@ typedef void (^SKYContainerUserOperationActionCompletion)(SKYUser *user, NSError
/// Undocumented
@property (nonatomic, strong) SKYPubsub *pubsubClient;

/// Undocumented
@property (nonatomic, strong) SKYAccessControl *defaultAccessControl;

/**
Returns the currently registered device ID.
*/
Expand Down Expand Up @@ -324,4 +321,16 @@ typedef void (^SKYContainerUserOperationActionCompletion)(SKYUser *user, NSError
- (void)defineCreationAccessWithRecordType:(NSString *)recordType
roles:(NSArray<SKYRole *> *)roles
completion:(void (^)(NSError *error))completionBlock;

/**
* Set default access of a record type
*
* @param recordType Record type to set creation access
* @param roles Roles can create the record
* @param completionBlock Completion Block
*/
- (void)defineDefaultAccessWithRecordType:(NSString *)recordType
access:(SKYAccessControl *)accessControl
completion:(void (^)(NSError *error))completionBlock;

@end
Loading

0 comments on commit d3d19bd

Please sign in to comment.