Skip to content

Commit

Permalink
Fixed secure coding issue that classes object couldn't be decoded. (#830
Browse files Browse the repository at this point in the history
)

Co-authored-by: Vein Guo <vein.guo@ui.com>
Co-authored-by: Frank <472730949@qq.com>
  • Loading branch information
3 people committed Dec 6, 2021
1 parent e3e7596 commit 6a33412
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 2 deletions.
6 changes: 5 additions & 1 deletion MJExtension/NSObject+MJCoding.m
Expand Up @@ -44,7 +44,11 @@ - (void)mj_decode:(NSCoder *)decoder
if ([ignoredCodingPropertyNames containsObject:property.name]) return;

// fixed `-[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSNumber'(This will be disallowed in the future.)` warning.
id value = [decoder decodeObjectOfClasses:[NSSet setWithObjects:NSNumber.class, property.type.typeClass, nil] forKey:property.name];
Class genericClass = [property objectClassInArrayForClass:property.srcClass];
// If genericClass exists, property.type.typeClass would be a collection type(Array, Set, Dictionary). This scenario([obj, nil, obj, nil]) would not happened.
NSSet *classes = [NSSet setWithObjects:NSNumber.class,
property.type.typeClass, genericClass, nil];
id value = [decoder decodeObjectOfClasses:classes forKey:property.name];
if (value == nil) { // 兼容以前的MJExtension版本
value = [decoder decodeObjectForKey:[@"_" stringByAppendingString:property.name]];
}
Expand Down
37 changes: 37 additions & 0 deletions MJExtensionTests/MJExtensionTests.m
Expand Up @@ -20,6 +20,7 @@
#import "MJFrenchUser.h"
#import "MJCat.h"
#import <MJExtensionTests-Swift.h>
#import "MJPerson.h"

@interface MJExtensionTests : XCTestCase

Expand Down Expand Up @@ -458,6 +459,42 @@ - (void)testCoding {
MJExtensionLog(@"name=%@, price=%f", decodedBag.name, decodedBag.price);
}

- (void)testCodingModelArrayProperty {
// 有 NSArray 属性 模型
MJPerson *person = [[MJPerson alloc] init];
person.name = @"boy1";
person.isVIP = YES;

MJPerson *friend1 = [[MJPerson alloc] init];
friend1.name = @"friend1";
friend1.isVIP = YES;

MJPerson *friend2 = [[MJPerson alloc] init];
friend2.name = @"friend2";
friend2.isVIP = NO;

person.friends = @[friend1, friend2];
person.books = @[@"book1", @"book2"];

NSString *file = [NSTemporaryDirectory() stringByAppendingPathComponent:@"person.data"];
NSError *error = nil;
// 归档
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person
requiringSecureCoding:YES
error:&error];
BOOL write = [data writeToFile:file atomically:true];
XCTAssert(write);

// 解档
NSData *readData = [NSFileManager.defaultManager contentsAtPath:file];
error = nil;
MJPerson *decodedPerson = [NSKeyedUnarchiver unarchivedObjectOfClass:MJPerson.class
fromData:readData
error:&error];
XCTAssert(decodedPerson.friends.count == 2);
XCTAssert(decodedPerson.books.count == 2);
}

#pragma mark 统一转换属性名(比如驼峰转下划线)
- (void)testReplacedKeyFromPropertyName121 {
// 1.定义一个字典
Expand Down
2 changes: 2 additions & 0 deletions MJExtensionTests/Model/MJPerson.h
Expand Up @@ -12,7 +12,9 @@ NS_ASSUME_NONNULL_BEGIN

@interface MJPerson : NSObject
@property (copy, nonatomic) NSString *name;
@property (nonatomic) BOOL isVIP;
@property (strong, nonatomic) NSArray<MJPerson *> *friends;
@property (strong, nonatomic) NSArray<NSString *> *books;
@end

NS_ASSUME_NONNULL_END
6 changes: 5 additions & 1 deletion MJExtensionTests/Model/MJPerson.m
Expand Up @@ -9,8 +9,12 @@
#import "MJPerson.h"
#import <MJExtension/MJExtension.h>

// NSSecureCoding实现
MJSecureCodingImplementation(MJPerson, YES)

@implementation MJPerson
+ (NSDictionary *)mj_objectClassInArray {
return @{@"friends" : @"MJPerson"};
return @{@"friends": [MJPerson class],
@"books": [NSString class]};
}
@end

0 comments on commit 6a33412

Please sign in to comment.