Export URLFormatter and SpoofChecker

This commit is contained in:
Brandon T
2022-05-20 10:35:33 -04:00
committed by Brandon-T
parent d1446fbb0e
commit f757191ae5
11 changed files with 429 additions and 5 deletions
+1
View File
@@ -47,6 +47,7 @@ source_set("app") {
"//brave/ios/browser/skus",
"//components/browser_sync",
"//components/component_updater",
"//components/component_updater/installer_policies",
"//components/history/core/browser",
"//components/keyed_service/core",
"//components/password_manager/core/browser",
+1
View File
@@ -5,6 +5,7 @@ include_rules = [
"+brave/ios/app",
"+brave/ios/browser",
"+components/component_updater/component_updater_switches.h",
"+components/component_updater/installer_policies",
"+components/sync/driver",
"+components/sync/base",
"+components/browser_sync",
+27 -5
View File
@@ -37,6 +37,7 @@
#include "brave/ios/browser/brave_web_client.h"
#include "brave/ios/browser/component_updater/component_updater_utils.h"
#include "components/component_updater/component_updater_switches.h"
#include "components/component_updater/installer_policies/safety_tips_component_installer.h"
#include "components/history/core/browser/history_service.h"
#include "components/keyed_service/core/service_access_type.h"
#include "components/password_manager/core/browser/password_store.h"
@@ -80,6 +81,7 @@ const BraveCoreSwitch BraveCoreSwitchSkusEnvironment =
NSMutableDictionary<NSNumber* /* BraveWalletCoinType */, NSString*>*
_providerScripts;
}
@property(nonatomic) bool appIsTerminating;
@property(nonatomic) BraveBookmarksAPI* bookmarksAPI;
@property(nonatomic) BraveHistoryAPI* historyAPI;
@property(nonatomic) BravePasswordAPI* passwordAPI;
@@ -113,6 +115,7 @@ const BraveCoreSwitch BraveCoreSwitchSkusEnvironment =
name:UIApplicationWillTerminateNotification
object:nil];
_appIsTerminating = false;
_providerScripts = [[NSMutableDictionary alloc] init];
// Register all providers before calling any Chromium code.
@@ -178,11 +181,33 @@ const BraveCoreSwitch BraveCoreSwitchSkusEnvironment =
}
- (void)onAppWillTerminate:(NSNotification*)notification {
VLOG(1) << "Terminating Brave-Core";
if (_appIsTerminating) {
// Previous handling of this method spun the runloop, resulting in
// recursive calls; this does not appear to happen with the new shutdown
// flow, but this is here to ensure that if it can happen, it gets noticed
// and fixed.
DCHECK(false);
VLOG(0) << "Brave-Core AppWillTerminate called more than once!";
}
_appIsTerminating = true;
[[NSNotificationCenter defaultCenter] removeObserver:self];
_bookmarksAPI = nil;
_historyAPI = nil;
_passwordAPI = nil;
_syncProfileService = nil;
_syncAPI = nil;
_mainBrowserState = nullptr;
_webMain.reset();
_delegate.reset();
_webClient.reset();
_appIsTerminating = false;
VLOG(1) << "Terminated Brave-Core";
}
- (void)scheduleLowPriorityStartupTasks {
@@ -198,15 +223,12 @@ const BraveCoreSwitch BraveCoreSwitchSkusEnvironment =
GetApplicationContext()->GetComponentUpdateService();
DCHECK(cus);
RegisterSafetyTipsComponent(cus);
brave_wallet::RegisterWalletDataFilesComponent(cus);
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
_mainBrowserState = nullptr;
_webMain.reset();
_delegate.reset();
_webClient.reset();
[self onAppWillTerminate:nil];
}
+ (void)setLogHandler:(BraveCoreLogHandler)logHandler {
+11
View File
@@ -7,11 +7,15 @@ source_set("url") {
configs += [ "//build/config/compiler:enable_arc" ]
sources = [
"url_formatter.h",
"url_formatter.mm",
"url_origin_ios+private.h",
"url_origin_ios.h",
"url_origin_ios.mm",
"url_pattern_ios.h",
"url_pattern_ios.mm",
"url_spoof_checker.h",
"url_spoof_checker.mm",
"url_utils.h",
"url_utils.mm",
]
@@ -19,6 +23,13 @@ source_set("url") {
deps = [
"//base",
"//brave/extensions:common",
"//components/lookalikes/core:core",
"//components/lookalikes/core:features",
"//components/reputation/core",
"//components/url_formatter",
"//components/url_formatter/spoof_checks/top_domains:common",
"//components/url_formatter/spoof_checks/top_domains:generate_top_domains_trie",
"//components/url_formatter/spoof_checks/top_domains:top500_domains",
"//net",
"//url",
]
+2
View File
@@ -1,5 +1,7 @@
browser_api_url_public_headers = [
"//brave/ios/browser/api/url/url_formatter.h",
"//brave/ios/browser/api/url/url_origin_ios.h",
"//brave/ios/browser/api/url/url_pattern_ios.h",
"//brave/ios/browser/api/url/url_spoof_checker.h",
"//brave/ios/browser/api/url/url_utils.h",
]
+33
View File
@@ -0,0 +1,33 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BRAVE_IOS_BROWSER_API_URL_URL_FORMATTER_H_
#define BRAVE_IOS_BROWSER_API_URL_URL_FORMATTER_H_
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef NSInteger BraveURLSchemeDisplay NS_TYPED_ENUM
NS_SWIFT_NAME(URLFormatter.SchemeDisplay);
OBJC_EXPORT BraveURLSchemeDisplay const BraveURLSchemeDisplayShow;
OBJC_EXPORT BraveURLSchemeDisplay const BraveURLSchemeDisplayOmitHttpAndHttps;
/// Omit cryptographic (i.e. https and wss).
OBJC_EXPORT BraveURLSchemeDisplay const BraveURLSchemeDisplayOmitCryptographic;
OBJC_EXPORT
NS_SWIFT_NAME(URLFormatter)
@interface BraveURLFormatter : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (NSString*)formatURLForSecurityDisplay:(NSString*)origin
schemeDisplay:(BraveURLSchemeDisplay)schemeDisplay;
+ (NSString*)formatURLForDisplayOmitSchemePathAndTrivialSubdomains:
(NSString*)origin;
@end
NS_ASSUME_NONNULL_END
#endif // BRAVE_IOS_BROWSER_API_URL_URL_FORMATTER_H_
+50
View File
@@ -0,0 +1,50 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "brave/ios/browser/api/url/url_formatter.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/notreached.h"
#include "base/strings/sys_string_conversions.h"
#include "build/build_config.h"
#include "components/url_formatter/elide_url.h"
#include "components/url_formatter/url_formatter.h"
#include "net/base/mac/url_conversions.h"
#include "url/gurl.h"
#include "url/origin.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// MARK: - SchemeDisplay
BraveURLSchemeDisplay const BraveURLSchemeDisplayShow =
static_cast<NSInteger>(url_formatter::SchemeDisplay::SHOW);
BraveURLSchemeDisplay const BraveURLSchemeDisplayOmitHttpAndHttps =
static_cast<NSInteger>(url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
/// Omit cryptographic (i.e. https and wss).
BraveURLSchemeDisplay const BraveURLSchemeDisplayOmitCryptographic =
static_cast<NSInteger>(url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);
// MARK: - Implementation
@implementation BraveURLFormatter
+ (NSString*)formatURLForSecurityDisplay:(NSString*)origin
schemeDisplay:(BraveURLSchemeDisplay)schemeDisplay {
std::u16string result = url_formatter::FormatUrlForSecurityDisplay(
GURL(base::SysNSStringToUTF8(origin)),
static_cast<url_formatter::SchemeDisplay>(schemeDisplay));
return base::SysUTF16ToNSString(result) ?: @"";
}
+ (NSString*)formatURLForDisplayOmitSchemePathAndTrivialSubdomains:
(NSString*)origin {
std::u16string result =
url_formatter::FormatUrlForDisplayOmitSchemePathAndTrivialSubdomains(
GURL(base::SysNSStringToUTF8(origin)));
return base::SysUTF16ToNSString(result) ?: @"";
}
@end
+86
View File
@@ -0,0 +1,86 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BRAVE_IOS_BROWSER_API_URL_URL_SPOOF_CHECKER_H_
#define BRAVE_IOS_BROWSER_API_URL_URL_SPOOF_CHECKER_H_
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/// The |SkeletonType| and |TopDomainEntry| are mirrored in trie_entry.h. These
/// are used to insert and read nodes from the Trie.
/// The type of skeleton in the trie node.
typedef NSInteger BraveSpoofCheckerSkeletonType NS_TYPED_ENUM
NS_SWIFT_NAME(URLSpoofChecker.SkeletonType);
OBJC_EXPORT BraveSpoofCheckerSkeletonType const
BraveSpoofCheckerSkeletonTypeFull;
OBJC_EXPORT BraveSpoofCheckerSkeletonType const
BraveSpoofCheckerSkeletonTypeSeparatorsRemoved;
typedef NSInteger BraveSpoofCheckerLookalikeURLMatchType NS_TYPED_ENUM
NS_SWIFT_NAME(URLSpoofChecker.LookalikeURLMatchType);
OBJC_EXPORT BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeNone;
OBJC_EXPORT BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeSiteEngagement;
OBJC_EXPORT BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeEditDistance;
OBJC_EXPORT BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeEditDistanceSiteEngagement;
OBJC_EXPORT BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeTargetEmbedding;
OBJC_EXPORT BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeSkeletonMatchTop500;
OBJC_EXPORT BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeSkeletonMatchTop5k;
OBJC_EXPORT BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeTargetEmbeddingForSafetyTips;
/// The domain name failed IDN spoof checks but didn't match a safe hostname.
/// As a result, there is no URL to suggest to the user in the form of "Did
/// you mean <url>?".
OBJC_EXPORT BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeFailedSpoofChecks;
OBJC_EXPORT BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeCharacterSwapSiteEngagement;
OBJC_EXPORT BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeCharacterSwapTop500;
OBJC_EXPORT
NS_SWIFT_NAME(URLSpoofChecker.TopDomainEntry)
@interface URLSpoofCheckerTopDomainEntry : NSObject
- (instancetype)init NS_UNAVAILABLE;
/// The domain name.
@property(nonatomic, readonly) NSString* domain;
/// True if the domain is in the top 500.
@property(nonatomic, readonly) bool isTop500;
/// Type of the skeleton stored in the trie node.
@property(nonatomic, readonly) BraveSpoofCheckerSkeletonType skeletonType;
@end
OBJC_EXPORT
NS_SWIFT_NAME(URLSpoofChecker.Result)
@interface BraveURLSpoofCheckerResult : NSObject
- (instancetype)init NS_UNAVAILABLE;
@property(nonatomic, readonly)
BraveSpoofCheckerLookalikeURLMatchType urlMatchType;
@property(nonatomic, readonly, nullable) NSURL* suggestedURL;
@end
OBJC_EXPORT
NS_SWIFT_NAME(URLSpoofChecker)
@interface BraveURLSpoofChecker : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (URLSpoofCheckerTopDomainEntry*)getSimilarTopDomain:(NSString*)hostname;
+ (URLSpoofCheckerTopDomainEntry*)lookupSkeletonInTopDomains:
(NSString*)hostname;
+ (NSArray<NSString*>*)getSkeletons:(NSString*)url;
+ (BraveURLSpoofCheckerResult*)isLookalikeURL:(NSString*)url;
@end
NS_ASSUME_NONNULL_END
#endif // BRAVE_IOS_BROWSER_API_URL_URL_SPOOF_CHECKER_H_
+211
View File
@@ -0,0 +1,211 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "brave/ios/browser/api/url/url_spoof_checker.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/notreached.h"
#include "base/strings/sys_string_conversions.h"
#include "build/build_config.h"
#include "components/lookalikes/core/features.h"
#include "components/lookalikes/core/lookalike_url_ui_util.h"
#include "components/lookalikes/core/lookalike_url_util.h"
#include "components/reputation/core/safety_tips_config.h"
#include "components/url_formatter/elide_url.h"
#include "components/url_formatter/spoof_checks/top_domains/domains-trie-inc.cc"
#include "components/url_formatter/spoof_checks/top_domains/top_domain_util.h"
#include "components/url_formatter/url_formatter.h"
#include "net/base/mac/url_conversions.h"
#include "url/gurl.h"
#include "url/origin.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// MARK: - SkeletonType
BraveSpoofCheckerSkeletonType const BraveSpoofCheckerSkeletonTypeFull =
static_cast<NSInteger>(url_formatter::SkeletonType::kFull);
BraveSpoofCheckerSkeletonType const
BraveSpoofCheckerSkeletonTypeSeparatorsRemoved =
static_cast<NSInteger>(url_formatter::SkeletonType::kSeparatorsRemoved);
// MARK: - LookalikeURLMatchType
BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeNone =
static_cast<NSInteger>(LookalikeUrlMatchType::kNone);
BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeSiteEngagement =
static_cast<NSInteger>(LookalikeUrlMatchType::kSiteEngagement);
BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeEditDistance =
static_cast<NSInteger>(LookalikeUrlMatchType::kEditDistance);
BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeEditDistanceSiteEngagement =
static_cast<NSInteger>(
LookalikeUrlMatchType::kEditDistanceSiteEngagement);
BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeTargetEmbedding =
static_cast<NSInteger>(LookalikeUrlMatchType::kTargetEmbedding);
BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeSkeletonMatchTop500 =
static_cast<NSInteger>(LookalikeUrlMatchType::kSkeletonMatchTop500);
BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeSkeletonMatchTop5k =
static_cast<NSInteger>(LookalikeUrlMatchType::kSkeletonMatchTop5k);
BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeTargetEmbeddingForSafetyTips =
static_cast<NSInteger>(
LookalikeUrlMatchType::kTargetEmbeddingForSafetyTips);
BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeFailedSpoofChecks =
static_cast<NSInteger>(LookalikeUrlMatchType::kFailedSpoofChecks);
BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeCharacterSwapSiteEngagement =
static_cast<NSInteger>(
LookalikeUrlMatchType::kCharacterSwapSiteEngagement);
BraveSpoofCheckerLookalikeURLMatchType const
BraveSpoofCheckerLookalikeURLMatchTypeCharacterSwapTop500 =
static_cast<NSInteger>(LookalikeUrlMatchType::kCharacterSwapTop500);
// MARK: - Implementation
@implementation URLSpoofCheckerTopDomainEntry
- (instancetype)initWithEntry:(url_formatter::TopDomainEntry)entry {
if ((self = [super init])) {
_domain = base::SysUTF8ToNSString(entry.domain) ?: @"";
_isTop500 = entry.is_top_500;
_skeletonType = static_cast<BraveSpoofCheckerLookalikeURLMatchType>(
entry.skeleton_type);
}
return self;
}
@end
@implementation BraveURLSpoofCheckerResult
- (instancetype)initWithMatchType:(LookalikeUrlMatchType)matchType
suggestedURL:(NSURL*)suggestedURL {
if ((self = [super init])) {
_urlMatchType =
static_cast<BraveSpoofCheckerLookalikeURLMatchType>(matchType);
_suggestedURL = suggestedURL;
}
return self;
}
@end
@implementation BraveURLSpoofChecker
+ (URLSpoofCheckerTopDomainEntry*)getSimilarTopDomain:(NSString*)hostname {
url_formatter::TopDomainEntry entry =
url_formatter::IDNSpoofChecker().GetSimilarTopDomain(
base::SysNSStringToUTF16(hostname));
return [[URLSpoofCheckerTopDomainEntry alloc] initWithEntry:entry];
}
+ (URLSpoofCheckerTopDomainEntry*)lookupSkeletonInTopDomains:
(NSString*)hostname {
url_formatter::TopDomainEntry entry =
url_formatter::IDNSpoofChecker().LookupSkeletonInTopDomains(
base::SysNSStringToUTF8(hostname));
return [[URLSpoofCheckerTopDomainEntry alloc] initWithEntry:entry];
}
+ (NSArray<NSString*>*)getSkeletons:(NSString*)url {
const url_formatter::IDNConversionResult result =
url_formatter::UnsafeIDNToUnicodeWithDetails(
GURL(base::SysNSStringToUTF8(url)).host());
Skeletons skeletons =
url_formatter::IDNSpoofChecker().GetSkeletons(result.result);
NSMutableArray* array = [[NSMutableArray alloc] init];
for (const auto& skeleton : skeletons) {
NSString* result = base::SysUTF8ToNSString(skeleton);
if (result) {
[array addObject:result];
}
}
return array;
}
+ (BraveURLSpoofCheckerResult*)isLookalikeURL:(NSString*)url {
// See:
// //ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper.mm
// For more info
GURL response_url = GURL(base::SysNSStringToUTF8(url));
// If the URL is not an HTTP or HTTPS page, don't show any warning.
if (!response_url.SchemeIsHTTPOrHTTPS()) {
return [[BraveURLSpoofCheckerResult alloc]
initWithMatchType:LookalikeUrlMatchType::kNone
suggestedURL:nil];
}
// Fetch the component allowlist.
const auto* proto = reputation::GetSafetyTipsRemoteConfigProto();
// When there's no proto (like at browser start), fail-safe and don't block.
if (!proto) {
return [[BraveURLSpoofCheckerResult alloc]
initWithMatchType:LookalikeUrlMatchType::kNone
suggestedURL:nil];
}
// If the URL is in the component updater allowlist, don't show any warning.
if (reputation::IsUrlAllowlistedBySafetyTipsComponent(
proto, response_url.GetWithEmptyPath())) {
return [[BraveURLSpoofCheckerResult alloc]
initWithMatchType:LookalikeUrlMatchType::kNone
suggestedURL:nil];
}
const DomainInfo navigated_domain = GetDomainInfo(response_url);
// Empty domain_and_registry happens on private domains.
if (navigated_domain.domain_and_registry.empty() ||
IsTopDomain(navigated_domain)) {
return [[BraveURLSpoofCheckerResult alloc]
initWithMatchType:LookalikeUrlMatchType::kNone
suggestedURL:nil];
}
std::vector<DomainInfo> engaged_sites;
std::string matched_domain;
LookalikeUrlMatchType match_type = LookalikeUrlMatchType::kNone;
// Target allowlist is not currently used in ios.
const LookalikeTargetAllowlistChecker in_target_allowlist =
base::BindRepeating(^(const std::string& hostname) {
return false;
});
if (!GetMatchingDomain(navigated_domain, engaged_sites, in_target_allowlist,
proto, &matched_domain, &match_type)) {
if (ShouldBlockBySpoofCheckResult(navigated_domain)) {
return [[BraveURLSpoofCheckerResult alloc]
initWithMatchType:LookalikeUrlMatchType::kFailedSpoofChecks
suggestedURL:nil];
}
return [[BraveURLSpoofCheckerResult alloc]
initWithMatchType:LookalikeUrlMatchType::kNone
suggestedURL:nil];
}
DCHECK(!matched_domain.empty());
if (ShouldBlockLookalikeUrlNavigation(match_type)) {
const std::string suggested_domain = GetETLDPlusOne(matched_domain);
DCHECK(!suggested_domain.empty());
GURL::Replacements replace_host;
replace_host.SetHostStr(suggested_domain);
const GURL suggested_url =
response_url.ReplaceComponents(replace_host).GetWithEmptyPath();
return [[BraveURLSpoofCheckerResult alloc]
initWithMatchType:match_type
suggestedURL:net::NSURLWithGURL(suggested_url)];
}
return [[BraveURLSpoofCheckerResult alloc]
initWithMatchType:LookalikeUrlMatchType::kNone
suggestedURL:nil];
}
@end
+3
View File
@@ -13,6 +13,9 @@ NS_ASSUME_NONNULL_BEGIN
OBJC_EXPORT
@interface NSURL (Utilities)
+ (nullable NSURL*)URLFromIDNString:(NSString*)idnString
NS_SWIFT_NAME(init(idnString:));
/// Returns the domain registry
/// google.co.uk -> co.uk
/// google.com -> com
+4
View File
@@ -37,6 +37,10 @@ std::string GetRegistry(const GURL& url) {
registry_length);
}
+ (NSURL*)URLFromIDNString:(NSString*)idnString {
return net::NSURLWithGURL(GURL(base::SysNSStringToUTF8(idnString)));
}
- (NSString*)brave_registry {
return base::SysUTF8ToNSString(GetRegistry(net::GURLWithNSURL(self)));
}