Bug 1769791, part 1 - Remove support for setting permissions in mozprofile. r=jmaher

The only permission that is set is allowXULXBL, and we don't want
to set that by default, because we don't normally allow XUL in
web content. It can be enabled on an individual test by adding
allow_xul_xbl = true to a test manifest, or by using pushPermissions
within the test.

This also removes the noxul test server, because no XUL is now
the default behavior.

Differential Revision: https://phabricator.services.mozilla.com/D148136
This commit is contained in:
Andrew McCreight 2022-08-18 22:14:53 +00:00
parent d9c49a3262
commit a3fb85df7b
5 changed files with 8 additions and 314 deletions

View File

@ -94,7 +94,6 @@ http://sub1.test1.example.com:80 privileged
http://sub1.test2.example.com:80 privileged
http://sub2.test1.example.com:80 privileged
http://sub2.test2.example.com:80 privileged
http://noxul.example.com:80 privileged,noxul
http://example.net:80 privileged
http://supports-insecure.expired.example.com:80 privileged
# Used to test that clearing Service Workers for domain example.com, does not clear prefixexample.com

View File

@ -11,11 +11,9 @@ from __future__ import absolute_import
import codecs
import os
import sqlite3
from six import string_types
from six.moves.urllib import parse
import six
__all__ = [
"MissingPrimaryLocationError",
@ -128,8 +126,7 @@ class ServerLocations(object):
callback is called, if given.
"""
def __init__(self, filename=None, add_callback=None):
self.add_callback = add_callback
def __init__(self, filename=None):
self._locations = []
self.hasPrimary = False
if filename:
@ -141,15 +138,13 @@ class ServerLocations(object):
def __len__(self):
return len(self._locations)
def add(self, location, suppress_callback=False):
def add(self, location):
if "primary" in location.options:
if self.hasPrimary:
raise MultiplePrimaryLocationsError()
self.hasPrimary = True
self._locations.append(location)
if self.add_callback and not suppress_callback:
self.add_callback([location])
def add_host(self, host, port="80", scheme="http", options="privileged"):
if isinstance(options, string_types):
@ -205,7 +200,7 @@ class ServerLocations(object):
try:
location = Location(scheme, host, port, options)
self.add(location, suppress_callback=True)
self.add(location)
except LocationError as e:
raise LocationsSyntaxError(lineno, e)
@ -215,21 +210,15 @@ class ServerLocations(object):
if check_for_primary and not self.hasPrimary:
raise LocationsSyntaxError(lineno + 1, MissingPrimaryLocationError())
if self.add_callback:
self.add_callback(new_locations)
class Permissions(object):
"""Allows handling of permissions for ``mozprofile``"""
def __init__(self, profileDir, locations=None):
self._profileDir = profileDir
self._locations = ServerLocations(add_callback=self.write_db)
def __init__(self, locations=None):
self._locations = ServerLocations()
if locations:
if isinstance(locations, ServerLocations):
self._locations = locations
self._locations.add_callback = self.write_db
self.write_db(self._locations._locations)
elif isinstance(locations, list):
for l in locations:
self._locations.add_host(**l)
@ -238,82 +227,6 @@ class Permissions(object):
elif os.path.exists(locations):
self._locations.read(locations)
def write_db(self, locations):
"""write permissions to the sqlite database"""
# Open database and create table
permDB = sqlite3.connect(os.path.join(self._profileDir, "permissions.sqlite"))
cursor = permDB.cursor()
# SQL copied from
# http://searchfox.org/mozilla-central/source/extensions/permissions/PermissionManager.cpp
cursor.execute(
"""CREATE TABLE IF NOT EXISTS moz_hosts (
id INTEGER PRIMARY KEY
,origin TEXT
,type TEXT
,permission INTEGER
,expireType INTEGER
,expireTime INTEGER
,modificationTime INTEGER
)"""
)
rows = cursor.execute("PRAGMA table_info(moz_hosts)")
count = len(rows.fetchall())
using_origin = False
# if the db contains 7 columns, we're using user_version 5
if count == 7:
statement = "INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0)"
cursor.execute("PRAGMA user_version=5;")
using_origin = True
# if the db contains 9 columns, we're using user_version 4
elif count == 9:
statement = "INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0, 0)"
cursor.execute("PRAGMA user_version=4;")
# if the db contains 8 columns, we're using user_version 3
elif count == 8:
statement = "INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0)"
cursor.execute("PRAGMA user_version=3;")
else:
statement = "INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0)"
cursor.execute("PRAGMA user_version=2;")
for location in locations:
# set the permissions
permissions = {"allowXULXBL": "noxul" not in location.options}
for perm, allow in six.iteritems(permissions):
if allow:
permission_type = 1
else:
permission_type = 2
if using_origin:
# This is a crude approximation of the origin generation
# logic from ContentPrincipal and nsStandardURL. It should
# suffice for the permissions which the test runners will
# want to insert into the system.
origin = location.scheme + "://" + location.host
if (location.scheme != "http" or location.port != "80") and (
location.scheme != "https" or location.port != "443"
):
origin += ":" + str(location.port)
cursor.execute(statement, (origin, perm, permission_type))
else:
# The database is still using a legacy system based on hosts
# We can insert the permission as a host
#
# XXX This codepath should not be hit, as tests are run with
# fresh profiles. However, if it was hit, permissions would
# not be added to the database correctly (bug 1183185).
cursor.execute(statement, (location.host, perm, permission_type))
# Commit and close
permDB.commit()
cursor.close()
def network_prefs(self, proxy=None):
"""
take known locations and generate preferences to handle permissions and proxy
@ -411,22 +324,3 @@ function FindProxyForURL(url, host)
prefs.append(("network.proxy.autoconfig_url", pacURL))
return prefs
def clean_db(self):
"""Removed permissions added by mozprofile."""
sqlite_file = os.path.join(self._profileDir, "permissions.sqlite")
if not os.path.exists(sqlite_file):
return
# Open database and create table
permDB = sqlite3.connect(sqlite_file)
cursor = permDB.cursor()
# TODO: only delete values that we add, this would require sending
# in the full permissions object
cursor.execute("DROP TABLE IF EXISTS moz_hosts")
# Commit and close
permDB.commit()
cursor.close()

View File

@ -248,7 +248,7 @@ class Profile(BaseProfile):
# Set additional preferences
self.set_preferences(self._preferences)
self.permissions = Permissions(self.profile, self._locations)
self.permissions = Permissions(self._locations)
prefs_js, user_js = self.permissions.network_prefs(self._proxy)
if self._whitelistpaths:
@ -293,8 +293,6 @@ class Profile(BaseProfile):
self.clean_preferences()
if getattr(self, "addons", None) is not None:
self.addons.clean()
if getattr(self, "permissions", None) is not None:
self.permissions.clean_db()
super(Profile, self).cleanup()
def clean_preferences(self):

View File

@ -6,16 +6,12 @@
from __future__ import absolute_import
import os
import sqlite3
import mozunit
import pytest
from mozprofile.permissions import Permissions
LOCATIONS = """http://mochi.test:8888 primary,privileged
http://127.0.0.1:80 noxul
http://127.0.0.1:8888 privileged
"""
@ -29,54 +25,7 @@ def locations_file(tmpdir):
@pytest.fixture
def perms(tmpdir, locations_file):
return Permissions(tmpdir.mkdir("profile").strpath, locations_file)
def test_create_permissions_db(perms):
profile_dir = perms._profileDir
perms_db_filename = os.path.join(profile_dir, "permissions.sqlite")
select_stmt = "select origin, type, permission from moz_hosts"
con = sqlite3.connect(perms_db_filename)
cur = con.cursor()
cur.execute(select_stmt)
entries = cur.fetchall()
assert len(entries) == 3
assert entries[0][0] == "http://mochi.test:8888"
assert entries[0][1] == "allowXULXBL"
assert entries[0][2] == 1
assert entries[1][0] == "http://127.0.0.1"
assert entries[1][1] == "allowXULXBL"
assert entries[1][2] == 2
assert entries[2][0] == "http://127.0.0.1:8888"
assert entries[2][1] == "allowXULXBL"
assert entries[2][2] == 1
perms._locations.add_host("a.b.c", port="8081", scheme="https", options="noxul")
cur.execute(select_stmt)
entries = cur.fetchall()
assert len(entries) == 4
assert entries[3][0] == "https://a.b.c:8081"
assert entries[3][1] == "allowXULXBL"
assert entries[3][2] == 2
# when creating a DB we should default to user_version==5
cur.execute("PRAGMA user_version")
entries = cur.fetchall()
assert entries[0][0] == 5
perms.clean_db()
# table should be removed
cur.execute("select * from sqlite_master where type='table'")
entries = cur.fetchall()
assert len(entries) == 0
return Permissions(locations_file)
def test_nw_prefs(perms):
@ -92,7 +41,7 @@ def test_nw_prefs(perms):
origins_decl = (
"var knownOrigins = (function () { return ['http://mochi.test:8888', "
"'http://127.0.0.1:80', 'http://127.0.0.1:8888'].reduce"
"'http://127.0.0.1:8888'].reduce"
)
assert origins_decl in user_prefs[1][1]
@ -105,121 +54,5 @@ def test_nw_prefs(perms):
assert all(c in user_prefs[1][1] for c in proxy_check)
@pytest.fixture
def perms_db_filename(tmpdir):
return tmpdir.join("permissions.sqlite").strpath
@pytest.fixture
def permDB(perms_db_filename):
permDB = sqlite3.connect(perms_db_filename)
yield permDB
permDB.cursor().close()
# pylint: disable=W1638
@pytest.fixture(params=range(2, 6))
def version(request, perms_db_filename, permDB, locations_file):
version = request.param
cursor = permDB.cursor()
cursor.execute("PRAGMA user_version=%d;" % version)
if version == 5:
cursor.execute(
"""CREATE TABLE IF NOT EXISTS moz_hosts (
id INTEGER PRIMARY KEY,
origin TEXT,
type TEXT,
permission INTEGER,
expireType INTEGER,
expireTime INTEGER,
modificationTime INTEGER)"""
)
elif version == 4:
cursor.execute(
"""CREATE TABLE IF NOT EXISTS moz_hosts (
id INTEGER PRIMARY KEY,
host TEXT,
type TEXT,
permission INTEGER,
expireType INTEGER,
expireTime INTEGER,
modificationTime INTEGER,
appId INTEGER,
isInBrowserElement INTEGER)"""
)
elif version == 3:
cursor.execute(
"""CREATE TABLE IF NOT EXISTS moz_hosts (
id INTEGER PRIMARY KEY,
host TEXT,
type TEXT,
permission INTEGER,
expireType INTEGER,
expireTime INTEGER,
appId INTEGER,
isInBrowserElement INTEGER)"""
)
elif version == 2:
cursor.execute(
"""CREATE TABLE IF NOT EXISTS moz_hosts (
id INTEGER PRIMARY KEY,
host TEXT,
type TEXT,
permission INTEGER,
expireType INTEGER,
expireTime INTEGER)"""
)
else:
raise Exception("version must be 2, 3, 4 or 5")
permDB.commit()
# Create a permissions object to read the db
Permissions(os.path.dirname(perms_db_filename), locations_file)
return version
def test_verify_user_version(version, permDB):
"""Verifies that we call INSERT statements using the correct number
of columns for existing databases.
"""
select_stmt = "select * from moz_hosts"
cur = permDB.cursor()
cur.execute(select_stmt)
entries = cur.fetchall()
assert len(entries) == 3
columns = {
1: 6,
2: 6,
3: 8,
4: 9,
5: 7,
}[version]
assert len(entries[0]) == columns
for x in range(4, columns):
assert entries[0][x] == 0
def test_schema_version(perms, locations_file):
profile_dir = perms._profileDir
perms_db_filename = os.path.join(profile_dir, "permissions.sqlite")
perms.write_db(open(locations_file, "w+b"))
stmt = "PRAGMA user_version;"
con = sqlite3.connect(perms_db_filename)
cur = con.cursor()
cur.execute(stmt)
entries = cur.fetchall()
schema_version = entries[0][0]
assert schema_version == 5
if __name__ == "__main__":
mozunit.main()

View File

@ -117,35 +117,5 @@ def test_server_locations(create_temp_file):
assert exc.lineno == 4
def test_server_locations_callback(create_temp_file):
class CallbackTest(object):
last_locations = None
def callback(self, locations):
self.last_locations = locations
c = CallbackTest()
f = create_temp_file(LOCATIONS)
locations = ServerLocations(f, c.callback)
# callback should be for all locations in file
assert len(c.last_locations) == 6
# validate arbitrary one
compare_location(c.last_locations[2], "http", "127.0.0.1", "8888", ["privileged"])
locations.add_host("a.b.c")
# callback should be just for one location
assert len(c.last_locations) == 1
compare_location(c.last_locations[0], "http", "a.b.c", "80", ["privileged"])
# read a second file, which should generate a callback with both
# locations.
f = create_temp_file(LOCATIONS_NO_PRIMARY)
locations.read(f)
assert len(c.last_locations) == 2
if __name__ == "__main__":
mozunit.main()