def get_addon_akismet_reports(user, user_agent, referrer, upload=None, addon=None, data=None, existing_data=()): if not waffle.switch_is_active('akismet-spam-check'): return [] assert addon or upload properties = ('name', 'summary', 'description') if upload: addon = addon or upload.addon data = data or Addon.resolve_webext_translations( parse_addon(upload, addon, user, minimal=True), upload) reports = [] for prop in properties: locales = data.get(prop) if not locales: continue if isinstance(locales, dict): # Avoid spam checking the same value more than once by using a set. locale_values = set(locales.values()) else: # It's not a localized dict, it's a flat string; wrap it anyway. locale_values = {locales} for comment in locale_values: if not comment or comment in existing_data: # We don't want to submit empty or unchanged content continue report = AkismetReport.create_for_addon( upload=upload, addon=addon, user=user, property_name=prop, property_value=comment, user_agent=user_agent, referrer=referrer) reports.append((prop, report)) return reports
def check_xpi_info(xpi_info, addon=None, xpi_file=None): from olympia.addons.models import Addon, DeniedGuid guid = xpi_info['guid'] is_webextension = xpi_info.get('is_webextension', False) # If we allow the guid to be omitted we assume that one was generated # or existed before and use that one. # An example are WebExtensions that don't require a guid but we generate # one once they're uploaded. Now, if you update that WebExtension we # just use the original guid. if addon and not guid and is_webextension: xpi_info['guid'] = guid = addon.guid if not guid and not is_webextension: raise forms.ValidationError(ugettext('Could not find an add-on ID.')) if guid: current_user = core.get_user() if current_user: deleted_guid_clashes = Addon.unfiltered.exclude( authors__id=current_user.id).filter(guid=guid) else: deleted_guid_clashes = Addon.unfiltered.filter(guid=guid) if addon and addon.guid != guid: msg = ugettext( 'The add-on ID in your manifest.json or install.rdf (%s) ' 'does not match the ID of your add-on on AMO (%s)') raise forms.ValidationError(msg % (guid, addon.guid)) if (not addon and # Non-deleted add-ons. ( Addon.objects.filter(guid=guid).exists() or # DeniedGuid objects for legacy deletions. DeniedGuid.objects.filter(guid=guid).exists() or # Deleted add-ons that don't belong to the uploader. deleted_guid_clashes.exists())): raise forms.ValidationError(ugettext('Duplicate add-on ID found.')) if len(xpi_info['version']) > 32: raise forms.ValidationError( ugettext('Version numbers should have fewer than 32 characters.')) if not VERSION_RE.match(xpi_info['version']): raise forms.ValidationError( ugettext('Version numbers should only contain letters, numbers, ' 'and these punctuation characters: +*.-_.')) if is_webextension and xpi_info.get('type') == amo.ADDON_STATICTHEME: if not waffle.switch_is_active('allow-static-theme-uploads'): raise forms.ValidationError( ugettext( 'WebExtension theme uploads are currently not supported.')) if xpi_file: # Make sure we pass in a copy of `xpi_info` since # `resolve_webext_translations` modifies data in-place translations = Addon.resolve_webext_translations( xpi_info.copy(), xpi_file) verify_mozilla_trademark(translations['name'], core.get_user()) return xpi_info
def get_addon_akismet_reports(user, user_agent, referrer, upload=None, addon=None, data=None): if not waffle.switch_is_active('akismet-spam-check'): return [] assert addon or upload properties = ('name', 'summary', 'description') if upload: addon = addon or upload.addon data = data or Addon.resolve_webext_translations( parse_addon(upload, addon, user), upload) if not data: return [] # bail early if no data to skip Translation lookups if addon and addon.has_listed_versions(): translation_ids_gen = (getattr(addon, prop + '_id', None) for prop in properties) translation_ids = [id_ for id_ in translation_ids_gen if id_] # Just get all the values together to make it simplier existing_data = { text_type(value) for value in Translation.objects.filter(id__in=translation_ids) } else: existing_data = () reports = [] for prop in properties: locales = data.get(prop) if not locales: continue if isinstance(locales, dict): # Avoid spam checking the same value more than once by using a set. locale_values = set(locales.values()) else: # It's not a localized dict, it's a flat string; wrap it anyway. locale_values = {locales} for comment in locale_values: if not comment or comment in existing_data: # We don't want to submit empty or unchanged content continue reports.append( AkismetReport.create_for_addon(upload=upload, addon=addon, user=user, property_name=prop, property_value=comment, user_agent=user_agent, referrer=referrer)) return reports
def get_addon_akismet_reports(user, user_agent, referrer, upload=None, addon=None, data=None, existing_data=()): if not waffle.switch_is_active('akismet-spam-check'): return [] assert addon or upload properties = ('name', 'summary', 'description') if upload: addon = addon or upload.addon if not data: try: data = Addon.resolve_webext_translations( parse_addon(upload, addon, user, minimal=True), upload) except ValidationError: # The xpi is broken - it'll be rejected by the linter so abort. return [] reports = [] for prop in properties: locales = data.get(prop) if not locales: continue if isinstance(locales, dict): # Avoid spam checking the same value more than once by using a set. locale_values = set(locales.values()) else: # It's not a localized dict, it's a flat string; wrap it anyway. locale_values = {locales} for comment in locale_values: if not comment or comment in existing_data: # We don't want to submit empty or unchanged content continue report = AkismetReport.create_for_addon( upload=upload, addon=addon, user=user, property_name=prop, property_value=comment, user_agent=user_agent, referrer=referrer) reports.append((prop, report)) return reports
def check_xpi_info(xpi_info, addon=None, xpi_file=None, user=None): from olympia.addons.models import Addon, DeniedGuid guid = xpi_info['guid'] is_webextension = xpi_info.get('is_webextension', False) # If we allow the guid to be omitted we assume that one was generated # or existed before and use that one. # An example are WebExtensions that don't require a guid but we generate # one once they're uploaded. Now, if you update that WebExtension we # just use the original guid. if addon and not guid and is_webextension: xpi_info['guid'] = guid = addon.guid if not guid and not is_webextension: raise forms.ValidationError(ugettext('Could not find an add-on ID.')) if guid: current_user = core.get_user() if current_user: deleted_guid_clashes = Addon.unfiltered.exclude( authors__id=current_user.id).filter(guid=guid) else: deleted_guid_clashes = Addon.unfiltered.filter(guid=guid) if addon and addon.guid != guid: msg = ugettext( 'The add-on ID in your manifest.json or install.rdf (%s) ' 'does not match the ID of your add-on on AMO (%s)') raise forms.ValidationError(msg % (guid, addon.guid)) if (not addon and # Non-deleted add-ons. ( Addon.objects.filter(guid=guid).exists() or # DeniedGuid objects for deletions for Mozilla disabled add-ons DeniedGuid.objects.filter(guid=guid).exists() or # Deleted add-ons that don't belong to the uploader. deleted_guid_clashes.exists())): raise forms.ValidationError(ugettext('Duplicate add-on ID found.')) if len(xpi_info['version']) > 32: raise forms.ValidationError( ugettext('Version numbers should have fewer than 32 characters.')) if not VERSION_RE.match(xpi_info['version']): raise forms.ValidationError( ugettext('Version numbers should only contain letters, numbers, ' 'and these punctuation characters: +*.-_.')) if is_webextension and xpi_info.get('type') == amo.ADDON_STATICTHEME: max_size = settings.MAX_STATICTHEME_SIZE if xpi_file and os.path.getsize(xpi_file.name) > max_size: raise forms.ValidationError( ugettext( u'Maximum size for WebExtension themes is {0}.').format( filesizeformat(max_size))) if xpi_file: # Make sure we pass in a copy of `xpi_info` since # `resolve_webext_translations` modifies data in-place translations = Addon.resolve_webext_translations( xpi_info.copy(), xpi_file) verify_mozilla_trademark(translations['name'], core.get_user()) # Parse the file to get and validate package data with the addon. if not acl.submission_allowed(user, xpi_info): raise forms.ValidationError( ugettext(u'You cannot submit this type of add-on')) if not addon and not system_addon_submission_allowed(user, xpi_info): guids = ' or '.join('"' + guid + '"' for guid in amo.SYSTEM_ADDON_GUIDS) raise forms.ValidationError( ugettext(u'You cannot submit an add-on with a guid ending ' u'%s' % guids)) if not mozilla_signed_extension_submission_allowed(user, xpi_info): raise forms.ValidationError( ugettext(u'You cannot submit a Mozilla Signed Extension')) return xpi_info
def check_xpi_info(xpi_info, addon=None, xpi_file=None, user=None): from olympia.addons.models import Addon, DeniedGuid guid = xpi_info['guid'] is_webextension = xpi_info.get('is_webextension', False) # If we allow the guid to be omitted we assume that one was generated # or existed before and use that one. # An example are WebExtensions that don't require a guid but we generate # one once they're uploaded. Now, if you update that WebExtension we # just use the original guid. if addon and not guid and is_webextension: xpi_info['guid'] = guid = addon.guid if not guid and not is_webextension: raise forms.ValidationError(ugettext('Could not find an add-on ID.')) if guid: current_user = core.get_user() if current_user: deleted_guid_clashes = Addon.unfiltered.exclude( authors__id=current_user.id).filter(guid=guid) else: deleted_guid_clashes = Addon.unfiltered.filter(guid=guid) if addon and addon.guid != guid: msg = ugettext( 'The add-on ID in your manifest.json or install.rdf (%s) ' 'does not match the ID of your add-on on AMO (%s)') raise forms.ValidationError(msg % (guid, addon.guid)) if (not addon and # Non-deleted add-ons. (Addon.objects.filter(guid=guid).exists() or # DeniedGuid objects for deletions for Mozilla disabled add-ons DeniedGuid.objects.filter(guid=guid).exists() or # Deleted add-ons that don't belong to the uploader. deleted_guid_clashes.exists())): raise forms.ValidationError(ugettext('Duplicate add-on ID found.')) if len(xpi_info['version']) > 32: raise forms.ValidationError( ugettext('Version numbers should have fewer than 32 characters.')) if not VERSION_RE.match(xpi_info['version']): raise forms.ValidationError( ugettext('Version numbers should only contain letters, numbers, ' 'and these punctuation characters: +*.-_.')) if is_webextension and xpi_info.get('type') == amo.ADDON_STATICTHEME: if not waffle.switch_is_active('allow-static-theme-uploads'): raise forms.ValidationError(ugettext( 'WebExtension theme uploads are currently not supported.')) if xpi_file: # Make sure we pass in a copy of `xpi_info` since # `resolve_webext_translations` modifies data in-place translations = Addon.resolve_webext_translations( xpi_info.copy(), xpi_file) verify_mozilla_trademark(translations['name'], core.get_user()) # Parse the file to get and validate package data with the addon. if not acl.submission_allowed(user, xpi_info): raise forms.ValidationError( ugettext(u'You cannot submit this type of add-on')) if not addon and not system_addon_submission_allowed( user, xpi_info): guids = ' or '.join( '"' + guid + '"' for guid in amo.SYSTEM_ADDON_GUIDS) raise forms.ValidationError( ugettext(u'You cannot submit an add-on with a guid ending ' u'%s' % guids)) if not mozilla_signed_extension_submission_allowed(user, xpi_info): raise forms.ValidationError( ugettext(u'You cannot submit a Mozilla Signed Extension')) return xpi_info
def check_xpi_info(xpi_info, addon=None, xpi_file=None, user=None): from olympia.addons.models import Addon, DeniedGuid guid = xpi_info['guid'] # If we allow the guid to be omitted we assume that one was generated # or existed before and use that one. # An example are WebExtensions that don't require a guid but we generate # one once they're uploaded. Now, if you update that WebExtension we # just use the original guid. if addon and not guid: xpi_info['guid'] = guid = addon.guid if guid: if user and waffle.switch_is_active('allow-deleted-guid-reuse'): deleted_guid_clashes = Addon.unfiltered.exclude( authors__id=user.id).filter(guid=guid) else: deleted_guid_clashes = Addon.unfiltered.filter(guid=guid) if addon and addon.guid != guid: msg = gettext('The add-on ID in your manifest.json (%s) ' 'does not match the ID of your add-on on AMO (%s)') raise forms.ValidationError(msg % (guid, addon.guid)) if not addon and ( # Non-deleted add-ons. Addon.objects.filter(guid=guid).exists() # DeniedGuid objects for deletions for Mozilla disabled add-ons or DeniedGuid.objects.filter(guid=guid).exists() # Deleted add-ons that don't belong to the uploader (or deleted # add-ons period if `allow-deleted-guid-reuse` waffle switch is # inactive). or deleted_guid_clashes.exists()): raise forms.ValidationError(gettext('Duplicate add-on ID found.')) if len(xpi_info['version']) > 32: raise forms.ValidationError( gettext('Version numbers should have fewer than 32 characters.')) if not VERSION_RE.match(xpi_info['version']): raise forms.ValidationError( gettext('Version numbers should only contain letters, numbers, ' 'and these punctuation characters: +*.-_.')) if xpi_info.get('type') == amo.ADDON_STATICTHEME: max_size = settings.MAX_STATICTHEME_SIZE if xpi_file and xpi_file.size > max_size: raise forms.ValidationError( gettext('Maximum size for WebExtension themes is {0}.').format( filesizeformat(max_size))) if xpi_file: # Make sure we pass in a copy of `xpi_info` since # `resolve_webext_translations` modifies data in-place translations = Addon.resolve_webext_translations( xpi_info.copy(), xpi_file) verify_mozilla_trademark(translations['name'], user) # Parse the file to get and validate package data with the addon. if not acl.experiments_submission_allowed(user, xpi_info): raise forms.ValidationError( gettext('You cannot submit this type of add-on')) if not addon and not acl.reserved_guid_addon_submission_allowed( user, xpi_info): raise forms.ValidationError( gettext( 'You cannot submit an add-on using an ID ending with this suffix' )) if not acl.mozilla_signed_extension_submission_allowed(user, xpi_info): raise forms.ValidationError( gettext('You cannot submit a Mozilla Signed Extension')) if (not addon and guid and guid.lower().endswith(amo.RESERVED_ADDON_GUIDS) and not xpi_info.get('is_mozilla_signed_extension')): raise forms.ValidationError( gettext( 'Add-ons using an ID ending with this suffix need to be signed with ' 'privileged certificate before being submitted')) if not acl.langpack_submission_allowed(user, xpi_info): raise forms.ValidationError( gettext('You cannot submit a language pack')) if not acl.site_permission_addons_submission_allowed(user, xpi_info): raise forms.ValidationError( gettext('You cannot submit this type of add-on')) return xpi_info