Exemple #1
0
async def stripe_request(app,
                         auth,
                         method,
                         path,
                         *,
                         idempotency_key=None,
                         **data):
    client: ClientSession = app['stripe_client']
    settings: Settings = app['settings']
    metadata = data.pop('metadata', None)
    if metadata:
        data.update({f'metadata[{k}]': v for k, v in metadata.items()})
    headers = {}
    if idempotency_key:
        headers[
            'Idempotency-Key'] = idempotency_key + settings.stripe_idempotency_extra
    full_path = settings.stripe_root + path
    async with client.request(method,
                              full_path,
                              data=data or None,
                              auth=auth,
                              headers=headers) as r:
        if r.status == 200:
            return await r.json()
        else:
            # check stripe > developer > logs for more info
            text = await r.text()
            raise RequestError(r.status, full_path, info=text)
Exemple #2
0
async def google_get_details(m: GoogleSiwModel, app):
    settings: Settings = app['settings']
    async with app['http_client'].get(settings.google_siw_url) as r:
        if r.status != 200:
            raise RequestError(r.status,
                               settings.google_siw_url,
                               info=await r.text())
        certs = await r.json()
    try:
        id_info = google_jwt.decode(m.id_token,
                                    certs=certs,
                                    audience=settings.google_siw_client_key)
    except ValueError as e:
        logger.warning('google jwt decode error: %s', e)
        raise JsonErrors.HTTPBadRequest(message='google jwt decode error')

    # this should happen very rarely, if it does someone is doing something nefarious or things have gone very wrong
    assert id_info['iss'] in {
        'accounts.google.com', 'https://accounts.google.com'
    }, 'wrong google iss'
    assert id_info['email_verified'], 'google email not verified'

    # TODO image
    return {
        'email': id_info['email'].lower(),
        'first_name': id_info.get('given_name'),
        'last_name': id_info.get('family_name'),
    }
Exemple #3
0
async def check_grecaptcha(m: GrecaptchaModel, request, *, error_headers=None):
    settings: Settings = request.app['settings']
    client_ip = get_ip(request)
    if not m.grecaptcha_token:
        logger.warning('grecaptcha not provided, path="%s" ip=%s',
                       request.path, client_ip)
        raise JsonErrors.HTTPBadRequest(message='No recaptcha value',
                                        headers_=error_headers)

    post_data = {
        'secret': settings.grecaptcha_secret,
        'response': m.grecaptcha_token,
        'remoteip': client_ip,
    }
    async with request.app['http_client'].post(settings.grecaptcha_url,
                                               data=post_data) as r:
        if r.status != 200:
            raise RequestError(r.status,
                               settings.grecaptcha_url,
                               text=await r.text())
        data = await r.json()

    if data['success'] and remove_port(request.host) == data['hostname']:
        logger.info('grecaptcha success')
    else:
        logger.warning('grecaptcha failure, path="%s" ip=%s response=%s',
                       request.path,
                       client_ip,
                       data,
                       extra={'data': {
                           'grecaptcha_response': data
                       }})
        raise JsonErrors.HTTPBadRequest(message='Invalid recaptcha value',
                                        headers_=error_headers)
Exemple #4
0
async def facebook_get_details(m: FacebookSiwModel, app):
    try:
        sig, data = m.signed_request.split(b'.', 1)
    except ValueError:
        raise JsonErrors.HTTPBadRequest(
            message='"signedRequest" not correctly formed')

    settings: Settings = app['settings']
    expected_sig = hmac.new(settings.facebook_siw_app_secret, data,
                            hashlib.sha256).digest()
    if not compare_digest(padded_urlsafe_b64decode(sig), expected_sig):
        raise JsonErrors.HTTPBadRequest(
            message='"signedRequest" not correctly signed')

    signed_data = json.loads(padded_urlsafe_b64decode(data).decode())

    # can add 'picture' here, but it seems to be low res.
    details_url = (settings.facebook_siw_url + '?' +
                   urlencode({
                       'access_token': m.access_token,
                       'fields': ['email', 'first_name', 'last_name']
                   }))
    async with app['http_client'].get(details_url) as r:
        if r.status != 200:
            raise RequestError(r.status, details_url, text=await r.text())
        response_data = await r.json()

    if not (response_data['id'] == signed_data['user_id'] == m.user_id):
        raise JsonErrors.HTTPBadRequest(
            message='facebook userID not consistent')
    if not response_data.get('email') or not response_data.get('last_name'):
        raise JsonErrors.HTTPBadRequest(
            message=
            'Your Facebook profile needs to have both a last name and email address associated with it.'
        )

    return {
        'email': response_data['email'].lower(),
        'first_name': response_data['first_name'],
        'last_name': response_data['last_name'],
    }
Exemple #5
0
 async def _request(self, method, path, *, idempotency_key=None, **data):
     post = {}
     for k, v in data.items():
         if isinstance(v, dict):
             post.update({f'{k}[{kk}]': str(vv) for kk, vv in v.items()})
         else:
             post[k] = str(v)
     headers = {'Stripe-Version': self._settings.stripe_api_version}
     if idempotency_key:
         headers[
             'Idempotency-Key'] = idempotency_key + self._settings.stripe_idempotency_extra
     full_path = self._settings.stripe_root_url + path
     async with self._client.request(method,
                                     full_path,
                                     data=post or None,
                                     auth=self._auth,
                                     headers=headers) as r:
         if r.status == 200:
             return await r.json()
         else:
             # check stripe > developer > logs for more info
             text = await r.text()
             raise RequestError(r.status, full_path, text=text)
Exemple #6
0
async def check_grecaptcha(m: GrecaptchaModel, client_ip, app):
    if not m.grecaptcha_token:
        # TODO remove once grecaptcha_token is required
        raise JsonErrors.HTTPBadRequest(message='grecaptcha token missing')

    settings: Settings = app['settings']
    post_data = {
        'secret': settings.grecaptcha_secret,
        'response': m.grecaptcha_token,
        'remoteip': client_ip,
    }
    async with app['http_client'].post(settings.grecaptcha_url,
                                       data=post_data) as r:
        if r.status != 200:
            raise RequestError(r.status,
                               settings.grecaptcha_url,
                               info=await r.text())
        data = await r.json()

    if not data['success'] or data['score'] < settings.grecaptcha_threshold:
        logger.warning('grecaptcha failure, ip=%s, response=%s', client_ip,
                       data)
        raise JsonErrors.HTTPBadRequest(message='Invalid recaptcha value')
Exemple #7
0
def test_request_error():
    r = RequestError(500, 'xxx', text='hello')
    assert str(r) == 'response 500 from "xxx":\nhello'
    assert r.extra() == 'hello'