0

[LNA] Add Local Network Access permission type

This adds a new PermissionType and ContentSettingsType for Local Network
Access (LNA) in preparation for adding a new permission prompt to
restrict this capability.

Followup CLs will add UI integrations and
permission prompts:
- crrev.com/c/6330700 (ContentSetting and PageInfo)
- crrev.com/c/6337340 (Permission request)

Bug: 400455013
Change-Id: Icc851197deb8162e8686fe13f035300dbcd5bf63
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6325710
Reviewed-by: Rainhard Findling <rainhard@chromium.org>
Commit-Queue: Chris Thompson <cthomp@chromium.org>
Reviewed-by: Camille Lamy <clamy@chromium.org>
Reviewed-by: Richard (Torne) Coles <torne@chromium.org>
Reviewed-by: Christian Dullweber <dullweber@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1431774}
This commit is contained in:
Chris Thompson
2025-03-12 14:59:57 -07:00
committed by Chromium LUCI CQ
parent 2e7502431b
commit a9d4580fce
22 changed files with 81 additions and 2 deletions
android_webview/browser
chrome
android
javatests
src
org
chromium
chrome
browser
components
browser_ui
site_settings
android
java
src
org
chromium
components
browser_ui
content_settings
permissions
content
headless/test/data/protocol/sanity
third_party/blink
common
public
common
devtools_protocol
mojom
permissions
renderer
tools/metrics/histograms

@ -416,6 +416,13 @@ void AwPermissionManager::RequestPermissions(
pending_request_raw->SetPermissionStatus(permissions[i], pending_request_raw->SetPermissionStatus(permissions[i],
PermissionStatus::DENIED); PermissionStatus::DENIED);
break; break;
case PermissionType::LOCAL_NETWORK_ACCESS:
// PermissionType::LOCAL_NETWORK_ACCESS requests are always granted so
// that local network requests in WebView work as-is. WebView is
// currently out-of-scope for Local Network Access restrictions.
pending_request_raw->SetPermissionStatus(permissions[i],
PermissionStatus::GRANTED);
break;
case PermissionType::NUM: case PermissionType::NUM:
NOTREACHED() << "PermissionType::NUM was not expected here."; NOTREACHED() << "PermissionType::NUM was not expected here.";
} }
@ -557,6 +564,7 @@ PermissionStatus AwPermissionManager::GetPermissionStatusInternal(
case blink::PermissionType::CLIPBOARD_SANITIZED_WRITE: case blink::PermissionType::CLIPBOARD_SANITIZED_WRITE:
case blink::PermissionType::MIDI: case blink::PermissionType::MIDI:
case blink::PermissionType::SENSORS: case blink::PermissionType::SENSORS:
case blink::PermissionType::LOCAL_NETWORK_ACCESS:
// These permissions are auto-granted by WebView. // These permissions are auto-granted by WebView.
return PermissionStatus::GRANTED; return PermissionStatus::GRANTED;
@ -751,6 +759,7 @@ void AwPermissionManager::CancelPermissionRequest(int request_id) {
case PermissionType::SENSORS: case PermissionType::SENSORS:
case PermissionType::WAKE_LOCK_SCREEN: case PermissionType::WAKE_LOCK_SCREEN:
case PermissionType::WAKE_LOCK_SYSTEM: case PermissionType::WAKE_LOCK_SYSTEM:
case PermissionType::LOCAL_NETWORK_ACCESS:
// There is nothing to cancel so this is simply ignored. // There is nothing to cancel so this is simply ignored.
break; break;
case PermissionType::NUM: case PermissionType::NUM:

@ -268,6 +268,17 @@ TEST_F(AwPermissionManagerTest, ClipboardPermissionIsGrantedSynchronously) {
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
} }
TEST_F(AwPermissionManagerTest,
LocalNetworkAccessPermissionIsGrantedSynchronously) {
RequestPermissions(
{PermissionType::LOCAL_NETWORK_ACCESS}, render_frame_host,
GURL(kRequestingOrigin1), true,
base::BindOnce(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 0));
ASSERT_EQ(1u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
}
// Test the case a delegate is called, and it resolves the permission // Test the case a delegate is called, and it resolves the permission
// synchronously. // synchronously.
TEST_F(AwPermissionManagerTest, SinglePermissionRequestIsGrantedSynchronously) { TEST_F(AwPermissionManagerTest, SinglePermissionRequestIsGrantedSynchronously) {

@ -700,6 +700,13 @@ public class WebsitePermissionsFetcherTest {
SITE_WILDCARD, SITE_WILDCARD,
/* isEmbargoed= */ false, /* isEmbargoed= */ false,
SessionModel.DURABLE)); SessionModel.DURABLE));
websitePreferenceBridge.addPermissionInfo(
new PermissionInfo(
ContentSettingsType.LOCAL_NETWORK_ACCESS,
ORIGIN,
SITE_WILDCARD,
/* isEmbargoed= */ false,
SessionModel.DURABLE));
// Add content setting exception types. // Add content setting exception types.
// If the ContentSettingsType.MAX_VALUE value changes *and* a new value has been exposed on // If the ContentSettingsType.MAX_VALUE value changes *and* a new value has been exposed on
@ -707,7 +714,7 @@ public class WebsitePermissionsFetcherTest {
// Otherwise, just update count in the assert. // Otherwise, just update count in the assert.
// TODO(https://b/332704817): Add test for Tracking Protection content setting after Android // TODO(https://b/332704817): Add test for Tracking Protection content setting after Android
// integration. // integration.
assertEquals(118, ContentSettingsType.MAX_VALUE); assertEquals(119, ContentSettingsType.MAX_VALUE);
websitePreferenceBridge.addContentSettingException( websitePreferenceBridge.addContentSettingException(
new ContentSettingException( new ContentSettingException(
ContentSettingsType.COOKIES, ContentSettingsType.COOKIES,
@ -881,6 +888,8 @@ public class WebsitePermissionsFetcherTest {
Assert.assertNotNull(site.getPermissionInfo(ContentSettingsType.VR)); Assert.assertNotNull(site.getPermissionInfo(ContentSettingsType.VR));
Assert.assertNotNull(site.getPermissionInfo(ContentSettingsType.HAND_TRACKING)); Assert.assertNotNull(site.getPermissionInfo(ContentSettingsType.HAND_TRACKING));
Assert.assertNotNull(site.getPermissionInfo(ContentSettingsType.AR)); Assert.assertNotNull(site.getPermissionInfo(ContentSettingsType.AR));
Assert.assertNotNull(
site.getPermissionInfo(ContentSettingsType.LOCAL_NETWORK_ACCESS));
// Check content setting exception types. // Check content setting exception types.
assertEquals( assertEquals(

@ -197,6 +197,7 @@ TEST_F(ControlledFramePermissionsTest, Verify) {
ARE_SUSPICIOUS_NOTIFICATIONS_ALLOWLISTED_BY_USER: ARE_SUSPICIOUS_NOTIFICATIONS_ALLOWLISTED_BY_USER:
case ContentSettingsType::CONTROLLED_FRAME: case ContentSettingsType::CONTROLLED_FRAME:
case ContentSettingsType::REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS: case ContentSettingsType::REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS:
case ContentSettingsType::LOCAL_NETWORK_ACCESS:
break; break;
default: default:
@ -254,6 +255,7 @@ TEST_F(ControlledFramePermissionsTest, Verify) {
case blink::PermissionType::AUTOMATIC_FULLSCREEN: case blink::PermissionType::AUTOMATIC_FULLSCREEN:
case blink::PermissionType::HAND_TRACKING: case blink::PermissionType::HAND_TRACKING:
case blink::PermissionType::WEB_APP_INSTALLATION: case blink::PermissionType::WEB_APP_INSTALLATION:
case blink::PermissionType::LOCAL_NETWORK_ACCESS:
break; break;
default: default:

@ -1035,6 +1035,8 @@ TEST_F(SafetyHubHandlerTest, RevokeAllContentSettingTypes) {
ContentSettingsType::CAMERA_PAN_TILT_ZOOM, ContentSettingsType::CAMERA_PAN_TILT_ZOOM,
ContentSettingsType::FILE_SYSTEM_ACCESS_EXTENDED_PERMISSION, ContentSettingsType::FILE_SYSTEM_ACCESS_EXTENDED_PERMISSION,
ContentSettingsType::POINTER_LOCK, ContentSettingsType::POINTER_LOCK,
// TODO(crbug.com/400455013): Remove once settings UI is added.
ContentSettingsType::LOCAL_NETWORK_ACCESS,
// clang-format on // clang-format on
}); });

@ -248,6 +248,8 @@ constexpr auto kContentSettingsTypeGroupNames = std::to_array<
// POINTER_LOCK has been deprecated. // POINTER_LOCK has been deprecated.
{ContentSettingsType::POINTER_LOCK, nullptr}, {ContentSettingsType::POINTER_LOCK, nullptr},
{ContentSettingsType::REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS, nullptr}, {ContentSettingsType::REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS, nullptr},
// TODO(crbug.com/400455013): Implement UI for LNA permission.
{ContentSettingsType::LOCAL_NETWORK_ACCESS, nullptr},
}); });
static_assert( static_assert(

@ -104,6 +104,7 @@ public class WebsitePermissionsFetcher {
case ContentSettingsType.PROTECTED_MEDIA_IDENTIFIER: case ContentSettingsType.PROTECTED_MEDIA_IDENTIFIER:
case ContentSettingsType.SENSORS: case ContentSettingsType.SENSORS:
case ContentSettingsType.VR: case ContentSettingsType.VR:
case ContentSettingsType.LOCAL_NETWORK_ACCESS:
return WebsitePermissionsType.PERMISSION_INFO; return WebsitePermissionsType.PERMISSION_INFO;
case ContentSettingsType.STORAGE_ACCESS: case ContentSettingsType.STORAGE_ACCESS:
return WebsitePermissionsType.EMBEDDED_PERMISSION; return WebsitePermissionsType.EMBEDDED_PERMISSION;

@ -860,6 +860,17 @@ void ContentSettingsRegistry::Init() {
WebsiteSettingsRegistry::PLATFORM_ANDROID, WebsiteSettingsRegistry::PLATFORM_ANDROID,
ContentSettingsInfo::INHERIT_IN_INCOGNITO, ContentSettingsInfo::INHERIT_IN_INCOGNITO,
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY); ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
Register(ContentSettingsType::LOCAL_NETWORK_ACCESS, "local-network-access",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
/*allowlisted_primary_schemes=*/{},
/*valid_settings=*/
{CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK, CONTENT_SETTING_ASK},
WebsiteSettingsInfo::TOP_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
WebsiteSettingsRegistry::PLATFORM_ANDROID,
ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE,
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
} }
void ContentSettingsRegistry::Register( void ContentSettingsRegistry::Register(

@ -154,6 +154,7 @@ constexpr auto kHistogramValue = base::MakeFixedFlatMap<ContentSettingsType,
132}, 132},
{ContentSettingsType::CONTROLLED_FRAME, 133}, {ContentSettingsType::CONTROLLED_FRAME, 133},
{ContentSettingsType::REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS, 134}, {ContentSettingsType::REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS, 134},
{ContentSettingsType::LOCAL_NETWORK_ACCESS, 135},
// As mentioned at the top, please don't forget to update ContentType in // As mentioned at the top, please don't forget to update ContentType in
// enums.xml when you add entries here! // enums.xml when you add entries here!

@ -479,5 +479,9 @@ enum ContentSettingsType {
// Website setting which is used for UnusedSitePermissionsService to // Website setting which is used for UnusedSitePermissionsService to
// store revoked notification permissions of disruptive sites. // store revoked notification permissions of disruptive sites.
REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS, REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS,
// Content setting for whether the site is allowed to make local network
// requests.
LOCAL_NETWORK_ACCESS,
}; };
// LINT.ThenChange(//components/content_settings/core/browser/content_settings_uma_util.cc:kHistogramValue) // LINT.ThenChange(//components/content_settings/core/browser/content_settings_uma_util.cc:kHistogramValue)

@ -212,6 +212,9 @@ bool PermissionUtil::GetPermissionType(ContentSettingsType type,
case ContentSettingsType::WEB_APP_INSTALLATION: case ContentSettingsType::WEB_APP_INSTALLATION:
*out = PermissionType::WEB_APP_INSTALLATION; *out = PermissionType::WEB_APP_INSTALLATION;
break; break;
case ContentSettingsType::LOCAL_NETWORK_ACCESS:
*out = PermissionType::LOCAL_NETWORK_ACCESS;
break;
default: default:
return false; return false;
} }
@ -384,6 +387,8 @@ ContentSettingsType PermissionUtil::PermissionTypeToContentSettingsTypeSafe(
return ContentSettingsType::AUTOMATIC_FULLSCREEN; return ContentSettingsType::AUTOMATIC_FULLSCREEN;
case PermissionType::WEB_APP_INSTALLATION: case PermissionType::WEB_APP_INSTALLATION:
return ContentSettingsType::WEB_APP_INSTALLATION; return ContentSettingsType::WEB_APP_INSTALLATION;
case PermissionType::LOCAL_NETWORK_ACCESS:
return ContentSettingsType::LOCAL_NETWORK_ACCESS;
case PermissionType::NUM: case PermissionType::NUM:
break; break;
} }

@ -207,6 +207,8 @@ Response PermissionDescriptorToPermissionType(
*permission_type = PermissionType::AUTOMATIC_FULLSCREEN; *permission_type = PermissionType::AUTOMATIC_FULLSCREEN;
} else if (name == "web-app-installation") { } else if (name == "web-app-installation") {
*permission_type = PermissionType::WEB_APP_INSTALLATION; *permission_type = PermissionType::WEB_APP_INSTALLATION;
} else if (name == "local-network-access") {
*permission_type = PermissionType::LOCAL_NETWORK_ACCESS;
} else { } else {
return Response::InvalidParams("Invalid PermissionDescriptor name: " + return Response::InvalidParams("Invalid PermissionDescriptor name: " +
name); name);
@ -300,6 +302,9 @@ Response FromProtocolPermissionType(
} else if (type == } else if (type ==
protocol::Browser::PermissionTypeEnum::WebAppInstallation) { protocol::Browser::PermissionTypeEnum::WebAppInstallation) {
*out_type = PermissionType::WEB_APP_INSTALLATION; *out_type = PermissionType::WEB_APP_INSTALLATION;
} else if (type ==
protocol::Browser::PermissionTypeEnum::LocalNetworkAccess) {
*out_type = PermissionType::LOCAL_NETWORK_ACCESS;
} else { } else {
return Response::InvalidParams("Unknown permission type: " + type); return Response::InvalidParams("Unknown permission type: " + type);
} }

@ -86,6 +86,7 @@ PermissionToSchedulingFeature(PermissionType permission_name) {
case PermissionType::POINTER_LOCK: case PermissionType::POINTER_LOCK:
case PermissionType::AUTOMATIC_FULLSCREEN: case PermissionType::AUTOMATIC_FULLSCREEN:
case PermissionType::WEB_APP_INSTALLATION: case PermissionType::WEB_APP_INSTALLATION:
case PermissionType::LOCAL_NETWORK_ACCESS:
return std::nullopt; return std::nullopt;
} }
} }

@ -76,6 +76,7 @@ bool IsAllowlistedPermissionType(PermissionType permission) {
case PermissionType::POINTER_LOCK: case PermissionType::POINTER_LOCK:
case PermissionType::AUTOMATIC_FULLSCREEN: case PermissionType::AUTOMATIC_FULLSCREEN:
case PermissionType::WEB_APP_INSTALLATION: case PermissionType::WEB_APP_INSTALLATION:
case PermissionType::LOCAL_NETWORK_ACCESS:
return false; return false;
} }

@ -34,4 +34,5 @@ Granted 'keyboardLock'
Granted 'pointerLock' Granted 'pointerLock'
Granted 'automaticFullscreen' Granted 'automaticFullscreen'
Granted 'handTracking' Granted 'handTracking'
Granted 'webAppInstallation' Granted 'webAppInstallation'
Granted 'localNetworkAccess'

@ -99,6 +99,8 @@ std::string GetPermissionString(PermissionType permission) {
return "AutomaticFullscreen"; return "AutomaticFullscreen";
case PermissionType::WEB_APP_INSTALLATION: case PermissionType::WEB_APP_INSTALLATION:
return "WebAppInstallation"; return "WebAppInstallation";
case PermissionType::LOCAL_NETWORK_ACCESS:
return "LocalNetworkAccess";
case PermissionType::NUM: case PermissionType::NUM:
NOTREACHED(); NOTREACHED();
} }
@ -171,6 +173,8 @@ PermissionTypeToPermissionsPolicyFeature(PermissionType permission) {
case PermissionType::NOTIFICATIONS: case PermissionType::NOTIFICATIONS:
case PermissionType::KEYBOARD_LOCK: case PermissionType::KEYBOARD_LOCK:
case PermissionType::POINTER_LOCK: case PermissionType::POINTER_LOCK:
// TODO(crbug.com/394009026): Add permission policy for LNA.
case PermissionType::LOCAL_NETWORK_ACCESS:
return std::nullopt; return std::nullopt;
case PermissionType::NUM: case PermissionType::NUM:
@ -307,6 +311,8 @@ std::optional<PermissionType> PermissionDescriptorInfoToPermissionType(
return std::nullopt; return std::nullopt;
case PermissionName::WEB_APP_INSTALLATION: case PermissionName::WEB_APP_INSTALLATION:
return PermissionType::WEB_APP_INSTALLATION; return PermissionType::WEB_APP_INSTALLATION;
case PermissionName::LOCAL_NETWORK_ACCESS:
return PermissionType::LOCAL_NETWORK_ACCESS;
default: default:
NOTREACHED(); NOTREACHED();
} }

@ -64,6 +64,7 @@ enum class PermissionType {
AUTOMATIC_FULLSCREEN = 40, AUTOMATIC_FULLSCREEN = 40,
HAND_TRACKING = 41, HAND_TRACKING = 41,
WEB_APP_INSTALLATION = 42, WEB_APP_INSTALLATION = 42,
LOCAL_NETWORK_ACCESS = 43,
// Always keep this at the end. // Always keep this at the end.
NUM, NUM,

@ -1481,6 +1481,7 @@ domain Browser
idleDetection idleDetection
keyboardLock keyboardLock
localFonts localFonts
localNetworkAccess
midi midi
midiSysex midiSysex
nfc nfc

@ -38,6 +38,7 @@ enum PermissionName {
POINTER_LOCK, POINTER_LOCK,
FULLSCREEN, FULLSCREEN,
WEB_APP_INSTALLATION, WEB_APP_INSTALLATION,
LOCAL_NETWORK_ACCESS,
}; };
struct MidiPermissionDescriptor { struct MidiPermissionDescriptor {

@ -42,6 +42,7 @@ enum PermissionName {
"pointer-lock", "pointer-lock",
"fullscreen", "fullscreen",
"web-app-installation", "web-app-installation",
"local-network-access",
}; };
// The PermissionDescriptor dictionary is a base to describe permissions. Some // The PermissionDescriptor dictionary is a base to describe permissions. Some

@ -133,6 +133,8 @@ String PermissionNameToString(PermissionName name) {
return "fullscreen"; return "fullscreen";
case PermissionName::WEB_APP_INSTALLATION: case PermissionName::WEB_APP_INSTALLATION:
return "web-app-installation"; return "web-app-installation";
case PermissionName::LOCAL_NETWORK_ACCESS:
return "local-network-access";
} }
} }

@ -2693,6 +2693,7 @@ Called by update_net_error_codes.py.-->
<int value="132" label="Are suspicious notifications allowlisted by user"/> <int value="132" label="Are suspicious notifications allowlisted by user"/>
<int value="133" label="Controlled Frame"/> <int value="133" label="Controlled Frame"/>
<int value="134" label="Revoked disruptive notification permissions"/> <int value="134" label="Revoked disruptive notification permissions"/>
<int value="135" label="Local network access"/>
</enum> </enum>
<!-- LINT.ThenChange(//components/content_settings/core/browser/content_settings_uma_util.cc:kHistogramValue) --> <!-- LINT.ThenChange(//components/content_settings/core/browser/content_settings_uma_util.cc:kHistogramValue) -->
@ -21586,6 +21587,7 @@ Called by update_net_error_codes.py.-->
<int value="32" label="PERMISSION_FILE_HANDLING__REMOVED_IN_M98"/> <int value="32" label="PERMISSION_FILE_HANDLING__REMOVED_IN_M98"/>
<int value="33" label="PERMISSION_TOP_LEVEL_STORAGE_ACCESS"/> <int value="33" label="PERMISSION_TOP_LEVEL_STORAGE_ACCESS"/>
<int value="34" label="PERMISSION_WEB_APP_INSTALLATION"/> <int value="34" label="PERMISSION_WEB_APP_INSTALLATION"/>
<int value="35" label="PERMISSION_LOCAL_NETWORK_ACCESS"/>
</enum> </enum>
<enum name="PIIType"> <enum name="PIIType">