Add AAM to FBSDKCoreKit

Summary: Add AAM to FBSDKCoreKit along with changes in podspec and BUCK

Reviewed By: tianqibt

Differential Revision: D17532337

fbshipit-source-id: 770f421602ba8757dce4db3cebf4091605e0169d
This commit is contained in:
Zilin Zhang
2019-09-26 13:53:11 -07:00
committed by Facebook Github Bot
parent d3ed4b996e
commit 9d1df4e172
5 changed files with 679 additions and 1 deletions

View File

@@ -66,7 +66,8 @@ Pod::Spec.new do |s|
'FBSDKCoreKit/FBSDKCoreKit/FBSDKDeviceViewControllerBase.{h,m}',
'FBSDKCoreKit/FBSDKCoreKit/Internal/Device/**/*',
'FBSDKCoreKit/FBSDKCoreKit/Swift/**/*'
ss.tvos.exclude_files = 'FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/Codeless/*',
ss.tvos.exclude_files = 'FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AAM/*',
'FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/Codeless/*',
'FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKHybridAppEventsScriptMessageHandler.{h,m}',
'FBSDKCoreKit/FBSDKCoreKit/AppLink/**/*',
'FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.{h,m}',

View File

@@ -1270,6 +1270,13 @@
F92F8F8B22BA275B00494727 /* FBSDKURLSessionTask.h in Headers */ = {isa = PBXBuildFile; fileRef = F92F8F7C22BA274300494727 /* FBSDKURLSessionTask.h */; };
F92F8F8C22BA275C00494727 /* FBSDKURLSessionTask.h in Headers */ = {isa = PBXBuildFile; fileRef = F92F8F7C22BA274300494727 /* FBSDKURLSessionTask.h */; };
F92F8F8D22BA275D00494727 /* FBSDKURLSessionTask.h in Headers */ = {isa = PBXBuildFile; fileRef = F92F8F7C22BA274300494727 /* FBSDKURLSessionTask.h */; };
F952EA472339403900B20652 /* FBSDKMetadataIndexer.m in Sources */ = {isa = PBXBuildFile; fileRef = F952EA452339403900B20652 /* FBSDKMetadataIndexer.m */; };
F952EA482339403900B20652 /* FBSDKMetadataIndexer.h in Headers */ = {isa = PBXBuildFile; fileRef = F952EA462339403900B20652 /* FBSDKMetadataIndexer.h */; };
F952EA492339405D00B20652 /* FBSDKMetadataIndexer.m in Sources */ = {isa = PBXBuildFile; fileRef = F952EA452339403900B20652 /* FBSDKMetadataIndexer.m */; };
F952EA4A2339405F00B20652 /* FBSDKMetadataIndexer.m in Sources */ = {isa = PBXBuildFile; fileRef = F952EA452339403900B20652 /* FBSDKMetadataIndexer.m */; };
F952EA4B2339406400B20652 /* FBSDKMetadataIndexer.h in Headers */ = {isa = PBXBuildFile; fileRef = F952EA462339403900B20652 /* FBSDKMetadataIndexer.h */; };
F952EA4C2339406500B20652 /* FBSDKMetadataIndexer.h in Headers */ = {isa = PBXBuildFile; fileRef = F952EA462339403900B20652 /* FBSDKMetadataIndexer.h */; };
F952EA4F2339432100B20652 /* FBSDKMetadataIndexerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F952EA4E2339432000B20652 /* FBSDKMetadataIndexerTests.m */; };
F96ADE7A21E6ABB400F6043F /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F96ADE6321E6ABB400F6043F /* StoreKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
F9FD9A6221659F120068DEAF /* FBSDKGateKeeperManager.h in Headers */ = {isa = PBXBuildFile; fileRef = F9FD9A6121659F120068DEAF /* FBSDKGateKeeperManager.h */; };
F9FD9A6321659F120068DEAF /* FBSDKGateKeeperManager.h in Headers */ = {isa = PBXBuildFile; fileRef = F9FD9A6121659F120068DEAF /* FBSDKGateKeeperManager.h */; };
@@ -1734,6 +1741,9 @@
F9169B832155A03C00FA1789 /* FBSDKUserDataStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBSDKUserDataStore.m; sourceTree = "<group>"; };
F92F8F7C22BA274300494727 /* FBSDKURLSessionTask.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBSDKURLSessionTask.h; sourceTree = "<group>"; };
F92F8F7D22BA274300494727 /* FBSDKURLSessionTask.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBSDKURLSessionTask.m; sourceTree = "<group>"; };
F952EA452339403900B20652 /* FBSDKMetadataIndexer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSDKMetadataIndexer.m; sourceTree = "<group>"; };
F952EA462339403900B20652 /* FBSDKMetadataIndexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBSDKMetadataIndexer.h; sourceTree = "<group>"; };
F952EA4E2339432000B20652 /* FBSDKMetadataIndexerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSDKMetadataIndexerTests.m; sourceTree = "<group>"; };
F96ADE6321E6ABB400F6043F /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
F9FD9A6121659F120068DEAF /* FBSDKGateKeeperManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBSDKGateKeeperManager.h; sourceTree = "<group>"; };
F9FD9A7C21659F320068DEAF /* FBSDKGateKeeperManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBSDKGateKeeperManager.m; sourceTree = "<group>"; };
@@ -2238,6 +2248,7 @@
9D18A8D91A95403F00A41042 /* AppEvents */ = {
isa = PBXGroup;
children = (
F952EA4D2339412C00B20652 /* AAM */,
C51121C720A27EF50041DC94 /* Codeless */,
9D18A8DA1A95405A00A41042 /* FBSDKAppEventsStateTests.m */,
9D18A8E81A95495D00A41042 /* FBSDKAppEventsUtilityTests.m */,
@@ -2456,6 +2467,7 @@
isa = PBXGroup;
children = (
5D9031C0233AAC5D0001450C /* RestrictiveDataFilter */,
F952EA442339403900B20652 /* AAM */,
C5696F1D209BBC35009C931F /* Codeless */,
9D0BC1531A8D23DB00BE8BA4 /* FBSDKAppEvents+Internal.h */,
5F7063FA1AF733F300E42ED7 /* FBSDKAppEventsDeviceInfo.h */,
@@ -2559,6 +2571,23 @@
path = Swift;
sourceTree = "<group>";
};
F952EA442339403900B20652 /* AAM */ = {
isa = PBXGroup;
children = (
F952EA462339403900B20652 /* FBSDKMetadataIndexer.h */,
F952EA452339403900B20652 /* FBSDKMetadataIndexer.m */,
);
path = AAM;
sourceTree = "<group>";
};
F952EA4D2339412C00B20652 /* AAM */ = {
isa = PBXGroup;
children = (
F952EA4E2339432000B20652 /* FBSDKMetadataIndexerTests.m */,
);
path = AAM;
sourceTree = "<group>";
};
FD2A237F22FBF7A700DC928F /* ErrorReport */ = {
isa = PBXGroup;
children = (
@@ -2678,6 +2707,7 @@
C5696F94209BBC35009C931F /* FBSDKEventBinding.h in Headers */,
C5C4B3EE2276B88600CA3706 /* FBSDKBasicUtility.h in Headers */,
81B71D531D19C87400933E93 /* FBSDKGraphErrorRecoveryProcessor.h in Headers */,
F952EA4B2339406400B20652 /* FBSDKMetadataIndexer.h in Headers */,
52963A89215992F400C7B252 /* FBSDKAppLinkReturnToRefererController.h in Headers */,
81B71D551D19C87400933E93 /* FBSDKBase64.h in Headers */,
81B71D571D19C87400933E93 /* FBSDKAppEventsUtility.h in Headers */,
@@ -2802,6 +2832,7 @@
C5C4B3ED2276B88600CA3706 /* FBSDKBasicUtility.h in Headers */,
9D3AF4501A9EA4BE00EEF724 /* FBSDKErrorConfiguration.h in Headers */,
9D0BC1511A8D236200BE8BA4 /* FBSDKTimeSpentData.h in Headers */,
F952EA482339403900B20652 /* FBSDKMetadataIndexer.h in Headers */,
891687D21AB33CA200F55364 /* FBSDKIcon.h in Headers */,
52963A92215992F400C7B252 /* FBSDKAppLinkReturnToRefererView.h in Headers */,
52963AA82159A13400C7B252 /* FBSDKMeasurementEvent_Internal.h in Headers */,
@@ -3222,6 +3253,7 @@
F487DB75231EBCD2008416A9 /* FBSDKHybridAppEventsScriptMessageHandler.h in Headers */,
F487DB76231EBCD2008416A9 /* FBSDKWebViewAppLinkResolver.h in Headers */,
5D9A705D23261D6900BF9783 /* FBSDKLibAnalyzer.h in Headers */,
F952EA4C2339406500B20652 /* FBSDKMetadataIndexer.h in Headers */,
F487DB77231EBCD2008416A9 /* FBSDKBridgeAPIProtocolWebV2.h in Headers */,
F487DB78231EBCD2008416A9 /* FBSDKInternalUtility.h in Headers */,
F487DB79231EBCD2008416A9 /* FBSDKConstants.h in Headers */,
@@ -3958,6 +3990,7 @@
52D4F0BC1D91A18D0030B7FC /* FBSDKDeviceRequestsHelper.m in Sources */,
81B71D421D19C87400933E93 /* FBSDKKeychainStoreViaBundleID.m in Sources */,
81B71D431D19C87400933E93 /* FBSDKServerConfiguration.m in Sources */,
F952EA492339405D00B20652 /* FBSDKMetadataIndexer.m in Sources */,
81B71D441D19C87400933E93 /* FBSDKMaleSilhouetteIcon.m in Sources */,
C5C7B74F22D84F64004A5A0C /* FBSDKFeatureManager.m in Sources */,
C554DB0B2304D11200A32E8B /* FBSDKErrorReport.m in Sources */,
@@ -4058,6 +4091,7 @@
520223F81D83C8D200CE0AB5 /* FBSDKDeviceRequestsHelper.m in Sources */,
9DE1F3CE1A89D9CD00B54D98 /* FBSDKKeychainStoreViaBundleID.m in Sources */,
89830F301A7805E100226ABB /* FBSDKServerConfiguration.m in Sources */,
F952EA472339403900B20652 /* FBSDKMetadataIndexer.m in Sources */,
FD8E438122FBF8F1008B6DD3 /* FBSDKErrorReport.m in Sources */,
899C3D031A8C1ED200EA8658 /* FBSDKMaleSilhouetteIcon.m in Sources */,
C5C7B74E22D84F64004A5A0C /* FBSDKFeatureManager.m in Sources */,
@@ -4086,6 +4120,7 @@
89C8B19C1A8D7A27009B07F5 /* FBSDKUtilityTests.m in Sources */,
C51121CC20A27EF50041DC94 /* FBSDKSampleEventBinding.m in Sources */,
5DBB0447227FEF700009E0A6 /* FBSDKBasicUtilityTests.m in Sources */,
F952EA4F2339432100B20652 /* FBSDKMetadataIndexerTests.m in Sources */,
5D68D7D822BAEEF60063A3E2 /* FBSDKTimeSpentDataTests.m in Sources */,
9D3AF4661A9ED47900EEF724 /* FBSDKGraphRequestConnectionTests.m in Sources */,
C51122A020A4BCEB0041DC94 /* FBSDKApplicationDelegateTests.m in Sources */,
@@ -4412,6 +4447,7 @@
F487DB2E231EBCD2008416A9 /* FBSDKURLSession.m in Sources */,
F487DB30231EBCD2008416A9 /* _FBSDKTemporaryErrorRecoveryAttempter.m in Sources */,
F487DB31231EBCD2008416A9 /* FBSDKMeasurementEvent.m in Sources */,
F952EA4A2339405F00B20652 /* FBSDKMetadataIndexer.m in Sources */,
F487DB32231EBCD2008416A9 /* FBSDKBridgeAPIProtocolNativeV1.m in Sources */,
5D9A709D2326EB5E00BF9783 /* FBSDKCrashObserver.m in Sources */,
F487DB33231EBCD2008416A9 /* FBSDKWebDialogView.m in Sources */,

View File

@@ -0,0 +1,27 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface FBSDKMetadataIndexer : NSObject
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,331 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "FBSDKMetadataIndexer.h"
#import <objc/runtime.h>
#import <sys/sysctl.h>
#import <sys/utsname.h>
#import <UIKit/UIKit.h>
#import <FBSDKCoreKit/FBSDKCoreKit+Internal.h>
static const int FBSDKMetadataIndexerMaxTextLength = 100;
static const int FBSDKMetadataIndexerMaxIndicatorLength = 100;
static const int FBSDKMetadataIndexerMaxValue = 5;
static NSString * const FIELD_K = @"k";
static NSString * const FIELD_V = @"v";
static NSString * const FIELD_K_DELIMITER = @",";
FBSDKAppEventUserDataType FBSDKAppEventRule1 = @"r1";
FBSDKAppEventUserDataType FBSDKAppEventRule2 = @"r2";
static NSMutableDictionary<NSString *, NSDictionary<NSString *, NSString *> *> *FBSDKMetadataIndexerRules;
static NSMutableDictionary<NSString *, NSMutableArray<NSString *> *> *FBSDKMetadataIndexerStore;
static dispatch_queue_t serialQueue;
@implementation FBSDKMetadataIndexer
+ (void)initialize
{
serialQueue = dispatch_queue_create("com.facebook.appevents.MetadataIndexer", DISPATCH_QUEUE_SERIAL);
}
+ (void)load
{
[self initStore];
[self loadAndSetup];
}
+ (void)initStore
{
FBSDKMetadataIndexerStore = [[NSMutableDictionary alloc] init];
NSString *userData = [[NSUserDefaults standardUserDefaults] stringForKey:@"com.facebook.appevents.UserDataStore.userData"];
if (userData) {
NSMutableDictionary<NSString *, NSString *> * hashedUserData = (NSMutableDictionary<NSString *, NSString *> *)[NSJSONSerialization JSONObjectWithData:[userData dataUsingEncoding:NSUTF8StringEncoding]
options:NSJSONReadingMutableContainers
error:nil];
for (NSString *key in FBSDKMetadataIndexerRules) {
if (hashedUserData[key].length > 0) {
FBSDKMetadataIndexerStore[key] = [NSMutableArray arrayWithArray:[hashedUserData[key] componentsSeparatedByString:FIELD_K_DELIMITER]];
}
}
}
for (NSString *key in FBSDKMetadataIndexerRules) {
if (!FBSDKMetadataIndexerStore[key]) {
FBSDKMetadataIndexerStore[key] = [[NSMutableArray alloc] init];
}
}
}
+ (void)loadAndSetup
{
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
initWithGraphPath:[NSString stringWithFormat:@"%@?fields=aam_rules", [FBSDKSettings appID]]
HTTPMethod:FBSDKHTTPMethodGET];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (error) {
return;
}
if ([result isKindOfClass:[NSDictionary class]]) {
NSString *json = [(NSDictionary *)result objectForKey:@"aam_rules"];
if (json) {
[FBSDKMetadataIndexer constructRules:[FBSDKBasicUtility objectForJSONString:json error:nil]];
BOOL isR1Enabled = (nil != [FBSDKMetadataIndexerRules objectForKey:FBSDKAppEventRule1]);
BOOL isR2Enabled = (nil != [FBSDKMetadataIndexerRules objectForKey:FBSDKAppEventRule2]);
if (!isR1Enabled) {
[FBSDKMetadataIndexerStore removeObjectForKey:FBSDKAppEventRule1];
[FBSDKUserDataStore setHashData:nil forType:FBSDKAppEventRule1];
}
if (!isR2Enabled) {
[FBSDKMetadataIndexerStore removeObjectForKey:FBSDKAppEventRule2];
[FBSDKUserDataStore setHashData:nil forType:FBSDKAppEventRule2];
}
if (isR1Enabled || isR2Enabled) {
[self setupMetadataIndexing];
}
}
}
}];
}
+ (void)constructRules:(NSDictionary<NSString *, id> *)rules
{
if (!FBSDKMetadataIndexerRules) {
FBSDKMetadataIndexerRules = [[NSMutableDictionary alloc] init];
}
for (NSString *key in rules) {
NSDictionary<NSString *, NSString *> *value = [self dictionaryValueOf:rules[key]];
if (value && value[FIELD_K].length > 0 && value[FIELD_V].length > 0) {
FBSDKMetadataIndexerRules[key] = value;
}
}
}
+ (void)setupMetadataIndexing
{
void (^block)(UIView *) = ^(UIView *view) {
// Indexing when the view is removed from window and conforms to UITextInput, and skip UIFieldEditor, which is an internval view of UITextField
if (![view window] && ![NSStringFromClass([view class]) isEqualToString:@"UIFieldEditor"] && [view conformsToProtocol:@protocol(UITextInput)]) {
NSString *text = [FBSDKViewHierarchy getText:view];
NSString *placeholder = [FBSDKViewHierarchy getHint:view];
BOOL secureTextEntry = [self checkSecureTextEntry:view];
NSArray<NSString *> *labels = [self getLabelsOfView:view];
UIKeyboardType keyboardType = [self getKeyboardType:view];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
[self getMetadataWithText:[self normalizedValue:text]
placeholder:[self normalizeField:placeholder]
labels:labels
secureTextEntry:secureTextEntry
inputType:keyboardType];
});
}
};
[FBSDKSwizzler swizzleSelector:@selector(didMoveToWindow) onClass:[UIView class] withBlock:block named:@"metadataIndexingUIView"];
// iOS 12: UITextField implements didMoveToWindow without calling parent implementation
if (@available(iOS 12, *)) {
[FBSDKSwizzler swizzleSelector:@selector(didMoveToWindow) onClass:[UITextField class] withBlock:block named:@"metadataIndexingUITextField"];
} else {
[FBSDKSwizzler swizzleSelector:@selector(didMoveToWindow) onClass:[UIControl class] withBlock:block named:@"metadataIndexingUIControl"];
}
}
+ (NSArray<UIView *> *)getSiblingViewsOfView:(UIView *)view
{
NSObject *parent = [FBSDKViewHierarchy getParent:view];
if (parent) {
NSArray<id> *views = [FBSDKViewHierarchy getChildren:parent];
if (views) {
NSMutableArray<id> *siblings = [NSMutableArray arrayWithArray:views];
[siblings removeObject:view];
return [siblings copy];
}
}
return nil;
}
+ (NSArray<NSString *> *)getLabelsOfView:(UIView *)view
{
NSMutableArray<NSString *> *labels = [[NSMutableArray alloc] init];
NSString *placeholder = [self normalizeField:[FBSDKViewHierarchy getHint:view]];
if (placeholder) {
[labels addObject:placeholder];
}
NSArray<id> *siblingViews = [self getSiblingViewsOfView:view];
for (id sibling in siblingViews) {
if ([sibling isKindOfClass:[UILabel class]]) {
NSString *text = [self normalizeField:[FBSDKViewHierarchy getText:sibling]];
if (text) {
[labels addObject:text];
}
}
}
return [labels copy];
}
+ (BOOL)checkSecureTextEntry:(UIView *)view
{
if ([view isKindOfClass:[UITextField class]]) {
return ((UITextField *)view).secureTextEntry;
}
if ([view isKindOfClass:[UITextView class]]) {
return ((UITextView *)view).secureTextEntry;
}
return NO;
}
+ (UIKeyboardType)getKeyboardType:(UIView *)view
{
if ([view isKindOfClass:[UITextField class]]) {
return ((UITextField *)view).keyboardType;
}
if ([view isKindOfClass:[UITextView class]]) {
return ((UITextView *)view).keyboardType;
}
return UIKeyboardTypeDefault;
}
+ (void)getMetadataWithText:(NSString *)text
placeholder:(NSString *)placeholder
labels:(NSArray<NSString *> *)labels
secureTextEntry:(BOOL)secureTextEntry
inputType:(UIKeyboardType)inputType
{
if (secureTextEntry ||
[placeholder containsString:@"password"] ||
text.length == 0 ||
text.length > FBSDKMetadataIndexerMaxTextLength ||
placeholder.length >= FBSDKMetadataIndexerMaxIndicatorLength) {
return;
}
for (NSString *key in FBSDKMetadataIndexerRules) {
NSDictionary<NSString *, NSString *> *rule = FBSDKMetadataIndexerRules[key];
BOOL isRuleKMatched = [self checkMetadataHint:placeholder matchRuleK:rule[FIELD_K]]
|| [self checkMetadataLabels:labels matchRuleK:rule[FIELD_K]];
BOOL isRuleVMatched = [self checkMetadataText:text matchRuleV:rule[FIELD_V]];
if (isRuleKMatched && isRuleVMatched) {
[FBSDKMetadataIndexer checkAndAppendData:text forKey:key];
}
}
}
#pragma mark - Helper Methods
+ (void)checkAndAppendData:(NSString *)data
forKey:(NSString *)key
{
NSString *hashData = [FBSDKUtility SHA256Hash:data];
dispatch_async(serialQueue, ^{
if (hashData.length == 0 || [FBSDKMetadataIndexerStore[key] containsObject:hashData]) {
return;
}
while (FBSDKMetadataIndexerStore[key].count >= FBSDKMetadataIndexerMaxValue) {
[FBSDKMetadataIndexerStore[key] removeObjectAtIndex:0];
}
[FBSDKMetadataIndexerStore[key] addObject:hashData];
[FBSDKUserDataStore setHashData:[FBSDKMetadataIndexerStore[key] componentsJoinedByString:@","]
forType:key];
});
}
+ (BOOL)checkMetadataLabels:(NSArray<NSString *> *)labels
matchRuleK:(NSString *)ruleK
{
for (NSString *label in labels) {
if ([self checkMetadataHint:label matchRuleK:ruleK]) {
return YES;
}
}
return NO;
}
+ (BOOL)checkMetadataHint:(NSString *)hint
matchRuleK:(NSString *)ruleK
{
if (hint.length > 0 && ruleK) {
NSArray<NSString *> *items = [ruleK componentsSeparatedByString:@","];
for (NSString *item in items) {
if ([hint containsString:item]) {
return YES;
}
}
}
return NO;
}
+ (BOOL)checkMetadataText:(NSString *)text
matchRuleV:(NSString *)ruleV
{
if (text.length > 0 && ruleV) {
NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:ruleV
options:NSRegularExpressionCaseInsensitive
error:nil];
NSUInteger matches = [regex numberOfMatchesInString:text options:0 range:NSMakeRange(0, text.length)];
NSString *prunedText = [[text componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"+- ()."]] componentsJoinedByString:@""];
NSUInteger prunedMatches = [regex numberOfMatchesInString:prunedText options:0 range:NSMakeRange(0, prunedText.length)];
return matches > 0 || prunedMatches > 0;
}
return NO;
}
+ (NSString *)normalizeField:(NSString *)field
{
if (!field) {
return nil;
}
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[_-]|\\s"
options:NSRegularExpressionCaseInsensitive
error:nil];
return [regex stringByReplacingMatchesInString:field
options:0
range:NSMakeRange(0, field.length)
withTemplate:@""].lowercaseString;
}
+ (NSString *)normalizedValue:(NSString *)value
{
if (!value) {
return nil;
}
return [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].lowercaseString;
}
+ (NSDictionary *)dictionaryValueOf:(id)object
{
if ([object isKindOfClass:[NSDictionary class]]) {
return (NSDictionary *)object;
}
return nil;
}
@end

View File

@@ -0,0 +1,283 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import "FBSDKMetadataIndexer.h"
extern FBSDKAppEventUserDataType FBSDKAppEventRule1;
extern FBSDKAppEventUserDataType FBSDKAppEventRule2;
@interface FBSDKMetadataIndexer ()
+ (void)constructRules:(NSDictionary<NSString *, id> *)rules;
+ (void)initStore;
+ (BOOL)checkSecureTextEntry:(UIView *)view;
+ (UIKeyboardType)getKeyboardType:(UIView *)view;
+ (void)getMetadataWithText:(NSString *)text
placeholder:(NSString *)placeholder
labels:(NSArray<NSString *> *)labels
secureTextEntry:(BOOL)secureTextEntry
inputType:(UIKeyboardType)inputType;
+ (void)checkAndAppendData:(NSString *)data forKey:(NSString *)key;
@end
@interface FBSDKMetadataIndexerTests : XCTestCase {
id _mockMetadataIndexer;
UITextField *_emailField;
UITextView *_emailView;
UITextField *_phoneField;
UITextView *_phoneView;
UITextField *_pwdField;
UITextView *_pwdView;
}
@end
@implementation FBSDKMetadataIndexerTests
- (void)setUp
{
_mockMetadataIndexer = OCMClassMock([FBSDKMetadataIndexer class]);
[FBSDKMetadataIndexer initStore];
[FBSDKMetadataIndexer constructRules:@{
@"r1": @{
@"k": @"email,e-mail,em,electronicmail",
@"v": @"^([A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})$",
},
@"r2": @{
@"k": @"phone,mobile,contact",
@"v": @"^([0-9]{5,15})$",
}
}];
_emailField = [[UITextField alloc] init];
_emailField.placeholder = @"Enter your email";
_emailField.keyboardType = UIKeyboardTypeEmailAddress;
_emailView = [[UITextView alloc] init];
_emailView.keyboardType = UIKeyboardTypeEmailAddress;
_phoneField = [[UITextField alloc] init];
_phoneField.placeholder = @"Enter your phone";
_phoneField.keyboardType = UIKeyboardTypePhonePad;
_pwdField = [[UITextField alloc] init];
_pwdField.placeholder = @"Enter your password";
_pwdField.secureTextEntry = YES;
_pwdView = [[UITextView alloc] init];
_pwdView.secureTextEntry = YES;
}
- (void)tearDown
{
[_mockMetadataIndexer stopMocking];
}
// test for geting secure text entry in UITextField
- (void)testCheckSecureTextEntryOfTextField
{
// without secure text
XCTAssertFalse([FBSDKMetadataIndexer checkSecureTextEntry:_emailField],
@"test for UITextField without secure text");
// with secure text
XCTAssertTrue([FBSDKMetadataIndexer checkSecureTextEntry:_pwdField],
@"test for UITextField with secure text");
}
// test for geting secure text entry in UITextView
- (void)testCheckSecureTextEntryOfTextView
{
// without secure text
XCTAssertFalse([FBSDKMetadataIndexer checkSecureTextEntry:_emailView],
@"test for UITextView without secure text");
// with secure text
XCTAssertTrue([FBSDKMetadataIndexer checkSecureTextEntry:_pwdView], @"test for UITextView with secure text");
}
// test for geting keyboard type from UITextField
- (void)testGetKeyboardTypeOfTextField
{
XCTAssertEqual(_emailField.keyboardType,
[FBSDKMetadataIndexer getKeyboardType:_emailField],
@"test for geting keyboard type from UITextField");
}
// test for geting keyboard type from UITextView
- (void)testGetKeyboardTypeOfTextView
{
XCTAssertEqual(_emailView.keyboardType,
[FBSDKMetadataIndexer getKeyboardType:_emailView],
@"test for geting keyboard type from UITextView");
}
// test for geting metadata with valid email
- (void)testGetMetadataWithEmail
{
NSString *text = @"test@fb.com";
[FBSDKMetadataIndexer getMetadataWithText:text
placeholder:@"enter your email"
labels:nil
secureTextEntry:NO
inputType:UIKeyboardTypeEmailAddress];
OCMVerify([_mockMetadataIndexer checkAndAppendData:text forKey:FBSDKAppEventRule1]);
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule2]);
}
// test for geting metadata with valid phone number
- (void)testGetMetadataWithPhoneNumber
{
NSString *text = @"1112223333";
[FBSDKMetadataIndexer getMetadataWithText:text
placeholder:@"enter your phone number"
labels:nil
secureTextEntry:NO
inputType:UIKeyboardTypePhonePad];
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule1]);
OCMVerify([_mockMetadataIndexer checkAndAppendData:text forKey:FBSDKAppEventRule2]);
}
// test for geting metadata with secure text
- (void)testGetMetadataWithSecureText
{
NSString *text = @"dfjald1314";
[FBSDKMetadataIndexer getMetadataWithText:text
placeholder:@"enter your password"
labels:nil
secureTextEntry:YES
inputType:UIKeyboardTypeDefault];
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule1]);
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule2]);
}
// test for geting metadata with invalid email
- (void)testGetMetadataWithInvalidEmail
{
NSString *text = @"test";
[FBSDKMetadataIndexer getMetadataWithText:text
placeholder:@"enter your email"
labels:nil
secureTextEntry:NO
inputType:UIKeyboardTypeEmailAddress];
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule1]);
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule2]);
}
// test for geting metadata with invalid email placeholder
- (void)testGetMetadataWithInvalidEmailPlaceholder
{
NSString *text = @"test@fb.com";
[FBSDKMetadataIndexer getMetadataWithText:text
placeholder:@"enter your"
labels:nil
secureTextEntry:NO
inputType:UIKeyboardTypeEmailAddress];
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule1]);
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule2]);
}
// test for geting metadata with invalid phone number
- (void)testGetMetadataWithInvalidPhoneNumber
{
NSString *text = @"1234";
[FBSDKMetadataIndexer getMetadataWithText:text
placeholder:@"enter your phone number"
labels:nil
secureTextEntry:NO
inputType:UIKeyboardTypePhonePad];
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule1]);
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule2]);
}
// test for geting metadata with invalid phone number placeholder
- (void)testGetMetadataWithInvalidPhoneNumberPlaceholder
{
NSString *text = @"1112223333";
[FBSDKMetadataIndexer getMetadataWithText:text
placeholder:@"enter your"
labels:nil
secureTextEntry:NO
inputType:UIKeyboardTypePhonePad];
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule1]);
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule2]);
}
// test for geting metadata with text which is neither email nor phone number
- (void)testGetMetadataWithTextNotEmailAndPhone
{
NSString *text = @"Facebook";
[FBSDKMetadataIndexer getMetadataWithText:text
placeholder:@"enter your name"
labels:nil
secureTextEntry:NO
inputType:UIKeyboardTypeAlphabet];
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule1]);
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule2]);
}
// test for geting metadata with no text
- (void)testGetMetadataWithNoText
{
NSString *text = @"";
[FBSDKMetadataIndexer getMetadataWithText:text
placeholder:@"enter your email"
labels:nil
secureTextEntry:NO
inputType:UIKeyboardTypeEmailAddress];
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule1]);
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule2]);
}
// test for geting metadata with too long text
- (void)testGetMetadataWithTooLongText
{
NSString *text = [NSString stringWithFormat:@"%@%@", [@"" stringByPaddingToLength:1000 withString: @"a" startingAtIndex:0], @"@fb.com"];
[FBSDKMetadataIndexer getMetadataWithText:text
placeholder:@"enter your email"
labels:nil
secureTextEntry:NO
inputType:UIKeyboardTypeEmailAddress];
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule1]);
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule2]);
}
// test for geting metadata with too long placeholder
- (void)testGetMetadataWithTooLongPlaceholder
{
NSString *text = @"test@fb.com";
NSString *indicator = [NSString stringWithFormat:@"%@", [@"" stringByPaddingToLength:1000 withString: @"enter your email " startingAtIndex:0]];
[FBSDKMetadataIndexer getMetadataWithText:text
placeholder:indicator
labels:nil
secureTextEntry:NO
inputType:UIKeyboardTypeEmailAddress];
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule1]);
OCMReject([_mockMetadataIndexer checkAndAppendData:[OCMArg any] forKey:FBSDKAppEventRule2]);
}
@end