Пример #1
0
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
Пример #2
0
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
Пример #3
0
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
Пример #4
0
def is_admin(user_id):
    response = send_request('put',
                            'authentication',
                            'is_admin',
                            timeout=3,
                            json={'user_id': user_id})
    return response.json['is_admin']
Пример #5
0
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
Пример #6
0
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
Пример #7
0
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
Пример #8
0
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
Пример #9
0
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