def revision_add_attachment(request, pk): """Add attachment, download if necessary """ revision = get_object_or_404(PackageRevision, pk=pk) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to add attachment to package (%s) by " "non-owner (%s)" % (revision.package, request.user)) log.warning(log_msg) return HttpResponseForbidden( 'You are not the author of this %s' % escape( revision.package.get_type_name())) url = request.POST.get('url', None) filename = request.POST.get('filename', None) if not filename or filename == "": log.error('Trying to create an attachment without name') return HttpResponseBadRequest('Path not found.') content = '' if url: log.info(('[%s] Preparing to download %s as an attachment of ' 'PackageRevision %d') % (filename, url, revision.pk)) # validate url field = URLField(verify_exists=True) encoding = request.POST.get('force_contenttype', False) try: url = field.clean(url) except ValidationError, err: log.warning('[%s] Invalid url provided\n%s' % (url, '\n'.join(err.messages))) return HttpResponseBadRequest(("Loading attachment failed\n" "%s") % parse_validation_messages(err)) except Exception, err: log.warning('[%s] Exception raised\n%s' % (url, str(err))) return HttpResponseBadRequest(str(err))
def _get_registered_user(directory, request): """Checks the directory for a registered user. Function returns a tuple of registered and details. Registered is True if a user is found and False otherwise. If registered is True then details contains info about the known user. The statsd timer ``larper.sasl_bind_time`` allows IT to detect timeouts between ldap and https://browserid.org/verify. If this counter gets large, check DNS routes between slapd servers and browserid.org. The statsd counter ``browserid.unknown_error_checking_registered_user`` allows IT to detect a problem with the backend auth system. """ registered = False details = None try: (registered, details) = directory.registered_user() if registered: request.session['unique_id'] = details else: request.session['verified_email'] = details except Exception, e: # Look at syslogs on slapd hosts to investigate unknown issues messages.error(request, _("We're Sorry, but Something Went Wrong!")) statsd.incr('browserid.unknown_error_checking_registered_user') log.error("Unknown error, clearing session assertion [%s]", e) store_assertion(request, None)
def revision_add_attachment(request, pk): """Add attachment, download if necessary """ revision = get_object_or_404(PackageRevision, pk=pk) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to add attachment to package (%s) by " "non-owner (%s)" % (revision.package, request.user)) log.warning(log_msg) return HttpResponseForbidden( 'You are not the author of this %s' % escape( revision.package.get_type_name())) url = request.POST.get('url', None) filename = request.POST.get('filename', None) log.debug(filename) if not filename or filename == "": log.error('Trying to create an attachment without name') return HttpResponseForbidden('Path not found.') content = '' if url: # validate url field = URLField(verify_exists=True) try: url = field.clean(url) except ValidationError, err: log.debug('Invalid url provided (%s)\n%s' % (url, '\n'.join(err.messages))) return HttpResponseForbidden(("Loading attachment failed<br/>" "%s") % '<br/>'.join(err.messages)) except Exception, err: return HttpResponseForbidden(str(err))
def json_upload_detail(upload): if not settings.VALIDATE_ADDONS: upload.task_error = '' upload.validation = json.dumps({'errors': 0, 'messages': [], 'notices': 0, 'warnings': 0}) upload.save() validation = json.loads(upload.validation) if upload.validation else "" url = reverse('devhub.upload_detail', args=[upload.uuid, 'json']) full_report_url = reverse('devhub.upload_detail', args=[upload.uuid]) plat_exclude = [] if validation: if validation['errors'] == 0: try: apps = parse_addon(upload.path).get('apps', []) app_ids = set([a.id for a in apps]) supported_platforms = [] if amo.MOBILE.id in app_ids: supported_platforms.extend(amo.MOBILE_PLATFORMS.keys()) app_ids.remove(amo.MOBILE.id) if len(app_ids): # Targets any other non-mobile app: supported_platforms.extend(amo.DESKTOP_PLATFORMS.keys()) s = amo.SUPPORTED_PLATFORMS.keys() plat_exclude = set(s) - set(supported_platforms) plat_exclude = [str(p) for p in plat_exclude] except django_forms.ValidationError, exc: # XPI parsing errors will be reported in the form submission # (next request). # TODO(Kumar) It would be nicer to present errors to the user # right here to avoid confusion about platform selection. log.error("XPI parsing error, ignored: %s" % exc)
def upload_attachment(request, revision_id): """ Upload new attachment to the PackageRevision """ revision = get_object_with_related_or_404(PackageRevision, pk=revision_id) log.debug(revision) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to upload attachment to package (%s) " "by non-owner (%s)" % (revision_id, request.user)) log.warning(log_msg) return HttpResponseForbidden( 'You are not the author of this %s' % escape( revision.package.get_type_name())) f = request.FILES.get('upload_attachment') filename = request.META.get('HTTP_X_FILE_NAME') if not f: log_msg = 'Path not found: %s, revision: %s.' % ( filename, revision_id) log.error(log_msg) return HttpResponseServerError('Path not found.') content = f.read() # try to force UTF-8 code, on error continue with original data try: content = unicode(content, 'utf-8') except: pass try: attachment = revision.attachment_create_by_filename( request.user, filename, content) except ValidationError, e: return HttpResponseForbidden( 'Validation errors.\n%s' % parse_validation_messages(e))
def is_authenticated(self, request): try: params = dict(request.POST.items()) if 'Authorization' not in request.META and \ 'HTTP_AUTHORIZATION' in request.META: request.META['Authorization'] = request.META['HTTP_AUTHORIZATION'] oauth_req = oauth.Request.from_request( request.method, request.build_absolute_uri(), headers=request.META, parameters=params, query_string=request.environ.get('QUERY_STRING', '')) if oauth_req is None: raise oauth.Error key = oauth_req.get_parameter('oauth_consumer_key') r = ConsumerModel.objects.get(key=key) consumer = oauth.Consumer(key=r.key, secret=r.secret) self.server.verify_request(oauth_req, consumer, None) return True except ConsumerModel.DoesNotExist, e: log.error(e) return False
def upload_attachments(request, id_number, type_id, revision_number=None, version_name=None): """ Upload new attachments to the PackageRevision """ revision = get_package_revision(None, id_number, type_id, revision_number, version_name) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to upload attachment to package (%s) " "by non-owner (%s)" % (id_number, request.user)) log.warning(log_msg) return HttpResponseForbidden( 'You are not the author of this %s' % escape( revision.package.get_type_name())) content = request.raw_post_data filename = request.META.get('HTTP_X_FILE_NAME') if not filename: log_msg = 'Path not found: %s, package: %s.' % ( filename, id_number) log.error(log_msg) return HttpResponseServerError('Path not found.') try: attachment = revision.attachment_create_by_filename( request.user, filename, content) except ValidationError, e: return HttpResponseForbidden( 'Validation errors.\n%s' % parse_validation_messages(e))
def verify(request): form = BrowserIDForm(data=request.POST) if form.is_valid(): url = settings.BROWSERID_VERIFICATION_URL audience = get_audience(request) extra_params = {'experimental_forceIssuer': settings.BROWSERID_UNVERIFIED_ISSUER, 'experimental_allowUnverified': 'true'} assertion = form.cleaned_data['assertion'] log.info('verifying Persona assertion. url: %s, audience: %s, ' 'extra_params: %s, assertion: %s' % (url, audience, extra_params, assertion)) result = verify_assertion(assertion, audience, extra_params) if result: log.info('Persona assertion ok: %s' % result) email = result.get('unverified-email', result.get('email')) user_hash = set_user(request, email) redirect_url = check_pin_status(request) return { 'needs_redirect': redirect_url is not None, 'redirect_url': redirect_url, 'user_hash': user_hash } log.error('Persona assertion failed.') request.session.flush() return http.HttpResponseBadRequest()
def support_mail(subject, template, context, sender, recipients): try: return send_mail_jinja(subject, template, context, from_email=sender, recipient_list=recipients) except SMTPRecipientsRefused, e: log.error('Tried to send mail from %s to %s: %s' % (sender, ', '.join(recipients), e), exc_info=True)
def request(action, params, notify_url, user_id=VIDLY_USER_ID, user_key=VIDLY_USER_KEY, api_url=VIDLY_API_URL): """Call the vid.ly API with the supplied parameters.""" if user_id is None or user_key is None: log.warning('You are missing a user id and/or key for vidly. You ' 'should pass these to the function you called or specify ' 'them in settings.VIDLY_USER_ID and ' 'settings.VIDLY_USER_KEY.') return None # Build XML Query query = ET.Element('Query') ET.SubElement(query, 'Action').text = action ET.SubElement(query, 'UserID').text = user_id ET.SubElement(query, 'UserKey').text = user_key ET.SubElement(query, 'Notify').text = notify_url _build_param_xml(query, params) # Getting an xml version header out of ElementTree is tough. # It's easier for our use case to just prepend it. xml_str = '<?xml version="1.0"?>%s' % ET.tostring(query) log.error('Vidly Request: %s' % xml_str) try: res = requests.post(api_url, data={'xml': xml_str}) except RequestException, e: log.error('Error connecting to Vidly: %s' % e) return None
def sign_app(src, dest, reviewer=False): """ Generate a manifest and signature and send signature to signing server to be signed. """ active_endpoint = _get_endpoint(reviewer) timeout = settings.SIGNED_APPS_SERVER_TIMEOUT if not active_endpoint: _no_sign(src, dest) return # Extract necessary info from the archive try: jar = JarExtractor( storage.open(src, 'r'), storage.open(dest, 'w'), omit_signature_sections=settings.SIGNED_APPS_OMIT_PER_FILE_SIGS) except: log.error('Archive extraction failed. Bad archive?', exc_info=True) raise SigningError('Archive extraction failed. Bad archive?') log.info('App signature contents: %s' % jar.signatures) log.info('Calling service: %s' % active_endpoint) try: with statsd.timer('services.sign.app'): response = requests.post(active_endpoint, timeout=timeout, files={'file': ('zigbert.sf', str(jar.signatures))}) except requests.exceptions.HTTPError, error: # Will occur when a 3xx or greater code is returned. log.error('Posting to app signing failed: %s, %s' % ( error.response.status, error)) raise SigningError('Posting to app signing failed: %s, %s' % ( error.response.status, error))
def _update_mdn_items(items): batch_updated = datetime.now() for item in items: for locale in locales: url = item['mdn'] % {'locale': locale} name = item['name'] + '.' + locale log.info('Fetching MDN article "%s": %s' % (name, url)) try: content = _fetch_mdn_page(url) except Http404: log.error(u'404 on MDN article "%s": %s' % (name, url)) continue except Exception as e: log.error(u'Error fetching MDN article "%s" reason: %s' % (name, e)) raise model, created = MdnCache.objects.get_or_create( name=item['name'], locale=locale) model.title = item['title'] model.content = content model.permalink = url model.save() log.info(u'Updated MDN article "%s"' % name) MdnCache.objects.filter(modified__lt=batch_updated).delete()
def access_request(request): try: oauth_req = server._create_request(request.build_absolute_uri(), request.method, request.body, get_request_headers(request)) valid, oauth_req = server.validate_access_token_request(oauth_req) except ValueError: valid = False if valid: req_t = Token.objects.get( token_type=REQUEST_TOKEN, key=oauth_req.resource_owner_key) t = Token.generate_new( token_type=ACCESS_TOKEN, creds=req_t.creds, user=req_t.user) # Clean up as we go. req_t.delete() return HttpResponse( urlencode({'oauth_token': t.key, 'oauth_token_secret': t.secret}), content_type='application/x-www-form-urlencoded') else: log.error('Invalid OAuth request for acquiring access token') return HttpResponse(status=401)
def is_authenticated(self, request, **kwargs): oauth_server, oauth_request = initialize_oauth_server_request(request) try: auth_header_value = request.META.get('HTTP_AUTHORIZATION') key = get_oauth_consumer_key_from_header(auth_header_value) if not key: return None consumer = get_consumer(key) oauth_server.verify_request(oauth_request, consumer, None) # Set the current user to be the consumer owner. request.user = consumer.user except: log.error(u'Error get OAuth headers', exc_info=True) request.user = AnonymousUser() return False # Check that consumer is valid. if consumer.status != 'accepted': log.info(u'Consumer not accepted: %s' % consumer) return False ACLMiddleware().process_request(request) # Do not allow any user with any roles to use the API. # Just in case. if request.amo_user.groups.all(): log.info(u'Attempt to use API with roles, user: %s' % request.amo_user.pk) return False return True
def authorize(request): if request.method == 'GET' and 'oauth_token' in request.GET: try: t = Token.objects.get(token_type=REQUEST_TOKEN, key=request.GET['oauth_token']) except Token.DoesNotExist: log.error('Invalid OAuth request for obtaining user authorization') return HttpResponse(status=401) return render(request, 'developers/oauth_authorize.html', {'app_name': t.creds.app_name, 'oauth_token': request.GET['oauth_token']}) elif request.method == 'POST': token = request.POST.get('oauth_token') try: t = Token.objects.get(token_type=REQUEST_TOKEN, key=token) except Token.DoesNotExist: return HttpResponse(status=401) if 'grant' in request.POST: t.user = request.user t.save() return HttpResponseRedirect( urlparams(t.creds.redirect_uri, oauth_token=token, oauth_verifier=t.verifier)) elif 'deny' in request.POST: t.delete() return HttpResponse(status=200) else: log.error('Invalid OAuth request for user access authorization') return HttpResponse(status=401)
def sign(receipt): """ Send the receipt to the signing service. This could possibly be made async via celery. """ destination = settings.SIGNING_SERVER # If no destination is set. Just ignore this request. if not destination: return destination += '/1.0/sign' timeout = settings.SIGNING_SERVER_TIMEOUT receipt_json = json.dumps(receipt) log.info('Calling service: %s' % destination) log.info('Receipt contents: %s' % receipt_json) headers = {'Content-Type': 'application/json'} data = receipt if isinstance(receipt, basestring) else receipt_json request = urllib2.Request(destination, data, headers) try: with statsd.timer('services.sign'): response = urllib2.urlopen(request, timeout=timeout) except urllib2.HTTPError, error: # Will occur when a 3xx or greater code is returned log.error('Posting to signing failed: %s' % (error.code)) raise SigningError
def access_request(request): oa = OAuthServer() try: valid, oauth_request = oa.verify_access_token_request( request.build_absolute_uri(), request.method, request.body, {'Authorization': request.META.get('HTTP_AUTHORIZATION'), 'Content-Type': request.META.get('CONTENT_TYPE') }) except ValueError: valid = False if valid: req_t = Token.objects.get( token_type=REQUEST_TOKEN, key=oauth_request.resource_owner_key) t = Token.generate_new( token_type=ACCESS_TOKEN, creds=req_t.creds, user=req_t.user) # Clean up as we go. req_t.delete() return HttpResponse( urlencode({'oauth_token': t.key, 'oauth_token_secret': t.secret}), content_type='application/x-www-form-urlencoded') else: log.error('Invalid OAuth request for acquiring access token') return HttpResponse(status=401)
def pay_status(request, config_pk, status): tpl_path = 'inapp_pay/' with transaction.commit_on_success(): cfg = get_object_or_404(InappConfig, pk=config_pk) uuid_ = None try: uuid_ = str(request.GET['uuid']) cnt = Contribution.objects.get(uuid=uuid_) except (KeyError, UnicodeEncodeError, ValueError, Contribution.DoesNotExist), exc: log.error('PayPal returned invalid uuid %r from in-app payment' % uuid_, exc_info=True) inapp_cef.log(request, cfg.addon, 'inapp_pay_status', 'PayPal or someone sent invalid uuid %r for ' 'in-app pay config %r; exception: %s: %s' % (uuid_, cfg.pk, exc.__class__.__name__, exc), severity=4) return render_error(request, exc) payment = InappPayment.objects.get(config=cfg, contribution=cnt) if status == 'complete': cnt.update(type=amo.CONTRIB_INAPP) tpl = tpl_path + 'complete.html' action = 'PAY_COMPLETE' elif status == 'cancel': tpl = tpl_path + 'payment_cancel.html' action = 'PAY_CANCEL' else: raise ValueError('Unexpected status: %r' % status)
def verify_webpay_jwt(signed_jwt): # This can probably be deleted depending upon solitude. try: jwt.decode(signed_jwt.encode('ascii'), secret) except Exception, e: log.error('Error decoding webpay jwt: %s' % e, exc_info=True) return {'valid': False}
def call_signing(file_obj, endpoint): """Get the jar signature and send it to the signing server to be signed.""" # We only want the (unique) temporary file name. with tempfile.NamedTemporaryFile() as temp_file: temp_filename = temp_file.name # Extract jar signature. jar = JarExtractor(path=storage.open(file_obj.file_path), outpath=temp_filename, omit_signature_sections=True, extra_newlines=True) log.debug(u'File signature contents: {0}'.format(jar.signatures)) log.debug(u'Calling signing service: {0}'.format(endpoint)) with statsd.timer('services.sign.addon'): response = requests.post( endpoint, timeout=settings.SIGNING_SERVER_TIMEOUT, data={'addon_id': get_id(file_obj.version.addon)}, files={'file': (u'mozilla.sf', unicode(jar.signatures))}) if response.status_code != 200: msg = u'Posting to add-on signing failed: {0}'.format(response.reason) log.error(msg) raise SigningError(msg) pkcs7 = b64decode(json.loads(response.content)['mozilla.rsa']) cert_serial_num = get_signature_serial_number(pkcs7) jar.make_signed(pkcs7, sigpath=u'mozilla') shutil.move(temp_filename, file_obj.file_path) return cert_serial_num
def wrapper(request, addon, *args, **kw): if not waffle.switch_is_active('marketplace'): log.error('Marketplace waffle switch is off') raise http.Http404 if not addon.can_be_purchased(): return http.HttpResponseForbidden() return f(request, addon, *args, **kw)
def package_upload_attachment(r, id_number, type_id, revision_number=None, version_name=None): """ Upload new attachment to the PackageRevision """ revision = get_package_revision(id_number, type_id, revision_number, version_name) if r.user.pk != revision.author.pk: log_msg = ("[security] Attempt to upload attachment to package (%s) " "by non-owner (%s)" % (id_number, r.user)) log.warning(log_msg) return HttpResponseForbidden( 'You are not the author of this %s' \ % escape(revision.package.get_type_name())) file = r.FILES.get('upload_attachment') filename = r.META.get('HTTP_X_FILE_NAME') if not file: log_msg = 'Path not found: %s, package: %s.' % ( filename, id_number) log.error(log_msg) return HttpResponseServerError('Path not found.') content = file.read() try: attachment = revision.attachment_create_by_filename( r.user, filename, content) except ValidationError, e: return HttpResponseForbidden('Validation errors.')
def delete_incomplete_addons(items, **kw): log.info("[%s@%s] Deleting incomplete add-ons" % (len(items), delete_incomplete_addons.rate_limit)) for addon in Addon.objects.filter(highest_status=0, status=0, pk__in=items): try: addon.delete("Deleted for incompleteness") except Exception as e: log.error("Couldn't delete add-on %s: %s" % (addon.id, e))
def set_modified_on_object(obj, **kw): """Sets modified on one object at a time.""" try: log.info("Setting modified on object: %s, %s" % (obj.__class__.__name__, obj.pk)) obj.update(modified=datetime.datetime.now(), **kw) except Exception, e: log.error("Failed to set modified on: %s, %s - %s" % (obj.__class__.__name__, obj.pk, e))
def purchase_complete(request, addon, status): result = '' if status == 'complete': con = Contribution.objects.get(uuid=request.GET.get('uuid'), type=amo.CONTRIB_PENDING) log.debug('Check purchase paypal addon: %s, user: %s, paykey: %s' % (addon.pk, request.amo_user.pk, con.paykey[:10])) try: result = paypal.check_purchase(con.paykey) except: log.error('Check purchase paypal addon: %s, user: %s, paykey: %s' % (addon.pk, request.amo_user.pk, con.paykey[:10]), exc_info=True) result = 'ERROR' status = 'error' log.debug('Paypal returned: %s for paykey: %s' % (result, con.paykey[:10])) if result == 'COMPLETED': # Markup the contribution suitably con.type = amo.CONTRIB_PURCHASE con.uuid = None con.save() response = jingo.render(request, 'addons/paypal_result.html', {'addon': addon, 'realurl': request.GET.get('realurl', ''), # What the client claimed they did. 'status': status, # And what paypal thought of that claim. 'result': result}) response['x-frame-options'] = 'allow' return response
def verify(request): form = BrowserIDForm(data=request.POST) if form.is_valid(): url = settings.BROWSERID_VERIFICATION_URL audience = get_audience(request) extra_params = {'forceIssuer': settings.BROWSERID_UNVERIFIED_ISSUER, 'allowUnverified': 'true'} assertion = form.cleaned_data['assertion'] log.info('verifying Persona assertion. url: %s, audience: %s, ' 'extra_params: %s, assertion: %s' % (url, audience, extra_params, assertion)) result = verify_assertion(assertion, audience, extra_params) if result: log.info('Persona assertion ok: %s' % result) email = result.get('unverified-email', result.get('email')) user_hash = set_user(request, email) return {'has_pin': request.session.get('uuid_has_pin'), 'pin_create': reverse('pin.create'), 'user_hash': user_hash} log.error('Persona assertion failed.') request.session.clear() return http.HttpResponseBadRequest()
def authorize(request): if request.method == "GET" and "oauth_token" in request.GET: try: t = Token.objects.get(token_type=REQUEST_TOKEN, key=request.GET["oauth_token"]) except Token.DoesNotExist: log.error("Invalid OAuth request for obtaining user authorization") return HttpResponse(status=401) return render( request, "developers/oauth_authorize.html", {"app_name": t.creds.app_name, "oauth_token": request.GET["oauth_token"]}, ) elif request.method == "POST": token = request.POST.get("oauth_token") try: t = Token.objects.get(token_type=REQUEST_TOKEN, key=token) except Token.DoesNotExist: return HttpResponse(status=401) if "grant" in request.POST: t.user = request.user t.save() return HttpResponseRedirect(urlparams(t.creds.redirect_uri, oauth_token=token, oauth_verifier=t.verifier)) elif "deny" in request.POST: t.delete() return HttpResponse(status=200) else: log.error("Invalid OAuth request for user access authorization") return HttpResponse(status=401)
def refresh_mdn_cache(**kw): log.info('Refreshing MDN Cache') try: _update_mdn_items(tutorials) except Exception as e: log.error(u'Failed to update MDN articles, reason: %s' % e, exc_info=True)
def add_empty_attachment(request, id_number, type_id, revision_number=None, version_name=None): """ Add new empty attachment to the PackageRevision """ revision = get_package_revision(None, id_number, type_id, revision_number, version_name) if request.user.pk != revision.author.pk: log_msg = ("[security] Attempt to add attachment to package (%s) by " "non-owner (%s)" % (id_number, request.user)) log.warning(log_msg) return HttpResponseForbidden( 'You are not the author of this %s' % escape( revision.package.get_type_name())) filename = request.POST.get('filename', False) if not filename: log_msg = 'Path not found: %s, package: %s.' % ( filename, id_number) log.error(log_msg) return HttpResponseServerError('Path not found.') try: attachment = revision.attachment_create_by_filename(request.user, filename, '') except ValidationError, e: return HttpResponseForbidden( 'Validation errors.\n%s' % parse_validation_messages(e))
def list(self, request, *args, **kwargs): if (not settings.RECOMMENDATIONS_ENABLED or not settings.RECOMMENDATIONS_API_URL or not self.request.user.is_authenticated()): return self._popular() else: app_ids = [] url = '{base_url}/api/v2/recommend/{limit}/{user_hash}/'.format( base_url=settings.RECOMMENDATIONS_API_URL, limit=20, user_hash=self.request.user.recommendation_hash) try: with statsd.timer('recommendation.get'): resp = requests.get( url, timeout=settings.RECOMMENDATIONS_API_TIMEOUT) if resp.status_code == 200: app_ids = resp.json()['recommendations'] except Timeout as e: log.warning(u'Recommendation timeout: {error}'.format(error=e)) except RequestException as e: # On recommendation API exceptions we return popular. log.error(u'Recommendation exception: {error}'.format(error=e)) if not app_ids: # Fall back to a popularity search. return self._popular() sq = WebappIndexer.get_app_filter(self.request, app_ids=app_ids) return Response({ 'objects': self.serializer_class( sq.execute().hits, many=True, context={'request': self.request}).data})
def list(self, request, *args, **kwargs): if (not settings.RECOMMENDATIONS_ENABLED or not settings.RECOMMENDATIONS_API_URL or not self.request.user.is_authenticated()): return self._popular() else: app_ids = [] url = '{base_url}/api/v2/recommend/{limit}/{user_hash}/'.format( base_url=settings.RECOMMENDATIONS_API_URL, limit=20, user_hash=self.request.user.recommendation_hash) try: with statsd.timer('recommendation.get'): resp = requests.get( url, timeout=settings.RECOMMENDATIONS_API_TIMEOUT) if resp.status_code == 200: app_ids = resp.json()['recommendations'] except Timeout as e: log.warning(u'Recommendation timeout: {error}'.format(error=e)) except RequestException as e: # On recommendation API exceptions we return popular. log.error(u'Recommendation exception: {error}'.format(error=e)) if not app_ids: # Fall back to a popularity search. return self._popular() # Get list of installed apps and remove from app_ids. installed = list( request.user.installed_set.values_list('addon_id', flat=True)) app_ids = filter(lambda a: a not in installed, app_ids) device = get_device_id(request) filters = {'device': device} if device else None sq = WebappIndexer.get_app_filter(self.request, filters, app_ids=app_ids) return Response({ 'objects': self.serializer_class(sq.execute().hits, many=True, context={ 'request': self.request }).data })
def recommendations(request, version, platform, limit=9): """ Figure out recommended add-ons for an anonymous user based on POSTed guids. POST body looks like {"guids": [...]} with an optional "token" key if they've been here before. """ try: POST = json.loads(request.raw_post_data) guids = POST['guids'] except (ValueError, TypeError, KeyError): # Errors: invalid json, didn't get a dict, didn't find "guids". return http.HttpResponseBadRequest() addon_ids = get_addon_ids(guids) index = Collection.make_index(addon_ids) ids, recs = Collection.get_recs_from_ids(addon_ids, request.APP, version) recs = _recommendations(request, version, platform, limit, index, ids, recs) # Users have a token2 if they've been here before. The token matches # addon_index in their SyncedCollection. if 'token2' in POST: token = POST['token2'] if token == index: # We've seen them before and their add-ons have not changed. return recs elif token != index: # We've seen them before and their add-ons changed. Remove the # reference to their old synced collection. (SyncedCollection.objects.filter(addon_index=index).update( count=F('count') - 1)) # Try to create the SyncedCollection. There's a unique constraint on # addon_index so it will fail if this addon_index already exists. If we # checked for existence first and then created a collection there would # be a race condition between multiple users with the same addon_index. try: c = SyncedCollection.objects.create(addon_index=index, count=1) c.set_addons(addon_ids) except IntegrityError: try: (SyncedCollection.objects.filter(addon_index=index).update( count=F('count') + 1)) except Exception, e: log.error(u'Could not count++ "%s" (%s).' % (index, e))
def sign(version_id, reviewer=False, resign=False, **kw): version = Version.objects.get(pk=version_id) app = version.addon log.info('Signing version: %s of app: %s' % (version_id, app)) if not app.is_packaged: log.error('[Webapp:%s] Attempt to sign a non-packaged app.' % app.id) raise SigningError('Not packaged') try: file_obj = version.all_files[0] except IndexError: log.error( '[Webapp:%s] Attempt to sign an app with no files in version.' % app.id) raise SigningError('No file') path = (file_obj.signed_reviewer_file_path if reviewer else file_obj.signed_file_path) if storage.exists(path) and not resign: log.info('[Webapp:%s] Already signed app exists.' % app.id) return path if reviewer: # Reviewers get a unique 'id' so the reviewer installed app won't # conflict with the public app, and also so multiple versions of the # same app won't conflict with themselves. ids = json.dumps({ 'id': 'reviewer-{guid}-{version_id}'.format(guid=app.guid, version_id=version_id), 'version': version_id }) else: ids = json.dumps({'id': app.guid, 'version': version_id}) with statsd.timer('services.sign.app'): try: sign_app(file_obj.file_path, path, ids, reviewer) except SigningError: log.info('[Webapp:%s] Signing failed' % app.id) if storage.exists(path): storage.delete(path) raise log.info('[Webapp:%s] Signing complete.' % app.id) return path
def process_failure_signal(exception, traceback, sender, task_id, signal, args, kwargs, einfo, **kw): """Catch any task failure signals from within our worker processes and log them as exceptions, so they appear in Sentry and ordinary logging output.""" exc_info = (type(exception), exception, traceback) log.error(u'Celery TASK exception: {0.__name__}: {1}'.format(*exc_info), exc_info=exc_info, extra={ 'data': { 'task_id': task_id, 'sender': sender, 'args': args, 'kwargs': kwargs } })
def register(request): """Registers Users. Pulls out an invite code if it exists and auto validates the user if so. Single-purpose view. """ if 'code' in request.GET: request.session['invite-code'] = request.GET['code'] return redirect('home') if request.user.is_authenticated(): return redirect(reverse('profile', args=[request.user.username])) authenticated_email = request.session.get('authenticated_email') if not authenticated_email: log.error('Browserid registration, but no verified email in session') return redirect('home') user = auth.authenticate(authenticated_email=authenticated_email) if not user: return redirect('home') user_form = UserForm(request.POST or None, instance=user) profile_form = RegisterForm(request.POST or None, instance=user.get_profile()) if request.method == 'POST': if (user_form.is_valid() and profile_form.is_valid()): user_form.save() profile_form.save() auth.login(request, user) _update_invites(request) messages.info(request, _(u'Your account has been created.')) return redirect(reverse('profile', args=[request.user.username])) # 'user' object must be passed in because we are not logged in return render( request, 'registration/register.html', dict( profile_form=profile_form, user_form=user_form, edit_form_action=reverse('register'), mode='new', profile=user.get_profile(), user=user, ))
def purchase_complete(request, addon, status): result = '' if status == 'complete': uuid_ = request.GET.get('uuid') log.debug('Looking up contrib for uuid: %s' % uuid_) # The IPN may, or may not have come through. Which means looking for # a for pre or post IPN contributions. If both fail, then we've not # got a matching contribution. lookup = (Q(uuid=uuid_, type=amo.CONTRIB_PENDING) | Q(transaction_id=uuid_, type=amo.CONTRIB_PURCHASE)) con = get_object_or_404(Contribution, lookup) log.debug('Check purchase paypal addon: %s, user: %s, paykey: %s' % (addon.pk, request.amo_user.pk, con.paykey[:10])) try: result = paypal.check_purchase(con.paykey) if result == 'ERROR': paypal.paypal_log_cef(request, addon, uuid_, 'Purchase Fail', 'PURCHASEFAIL', 'Checking purchase state returned error') raise except: paypal.paypal_log_cef(request, addon, uuid_, 'Purchase Fail', 'PURCHASEFAIL', 'There was an error checking purchase state') log.error('Check purchase paypal addon: %s, user: %s, paykey: %s' % (addon.pk, request.amo_user.pk, con.paykey[:10]), exc_info=True) result = 'ERROR' status = 'error' log.debug('Paypal returned: %s for paykey: %s' % (result, con.paykey[:10])) if result == 'COMPLETED' and con.type == amo.CONTRIB_PENDING: con.update(type=amo.CONTRIB_PURCHASE) response = jingo.render(request, 'addons/paypal_result.html', {'addon': addon, 'realurl': request.GET.get('realurl', ''), # What the client claimed they did. 'status': status, # And what paypal thought of that claim. 'result': result}) response['x-frame-options'] = 'allow' return response
def landing(request): """Developer Hub landing page.""" videos = [ { 'name': 'airbnb', 'path': 'FirefoxMarketplace-airbnb-BR-RC-SD1%20640' }, { 'name': 'evernote', 'path': 'FirefoxMarketplace-Evernote_BR-RC-SD1%20640' }, { 'name': 'uken', 'path': 'FirefoxMarketplace-uken-BR-RC-SD1%20640' }, { 'name': 'soundcloud', 'path': 'FirefoxMarketplace-Soundcloud-BR-RC-SD1%20640' }, { 'name': 'box', 'path': 'FirefoxMarketplace_box-BR-RC-SD1%20640' } ] form = DevNewsletterForm(request.LANG, request.POST or None) if request.method == 'POST' and form.is_valid(): data = form.cleaned_data try: basket.subscribe(data['email'], 'app-dev', format=data['email_format'], source_url=settings.SITE_URL) messages.success(request, _('Thank you for subscribing!')) return redirect('ecosystem.landing') except basket.BasketException as e: log.error( 'Basket exception in ecosystem newsletter: %s' % e) messages.error( request, _('We apologize, but an error occurred in our ' 'system. Please try again later.')) return jingo.render(request, 'ecosystem/landing.html', {'videos': videos, 'newsletter_form': form})
def register(request): if request.user.is_authenticated(): messages.info(request, _("You are already logged in to an account.")) form = None elif request.method == 'POST': form = forms.UserRegisterForm(request.POST) if form.is_valid(): try: u = form.save(commit=False) u.set_password(form.cleaned_data['password']) u.generate_confirmationcode() u.save() u.create_django_user() log.info(u"Registered new account for user (%s)", u) u.email_confirmation_code() msg = _('Congratulations! Your user account was successfully ' 'created.') messages.success(request, msg) msg = _(('An email has been sent to your address {0} to ' 'confirm your account. Before you can log in, you ' 'have to activate your account by clicking on the ' 'link provided in this email.').format(u.email)) messages.info(request, _('Confirmation Email Sent'), msg) except IntegrityError, e: # I was unable to reproduce this, but I suspect it happens # when they POST twice quickly and the slaves don't have the # new info yet (total guess). Anyway, I'm assuming the # first one worked properly, so this is still a success # case to tne end user so we just log it... log.error("Failed to register new user (%s): %s" % (u, e)) amo.utils.clear_messages(request) return http.HttpResponseRedirect(reverse('users.login') + '?m=3') # TODO POSTREMORA Replace the above two lines # when remora goes away with this: #return http.HttpResponseRedirect(reverse('users.login')) else: messages.error(request, _('There are errors in this form'), _('Please correct them and resubmit.'))
def save(self, **kw): if not self.users_cache: log.info("Unknown email used for password reset: {email}".format( **self.cleaned_data)) return for user in self.users_cache: if user.needs_tougher_password: log.info( u'Password reset email sent for privileged user (%s)' % user) else: log.info(u'Password reset email sent for user (%s)' % user) try: # Django calls send_mail() directly and has no option to pass # in fail_silently, so we have to catch the SMTP error ourselves self.base_save(**kw) except SMTPException, e: log.error("Failed to send mail for (%s): %s" % (user, e))
def save(self, **kw): for user in self.users_cache: log.info(u'Password reset email sent for user (%s)' % user) if user.needs_tougher_password: log_cef('Password Reset', 5, self.request, username=user, signature='PASSWORDRESET', msg='Privileged user requested password reset') else: log_cef('Password Reset', 5, self.request, username=user, signature='PASSWORDRESET', msg='User requested password reset') try: # Django calls send_mail() directly and has no option to pass # in fail_silently, so we have to catch the SMTP error ourselves super(PasswordResetForm, self).save(**kw) except SMTPException, e: log.error("Failed to send mail for (%s): %s" % (user, e))
def save(self, *args, **kw): if not self.version_int and self.version: v_int = version_int(self.version) # Magic number warning, this is the maximum size # of a big int in MySQL to prevent version_int overflow, for # people who have rather crazy version numbers. # http://dev.mysql.com/doc/refman/5.5/en/numeric-types.html if v_int < 9223372036854775807: self.version_int = v_int else: log.error('No version_int written for version %s, %s' % (self.pk, self.version)) creating = not self.id super(Version, self).save(*args, **kw) if creating: from mkt.webapps.models import AppFeatures if self.addon.type == amo.ADDON_WEBAPP: AppFeatures.objects.create(version=self) return self
def save_from_email_reply(reply_text): parser = CommEmailParser(reply_text) uuid = parser.get_uuid() if not uuid: return False try: tok = CommunicationThreadToken.objects.get(uuid=uuid) except CommunicationThreadToken.DoesNotExist: log.error('An email was skipped with non-existing uuid %s' % uuid) return False if (user_has_perm_thread(tok.thread, tok.user) and tok.is_valid()): n = CommunicationNote.objects.create(note_type=comm.NO_ACTION, thread=tok.thread, author=tok.user, body=parser.get_body()) log.info('A new note has been created (from %s using tokenid %s)' % (tok.user.id, uuid)) return n return False
def get_locale_directory(project, locale): """ Get path to the directory with locale files. Args: project: Project instance locale: Locale instance Returns: Dict with directory name and path as keys. """ path = get_repository_path_master(project) for root, dirnames, filenames in os.walk(path): # Ignore hidden folders dirnames[:] = [d for d in dirnames if not d[0] == '.'] for dirname in fnmatch.filter(dirnames, locale.code): return { 'name': dirname, 'path': os.path.join(root, dirname), } # Also check for locale variants with underscore, e.g. de_AT for dirname in fnmatch.filter(dirnames, locale.code.replace('-', '_')): return { 'name': dirname, 'path': os.path.join(root, dirname), } # Projects not using locale directories (.ini, file) formats = Resource.objects.filter(project=project).values_list( 'format', flat=True).distinct() if 'ini' in formats or project.repository_type == 'file': return { 'name': '', 'path': path, } error = "Directory for locale %s not found." % locale.code log.error(error) raise Exception(error)
def get_object_with_related_or_404(klass, *args, **kwargs): """ Uses get() to return an object, or raises a Http404 exception if the object does not exist. klass may be a Model, Manager, or QuerySet object. All other passed arguments and keyword arguments are used in the get() query. Note: Like with get(), an MultipleObjectsReturned will be raised if more than one object is found. """ queryset = _get_queryset(klass).select_related() try: return queryset.get(*args, **kwargs) except queryset.model.DoesNotExist: pass except Exception, err: log.error("Getting %s failed (%s)" % (queryset.model._meta.object_name, str(err)))
def token_request(request): try: oauth_req = server._create_request(request.build_absolute_uri(), request.method, request.body, get_request_headers(request)) valid, oauth_req = server.validate_request_token_request(oauth_req) except ValueError: valid = False if valid: consumer = Access.objects.get(key=oauth_req.client_key) t = Token.generate_new(token_type=REQUEST_TOKEN, creds=consumer) return HttpResponse(urlencode({ 'oauth_token': t.key, 'oauth_token_secret': t.secret, 'oauth_callback_confirmed': True }), content_type='application/x-www-form-urlencoded') else: log.error('Invalid OAuth request for acquiring request token') return HttpResponse(status=401)
def run_indexing(cls, ids, ES=None, index=None, **kw): """Override run_indexing to use app transformers.""" from mkt.webapps.models import Webapp log.info('Indexing %s webapps' % len(ids)) qs = Webapp.with_deleted.filter(id__in=ids) ES = ES or cls.get_es() docs = [] for obj in list(qs): try: docs.append(cls.extract_document(obj.id, obj=obj)) except Exception as e: log.error( 'Failed to index webapp {0}: {1}'.format(obj.id, repr(e)), # Trying to chase down a cache-machine problem. exc_info="marketplace:" in str(e)) cls.bulk_index(docs, es=ES, index=index or cls.get_index())
def is_authenticated(self, request, **kwargs): oauth_server, oauth_request = initialize_oauth_server_request(request) try: auth_header_value = request.META.get('HTTP_AUTHORIZATION') key = get_oauth_consumer_key_from_header(auth_header_value) if not key: return None consumer = Access.objects.get(key=key) oauth_server.verify_request(oauth_request, consumer, None) # Set the current user to be the consumer owner. request.user = consumer.user except Access.DoesNotExist: log.error(u'Cannot find APIAccess token with that key: %s' % key) request.user = AnonymousUser() return self._error('headers') except: log.error(u'Error getting OAuth headers', exc_info=True) request.user = AnonymousUser() return self._error('headers') ACLMiddleware().process_request(request) # Do not allow access without agreeing to the dev agreement. if not request.amo_user.read_dev_agreement: log.info(u'Attempt to use API without dev agreement: %s' % request.amo_user.pk) return self._error('terms') # Do not allow any user with any roles to use the API. # Just in case. if request.amo_user.groups.all(): log.info(u'Attempt to use API with roles, user: %s' % request.amo_user.pk) return self._error('roles') return True
def get_manifest_json(self, file_obj=None): file_ = file_obj or self.get_latest_file() if not file_: return file_path = file_.file_path try: if zipfile.is_zipfile(file_path): zf = zipfile.ZipFile(file_path) data = zf.open('manifest.webapp').read() zf.close() return json.loads(data) else: file = storage.open(file_path, 'r') data = file.read() return json.loads(data) except Exception, e: log.error(u'[Webapp:%s] Failed to open saved file %r, %s.' % (self, file_path, e)) raise
def unhide_disabled_files(): # Files are getting stuck in /guarded-addons for some reason. This job # makes sure guarded add-ons are supposed to be disabled. log = logging.getLogger('z.files.disabled') q = (Q(version__addon__status=amo.STATUS_DISABLED) | Q(version__addon__disabled_by_user=True)) files = set(File.objects.filter(q | Q(status=amo.STATUS_DISABLED)) .values_list('version__addon', 'filename')) for filepath in walkfiles(settings.GUARDED_ADDONS_PATH): addon, filename = filepath.split('/')[-2:] if tuple([int(addon), filename]) not in files: log.warning('File that should not be guarded: %s.' % filepath) try: file_ = (File.objects.select_related('version__addon') .get(version__addon=addon, filename=filename)) file_.unhide_disabled_file() except File.DoesNotExist: log.warning('File object does not exist for: %s.' % filepath) except Exception: log.error('Could not unhide file: %s.' % filepath, exc_info=True)
def process_file(user_email, filename, session_key, **kw): sp = subprocess.Popen([ 'ffprobe', '-v', 'quiet', '-print_format', 'json', '-show_format', '-show_streams', filename ], stdout=subprocess.PIPE) data = json.load(sp.stdout) ret = sp.wait() if ret != 0: raise RuntimeError('ffprobe failed') artist = data['format']['tags']['artist'] album = data['format']['tags']['album'] track = data['format']['tags']['title'] track_num = data['format']['tags']['track'] track_num = track_num.split('/')[0] # 1/30 try: track_num = int(track_num) if track_num else None except ValueError, exc: log.error('Unable to decipher track number from %r: %s' % (data['format']['tags']['track'], exc)) track_num = None
def sign(version_id, reviewer=False): version = Version.objects.get(pk=version_id) app = version.addon log.info('Signing version: %s of app: %s' % (version_id, app)) if not app.type == amo.ADDON_WEBAPP: log.error('Attempt to sign something other than an app.') raise SigningError('Not an app') if not app.is_packaged: log.error('Attempt to sign a non-packaged app.') raise SigningError('Not packaged') try: file_obj = version.all_files[0] except IndexError: log.error('Attempt to sign an app with no files in version.') raise SigningError('No file') path = (file_obj.signed_reviewer_file_path if reviewer else file_obj.signed_file_path) if storage.exists(path): log.info('Already signed app exists.') return path # When we know how to sign, we will sign. For the moment, let's copy. with statsd.timer('services.sign.app'): sign_app(file_obj.file_path, path) log.info('Signing complete.') return path
def pay(request, signed_req, pay_req): amount = pay_req['request']['price'] currency = pay_req['request']['currency'] source = request.POST.get('source', '') product = pay_req['_config'].addon # L10n: {0} is the product name. {1} is the application name. contrib_for = ( _(u'Mozilla Marketplace in-app payment for {0} to {1}').format( pay_req['request']['name'], product.name)) uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() paykey, status = '', '' preapproval = None if request.amo_user: preapproval = request.amo_user.get_preapproval() try: paykey, status = paypal.get_paykey( dict( amount=amount, chains=settings.PAYPAL_CHAINS, currency=currency, email=product.paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern='inapp_pay.pay_status', preapproval=preapproval, qs={'realurl': request.POST.get('realurl')}, slug=pay_req['_config']. pk, # passed to pay_done() via reverse() uuid=uuid_)) except paypal.PaypalError, exc: paypal.paypal_log_cef(request, product, uuid_, 'in-app PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error(u'Error getting paykey, in-app payment: %s' % pay_req['_config'].pk, exc_info=True) InappPayLog.log(request, 'PAY_ERROR', config=pay_req['_config']) return render_error(request, exc)
def save_from_email_reply(reply_text): parser = CommEmailParser(reply_text) if hasattr(parser, 'decode_error'): return False uuid = parser.get_uuid() if not uuid: return False try: tok = CommunicationThreadToken.objects.get(uuid=uuid) except CommunicationThreadToken.DoesNotExist: log.error('An email was skipped with non-existing uuid %s.' % uuid) return False if user_has_perm_thread(tok.thread, tok.user) and tok.is_valid(): t, note = create_comm_note(tok.thread.addon, tok.thread.version, tok.user, parser.get_body()) log.info('A new note has been created (from %s using tokenid %s).' % (tok.user.id, uuid)) return note elif tok.is_valid(): log.error('%s did not have perms to reply to comm email thread %s.' % (tok.user.email, tok.thread.id)) else: log.error('%s tried to use an invalid comm token for thread %s.' % (tok.user.email, tok.thread.id)) return False
def verify_data(self, data): client = lib.iarc.client.get_iarc_client('services') xml = lib.iarc.utils.render_xml('get_app_info.xml', data) resp = client.Get_App_Info(XMLString=xml) check_data = lib.iarc.utils.IARC_XML_Parser().parse_string(resp) try: check_data = check_data.get('rows', [])[0] except IndexError: return False rates_bad = data.get('ratings') != check_data.get('ratings') inter_bad = (set(data.get('interactives', [])) != set( check_data.get('interactives', []))) descs_bad = (set(data.get('descriptors', [])) != set( check_data.get('descriptors', []))) if rates_bad: log.error('IARC pingback did not match rating %s vs %s' % (data.get('ratings'), check_data.get('ratings'))) if inter_bad: log.error( 'IARC pingback did not match interactives %s vs %s' % (data.get('interactives'), check_data.get('interactives'))) if descs_bad: log.error('IARC pingback did not match descriptors %s vs %s' % (data.get('descriptors'), check_data.get('descriptors'))) if rates_bad or inter_bad or descs_bad: return False return True
def token_request(request): oa = OAuthServer() try: valid, oauth_request = oa.verify_request_token_request( request.build_absolute_uri(), request.method, request.body, { 'Authorization': request.META.get('HTTP_AUTHORIZATION'), 'Content-Type': request.META.get('CONTENT_TYPE') }) except ValueError: valid = False if valid: consumer = Access.objects.get(key=oauth_request.client_key) t = Token.generate_new(token_type=REQUEST_TOKEN, creds=consumer) return HttpResponse(urlencode({ 'oauth_token': t.key, 'oauth_token_secret': t.secret, 'oauth_callback_confirmed': True }), content_type='application/x-www-form-urlencoded') else: log.error('Invalid OAuth request for acquiring request token') return HttpResponse(status=401)
def sign_app(src, dest, ids, reviewer=False): """ Generate a manifest and signature and send signature to signing server to be signed. """ active_endpoint = _get_endpoint(reviewer) timeout = settings.SIGNED_APPS_SERVER_TIMEOUT if not active_endpoint: _no_sign(src, dest) return # Extract necessary info from the archive tempname = tempfile.mktemp() try: jar = JarExtractor( storage.open(src, 'r'), tempname, ids, omit_signature_sections=settings.SIGNED_APPS_OMIT_PER_FILE_SIGS) except: log.error('Archive extraction failed. Bad archive?', exc_info=True) raise SigningError('Archive extraction failed. Bad archive?') log.info('App signature contents: %s' % jar.signatures) log.info('Calling service: %s' % active_endpoint) try: with statsd.timer('services.sign.app'): response = requests.post( active_endpoint, timeout=timeout, files={'file': ('zigbert.sf', str(jar.signatures))}) except requests.exceptions.HTTPError, error: # Will occur when a 3xx or greater code is returned. log.error('Posting to app signing failed: %s, %s' % (error.response.status, error)) raise SigningError('Posting to app signing failed: %s, %s' % (error.response.status, error))
def process_email(message, **kwargs): """Parse emails and save activity log entry.""" # Some emails (gmail, at least) come with Message-ID instead of MessageId. msg_id = message.get('MessageId') if not msg_id: custom_headers = message.get('CustomHeaders', []) for header in custom_headers: if header.get('Name') == 'Message-ID': msg_id = header.get('Value') if not msg_id: log.error('No MessageId in message, aborting.') log.error(message) return _, created = ActivityLogEmails.objects.get_or_create(messageid=msg_id) if not created: log.error('Already processed [%s], skipping' % msg_id) log.error(message) return res = add_email_to_activity_log_wrapper(message) if not res: log.error('Failed to save email.')
def cancel(self, disable_refs=False): """Cancels the payment account. If `disable_refs` is set, existing apps that use this payment account will be set to STATUS_NULL. """ account_refs = AddonPaymentAccount.objects.filter(account_uri=self.uri) if self.shared and account_refs: # With sharing a payment account comes great responsibility. It # would be really mean to create a payment account, share it # and have lots of apps use it. Then one day you remove it and # make a whole pile of apps in the marketplace get removed from # the store, or have in-app payments fail. # # For the moment I'm just stopping this completely, if this ever # happens, we'll have to go through a deprecation phase. # - let all the apps that use it know # - when they have all stopped sharing it # - re-run this log.error('Cannot cancel a shared payment account that has ' 'apps using it.') raise CantCancel('You cannot cancel a shared payment account.') self.update(inactive=True) log.info('Soft-deleted payment account (uri: %s)' % self.uri) for acc_ref in account_refs: if (disable_refs and not acc_ref.addon.has_multiple_payment_accounts()): log.info('Changing app status to NULL for app: {0}' 'because of payment account deletion'.format( acc_ref.addon_id)) acc_ref.addon.update(status=amo.STATUS_NULL) log.info('Deleting AddonPaymentAccount for app: {0} because of ' 'payment account deletion'.format(acc_ref.addon_id)) acc_ref.delete()
def reverify(request): form = BrowserIDForm(data=request.POST) if form.is_valid(): url = settings.BROWSERID_VERIFICATION_URL audience = get_audience(request) # TODO: when we want to require a forced-auth login across the # entire site then how do we do it? # See bug 836060. extra_params = { 'experimental_forceIssuer': settings.BROWSERID_UNVERIFIED_ISSUER, # TODO: how do we make sure this is a proper forced # auth assertion? # This can also be addressed in bug 836060 'experimental_forceAuthentication': 'true', 'experimental_allowUnverified': 'true' } log.info('Re-verifying Persona assertion. url: %s, audience: %s, ' 'extra_params: %s' % (url, audience, extra_params)) result = verify_assertion(form.cleaned_data['assertion'], audience, extra_params) log.info('Reverify got result: %s') if result: logged_user = request.session.get('uuid') email = result.get('unverified-email', result.get('email')) reverified_user = get_uuid(email) if logged_user and logged_user != reverified_user: # TODO: Should we try to support this? raise ValueError('A user tried to reverify herself with a ' 'new email: %s' % email) return {'user_hash': reverified_user} log.error('Persona assertion failed.') request.session.clear() return http.HttpResponseBadRequest()
def purchase(request, addon): log.debug('Starting purchase of addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) amount = addon.premium.get_price() source = request.GET.get('source', '') uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() # l10n: {0} is the addon name contrib_for = _(u'Purchase of {0}').format(jinja2.escape(addon.name)) paykey, error = '', '' try: paykey = paypal.get_paykey(dict(uuid=uuid_, slug=addon.slug, amount=amount, memo=contrib_for, email=addon.paypal_id, ip=request.META.get('REMOTE_ADDR'), pattern='addons.purchase.finished', qs={'realurl': request.GET.get('realurl')}, ipn=False)) except: log.error('Error getting paykey, purchase of addon: %s' % addon.pk, exc_info=True) error = _('There was an error communicating with PayPal.') if paykey: contrib = Contribution(addon_id=addon.id, amount=amount, source=source, source_locale=request.LANG, uuid=str(uuid_), type=amo.CONTRIB_PENDING, paykey=paykey, user=request.amo_user) contrib.save() log.debug('Got paykey for addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey) if request.GET.get('result_type') == 'json' or request.is_ajax(): return http.HttpResponse(json.dumps({'url': url, 'paykey': paykey, 'error': error}), content_type='application/json') return http.HttpResponseRedirect(url)