blob: dd3b0d8f464e010900ab934b69e0028cc70eafd8 [file] [log] [blame]
/*
* Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#import <Availability.h>
#import <wtf/Assertions.h>
#import <wtf/RetainPtr.h>
#define USE_SECURE_ARCHIVER_API ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101302 && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110200) || (PLATFORM(WATCHOS) && __WATCH_OS_VERSION_MIN_REQUIRED >= 40200) || (PLATFORM(APPLETV) && __TV_OS_VERSION_MIN_REQUIRED >= 110200))
#define USE_SECURE_ARCHIVER_FOR_ATTRIBUTED_STRING ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101302 && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) || (PLATFORM(WATCHOS) && __WATCH_OS_VERSION_MIN_REQUIRED >= 60000) || (PLATFORM(APPLETV) && __TV_OS_VERSION_MIN_REQUIRED >= 130000))
#if USE(SECURE_ARCHIVER_API)
#if USE(APPLE_INTERNAL_SDK)
#import <Foundation/NSKeyedArchiver_Private.h>
#else
#import <Foundation/NSCoder.h>
#import <Foundation/NSKeyedArchiver.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSKeyedArchiver (NSKeyedArchiverSecureCodingInitializers)
- (instancetype)initRequiringSecureCoding:(BOOL)requiresSecureCoding API_AVAILABLE(macos(10.13), ios(11.0));
+ (nullable NSData *)archivedDataWithRootObject:(id)object requiringSecureCoding:(BOOL)requiresSecureCoding error:(NSError **)error API_AVAILABLE(macos(10.13), ios(11.0));
@end
@interface NSKeyedUnarchiver (NSKeyedUnarchiverSecureCodingInitializer)
- (nullable instancetype)initForReadingFromData:(NSData *)data error:(NSError **)error API_AVAILABLE(macos(10.13), ios(11.0));
+ (nullable id)unarchivedObjectOfClass:(Class)cls fromData:(NSData *)data error:(NSError **)error API_AVAILABLE(macos(10.13), ios(11.0));
+ (nullable id)unarchivedObjectOfClasses:(NSSet<Class> *)classes fromData:(NSData *)data error:(NSError **)error API_AVAILABLE(macos(10.13), ios(11.0));
@end
NS_ASSUME_NONNULL_END
#endif /* USE(APPLE_INTERNAL_SDK) */
#endif /* USE(SECURE_ARCHIVER_API) */
inline NSData *_Nullable securelyArchivedDataWithRootObject(id _Nonnull object)
{
#if USE(SECURE_ARCHIVER_API)
NSError *error;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object requiringSecureCoding:YES error:&error];
if (!data)
LOG_ERROR("Unable to archive data: %@", error);
return data;
#else
return [NSKeyedArchiver archivedDataWithRootObject:object];
#endif
}
inline NSData *_Nullable insecurelyArchivedDataWithRootObject(id _Nonnull object)
{
#if USE(SECURE_ARCHIVER_API)
NSError *error;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object requiringSecureCoding:NO error:&error];
if (!data)
LOG_ERROR("Unable to archive data: %@", error);
return data;
#else
return [NSKeyedArchiver archivedDataWithRootObject:object];
#endif
}
inline id _Nullable insecurelyUnarchiveObjectFromData(NSData * _Nonnull data)
{
ALLOW_DEPRECATED_DECLARATIONS_BEGIN
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
ALLOW_DEPRECATED_DECLARATIONS_END
}
inline id _Nullable unarchivedObjectOfClassesFromData(NSSet<Class> * _Nonnull classes, NSData * _Nonnull data)
{
#if USE(SECURE_ARCHIVER_API)
#if !USE(SECURE_ARCHIVER_FOR_ATTRIBUTED_STRING)
// Remove this code when the fix from <rdar://problem/31376830> is deployed to all relevant build targets.
if ([classes containsObject:[NSAttributedString class]])
return insecurelyUnarchiveObjectFromData(data);
#endif
NSError *error;
id value = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:data error:&error];
if (!value)
LOG_ERROR("Unable to unarchive data: %@", error);
return value;
#else
UNUSED_PARAM(classes);
return insecurelyUnarchiveObjectFromData(data);
#endif
}
inline RetainPtr<NSKeyedArchiver> secureArchiver()
{
#if USE(SECURE_ARCHIVER_API)
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
#else
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] init];
[archiver setRequiresSecureCoding:YES];
#endif
return adoptNS(archiver);
}
inline RetainPtr<NSKeyedUnarchiver> secureUnarchiverFromData(NSData *_Nonnull data)
{
#if USE(SECURE_ARCHIVER_API)
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:nil];
unarchiver.decodingFailurePolicy = NSDecodingFailurePolicyRaiseException;
#else
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
[unarchiver setRequiresSecureCoding:YES];
#endif
return adoptNS(unarchiver);
}
inline id _Nullable decodeObjectOfClassForKeyFromCoder(Class _Nonnull cls, NSString * _Nonnull key, NSCoder * _Nonnull coder)
{
#if USE(SECURE_ARCHIVER_API)
return [coder decodeObjectOfClass:cls forKey:key];
#else
UNUSED_PARAM(cls);
return [coder decodeObjectForKey:key];
#endif
}