Skip to content
This repository has been archived by the owner on Mar 15, 2018. It is now read-only.

Commit

Permalink
Merge branch 'inapp-revoke'
Browse files Browse the repository at this point in the history
  • Loading branch information
kumar303 committed Jun 8, 2012
2 parents ceabafc + 76e2353 commit e576444
Show file tree
Hide file tree
Showing 15 changed files with 325 additions and 117 deletions.
86 changes: 86 additions & 0 deletions lib/cef_loggers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""Our app specific CEF loggers."""
from django.conf import settings
from django.http import HttpRequest

from cef import log_cef as _log_cef


class CEFLogger:
"""Abstract base CEF logger.
Class attributes to set in a concrete class:
**sig_prefix**
Prefix to the CEF signature. Example: RECEIPT
**cs2label**
cs2label parameter. Example: ReceiptTransaction
**msg_prefix**
Prefix to all CEF log messages. Example: Receipt
**default_severity**
If set, this should be a 0-10 int.
"""
sig_prefix = ''
cs2label = None
msg_prefix = ''
default_severity = None

def log(self, environ, app, msg, longer, severity=None,
extra_kwargs=None):
"""Log something important using the CEF library.
Parameters:
**environ**
Typically a Django request object. It can also be
a plain dict.
**app**
An app/addon object.
**msg**
A short message about the incident.
**longer**
A more description message about the incident.
**severity=None**
A 0-10 int to override the default severity.
**extra_kwargs**
A dict to override anything sent to the CEF library.
"""
c = {'cef.product': getattr(settings, 'CEF_PRODUCT', 'AMO'),
'cef.vendor': getattr(settings, 'CEF_VENDOR', 'Mozilla'),
'cef.version': getattr(settings, 'CEF_VERSION', '0'),
'cef.device_version': getattr(settings, 'CEF_DEVICE_VERSION', '0'),
'cef.file': getattr(settings, 'CEF_FILE', 'syslog'), }

kwargs = {'username': getattr(environ, 'amo_user', ''),
'signature': '%s%s' % (self.sig_prefix, msg.upper()),
'msg': longer, 'config': c,
'cs2': app, 'cs2Label': self.cs2label}
if extra_kwargs:
kwargs.update(extra_kwargs)

if not severity:
severity = self.default_severity
if not severity:
raise ValueError('CEF severity was not defined')

if isinstance(environ, HttpRequest):
environ = environ.META.copy()
return _log_cef('%s %s' % (self.msg_prefix, msg), severity,
environ, **kwargs)


class ReceiptCEFLogger(CEFLogger):
sig_prefix = 'RECEIPT'
cs2label = 'ReceiptTransaction'
msg_prefix = 'Receipt'
default_severity = 5


receipt_cef = ReceiptCEFLogger()


class InappCEFLogger(CEFLogger):
sig_prefix = 'INAPP_PAY'
cs2label = 'InappPayment'
msg_prefix = 'InappPayment'
default_severity = 5


inapp_cef = InappCEFLogger()
20 changes: 0 additions & 20 deletions lib/crypto/receipt.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
import urllib2

from django.conf import settings
from django.http import HttpRequest
from django_statsd.clients import statsd

from cef import log_cef as _log_cef
import commonware.log

log = commonware.log.getLogger('z.services')
Expand Down Expand Up @@ -64,21 +62,3 @@ def decode(receipt):
if it is valid.
"""
raise NotImplementedError


def cef(environ, app, msg, longer):
"""Log receipt transactions to the CEF library."""
c = {'cef.product': getattr(settings, 'CEF_PRODUCT', 'AMO'),
'cef.vendor': getattr(settings, 'CEF_VENDOR', 'Mozilla'),
'cef.version': getattr(settings, 'CEF_VERSION', '0'),
'cef.device_version': getattr(settings, 'CEF_DEVICE_VERSION', '0'),
'cef.file': getattr(settings, 'CEF_FILE', 'syslog'), }

kwargs = {'username': getattr(environ, 'amo_user', ''),
'signature': 'RECEIPT%s' % msg.upper(),
'msg': longer, 'config': c,
'cs2': app, 'cs2Label': 'ReceiptTransaction'}

if isinstance(environ, HttpRequest):
environ = environ.META.copy()
return _log_cef('Receipt %s' % msg, 5, environ, **kwargs)
12 changes: 6 additions & 6 deletions lib/crypto/util.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import base64
import os


__all__ = ['generate_key']


def generate_key(byte_length):
"""Return a true random ascii string that is byte_length long.
"""Return a true random ascii string containing byte_length of randomness.
The resulting key is suitable for cryptogrpahy.
The key will be hex encoded which means it will be twice as long
as byte_length, i.e. 40 random bytes yields an 80 byte string.
byte_length must be at least 32.
"""
if byte_length < 32: # at least 256 bit
raise ValueError('um, %s is probably not long enough for cryptography'
% byte_length)
key = os.urandom(byte_length)
key = base64.b64encode(key).rstrip('=') # strip off padding
key = key[0:byte_length]
return key
return os.urandom(byte_length).encode('hex')
2 changes: 1 addition & 1 deletion media/css/devreg/in-app-config.less
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

.devhub-form .in-app-config {
input[type="text"] {
width: 30em;
width: 37em;
}
.is-https.hint {
display: inline;
Expand Down
12 changes: 6 additions & 6 deletions mkt/detail/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ def test_record_logged_out(self):
res = self.client.post(self.url)
eq_(res.status_code, 302)

@mock.patch('mkt.detail.views.cef')
@mock.patch('mkt.detail.views.receipt_cef.log')
def test_log_metrics(self, cef):
res = self.client.post(self.url)
eq_(res.status_code, 200)
Expand All @@ -574,15 +574,15 @@ def test_log_metrics(self, cef):
eq_(logs[0].activity_log.action, amo.LOG.INSTALL_ADDON.id)

@mock.patch('mkt.detail.views.send_request')
@mock.patch('mkt.detail.views.cef')
@mock.patch('mkt.detail.views.receipt_cef.log')
def test_record_metrics(self, cef, send_request):
res = self.client.post(self.url)
eq_(res.status_code, 200)
eq_(send_request.call_args[0][0], 'install')
eq_(send_request.call_args[0][2], {'app-domain': u'cbc.ca',
'app-id': self.addon.pk})

@mock.patch('mkt.detail.views.cef')
@mock.patch('mkt.detail.views.receipt_cef.log')
def test_cef_logs(self, cef):
res = self.client.post(self.url)
eq_(res.status_code, 200)
Expand All @@ -596,13 +596,13 @@ def test_cef_logs(self, cef):
eq_([x[0][2] for x in cef.call_args_list],
['request', 'sign', 'request'])

@mock.patch('mkt.detail.views.cef')
@mock.patch('mkt.detail.views.receipt_cef.log')
def test_record_install(self, cef):
res = self.client.post(self.url)
eq_(res.status_code, 200)
eq_(self.user.installed_set.count(), 1)

@mock.patch('mkt.detail.views.cef')
@mock.patch('mkt.detail.views.receipt_cef.log')
def test_record_multiple_installs(self, cef):
self.client.post(self.url)
res = self.client.post(self.url)
Expand All @@ -611,7 +611,7 @@ def test_record_multiple_installs(self, cef):

@mock.patch.object(settings, 'WEBAPPS_RECEIPT_KEY',
amo.tests.AMOPaths.sample_key())
@mock.patch('mkt.detail.views.cef')
@mock.patch('mkt.detail.views.receipt_cef.log')
def test_record_receipt(self, cef):
res = self.client.post(self.url)
content = json.loads(res.content)
Expand Down
9 changes: 5 additions & 4 deletions mkt/detail/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
from addons.decorators import addon_view_factory
import amo
import amo.log
from amo.decorators import json_view, login_required, post_required, write
from amo.decorators import json_view, post_required, write
from amo.forms import AbuseForm
from amo.urlresolvers import reverse
from amo.utils import memoize_get
from lib.metrics import send_request
from lib.crypto.receipt import cef, SigningError
from lib.crypto.receipt import SigningError
from lib.cef_loggers import receipt_cef

from mkt.ratings.models import Rating
from mkt.site import messages
Expand Down Expand Up @@ -113,9 +114,9 @@ def _record(request, addon):
# to recreate it.
receipt = memoize_get('create-receipt', installed.pk)
error = ''
cef(request, addon, 'request', 'Receipt requested')
receipt_cef.log(request, addon, 'request', 'Receipt requested')
if not receipt:
cef(request, addon, 'sign', 'Receipt signing')
receipt_cef.log(request, addon, 'sign', 'Receipt signing')
try:
receipt = create_receipt(installed.pk)
except SigningError:
Expand Down
149 changes: 89 additions & 60 deletions mkt/developers/templates/developers/payments/in-app-config.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,69 +14,98 @@
{{ hub_breadcrumbs(addon, items=[(None, title)]) }}
<h1>{{ title }}</h1>
</header>
<section id="in-app-config" class="primary devhub-form island" role="main">
<form class="item in-app-config" method="post" action="{{ request.path }}">
<p>
{{ _('The Mozilla Marketplace allows your app to take in-app payments.
The <a href="{guide}">in-app payment guide</a> explains how to
configure your app for payments with the parameters below.
')|f(guide='https://developer.mozilla.org/en/Apps/In-app_payments')|safe }}
</p>
{{ csrf() }}
<table>
<tr>
<th class="label">{{ _('Application Domain') }}</th>
<td><span class="inapp-domain-protocol">https://</span>{{ addon.app_domain }}</td>
</tr>
<tr>
<th><label for="id_is_https">{{ _("SSL") }} {{ required() }}</label></th>
<td>
{{ inapp_form.is_https }}
{{ inapp_form.is_https.errors }}
<span class="is-https hint">{{ inapp_form.is_https.help_text }}</span>
</td>
</tr>
<tr>
<th><label for="id_postback_url">{{ _("Postback URL") }} {{ required() }}</label></th>
<td>
{{ inapp_form.postback_url }}
{{ inapp_form.postback_url.errors }}
<span class="hint">{{ inapp_form.postback_url.help_text }}</span>
</td>
</tr>
<tr>
<th><label for="id_chargeback_url">{{ _("Chargeback URL") }} {{ required() }}</label></th>
<td>
{{ inapp_form.chargeback_url }}
{{ inapp_form.chargeback_url.errors }}
<span class="hint">{{ inapp_form.chargeback_url.help_text }}</span>
</td>
</tr>
<tr id="in-app-public-key">
<th class="label">{{ _('Application Key') }}</th>
{% if inapp_config %}
<td><input type="text" value="{{ inapp_config.public_key }}" readonly></td>
{% else %}
<td class="not-generated">({{ _('Not yet generated.') }})</td>
{% endif %}
</tr>
<tr id="in-app-private-key">
<th class="label">{{ _('Application Secret') }}</th>
{% if inapp_config %}
<section class="primary manage" role="main">
<div id="in-app-config" class="devhub-form island">
<form class="item in-app-config" method="post" action="{{ request.path }}">
<p>
{{ _('The Mozilla Marketplace allows your app to take in-app payments.
The <a href="{guide}">in-app payment guide</a> explains how to
configure your app for payments with the parameters below.
')|f(guide='https://developer.mozilla.org/en/Apps/In-app_payments')|safe }}
</p>
{{ csrf() }}
<table>
<tr>
<th class="label">{{ _('Application Domain') }}</th>
<td><span class="inapp-domain-protocol">https://</span>{{ addon.app_domain }}</td>
</tr>
<tr>
<th><label for="id_is_https">{{ _("SSL") }} {{ required() }}</label></th>
<td>
{{ inapp_form.is_https }}
{{ inapp_form.is_https.errors }}
<span class="is-https hint">{{ inapp_form.is_https.help_text }}</span>
</td>
</tr>
<tr>
<th><label for="id_postback_url">{{ _("Postback URL") }} {{ required() }}</label></th>
<td>
{{ inapp_form.postback_url }}
{{ inapp_form.postback_url.errors }}
<span class="hint">{{ inapp_form.postback_url.help_text }}</span>
</td>
</tr>
<tr>
<th><label for="id_chargeback_url">{{ _("Chargeback URL") }} {{ required() }}</label></th>
<td>
<button data-url="{{ addon.get_dev_url('in_app_secret') }}"
class="generator">{{ _('Show secret') }}</button>
<input type="text" class="secret" type="text" value="" readonly>
{{ inapp_form.chargeback_url }}
{{ inapp_form.chargeback_url.errors }}
<span class="hint">{{ inapp_form.chargeback_url.help_text }}</span>
</td>
{% else %}
<td class="not-generated">({{ _('Not yet generated.') }})</td>
</tr>
<tr id="in-app-public-key">
<th class="label">{{ _('Application Key') }}</th>
{% if inapp_config %}
<td><input type="text" value="{{ inapp_config.public_key }}" readonly></td>
{% else %}
<td class="not-generated">({{ _('Not yet generated.') }})</td>
{% endif %}
</tr>
<tr id="in-app-private-key">
<th class="label">{{ _('Application Secret') }}</th>
{% if inapp_config %}
<td>
<button data-url="{{ addon.get_dev_url('in_app_secret') }}"
class="generator">{{ _('Show secret') }}</button>
<input type="text" class="secret" type="text" value="" readonly>
</td>
{% else %}
<td class="not-generated">({{ _('Not yet generated.') }})</td>
{% endif %}
</tr>
</table>
<div class="listing-footer">
{% if inapp_config %}
{% endif %}
</tr>
</table>
<div class="listing-footer">
<button type="submit">{{ _('Save Changes') }}</button>
</div>
</form>
<button type="submit">{{ _('Save Changes') }}</button>
</div>
</form>
</div>
<h2>{{ _('Reset credentials') }}</h2>
<div class="devhub-form island">
{% if inapp_config %}
{% set reset = addon.get_dev_url('reset_in_app_config', [inapp_config.pk]) %}
{% else %}
{% set reset = '' %}
{% endif %}
<form method="post" action="{{ reset }}">
{{ csrf() }}
<p>
{% trans %}
In case your <b>Application Key</b> or <b>Application Secret</b>
ever gets compromised, you can reset them here to stop all payments.
After the reset, your app can no longer make payments with the
old credentials.
You will be granted new credentials that you can use to
accept in-app payments immediately.
{% endtrans %}
</p>
<div class="listing-footer">
<button {% if not inapp_config %}disabled{% endif %}
type="submit">{{ _('Reset credentials') }}</button>
</div>
</form>
</div>
</section>
{% include "developers/includes/addons_edit_nav.html" %}
{% endblock %}
Loading

0 comments on commit e576444

Please sign in to comment.