def verify_password(user_id_or_token_or_username, password): if os.environ.get('TESTING') == "True": g.user_id_or_token = "" g.password = "" return True response_obj = send_request('get', 'users', f'users/name/{user_id_or_token_or_username}', timeout=3) if response_obj.status_code == 200: user_id_or_token_or_username = response_obj.json['data']['id'] response = send_request('get', 'authentication', 'verify_credentials', timeout=3, auth=(user_id_or_token_or_username, password)) if response.status_code == 401: g.reason = 'Wrong credentials' return False elif response.status_code != 200: g.reason = 'Other reason' return False try: g.user_id = response.json['user_id'] except KeyError: g.user_id = None g.user_id_or_token = user_id_or_token_or_username g.password = password return True
def create_message(): """ Creates a new message. Notifies: anti-cyberbullying, ad """ post_data = request.get_json() response_object = { 'status': 'fail', 'message': 'Invalid payload.' } if not post_data: return jsonify(response_object), 400 contents = post_data.get('contents') sender_id = post_data.get('sender_id') receiver_id = post_data.get('receiver_id') if contents is None or sender_id is None or receiver_id is None: return jsonify(response_object), 400 try: # Check for bad words r_obj = send_request('post', 'anti-cyberbullying', 'anti_cyberbullying/contains_bad_word', timeout=3, json={'sentence': str(contents)}, auth=(g.user_id_or_token, g.password)) response_object['anti-cyberbullying'] = r_obj.json if r_obj.status_code == 201: if r_obj.json['result']: response_object['message'] = f'Post contains bad words: {r_obj.json["bad_word"]}' return jsonify(response_object), 201 # Update user categories for ads r_obj = send_request('post', 'ad', f'ads/user/{sender_id}', timeout=3, json={'sentence': str(contents)}, auth=(g.user_id_or_token, g.password)) response_object['ad'] = r_obj.json # Send notification to receiver try: response_obj = send_request('get', 'users', f'users/{sender_id}', timeout=3, auth=(g.user_id_or_token, g.password)) response_object['users'] = response_obj.json username = response_obj.json['data']['username'] send_request('post', 'notification', 'notifications', timeout=3, json={'content': f'{username} has sent you a message', 'recipients': [receiver_id]}, auth=(g.user_id_or_token, g.password)) response_object['notification'] = response_obj.json except: pass db.session.add(Message(contents=contents, sender_id=sender_id, receiver_id=receiver_id)) db.session.commit() response_object['status'] = 'success' response_object['message'] = 'message was successfully created' return jsonify(response_object), 201 except Exception as e: db.session.rollback() return jsonify(response_object), 400
def create_friend(): """Create friend request""" post_data = request.get_json() response_object = { 'status': 'fail', 'message': 'Invalid payload.' } if not post_data: return jsonify(response_object), 400 friend_initiator_id = post_data.get('friend_initiator_id') friend_acceptor_id = post_data.get('friend_acceptor_id') if friend_initiator_id is None or friend_acceptor_id is None: return jsonify(response_object), 400 if int(friend_initiator_id) == int(friend_acceptor_id): response_object['message'] = 'You cannot friend yourself' return jsonify(response_object), 400 try: if Friend.query.filter_by(friend_initiator_id=friend_acceptor_id, friend_acceptor_id=friend_initiator_id).count(): response_object['message'] = 'Friendship already exists or is already requested' return jsonify(response_object), 400 db.session.add(Friend(friend_initiator_id=friend_initiator_id, friend_acceptor_id=friend_acceptor_id)) db.session.commit() response_object['status'] = 'success' response_object['message'] = 'friendship request was successfully created' try: response_obj = send_request('get', 'users', f'users/{friend_initiator_id}', timeout=3, auth=(g.user_id_or_token, g.password)) response_object['users'] = response_obj.json username = f'User {friend_initiator_id}' try: username = response_obj.json['data']['username'] except: pass response_obj = send_request('post', 'notification', 'notifications', timeout=3, json={'content': f'{username} has sent you a friend invite', 'recipients': [friend_acceptor_id]}, auth=(g.user_id_or_token, g.password)) response_object['notification'] = response_obj.json except: response_object['warning'] = 'failed creating a notification' return jsonify(response_object), 201 except Exception as e: db.session.rollback() # response_object["what"] = str(e) return jsonify(response_object), 400
def is_admin(user_id): response = send_request('put', 'authentication', 'is_admin', timeout=3, json={'user_id': user_id}) return response.json['is_admin']
def accept_friend(): """Accept friend request""" put_data = request.get_json() response_object = { 'status': 'fail', 'message': 'Invalid payload.' } if not put_data: return jsonify(response_object), 400 friend_initiator_id = put_data.get('friend_initiator_id') friend_acceptor_id = put_data.get('friend_acceptor_id') if friend_initiator_id is None or friend_acceptor_id is None: return jsonify(response_object), 400 try: friend = Friend.query.filter_by( friend_initiator_id=friend_initiator_id, friend_acceptor_id=friend_acceptor_id).first() friend.is_accepted = True db.session.commit() response_object['status'] = 'success' response_object['message'] = 'friendship request was successfully accepted' # Get name of acceptor r_obj = send_request('get', 'users', f'users/{friend_acceptor_id}', timeout=3, auth=(g.user_id_or_token, g.password)) try: friend_acceptor_name = r_obj.json['data']['username'] except: friend_acceptor_name = f'User {friend_initiator_id}' # Send notification to initiator r_obj = send_request('post', 'notification', 'notifications', timeout=3, json={'content': f'{friend_acceptor_name} has sent you a friend invite', 'recipients': [friend_initiator_id]}, auth=(g.user_id_or_token, g.password)) response_object['notification'] = r_obj.json return jsonify(response_object), 200 except Exception as e: db.session.rollback() # response_object["what"] = str(e) return jsonify(response_object), 400
def add_user(): response_object = {'status': 'fail', 'message': 'Invalid payload'} parameters = request.get_json() if not parameters: return jsonify(response_object), 400 try: username = str(parameters.get('username')) password = str(parameters.get('password')) user = User.query.filter_by(username=username).first() if not user: # SHA256 is used to hash passwords now, in the real world it's better to use salt and whatnot password_hash = hashlib.sha256(password.encode('utf8')).hexdigest() user = User(username=username, password=password_hash) db.session.add(user) db.session.commit() # Generate key (and IV) for this specific user to encrypt future information response_obj = send_request('post', 'encryption', 'keys', json={'user_id': user.id}) if response_obj.status_code != 201: raise RequestException('Failed generating key for user') response_object['status'] = 'success' response_object['message'] = f'{username} was successfully added' response_object['user_id'] = user.id return jsonify(response_object), 201 else: response_object['message'] = f'Username {username} already exists' return jsonify(response_object), 400 except (exc.IntegrityError, RequestException) as e: response_object['message'] = str(e) db.session.rollback() return jsonify(response_object), 400
def create_payment(): """Generate a new key of a user""" response_object = {'status': 'fail', 'message': 'Invalid payload'} parameters = request.get_json() if not parameters: return jsonify(response_object), 400 try: payment_successful = False user_id = int(parameters.get('user_id')) card_type = str(parameters.get('card_type')) amount = int(parameters.get('amount')) # Get key (and IV) to encrypt the sensitive information response_obj = send_request('get', 'encryption', f'keys/{user_id}') if response_obj.status_code != 200: raise RequestException('Failed retrieving key for user') # Initialize some AES parameters response_json = response_obj.json key = bytes.fromhex(response_json['key']['key']) IV = bytes.fromhex(response_json['key']['IV']) unpad = lambda s: s[:-ord(s[len(s) - 1:])] # Get encrypted data _card_holder_name = base64.b64decode( parameters.get('card_holder_name')) _card_number = base64.b64decode(parameters.get('card_number')) _expiration_date_month = base64.b64decode( parameters.get('expiration_date_month')) _expiration_date_year = base64.b64decode( parameters.get('expiration_date_year')) _cvv = base64.b64decode(parameters.get('cvv')) # Set up AES's aes_card_holder_name = AES.new(key, AES.MODE_CBC, _card_holder_name[:16]) aes_card_number = AES.new(key, AES.MODE_CBC, _card_number[:16]) aes_expiration_date_month = AES.new(key, AES.MODE_CBC, _expiration_date_month[:16]) aes_expiration_date_year = AES.new(key, AES.MODE_CBC, _expiration_date_year[:16]) aes_cvv = AES.new(key, AES.MODE_CBC, _cvv[:16]) # Decrypt the credit card information card_holder_name = unpad( aes_card_holder_name.decrypt( _card_holder_name[16:]).decode("utf-8")) card_number = unpad( aes_card_number.decrypt(_card_number[16:]).decode("utf-8")) expiration_date_month = unpad( aes_expiration_date_month.decrypt( _expiration_date_month[16:]).decode("utf-8")) expiration_date_year = unpad( aes_expiration_date_year.decrypt( _expiration_date_year[16:]).decode("utf-8")) cvv = unpad(aes_cvv.decrypt(_cvv[16:]).decode("utf-8")) # Actual call to payment API if card_type == 'VISA': time.sleep(float( os.environ.get('API_RESPONSE_TIME'))) # Just "mock" for now payment_successful = True elif card_type == 'MasterCard': time.sleep(float( os.environ.get('API_RESPONSE_TIME'))) # Just "mock" for now payment_successful = True elif card_type == 'American Express': time.sleep(float( os.environ.get('API_RESPONSE_TIME'))) # Just "mock" for now payment_successful = True else: raise RequestException('Unsupported credit card type') response_object['status'] = 'success' response_object['message'] = f'Successfully processed transaction' response_object['payment_successful'] = payment_successful return jsonify(response_object), 201 except Exception as e: response_object['message'] = str(e) return jsonify(response_object), 400
def order_ticket(): response_object = { 'status': 'fail', 'message': 'Invalid payload' } parameters = request.get_json() if not parameters: return jsonify(response_object), 400 try: user_id = int(parameters.get('user_id')) token = str(parameters.get('token')) # Verify user response_obj = send_request('post', 'user', 'users/verify', json={ 'user_id': user_id, 'token': token }) valid_token = False user = None if response_obj.status_code == 200: response = response_obj.json valid_token = response['valid_token'] user = response['user'] else: response_object = response_obj return jsonify(response_object), 400 if valid_token: stop = False # Choose the database shard shards = int(os.environ['NR_OF_SHARDS']) initial_shard = hash(token) % shards shard_nr = initial_shard while not stop: # Lock the tickets count until the end of the transaction # EXCLUSIVE MODE = most strict, only one transaction per table db.session.execute(f'LOCK TABLE "count-{shard_nr}" IN ACCESS EXCLUSIVE MODE;') # Check if there are any tickets left in this shard ticketsLeft = ticketsLeftDBs[shard_nr].query.first() if ticketsLeft.count > 0: # Try the actual payment response_obj = send_request('post', 'payment', 'payment', json={ 'user_id': user['id'], 'card_type': user['card_type'], 'card_holder_name': user['card_holder_name'], 'card_number': user['card_number'], 'expiration_date_month': user['expiration_date_month'], 'expiration_date_year': user['expiration_date_year'], 'cvv': user['cvv'], 'amount': 100 }) if response_obj.status_code != 201 or not response_obj.json['payment_successful']: raise RequestException(f'Failed processing the payment with {user["card_type"]}') # Everything went successful => create new ticket ticket = ticketDBs[shard_nr](user_id, token) db.session.add(ticket) ticketsLeft.count -= 1 db.session.commit() response_object['ticket_id'] = ticket.id response_object['message'] = 'Successfully ordered a new ticket' stop = True else: # Go to the next shard shard_nr = (shard_nr + 1) % shards if shard_nr == initial_shard: # No more tickets in all DB's response_object['message'] = 'No more tickets left' stop = True else: response_object['message'] = 'User verification failed' response_object['status'] = 'success' return jsonify(response_object), 200 except (exc.IntegrityError, RequestException) as e: response_object['message'] = str(e) db.session.rollback() return jsonify(response_object), 400
def update_user(): response_object = {'status': 'fail', 'message': 'Invalid payload'} parameters = request.get_json() if not parameters: return jsonify(response_object), 400 user_id = str(parameters.get('user_id')) try: user = User.query.filter_by(id=int(user_id)).first() if not user: response_object['message'] = 'User does not exist' return jsonify(response_object), 404 else: # Get key (and IV) to encrypt the sensitive information response_obj = send_request('get', 'encryption', f'keys/{user_id}') if response_obj.status_code != 200: raise RequestException('Failed retrieving key for user') # Initialize some AES parameters response_json = response_obj.json key = bytes.fromhex(response_json['key']['key']) IV = bytes.fromhex(response_json['key']['IV']) pad = lambda s: s + (16 - len(s) % 16) * chr(16 - len(s) % 16) # Get raw data user.gender = str(parameters.get('gender')) user.country = str(parameters.get('country')) user.city = str(parameters.get('city')) user.zip_code = str(parameters.get('zip_code')) user.street = str(parameters.get('street')) user.card_type = str(parameters.get('card_type')) # Encrypt credit card information aes = AES.new(key, AES.MODE_CBC, IV) user.card_holder_name = base64.b64encode(IV + aes.encrypt( pad(str(parameters.get('card_holder_name'))))).decode('utf-8') aes = AES.new(key, AES.MODE_CBC, IV) user.card_number = base64.b64encode(IV + aes.encrypt( pad(str(parameters.get('card_number'))))).decode('utf-8') aes = AES.new(key, AES.MODE_CBC, IV) user.expiration_date_month = base64.b64encode( IV + aes.encrypt(pad(str(parameters.get('expiration_date_month')))) ).decode('utf-8') aes = AES.new(key, AES.MODE_CBC, IV) user.expiration_date_year = base64.b64encode( IV + aes.encrypt(pad(str(parameters.get('expiration_date_year')))) ).decode('utf-8') aes = AES.new(key, AES.MODE_CBC, IV) user.cvv = base64.b64encode( IV + aes.encrypt(pad(str(parameters.get('cvv'))))).decode('utf-8') # Create token based on hash of User token = str(hash(user)) user.token = token db.session.commit() response_object['status'] = 'success' response_object[ 'message'] = f'{user.username} was successfully updated' response_object['token'] = token return jsonify(response_object), 200 except (exc.IntegrityError, RequestException) as e: response_object['message'] = str(e) db.session.rollback() return jsonify(response_object), 400