From f757191ae51ea1341320ce48ac0773b6a6f4fa71 Mon Sep 17 00:00:00 2001 From: Brandon T Date: Mon, 16 May 2022 16:03:09 -0400 Subject: [PATCH] Export URLFormatter and SpoofChecker --- ios/app/BUILD.gn | 1 + ios/app/DEPS | 1 + ios/app/brave_core_main.mm | 32 +++- ios/browser/api/url/BUILD.gn | 11 ++ ios/browser/api/url/headers.gni | 2 + ios/browser/api/url/url_formatter.h | 33 ++++ ios/browser/api/url/url_formatter.mm | 50 ++++++ ios/browser/api/url/url_spoof_checker.h | 86 +++++++++ ios/browser/api/url/url_spoof_checker.mm | 211 +++++++++++++++++++++++ ios/browser/api/url/url_utils.h | 3 + ios/browser/api/url/url_utils.mm | 4 + 11 files changed, 429 insertions(+), 5 deletions(-) create mode 100644 ios/browser/api/url/url_formatter.h create mode 100644 ios/browser/api/url/url_formatter.mm create mode 100644 ios/browser/api/url/url_spoof_checker.h create mode 100644 ios/browser/api/url/url_spoof_checker.mm diff --git a/ios/app/BUILD.gn b/ios/app/BUILD.gn index 8a3faab7c30..b1193a6d1a5 100644 --- a/ios/app/BUILD.gn +++ b/ios/app/BUILD.gn @@ -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", diff --git a/ios/app/DEPS b/ios/app/DEPS index c7cf7fece12..20f1a7f2884 100644 --- a/ios/app/DEPS +++ b/ios/app/DEPS @@ -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", diff --git a/ios/app/brave_core_main.mm b/ios/app/brave_core_main.mm index 229864ad5e3..44ac86e8fb7 100644 --- a/ios/app/brave_core_main.mm +++ b/ios/app/brave_core_main.mm @@ -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* _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 { diff --git a/ios/browser/api/url/BUILD.gn b/ios/browser/api/url/BUILD.gn index 151ec25729e..150f57344b3 100644 --- a/ios/browser/api/url/BUILD.gn +++ b/ios/browser/api/url/BUILD.gn @@ -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", ] diff --git a/ios/browser/api/url/headers.gni b/ios/browser/api/url/headers.gni index 68bf4f65508..ee7bc9951fe 100644 --- a/ios/browser/api/url/headers.gni +++ b/ios/browser/api/url/headers.gni @@ -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", ] diff --git a/ios/browser/api/url/url_formatter.h b/ios/browser/api/url/url_formatter.h new file mode 100644 index 00000000000..65ad94cfaed --- /dev/null +++ b/ios/browser/api/url/url_formatter.h @@ -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 + +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_ diff --git a/ios/browser/api/url/url_formatter.mm b/ios/browser/api/url/url_formatter.mm new file mode 100644 index 00000000000..2680100fac4 --- /dev/null +++ b/ios/browser/api/url/url_formatter.mm @@ -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(url_formatter::SchemeDisplay::SHOW); +BraveURLSchemeDisplay const BraveURLSchemeDisplayOmitHttpAndHttps = + static_cast(url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS); +/// Omit cryptographic (i.e. https and wss). +BraveURLSchemeDisplay const BraveURLSchemeDisplayOmitCryptographic = + static_cast(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(schemeDisplay)); + return base::SysUTF16ToNSString(result) ?: @""; +} + ++ (NSString*)formatURLForDisplayOmitSchemePathAndTrivialSubdomains: + (NSString*)origin { + std::u16string result = + url_formatter::FormatUrlForDisplayOmitSchemePathAndTrivialSubdomains( + GURL(base::SysNSStringToUTF8(origin))); + return base::SysUTF16ToNSString(result) ?: @""; +} +@end diff --git a/ios/browser/api/url/url_spoof_checker.h b/ios/browser/api/url/url_spoof_checker.h new file mode 100644 index 00000000000..d60707c8bf4 --- /dev/null +++ b/ios/browser/api/url/url_spoof_checker.h @@ -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 + +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 ?". +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*)getSkeletons:(NSString*)url; ++ (BraveURLSpoofCheckerResult*)isLookalikeURL:(NSString*)url; +@end + +NS_ASSUME_NONNULL_END + +#endif // BRAVE_IOS_BROWSER_API_URL_URL_SPOOF_CHECKER_H_ diff --git a/ios/browser/api/url/url_spoof_checker.mm b/ios/browser/api/url/url_spoof_checker.mm new file mode 100644 index 00000000000..6e861585ec0 --- /dev/null +++ b/ios/browser/api/url/url_spoof_checker.mm @@ -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(url_formatter::SkeletonType::kFull); +BraveSpoofCheckerSkeletonType const + BraveSpoofCheckerSkeletonTypeSeparatorsRemoved = + static_cast(url_formatter::SkeletonType::kSeparatorsRemoved); + +// MARK: - LookalikeURLMatchType + +BraveSpoofCheckerLookalikeURLMatchType const + BraveSpoofCheckerLookalikeURLMatchTypeNone = + static_cast(LookalikeUrlMatchType::kNone); +BraveSpoofCheckerLookalikeURLMatchType const + BraveSpoofCheckerLookalikeURLMatchTypeSiteEngagement = + static_cast(LookalikeUrlMatchType::kSiteEngagement); +BraveSpoofCheckerLookalikeURLMatchType const + BraveSpoofCheckerLookalikeURLMatchTypeEditDistance = + static_cast(LookalikeUrlMatchType::kEditDistance); +BraveSpoofCheckerLookalikeURLMatchType const + BraveSpoofCheckerLookalikeURLMatchTypeEditDistanceSiteEngagement = + static_cast( + LookalikeUrlMatchType::kEditDistanceSiteEngagement); +BraveSpoofCheckerLookalikeURLMatchType const + BraveSpoofCheckerLookalikeURLMatchTypeTargetEmbedding = + static_cast(LookalikeUrlMatchType::kTargetEmbedding); +BraveSpoofCheckerLookalikeURLMatchType const + BraveSpoofCheckerLookalikeURLMatchTypeSkeletonMatchTop500 = + static_cast(LookalikeUrlMatchType::kSkeletonMatchTop500); +BraveSpoofCheckerLookalikeURLMatchType const + BraveSpoofCheckerLookalikeURLMatchTypeSkeletonMatchTop5k = + static_cast(LookalikeUrlMatchType::kSkeletonMatchTop5k); +BraveSpoofCheckerLookalikeURLMatchType const + BraveSpoofCheckerLookalikeURLMatchTypeTargetEmbeddingForSafetyTips = + static_cast( + LookalikeUrlMatchType::kTargetEmbeddingForSafetyTips); +BraveSpoofCheckerLookalikeURLMatchType const + BraveSpoofCheckerLookalikeURLMatchTypeFailedSpoofChecks = + static_cast(LookalikeUrlMatchType::kFailedSpoofChecks); +BraveSpoofCheckerLookalikeURLMatchType const + BraveSpoofCheckerLookalikeURLMatchTypeCharacterSwapSiteEngagement = + static_cast( + LookalikeUrlMatchType::kCharacterSwapSiteEngagement); +BraveSpoofCheckerLookalikeURLMatchType const + BraveSpoofCheckerLookalikeURLMatchTypeCharacterSwapTop500 = + static_cast(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( + entry.skeleton_type); + } + return self; +} +@end + +@implementation BraveURLSpoofCheckerResult +- (instancetype)initWithMatchType:(LookalikeUrlMatchType)matchType + suggestedURL:(NSURL*)suggestedURL { + if ((self = [super init])) { + _urlMatchType = + static_cast(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*)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 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 diff --git a/ios/browser/api/url/url_utils.h b/ios/browser/api/url/url_utils.h index 9aefcbe05a5..8c29325a746 100644 --- a/ios/browser/api/url/url_utils.h +++ b/ios/browser/api/url/url_utils.h @@ -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 diff --git a/ios/browser/api/url/url_utils.mm b/ios/browser/api/url/url_utils.mm index 503c1d40398..adcbecd4ead 100644 --- a/ios/browser/api/url/url_utils.mm +++ b/ios/browser/api/url/url_utils.mm @@ -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))); }