remove webextension permission descriptions (#10514)

This commit is contained in:
Andrew Williamson 2019-01-28 18:15:56 +08:00 коммит произвёл GitHub
Родитель 715b221626
Коммит 3290551aa9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 9 добавлений и 425 удалений

Просмотреть файл

@ -86,7 +86,6 @@ initialize_db:
schematic --fake src/olympia/migrations/
$(PYTHON_COMMAND) manage.py createsuperuser
$(PYTHON_COMMAND) manage.py loaddata zadmin/users
$(PYTHON_COMMAND) manage.py update_permissions_from_mc
populate_data:
# reindex --wipe will force the ES mapping to be re-installed. Useful to
@ -104,7 +103,6 @@ populate_data:
$(PYTHON_COMMAND) manage.py reindex --force --noinput
# Also update category counts (denormalized field)
$(PYTHON_COMMAND) manage.py cron category_totals
$(PYTHON_COMMAND) manage.py update_permissions_from_mc
cleanup_python_build_dir:
# Work arounds "Multiple .dist-info directories" issue.
@ -146,7 +144,6 @@ update_assets:
$(PYTHON_COMMAND) manage.py generate_jsi18n_files
update: update_deps update_db update_assets
$(PYTHON_COMMAND) manage.py update_permissions_from_mc
reindex:
$(PYTHON_COMMAND) manage.py reindex $(ARGS)
@ -164,7 +161,6 @@ setup-ui-tests:
$(PYTHON_COMMAND) manage.py loaddata src/olympia/access/fixtures/initial.json
$(PYTHON_COMMAND) manage.py import_prod_versions
$(PYTHON_COMMAND) manage.py update_permissions_from_mc
# Create a proper superuser that can be used to access the API
$(PYTHON_COMMAND) manage.py waffle_switch super-create-accounts on --create

Просмотреть файл

@ -1426,7 +1426,7 @@ class Addon(OnChangeMixin, ModelBase):
return (self.type == amo.ADDON_EXTENSION and
version and version.all_files[0] and
(not version.all_files[0].is_webextension or
version.all_files[0].webext_permissions))
version.all_files[0].webext_permissions_list))
@property
def needs_admin_code_review(self):

Просмотреть файл

@ -280,7 +280,7 @@
<a href="#" class="close">{{ _('close') }}</a>
<h2>{{ _('Permissions') }}</h2>
{% if addon.current_version.all_files[0].is_webextension %}
{% set permissions = addon.current_version.all_files[0].webext_permissions %}
{% set permissions = addon.current_version.all_files[0].webext_permissions_list %}
<div class="prose">
<p>
{{ _('Some add-ons ask for permission to perform certain functions (example: a tab management add-on will ask permission to access your browsers tab system).') }}
@ -294,7 +294,7 @@
<h3>{{ _('This add-on can:') }}</h3>
<ul class="webext-permissions-list">
{% for perm in permissions %}
<li class="webext-permissions-list">{{ perm.description|e }}</li>
<li class="webext-permissions-list">{{ perm|e }}</li>
{% endfor %}
</ul>
</p>

Просмотреть файл

@ -37,7 +37,7 @@ from olympia.amo.urlresolvers import get_outgoing_url, reverse
from olympia.bandwagon.models import Collection, FeaturedCollection
from olympia.constants.categories import CATEGORIES, CATEGORIES_BY_ID
from olympia.constants.licenses import LICENSES_BY_BUILTIN
from olympia.files.models import WebextPermission, WebextPermissionDescription
from olympia.files.models import WebextPermission
from olympia.ratings.models import Rating
from olympia.users.models import UserProfile
from olympia.users.templatetags.jinja_helpers import users_list
@ -479,34 +479,6 @@ class TestDetailPage(TestCase):
privacy_url = reverse('addons.privacy', args=[self.addon.slug])
assert doc('.privacy-policy').attr('href').endswith(privacy_url)
def test_permissions_webext(self):
file_ = self.addon.current_version.all_files[0]
file_.update(is_webextension=True)
WebextPermission.objects.create(file=file_, permissions=[
u'http://*/*', u'<all_urls>', u'bookmarks', u'nativeMessaging',
u'made up permission'])
WebextPermissionDescription.objects.create(
name=u'bookmarks', description=u'Read and modify bookmarks')
WebextPermissionDescription.objects.create(
name=u'nativeMessaging',
description=u'Exchange messages with programs other than Firefox')
response = self.client.get(self.url)
doc = pq(response.content)
# The link next to the button
assert doc('a.webext-permissions').length == 1
# And the model dialog
assert doc('#webext-permissions').length == 1
assert u'perform certain functions (example: a tab management' in (
doc('#webext-permissions div.prose').text())
assert doc('ul.webext-permissions-list').length == 1
assert doc('li.webext-permissions-list').length == 3
# See File.webext_permissions for the order logic
assert doc('li.webext-permissions-list').text() == (
u'Access your data for all websites '
u'Exchange messages with programs other than Firefox '
u'Read and modify bookmarks')
def test_permissions_webext_no_permissions(self):
file_ = self.addon.current_version.all_files[0]
file_.update(is_webextension=True)
@ -552,7 +524,6 @@ class TestDetailPage(TestCase):
response = self.client.get(self.url)
doc = pq(response.content)
assert doc('li.webext-permissions-list').text() == (
u'Access your data for '
u'<script>alert("//")</script>')
assert b'<script>alert(' not in response.content
assert b'&lt;script&gt;alert(' in response.content
@ -566,8 +537,7 @@ class TestDetailPage(TestCase):
response = self.client.get(self.url)
doc = pq(response.content)
assert doc('li.webext-permissions-list').text() == (
u'Access your data on the following websites:\n'
u'<script>alert("//")</script>\n'
u'<script>alert("//")</script> '
u'<script>foo("https://")</script>')
assert b'<script>alert(' not in response.content
assert b'<script>foo(' not in response.content

Просмотреть файл

@ -1,34 +0,0 @@
# -*- coding: utf-8 -*-
from django.conf import settings
from django.core.management.base import BaseCommand
from olympia.files.models import WebextPermissionDescription
from olympia.files.tasks import update_webext_descriptions_all
class Command(BaseCommand):
help = ('Download and update webextension permission descriptions from '
'mozilla-central.')
def add_arguments(self, parser):
"""Handle command arguments."""
parser.add_argument(
'--clear',
action='store_true',
dest='clear',
default=False,
help='Clear existing descriptions in the database first.')
def handle(self, *args, **options):
if options['clear']:
WebextPermissionDescription.objects.all().delete()
central_url = settings.WEBEXT_PERM_DESCRIPTIONS_URL
locales_url = settings.WEBEXT_PERM_DESCRIPTIONS_LOCALISED_URL
amo_locales = [l for l in settings.AMO_LANGUAGES
if l not in ('en-US',)]
# Fetch canonical en-US descriptions first; then l10n after.
update_webext_descriptions_all.apply_async(
args=[(central_url, 'en-US'),
[(locales_url.format(locale=locale), locale)
for locale in amo_locales]])

Просмотреть файл

@ -8,8 +8,6 @@ import unicodedata
import uuid
import zipfile
from collections import namedtuple
from django.core.files.storage import default_storage as storage
from django.db import models
from django.dispatch import receiver
@ -17,14 +15,11 @@ from django.template.defaultfilters import slugify
from django.utils.encoding import (
force_bytes, force_text, python_2_unicode_compatible)
from django.utils.functional import cached_property
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext, ugettext_lazy as _
import six
from django_extensions.db.fields.json import JSONField
from django_statsd.clients import statsd
from jinja2 import escape as jinja2_escape
import olympia.core.logger
@ -39,7 +34,6 @@ from olympia.amo.urlresolvers import reverse
from olympia.applications.models import AppVersion
from olympia.files.utils import SafeZip, get_sha256, write_crx_as_xpi
from olympia.lib.cache import memoize
from olympia.translations.fields import TranslatedField
log = olympia.core.logger.getLogger('z.files')
@ -373,52 +367,6 @@ class File(OnChangeMixin, ModelBase):
statsd.timing('files.extract.localepicker', (end * 1000))
return res
@property
def webext_permissions(self):
"""Return permissions that should be displayed, with descriptions, in
defined order:
1) Either the match all permission, if present (e.g. <all-urls>), or
match urls for sites (<all-urls> takes preference over match urls)
2) nativeMessaging permission, if present
3) other known permissions in alphabetical order
"""
knowns = list(WebextPermissionDescription.objects.filter(
name__in=self.webext_permissions_list))
urls = []
match_url = None
for name in self.webext_permissions_list:
if re.match(WebextPermissionDescription.MATCH_ALL_REGEX, name):
match_url = WebextPermissionDescription.ALL_URLS_PERMISSION
elif name == WebextPermission.NATIVE_MESSAGING_NAME:
# Move nativeMessaging to front of the list
for index, perm in enumerate(knowns):
if perm.name == WebextPermission.NATIVE_MESSAGING_NAME:
knowns.pop(index)
knowns.insert(0, perm)
break
elif '//' in name:
# Filter out match urls so we can group them.
urls.append(name)
# Other strings are unknown permissions we don't care about
if match_url is None and len(urls) == 1:
match_url = Permission(
u'single-match',
ugettext(u'Access your data for {name}')
.format(name=urls[0]))
elif match_url is None and len(urls) > 1:
details = (u'<details><summary>{copy}</summary><ul>{sites}</ul>'
u'</details>')
copy = ugettext(u'Access your data on the following websites:')
sites = ''.join(
[u'<li>%s</li>' % jinja2_escape(name) for name in urls])
match_url = Permission(
u'multiple-match',
mark_safe(details.format(copy=copy, sites=sites)))
return ([match_url] if match_url else []) + knowns
@cached_property
def webext_permissions_list(self):
if not self.is_webextension:
@ -748,24 +696,6 @@ class WebextPermission(ModelBase):
db_table = 'webext_permissions'
Permission = namedtuple('Permission',
'name, description')
class WebextPermissionDescription(ModelBase):
MATCH_ALL_REGEX = r'^\<all_urls\>|(\*|http|https):\/\/\*\/'
ALL_URLS_PERMISSION = Permission(
u'all_urls',
_(u'Access your data for all websites')
)
name = models.CharField(max_length=255, unique=True)
description = TranslatedField()
class Meta:
db_table = 'webext_permission_descriptions'
ordering = ['name']
def nfd_str(u):
"""Uses NFD to normalize unicode strings."""
if isinstance(u, six.text_type):

Просмотреть файл

@ -1,20 +1,11 @@
import re
from django.conf import settings
from django.utils import translation
import requests
from requests.exceptions import RequestException
import olympia.core.logger
from olympia.amo.celery import task
from olympia.amo.decorators import use_primary_db
from olympia.files.models import (
File, WebextPermission, WebextPermissionDescription)
from olympia.files.models import File, WebextPermission
from olympia.files.utils import parse_xpi
from olympia.translations.models import Translation
from olympia.users.models import UserProfile
@ -47,60 +38,3 @@ def extract_webext_permissions(ids, **kw):
defaults={'permissions': permissions}, file=file_)
except Exception as err:
log.error('Failed to extract: %s, error: %s' % (file_.pk, err))
WEBEXTPERMS_DESCRIPTION_REGEX = r'^webextPerms\.description\.(.+)=(.+)'
@task
@use_primary_db
def update_webext_descriptions_all(primary, additional, **kw):
"""primary is a (url, locale) tuple; additional is a list of tuples."""
url, locale = primary
update_webext_descriptions(url, locale)
for url, locale in additional:
update_webext_descriptions(url, locale, create=False)
def update_webext_descriptions(url, locale='en-US', create=True, **kw):
class DummyContextManager(object):
def __enter__(self):
pass
def __exit__(*x):
pass
log.info('Updating webext permission descriptions in [%s] from %s' %
(locale, url))
try:
response = requests.get(url)
response.raise_for_status()
except RequestException as e:
log.warning('Error retrieving %s: %s' % (url, e))
return
# We only need to activate the locale for creating new permission objects.
context = translation.override(locale) if create else DummyContextManager()
with context:
for line in response.text.splitlines():
match = re.match(WEBEXTPERMS_DESCRIPTION_REGEX, line)
if match:
(perm, description) = match.groups()
description = description.replace('%S', u'Firefox')
if create:
log.info(u'Adding permission "%s" = "%s"' %
(perm, description))
WebextPermissionDescription.objects.update_or_create(
name=perm, defaults={'description': description})
else:
log.info(u'Updating permission "%s" = "%s" for [%s]' %
(perm, description, locale))
try:
perm_obj = WebextPermissionDescription.objects.get(
name=perm)
Translation.objects.update_or_create(
id=perm_obj.description_id, locale=locale.lower(),
defaults={'localized_string': description})
except WebextPermissionDescription.DoesNotExist:
log.warning('No "%s" permission found to update with '
'[%s] locale' % (perm, locale))

Просмотреть файл

@ -1,23 +1,15 @@
# -*- coding: utf-8 -*-
from django.conf import settings
from django.core.management import call_command
from django.test.utils import override_settings
from django.utils import translation
import mock
import responses
from requests import HTTPError
from olympia import amo
from olympia.addons.models import Addon
from olympia.amo.tests import TestCase
from olympia.applications.models import AppVersion
from olympia.files.models import (
File, WebextPermission, WebextPermissionDescription)
from olympia.files.models import File, WebextPermission
from olympia.files.tests.test_models import UploadTest
from olympia.files.utils import parse_addon
from olympia.translations.models import Translation
from olympia.versions.models import Version
from olympia.users.models import UserProfile
@ -77,138 +69,3 @@ class TestWebextExtractPermissions(UploadTest):
file_ = File.objects.get(id=file_.id)
assert WebextPermission.objects.get(file=file_)
assert len(file_.webext_permissions_list) == 8
@override_settings(AMO_LANGUAGES=('fr', 'de', 'elvish', 'zh-CN'))
class TestWebextUpdateDescriptions(TestCase):
def _register_uris(self):
responses.add(
responses.GET, settings.WEBEXT_PERM_DESCRIPTIONS_URL,
content_type='text/plain; charset="UTF-8"',
body=u'\n'.join([
u'webextPerms.description.bookmarks=Read and modify bookmarks',
u'webextPerms.description.geolocation=Access your location',
u'webextPerms.description.tabs=Access browser tabs',
u'webextPerms.description.nativeMessaging=' # no linebreak
u'Exchange messages with programs other than %S']))
localised_url = settings.WEBEXT_PERM_DESCRIPTIONS_LOCALISED_URL
responses.add(
responses.GET,
localised_url.format(locale='fr'),
content_type='text/plain; charset="UTF-8"',
body=u'\n'.join([
u'webextPerms.description.bookmarks=Réad n wríte le bookmarks',
u'webextPerms.description.tabs=Accéder browser onglets']))
responses.add(
responses.GET,
localised_url.format(locale='de'),
content_type='text/plain; charset="UTF-8"',
body=u'\n'.join([
u'webextPerms.description.bookmarks=Eich bin bookmark',
u'webextPerms.description.tabs=']))
responses.add(
responses.GET,
localised_url.format(locale='zh-CN'),
content_type='text/plain; charset="UTF-8"',
body=u'\n'.join([
u'webextPerms.description.bookmarks=讀取並修改書籤',
u'webextPerms.description.sessions=存取瀏覽器最近關閉的分頁',
u'webextPerms.description.nativeMessaging=' # no linebreak
u'%S 以外的程式交換訊息']))
responses.add(
responses.GET,
localised_url.format(locale='elvish'),
body=HTTPError('Only the tongues of men are spoken here'))
def _check_objects(self):
assert WebextPermissionDescription.objects.get(
name='bookmarks').description == u'Read and modify bookmarks'
assert WebextPermissionDescription.objects.get(
name='geolocation').description == u'Access your location'
assert WebextPermissionDescription.objects.get(
name='tabs').description == u'Access browser tabs'
# %S in the description is replaced with Firefox.
assert WebextPermissionDescription.objects.get(
name='nativeMessaging').description == (
u'Exchange messages with programs other than Firefox')
def _check_locales(self):
with translation.override('fr'):
assert WebextPermissionDescription.objects.get(
name='bookmarks').description == u'Réad n wríte le bookmarks'
# There wasn't any French l10n for this perm; so en fallback.
assert WebextPermissionDescription.objects.get(
name='geolocation').description == u'Access your location'
assert WebextPermissionDescription.objects.get(
name='tabs').description == u'Accéder browser onglets'
with translation.override('de'):
assert WebextPermissionDescription.objects.get(
name='bookmarks').description == u'Eich bin bookmark'
# There wasn't any German l10n for this perm; so en fallback.
assert WebextPermissionDescription.objects.get(
name='geolocation').description == u'Access your location'
# There was an empty German l10n; so en fallback
assert WebextPermissionDescription.objects.get(
name='tabs').description == u'Access browser tabs'
with translation.override('zh-CN'):
assert WebextPermissionDescription.objects.get(
name='bookmarks').description == u'讀取並修改書籤'
# There wasn't any Chinese l10n for this perm; so en fallback.
assert WebextPermissionDescription.objects.get(
name='geolocation').description == u'Access your location'
# There wasn't any Chinese l10n; so en fallback
assert WebextPermissionDescription.objects.get(
name='tabs').description == u'Access browser tabs'
# %S replaced with Firefox in 110ns too.
assert WebextPermissionDescription.objects.get(
name='nativeMessaging').description == (
u'與 Firefox 以外的程式交換訊息')
# Chinese had an extra localisation, check it was ignored.
assert not Translation.objects.filter(
localized_string=u'存取瀏覽器最近關閉的分頁').exists()
# Confirm that all the bookmark localisations were saved.
bookmarks_perm = WebextPermissionDescription.objects.get(
name='bookmarks')
assert Translation.objects.filter(
id=bookmarks_perm.description_id).count() == 4
# Check we didn't save any translation for unsupported (klingon) locale
assert not Translation.objects.filter(
locale='klingon').exists()
def test_add_descriptions(self):
self._register_uris()
assert WebextPermissionDescription.objects.count() == 0
# Add an existing permission that won't be updated.
WebextPermissionDescription.objects.create(
name='oldpermission', description=u'somethunk craaazie')
# Add a permission that will be updated.
WebextPermissionDescription.objects.create(
name='bookmarks', description=u'Not updating your bookmarks!')
call_command('update_permissions_from_mc')
assert WebextPermissionDescription.objects.count() == 5
self._check_objects()
self._check_locales()
# Existing permission is still there.
assert WebextPermissionDescription.objects.filter(
name='oldpermission').exists()
def test_clear_then_add_descriptions(self):
self._register_uris()
# Add an existing permission that won't be updated and will be cleared.
WebextPermissionDescription.objects.create(
name='oldpermission', description='somethunk craaazie')
assert WebextPermissionDescription.objects.filter(
name='oldpermission').exists()
call_command('update_permissions_from_mc', clear=True)
assert WebextPermissionDescription.objects.count() == 4
self._check_objects()
# Existing permission is cleared.
assert not WebextPermissionDescription.objects.filter(
name='oldpermission').exists()

Просмотреть файл

@ -24,8 +24,8 @@ from olympia.amo.tests import TestCase, user_factory
from olympia.amo.utils import chunked
from olympia.applications.models import AppVersion
from olympia.files.models import (
EXTENSIONS, File, FileUpload, FileValidation, Permission, WebextPermission,
WebextPermissionDescription, nfd_str, track_file_status_change)
EXTENSIONS, File, FileUpload, FileValidation, WebextPermission,
nfd_str, track_file_status_change)
from olympia.files.utils import (
Extractor, check_xpi_info, parse_addon, parse_xpi)
from olympia.versions.models import Version
@ -256,68 +256,6 @@ class TestFile(TestCase, amo.tests.AMOPaths):
return (perm_a.name == perm_b.name and
perm_a.description == perm_b.description)
def test_webext_permissions_order(self):
perm_list = [u'tabs', u'bookmarks', u'nativeMessaging',
u'made up permission', u'https://google.com/']
WebextPermissionDescription.objects.create(
name=u'bookmarks', description=u'Read and modify bookmarks')
WebextPermissionDescription.objects.create(
name=u'tabs', description=u'Access browser tabs')
WebextPermissionDescription.objects.create(
name=u'nativeMessaging',
description=u'Exchange messages with programs other than Firefox')
result = [
# First match urls for specified site(s).
Permission('single-match',
'Access your data for https://google.com/'),
# Then nativeMessaging, if specified
Permission(u'nativeMessaging',
u'Exchange messages with programs other than Firefox'),
# Then any other known permission(s).
Permission(u'bookmarks',
u'Read and modify bookmarks'),
Permission(u'tabs',
u'Access browser tabs'),
]
file_ = File.objects.get(pk=67442)
file_.webext_permissions_list = perm_list
# Check the order
assert len(file_.webext_permissions) == len(result)
assert all(map(self._cmp_permission, result,
file_.webext_permissions))
# Check the order isn't dependent on the order in the manifest
file_.webext_permissions_list.reverse()
assert all(map(self._cmp_permission, result,
file_.webext_permissions))
# Unknown permission strings aren't included.
assert ((u'made up permission', u'made up permission')
not in file_.webext_permissions)
def test_webext_permissions_match_urls(self):
file_ = File.objects.get(pk=67442)
# Multiple urls for specified sites should be grouped together
file_.webext_permissions_list = [
u'https://mozilla.org/', u'https://mozillians.org/']
assert len(file_.webext_permissions) == 1
perm = file_.webext_permissions[0]
assert perm.name == u'multiple-match'
assert perm.description == (
u'<details><summary>Access your data on the following websites:'
u'</summary><ul><li>https://mozilla.org/</li>'
u'<li>https://mozillians.org/</li></ul></details>')
file_.webext_permissions_list += [u'http://*/*', u'<all_urls>']
# Match-all patterns should override the specific sites
assert len(file_.webext_permissions) == 1
assert file_.webext_permissions[0] == (
WebextPermissionDescription.ALL_URLS_PERMISSION)
def test_webext_permissions_list_string_only(self):
file_ = File.objects.get(pk=67442)
file_.update(is_webextension=True)

Просмотреть файл

@ -1799,13 +1799,6 @@ SHELL_PLUS_POST_IMPORTS = (
DEFAULT_FXA_CONFIG_NAME = 'default'
ALLOWED_FXA_CONFIGS = ['default']
WEBEXT_PERM_DESCRIPTIONS_URL = (
'https://hg.mozilla.org/mozilla-central/raw-file/tip/'
'browser/locales/en-US/chrome/browser/browser.properties')
WEBEXT_PERM_DESCRIPTIONS_LOCALISED_URL = (
'https://hg.mozilla.org/l10n-central/{locale}/raw-file/tip/'
'browser/chrome/browser/browser.properties')
# List all jobs that should be callable with cron here.
# syntax is: job_and_method_name: full.package.path
CRON_JOBS = {