Skip to content

Commit 4f7e4c1

Browse files
committed
Improved fetch and delete PFObject validation logic.
1 parent 2bb2ede commit 4f7e4c1

File tree

6 files changed

+86
-63
lines changed

6 files changed

+86
-63
lines changed

Parse/Internal/Object/BatchController/PFObjectBatchController.m

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ - (BFTask *)deleteObjectsAsync:(NSArray *)objects withSessionToken:(NSString *)s
150150
- (PFRESTCommand *)_deleteCommandForObjects:(NSArray *)objects withSessionToken:(NSString *)sessionToken {
151151
NSMutableArray *commands = [NSMutableArray arrayWithCapacity:objects.count];
152152
for (PFObject *object in objects) {
153-
[object checkDeleteParams];
154153
PFRESTCommand *deleteCommand = [PFRESTObjectCommand deleteObjectCommandForObjectState:object._state
155154
withSessionToken:sessionToken];
156155
[commands addObject:deleteCommand];

Parse/Internal/Object/Controller/PFObjectController.m

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,11 @@ + (instancetype)controllerWithDataSource:(id<PFCommandRunnerProvider>)dataSource
5252

5353
- (BFTask *)fetchObjectAsync:(PFObject *)object withSessionToken:(NSString *)sessionToken {
5454
@weakify(self);
55-
return [[[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{
55+
return [[[[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{
56+
return [object _validateFetchAsync];
57+
}] continueWithSuccessBlock:^id(BFTask *task) {
5658
@strongify(self);
57-
PFObjectState *state = [object._state copy];
58-
if (!state.objectId) {
59-
NSError *error = [PFErrorUtilities errorWithCode:kPFErrorMissingObjectId
60-
message:@"Can't fetch an object that hasn't been saved to the server."];
61-
return [BFTask taskWithError:error];
62-
}
63-
PFRESTCommand *command = [PFRESTObjectCommand fetchObjectCommandForObjectState:state
59+
PFRESTCommand *command = [PFRESTObjectCommand fetchObjectCommandForObjectState:[object._state copy]
6460
withSessionToken:sessionToken];
6561
return [self _runFetchCommand:command forObject:object];
6662
}] continueWithSuccessBlock:^id(BFTask *task) {
@@ -89,7 +85,9 @@ - (BFTask *)processFetchResultAsync:(NSDictionary *)result forObject:(PFObject *
8985

9086
- (BFTask *)deleteObjectAsync:(PFObject *)object withSessionToken:(nullable NSString *)sessionToken {
9187
@weakify(self);
92-
return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{
88+
return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{
89+
return [object _validateDeleteAsync];
90+
}] continueWithSuccessBlock:^id(BFTask *task) {
9391
@strongify(self);
9492
PFObjectState *state = [object._state copy];
9593
if (!state.objectId) {

Parse/Internal/Object/PFObjectPrivate.h

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,6 @@
4848
objectId:(NSString *)objectId
4949
isComplete:(BOOL)complete;
5050

51-
///--------------------------------------
52-
/// @name Validation
53-
///--------------------------------------
54-
55-
/*!
56-
Validate the save eventually operation with the current state.
57-
The result of this task is ignored. The error/cancellation/exception will prevent `saveEventually`.
58-
59-
@returns Task that encapsulates the validtion.
60-
*/
61-
- (BFTask *)_validateSaveEventuallyAsync;
62-
6351
@optional
6452

6553
///--------------------------------------
@@ -107,6 +95,21 @@
10795

10896
#endif
10997

98+
///--------------------------------------
99+
/// @name Validation
100+
///--------------------------------------
101+
102+
- (BFTask PF_GENERIC(PFVoid) *)_validateFetchAsync NS_REQUIRES_SUPER;
103+
- (BFTask PF_GENERIC(PFVoid) *)_validateDeleteAsync NS_REQUIRES_SUPER;
104+
105+
/*!
106+
Validate the save eventually operation with the current state.
107+
The result of this task is ignored. The error/cancellation/exception will prevent `saveEventually`.
108+
109+
@returns Task that encapsulates the validation.
110+
*/
111+
- (BFTask PF_GENERIC(PFVoid) *)_validateSaveEventuallyAsync NS_REQUIRES_SUPER;
112+
110113
///--------------------------------------
111114
/// @name Pin
112115
///--------------------------------------
@@ -177,7 +180,6 @@
177180
///--------------------------------------
178181
#pragma mark - Validations
179182
///--------------------------------------
180-
- (void)checkDeleteParams;
181183
- (void)_checkSaveParametersWithCurrentUser:(PFUser *)currentUser;
182184
/*!
183185
Checks if Parse class name could be used to initialize a given instance of PFObject or it's subclass.

Parse/PFInstallation.m

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#import "PFPushPrivate.h"
2828
#import "PFQueryPrivate.h"
2929
#import "Parse_Private.h"
30+
#import "PFErrorUtilities.h"
3031

3132
@implementation PFInstallation (Private)
3233

@@ -51,9 +52,12 @@ - (void)_clearDeviceToken {
5152
[super removeObjectForKey:PFInstallationKeyDeviceToken];
5253
}
5354

54-
// Check security on delete.
55-
- (void)checkDeleteParams {
56-
PFConsistencyAssert(NO, @"Installations cannot be deleted.");
55+
- (BFTask<PFVoid> *)_validateDeleteAsync {
56+
return [[super _validateDeleteAsync] continueWithSuccessBlock:^id(BFTask PF_GENERIC(PFVoid) *task) {
57+
NSError *error = [PFErrorUtilities errorWithCode:kPFErrorCommandUnavailable
58+
message:@"Installation cannot be deleted"];
59+
return [BFTask taskWithError:error];
60+
}];
5761
}
5862

5963
// Validates a class name. We override this to only allow the installation class name.

Parse/PFObject.m

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -798,11 +798,6 @@ - (BOOL)isDataAvailableForKey:(NSString *)key {
798798
#pragma mark - Validations
799799
///--------------------------------------
800800

801-
// Validations that are done on delete. For now, there is nothing.
802-
- (void)checkDeleteParams {
803-
return;
804-
}
805-
806801
// Validations that are done on save. For now, there is nothing.
807802
- (void)_checkSaveParametersWithCurrentUser:(PFUser *)currentUser {
808803
return;
@@ -1531,8 +1526,6 @@ - (BFTask *)fetchAsync:(BFTask *)toAwait {
15311526
}
15321527

15331528
- (BFTask *)deleteAsync:(BFTask *)toAwait {
1534-
[self checkDeleteParams];
1535-
15361529
PFCurrentUserController *controller = [[self class] currentUserController];
15371530
return [[controller getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) {
15381531
NSString *sessionToken = task.result;
@@ -1568,11 +1561,7 @@ - (PFRESTCommand *)_constructSaveCommandForChanges:(PFOperationSet *)changes
15681561
}
15691562

15701563
- (PFRESTCommand *)_currentDeleteCommandWithSessionToken:(NSString *)sessionToken {
1571-
@synchronized (lock) {
1572-
[self checkDeleteParams];
1573-
return [PFRESTObjectCommand deleteObjectCommandForObjectState:self._state
1574-
withSessionToken:sessionToken];
1575-
}
1564+
return [PFRESTObjectCommand deleteObjectCommandForObjectState:self._state withSessionToken:sessionToken];
15761565
}
15771566

15781567
///--------------------------------------
@@ -1797,9 +1786,24 @@ + (PFObjectState *)_newObjectStateWithParseClassName:(NSString *)className
17971786
return [PFObjectState stateWithParseClassName:className objectId:objectId isComplete:complete];
17981787
}
17991788

1800-
#pragma mark Validation
1789+
///--------------------------------------
1790+
#pragma mark - Validation
1791+
///--------------------------------------
18011792

1802-
- (BFTask *)_validateSaveEventuallyAsync {
1793+
- (BFTask PF_GENERIC(PFVoid) *)_validateFetchAsync {
1794+
if (!self._state.objectId) {
1795+
NSError *error = [PFErrorUtilities errorWithCode:kPFErrorMissingObjectId
1796+
message:@"Can't fetch an object that hasn't been saved to the server."];
1797+
return [BFTask taskWithError:error];
1798+
}
1799+
return [BFTask taskWithResult:nil];
1800+
}
1801+
1802+
- (BFTask PF_GENERIC(PFVoid) *)_validateDeleteAsync {
1803+
return [BFTask taskWithResult:nil];
1804+
}
1805+
1806+
- (BFTask PF_GENERIC(PFVoid) *)_validateSaveEventuallyAsync {
18031807
return [BFTask taskWithResult:nil];
18041808
}
18051809

@@ -2012,9 +2016,10 @@ - (void)saveEventually:(PFBooleanResultBlock)block {
20122016
- (BFTask *)deleteEventually {
20132017
return [[[_eventuallyTaskQueue enqueue:^BFTask *(BFTask *toAwait) {
20142018
NSString *sessionToken = [PFUser currentSessionToken];
2015-
return [toAwait continueAsyncWithBlock:^id(BFTask *task) {
2019+
return [[toAwait continueAsyncWithBlock:^id(BFTask *task) {
2020+
return [self _validateDeleteAsync];
2021+
}] continueWithSuccessBlock:^id(BFTask *task) {
20162022
@synchronized (lock) {
2017-
[self checkDeleteParams];
20182023
_deletingEventually += 1;
20192024

20202025
PFOfflineStore *store = [Parse _currentManager].offlineStore;
@@ -2472,12 +2477,18 @@ + (BOOL)deleteAll:(NSArray *)objects error:(NSError **)error {
24722477
NSArray *uniqueObjects = [PFObjectBatchController uniqueObjectsArrayFromArray:deleteObjects usingFilter:^BOOL(PFObject *object) {
24732478
return (object.objectId != nil);
24742479
}];
2475-
[uniqueObjects makeObjectsPerformSelector:@selector(checkDeleteParams)]; // TODO: (nlutsenko) Make it async?
2476-
return [self _enqueue:^BFTask *(BFTask *toAwait) {
2477-
return [toAwait continueAsyncWithBlock:^id(BFTask *task) {
2478-
return [[self objectBatchController] deleteObjectsAsync:uniqueObjects withSessionToken:sessionToken];
2479-
}];
2480-
} forObjects:uniqueObjects];
2480+
NSMutableArray PF_GENERIC(BFTask <PFVoid> *) *validationTasks = [NSMutableArray array];
2481+
for (PFObject *object in uniqueObjects) {
2482+
[validationTasks addObject:[object _validateDeleteAsync]];
2483+
}
2484+
return [[BFTask taskForCompletionOfAllTasks:validationTasks] continueWithSuccessBlock:^id(BFTask *task) {
2485+
return [self _enqueue:^BFTask *(BFTask *toAwait) {
2486+
return [toAwait continueAsyncWithBlock:^id(BFTask *task) {
2487+
return [[self objectBatchController] deleteObjectsAsync:uniqueObjects
2488+
withSessionToken:sessionToken];
2489+
}];
2490+
} forObjects:uniqueObjects];
2491+
}];
24812492
}] continueWithSuccessResult:@YES];
24822493
}
24832494

Parse/PFUser.m

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,32 @@ + (BFTask *)_getCurrentUserSessionTokenAsync {
9292
#pragma mark - PFObject
9393
///--------------------------------------
9494

95-
// Check security on delete
96-
- (void)checkDeleteParams {
97-
PFConsistencyAssert(self.isAuthenticated, @"User cannot be deleted unless they have been authenticated via logIn or signUp");
98-
[super checkDeleteParams];
95+
#pragma mark Validation
96+
97+
- (BFTask PF_GENERIC(PFVoid) *)_validateDeleteAsync {
98+
return [[super _validateDeleteAsync] continueWithSuccessBlock:^id(BFTask PF_GENERIC(PFVoid) *task) {
99+
if (!self.isAuthenticated) {
100+
NSError *error = [PFErrorUtilities errorWithCode:kPFErrorUserCannotBeAlteredWithoutSession
101+
message:@"User cannot be deleted unless they have been authenticated."];
102+
return [BFTask taskWithError:error];
103+
}
104+
return nil;
105+
}];
106+
}
107+
108+
- (BFTask PF_GENERIC(PFVoid) *)_validateSaveEventuallyAsync {
109+
return [[super _validateSaveEventuallyAsync] continueWithSuccessBlock:^id(BFTask PF_GENERIC(PFVoid) *task) {
110+
if ([self isDirtyForKey:PFUserPasswordRESTKey]) {
111+
NSError *error = [PFErrorUtilities errorWithCode:kPFErrorOperationForbidden
112+
message:@"Unable to saveEventually a PFUser with dirty password."];
113+
return [BFTask taskWithError:error];
114+
}
115+
return nil;
116+
}];
99117
}
100118

119+
#pragma mark Else
120+
101121
- (NSString *)displayClassName {
102122
if ([self isMemberOfClass:[PFUser class]]) {
103123
return @"PFUser";
@@ -1202,15 +1222,4 @@ + (PFObjectState *)_newObjectStateWithParseClassName:(NSString *)className
12021222
return [PFUserState stateWithParseClassName:className objectId:objectId isComplete:complete];
12031223
}
12041224

1205-
#pragma mark Validation
1206-
1207-
- (BFTask *)_validateSaveEventuallyAsync {
1208-
if ([self isDirtyForKey:PFUserPasswordRESTKey]) {
1209-
NSError *error = [PFErrorUtilities errorWithCode:kPFErrorOperationForbidden
1210-
message:@"Unable to saveEventually a PFUser with dirty password."];
1211-
return [BFTask taskWithError:error];
1212-
}
1213-
return [BFTask taskWithResult:nil];
1214-
}
1215-
12161225
@end

0 commit comments

Comments
 (0)