def auth_async(code): try: result = yield _fetch_async( 'https://www.googleapis.com/oauth2/v4/token', method='POST', payload=urllib.urlencode({ 'client_id': '_REMOVED_', 'code': code, 'grant_type': 'authorization_code', 'redirect_uri': 'cam.reaction.ReactionCam:/youtube_oauth2redirect', }), follow_redirects=False, deadline=10) data = json.loads(result.content) except Exception as e: logging.exception('YouTube token exchange failed.') raise errors.ServerError() if result.status_code != 200: logging.debug('Could not exchange code: %r', data) raise errors.InvalidArgument('Failed to exchange code for token') try: id_token = data.pop('id_token') id_hdr, id_bdy, id_sig = (p + ('=' * (-len(p) % 4)) for p in id_token.split('.')) profile = json.loads(base64.b64decode(id_bdy)) assert 'sub' in profile except: logging.debug('Could not extract profile data: %r', data) raise errors.InvalidArgument('Missing profile in token response') raise ndb.Return((data, profile))
def get_video_async(video_id, snippet=True, statistics=False): if not (snippet or statistics): raise errors.InvalidArgument( 'Specify at least one of snippet, statistics') parts = [] if snippet: parts.append('snippet') if statistics: parts.append('statistics') try: qs = urllib.urlencode({ 'id': video_id, 'key': config.YOUTUBE_API_KEY, 'part': ','.join(parts), }) result = yield _fetch_async( 'https://www.googleapis.com/youtube/v3/videos?%s' % (qs, ), follow_redirects=False, deadline=10) data = json.loads(result.content) except Exception as e: logging.exception('YouTube call failed.') raise errors.ServerError() if result.status_code == 404: raise errors.ResourceNotFound('That video does not exist') elif result.status_code != 200: logging.debug('Could not get YouTube video (%d): %r', result.status_code, data) raise errors.InvalidArgument('Invalid video id') if data['pageInfo']['totalResults'] == 0: raise ndb.Return(None) if not data['items']: logging.warning('Expected at least one item in data: %r', data) raise ndb.Return(None) raise ndb.Return(data['items'][0])
def _tx(self, method, *args, **kwargs): for _ in xrange(2): stream = method(self._stream.key, *args, **kwargs) if stream: break else: # If the loop falls through, stream was never set. raise errors.ServerError( 'Failed to update stream (transaction rolled back)') self._stream = stream self._chunks = None
def validate(self, secret): result = models.Challenge.validate(self.client, self.identifier, secret) if result == models.Challenge.SUCCESS: return True elif result == models.Challenge.INVALID_SECRET: raise errors.InvalidArgument('An invalid secret was provided') elif result == models.Challenge.TOO_MANY_ATTEMPTS: raise errors.ResourceNotFound('Too many attempts') elif result == models.Challenge.EXPIRED: raise errors.ResourceNotFound('Challenge has expired') # Unexpected result. raise errors.ServerError()
def react_to_chunk(self, chunk_id, reaction_type): chunk_key = ndb.Key('Chunk', int(chunk_id), parent=self.key) stream, chunk = models.Stream.set_chunk_reaction( chunk_key, self.account.key, reaction_type) if not stream: raise errors.ServerError( 'Failed to update stream (transaction rolled back)') self._stream = stream self._chunks = None self.notify(notifs.ON_STREAM_CHUNK_REACTION, add_stream=True, chunk=chunk) return chunk
def itunes(receipt_data, url='https://buy.itunes.apple.com/verifyReceipt'): try: result = urlfetch.fetch(url=url, method=urlfetch.POST, payload=json.dumps( {'receipt-data': receipt_data}), deadline=30) data = json.loads(result.content) except Exception: logging.exception('Could not get result from Apple payment server.') raise errors.ServerError() if result.status_code != 200: logging.error('Apple payment server HTTP %d: %r', result.status_code, data) raise errors.InvalidArgument( 'Failed to validate receipt data with Apple') status = data.get('status') if not isinstance(status, (int, long)): logging.error('Could not get status: %r', data) raise errors.ServerError() if status == 0: return data elif status in (21000, 21002, 21003): raise errors.InvalidArgument('Invalid receipt data provided') elif status == 21005: raise errors.ExternalError() elif status == 21007: return itunes(receipt_data, url='https://sandbox.itunes.apple.com/verifyReceipt') elif status == 21008: return itunes(receipt_data) elif status == 21010: raise errors.InvalidArgument('Invalid purchase') elif 21100 <= status <= 21199: logging.error('Internal data access error: %r', data) raise errors.InvalidArgument('Invalid receipt data provided') logging.error('Unsupported status: %r', data) raise errors.NotSupported()
def _s3_upload(data, data_sha256, extension, mime_type): filename = data_sha256 + extension try: result = _aws4_signed_fetch(region='us-east-1', service='s3', headers={'x-amz-acl': 'public-read', 'x-amz-content-sha256': data_sha256, 'Content-Type': mime_type}, method='PUT', host='s3.amazonaws.com', path='/%s/%s' % (config.S3_BUCKET, filename), payload=data, payload_sha256=data_sha256) except: logging.exception('Could not upload to S3.') raise errors.ServerError() if result.status_code != 200: logging.debug('Could not upload file: %r', result.content) raise errors.InvalidArgument('Failed to upload file') return config.S3_BUCKET_CDN + filename
def get_channels_async(youtube_refresh_token): try: qs = urllib.urlencode({ 'youtube_token': youtube_refresh_token, }) result = yield _fetch_async( 'https://upload.reaction.cam/v2/channels?%s' % (qs, ), follow_redirects=False, headers={'Authorization': 'Bearer ' + ACCESS_TOKEN}, deadline=10) data = json.loads(result.content) except Exception as e: logging.exception('YouTube call failed.') raise errors.ServerError() if result.status_code in (400, 401): # TODO: We should probably invalidate the token. raise ndb.Return([]) if result.status_code != 200: logging.debug('Could not get channels (%d): %r', result.status_code, data) raise errors.ExternalError('Could not get channels') raise ndb.Return(data['channels'])