コード例 #1
0
    def post(self):
        request_data = request.get_json()
        user = g.user
        otp_token = request_data.get('otp')
        otp_expiry_interval = request_data.get('otp_expiry_interval')

        malformed_otp = False
        try:
            int(otp_token)
        except ValueError:
            malformed_otp = True

        if not isinstance(otp_token, str) or len(otp_token) != 6:
            malformed_otp = True

        if malformed_otp:
            response_object = {
                'status': "Failed",
                'message': "OTP must be a 6 digit numeric string"
            }

            return make_response(jsonify(attach_host(response_object))), 400

        if user.validate_OTP(otp_token):
            tfa_auth_token = user.encode_TFA_token(otp_expiry_interval)
            user.TFA_enabled = True

            db.session.commit()

            if tfa_auth_token:
                auth_token = g.user.encode_auth_token()

                response_object = create_user_response_object(
                    user, auth_token, 'Successfully logged in.')

                response_object['tfa_auth_token'] = tfa_auth_token.decode()

                return make_response(jsonify(
                    attach_host(response_object))), 200

        response_object = {
            'status': "Failed",
            'message': "Validation failed. Please try again."
        }

        return make_response(jsonify(response_object)), 400
コード例 #2
0
    def get(self):
        response_object = {
            'username': g.active_organisation.
            external_auth_username,  # Change this to org's credentials
            'password': g.active_organisation.external_auth_password
        }

        return make_response(jsonify(attach_host(response_object))), 200
コード例 #3
0
    def get(self):
        chain = get_chain()
        response_object = {
            'status': 'success',
            'message': 'Key loaded',
            'private_key': current_app.config['CHAINS'][chain]['MASTER_WALLET_PRIVATE_KEY'],
            'address': current_app.config['CHAINS'][chain]['MASTER_WALLET_ADDRESS']
        }

        return make_response(jsonify(attach_host(response_object))), 200
コード例 #4
0
    def post(self):
        # get auth token
        auth_header = request.headers.get('Authorization')
        if auth_header:
            auth_token = auth_header.split(" ")[0]
        else:
            auth_token = ''
        auth_token = auth_header.split("|")[0]
        if auth_token:
            resp = User.decode_auth_token(auth_token)
            if not isinstance(resp, str):
                # mark the token as blacklisted
                blacklist_token = BlacklistToken(token=auth_token)
                try:
                    # insert the token
                    db.session.add(blacklist_token)
                    db.session.commit()
                    response_object = {
                        'status': 'success',
                        'message': 'Successfully logged out.'
                    }
                    return make_response(jsonify(attach_host(response_object))), 200
                except Exception as e:
                    response_object = {
                        'status': 'fail',
                        'message': e
                    }
                    return make_response(jsonify(attach_host(response_object))), 200
            else:
                response_object = {
                    'status': 'fail',
                    'message': resp
                }
                return make_response(jsonify(response_object)), 401

        else:
            response_object = {
                'status': 'fail',
                'message': 'Provide a valid auth token.'
            }
            return make_response(jsonify(response_object)), 403
コード例 #5
0
    def get(self):

        print("process started")

        challenges = [
            ('Why don’t they play poker in the jungle?', 'Too many cheetahs.'),
            ('What did the Buddhist say to the hot dog vendor?',
             'Make me one with everything.'),
            ('What does a zombie vegetarian eat?', 'Graaaaaaaains!'),
            ('My new thesaurus is terrible.',
             'Not only that, but it’s also terrible.'),
            ('Why didn’t the astronaut come home to his wife?',
             'He needed his space.'),
            ('I got fired from my job at the bank today.',
             'An old lady came in and asked me to check her balance, so I pushed her over.'
             ),
            ('I like to spend every day as if it’s my last',
             'Staying in bed and calling for a nurse to bring me more pudding.'
             )
        ]

        challenge = random.choice(challenges)

        # time.sleep(int(request.args.get('delay', 0)))
        # from functools import reduce
        # reduce(lambda x, y: x + y, range(0, int(request.args.get('count', 1))))

        # memory_to_consume = int(request.args.get('MB', 0)) * 1000000
        # bytearray(memory_to_consume)

        ip_address = request.environ.get('HTTP_X_REAL_IP', request.remote_addr)
        user_agent = request.environ["HTTP_USER_AGENT"]
        ip = request.environ["REMOTE_ADDR"]
        # proxies = request.headers.getlist("X-Forwarded-For")
        # http://esd.io/blog/flask-apps-heroku-real-ip-spoofing.html

        response_object = {
            'status': 'success',
            'who_allows_a_get_request_to_their_auth_endpoint': 'We do.',
            challenge[0]: challenge[1],
            # 'metadata': {'user_agent': user_agent, 'ip': ip_address, 'otherip': ip, 'proxies': proxies},
        }
        return make_response(jsonify(attach_host(response_object))), 200
コード例 #6
0
    def get(self):
        try:

            auth_token = g.user.encode_auth_token()

            response_object = create_user_response_object(g.user, auth_token, 'Token refreshed successfully.')

            # Update the last_seen TS for this user
            g.user.update_last_seen_ts()

            return make_response(jsonify(attach_host(response_object))), 200

        except Exception as e:

            response_object = {
                'status': 'fail',
                'message': 'Some error occurred. Please try again.'
            }

            return make_response(jsonify(response_object)), 403
コード例 #7
0
    def get(self):

        admins = User.query.filter_by(has_admin_role=True).all()
        invites = EmailWhitelist.query.filter_by(
            used=False, allow_partial_match=False).all()

        admin_list = []
        for admin in admins:

            admin_list.append({
                'id': admin.id,
                'email': admin.email,
                'admin_tier': admin.admin_tier,
                'created': admin.created,
                'is_activated': admin.is_activated,
                'is_disabled': admin.is_disabled
            })

        invite_list = []
        for invite in invites:
            invite_list.append({
                'id': invite.id,
                'email': invite.email,
                'admin_tier': invite.tier,
                'created': invite.created,
            })

        response_object = {
            'status': 'success',
            'message': 'Admin List Loaded',
            'data': {
                'admins': admin_list,
                'invites': invite_list
            },
        }

        return make_response(jsonify(attach_host(response_object))), 200
コード例 #8
0
    def get(self):
        response_object = {
            'status': 'success',
        }

        return make_response(jsonify(attach_host(response_object))), 200
コード例 #9
0
    def put(self):

        put_data = request.get_json()

        user_id = put_data.get('user_id')
        admin_tier = put_data.get('admin_tier')
        deactivated = put_data.get('deactivated', None)

        invite_id = put_data.get('invite_id')
        resend = put_data.get('resend', False)

        if resend:
            invite = EmailWhitelist.query.get(invite_id)

            if not invite:
                return make_response(jsonify({'message': 'Invite not found'})), 404

            organisation = Organisation.query.get(invite.organisation_id)
            if not organisation:
                response_object = {'message': 'Organisation Not Found'}
                return make_response(jsonify(response_object)), 404

            invite.set_referral_code()
            invite.sent += 1

            db.session.flush()

            send_invite_email(invite, organisation)

            response_object = {'message': 'An invite has been re-sent!'}

            return make_response(jsonify(attach_host(response_object))), 200

        else:
            if not user_id:
                return make_response(jsonify({'message': 'User ID not provided'})), 400
            user = User.query.get(user_id)

            if not user:
                response_object = {
                    'status': 'fail',
                    'message': 'User not found'
                }

                return make_response(jsonify(response_object)), 404

            if admin_tier:
                user.set_held_role('ADMIN',admin_tier)
                flag_modified(user, '_held_roles')
            if deactivated is not None:
                user.is_disabled = deactivated

            response_object = {
                'message': 'Account status modified',
                'data': {
                    'admin': {
                        'id': user.id,
                        'email': user.email,
                        'admin_tier': user.admin_tier,
                        'created': user.created,
                        'is_activated': user.is_activated,
                        'is_disabled': user.is_disabled
                    }
                }
            }

            return make_response(jsonify(attach_host(response_object))), 200
コード例 #10
0
    def post(self):

        post_data = request.get_json()

        email = post_data.get('email', '')
        email = email.lower() if email else ''
        tier = post_data.get('tier')
        organisation_id = post_data.get('organisation_id', None)

        if not (email and tier):
            response_object = {'message': 'No email or tier provided'}
            return make_response(jsonify(response_object)), 400

        if not AccessControl.has_sufficient_tier(g.user.roles, 'ADMIN', tier):
            return make_response(jsonify({'message': f'User does not have permission to invite {tier}'})), 400

        if organisation_id and not AccessControl.has_sufficient_tier(g.user.roles, 'ADMIN', 'sempoadmin'):
            response_object = {'message': 'Not Authorised to set organisation ID'}
            return make_response(jsonify(response_object)), 401

        target_organisation_id = organisation_id or g.active_organisation.id
        if not target_organisation_id:
            response_object = {'message': 'Must provide an organisation to bind user to'}
            return make_response(jsonify(response_object)), 400

        organisation = Organisation.query.get(target_organisation_id)
        if not organisation:
            response_object = {'message': 'Organisation Not Found'}
            return make_response(jsonify(response_object)), 404

        email_exists_for_org = EmailWhitelist.query.filter(func.lower(EmailWhitelist.email)==email).first()
        if email_exists_for_org:
            response_object = {'message': 'Email already on organisation whitelist.'}
            return make_response(jsonify(response_object)), 400

        email_exists = EmailWhitelist.query.filter(func.lower(EmailWhitelist.email)==email)\
            .execution_options(show_all=True).first()
        if email_exists and not email_exists.used:
            response_object = {'message': 'Email already on another organisation whitelist. '
                                          'Please ask user to create an account first. '
                                          'Contact support if issue persists.'}
            return make_response(jsonify(response_object)), 400

        user = User.query.filter(func.lower(User.email)==email).execution_options(show_all=True).first()
        if user:
            user.add_user_to_organisation(organisation, is_admin=True)
            send_invite_email_to_existing_user(organisation, user.email)
            db.session.commit()
            response_object = {
                'message': 'An invite has been sent to an existing user!',
            }

            return make_response(jsonify(attach_host(response_object))), 201

        invite = EmailWhitelist(email=email,
                                tier=tier,
                                organisation_id=target_organisation_id)

        db.session.add(invite)

        send_invite_email(invite, organisation)

        db.session.commit()

        response_object = {
            'message': 'An invite has been sent!',
        }

        return make_response(jsonify(attach_host(response_object))), 201
コード例 #11
0
    def post(self):
        # get the post data
        post_data = request.get_json()

        email = post_data.get('email', '') or post_data.get('username', '')
        email = email.lower() if email else ''
        password = post_data.get('password')
        phone = post_data.get('phone')
        referral_code = post_data.get('referral_code')

        if phone is not None:
            # this is a registration from a mobile device THUS a vendor or recipient.
            response_object, response_code = UserUtils.proccess_create_or_modify_user_request(
                post_data,
                is_self_sign_up=True,
            )

            if response_code == 200:
                db.session.commit()

            return make_response(jsonify(attach_host(response_object))), response_code

        email_ok = False

        whitelisted_emails = EmailWhitelist.query\
            .filter_by(referral_code=referral_code, used=False) \
            .execution_options(show_all=True).all()

        selected_whitelist_item = None
        exact_match = False

        tier = None
        sempoadmin_emails = current_app.config['SEMPOADMIN_EMAILS']

        if sempoadmin_emails != [''] and email in sempoadmin_emails:
            email_ok = True
            tier = 'sempoadmin'

        for whitelisted in whitelisted_emails:
            if whitelisted.allow_partial_match and whitelisted.email in email:
                email_ok = True
                tier = whitelisted.tier
                selected_whitelist_item = whitelisted
                exact_match = False
                continue
            elif whitelisted.email == email:
                email_ok = True

                whitelisted.used = True
                tier = whitelisted.tier
                selected_whitelist_item = whitelisted
                exact_match = True
                continue

        if not email_ok:
            response_object = {
                'status': 'fail',
                'message': 'Invalid email domain.',
            }
            return make_response(jsonify(response_object)), 403

        if len(password) < 7:
            response_object = {
                'status': 'fail',
                'message': 'Password must be at least 6 characters long',
            }
            return make_response(jsonify(response_object)), 403

        # check if user already exists
        user = User.query.filter(func.lower(User.email)==email).execution_options(show_all=True).first()
        if user:
            response_object = {
                'status': 'fail',
                'message': 'User already exists. Please Log in.',
            }
            return make_response(jsonify(response_object)), 403

        if tier is None:
            tier = 'subadmin'

        if selected_whitelist_item:
            organisation = selected_whitelist_item.organisation
        else:
            organisation = Organisation.master_organisation()

        user = User(blockchain_address=organisation.primary_blockchain_address)

        user.create_admin_auth(email, password, tier, organisation)

        # insert the user
        db.session.add(user)

        db.session.flush()

        if exact_match:
            user.is_activated = True

            auth_token = user.encode_auth_token()

            # Possible Outcomes:
            # TFA required, but not set up
            # TFA not required

            tfa_response_oject = tfa_logic(user, tfa_token=None)
            if tfa_response_oject:
                tfa_response_oject['auth_token'] = auth_token.decode()

                db.session.commit()  # need this here to commit a created user to the db

                return make_response(jsonify(tfa_response_oject)), 401

            # Update the last_seen TS for this user
            user.update_last_seen_ts()

            response_object = create_user_response_object(user, auth_token, 'Successfully activated.')

            db.session.commit()

            return make_response(jsonify(attach_host(response_object))), 201

        activation_token = user.encode_single_use_JWS('A')

        send_activation_email(activation_token, email)

        db.session.commit()

        # generate the auth token
        response_object = {
            'status': 'success',
            'message': 'Successfully registered. You must activate your email.',
        }

        return make_response(jsonify(attach_host(response_object))), 201
コード例 #12
0
    def post(self):

        # get the post data
        post_data = request.get_json()
        old_password = post_data.get('old_password')
        new_password = post_data.get('new_password')
        new_pin = post_data.get('new_pin')
        phone = proccess_phone_number(phone_number=post_data.get('phone'), region=post_data.get('region'))
        one_time_code = post_data.get('one_time_code')

        auth_header = request.headers.get('Authorization')

        # Check authorisation using a one time code
        if phone and one_time_code:
            card = phone[-6:]
            user = (User.query.filter_by(phone=phone).execution_options(show_all=True).first() or
                    User.query.filter_by(public_serial_number=card).execution_options(show_all=True).first()
                    )

            if not user:
                response_object = {
                    'status': 'fail',
                    'message': 'invalid password'
                }

                return make_response(jsonify(response_object)), 401

            if not one_time_code or str(one_time_code) != user.one_time_code:
                response_object = {
                    'status': 'fail',
                    'message': 'One time code not valid'
                }

                return make_response(jsonify(response_object)), 401

            if new_password:
                user.hash_password(new_password)
            else:
                user.hash_pin(new_pin)

            user.is_phone_verified = True
            user.is_activated = True
            user.one_time_code = None

            auth_token = user.encode_auth_token()

            response_object = create_user_response_object(user, auth_token, 'Successfully set pin')

            db.session.commit()

            return make_response(jsonify(attach_host(response_object))), 200

        # Check authorisation using regular auth
        elif auth_header and auth_header != 'null' and old_password:
            split_header = auth_header.split("|")
            auth_token = split_header[0]

            resp = User.decode_auth_token(auth_token)

            if isinstance(resp, str):
                response_object = {
                    'status': 'fail',
                    'message': 'Invalid auth token'
                }

                return make_response(jsonify(response_object)), 401

            user = User.query.filter_by(id=resp.get('id')).execution_options(show_all=True).first()

            if not user:
                response_object = {
                    'status': 'fail',
                    'message': 'invalid password'
                }

                return make_response(jsonify(response_object)), 401

            if not user.verify_password(old_password):
                response_object = {
                    'status': 'fail',
                    'message': 'invalid password'
                }

                return make_response(jsonify(response_object)), 401

        # Check authorisation using a reset token provided via email
        else:

            reset_password_token = post_data.get('reset_password_token')

            if not reset_password_token:
                response_object = {
                    'status': 'fail',
                    'message': 'Missing token.'
                }

                return make_response(jsonify(response_object)), 401

            reset_password_token = reset_password_token.split(" ")[0]

            validity_check = User.decode_single_use_JWS(reset_password_token, 'R')

            if not validity_check['success']:
                response_object = {
                    'status': 'fail',
                    'message': validity_check['message']
                }

                return make_response(jsonify(response_object)), 401

            user = validity_check['user']

            reuse_check = user.check_reset_token_already_used(
                reset_password_token)

            
            if not reuse_check:
                response_object = {
                    'status': 'fail',
                    'message': 'Token already used'
                }

                return make_response(jsonify(response_object)), 401

        if not new_password or len(new_password) < 6:
            response_object = {
                'status': 'fail',
                'message': 'Password must be at least 6 characters long'
            }

            return make_response(jsonify(response_object)), 401

        user.hash_password(new_password)
        user.delete_password_reset_tokens()
        db.session.commit()

        response_object = {
            'status': 'success',
            'message': 'Password changed, please log in'
        }

        return make_response(jsonify(attach_host(response_object))), 200
コード例 #13
0
    def post(self):
        # There is an unique case where users are using their mobile number from the App to either login or register
        # The app uses g.active_organisation to reference user.transfer_account to send an SMS to the User.
        # This means that g.active_organisation should default to the master_organisation
        # For admin users, it doesn't matter as this endpoint is unauthed.
        g.active_organisation = Organisation.master_organisation()

        post_data = request.get_json()
        user = None
        phone = None
        email = post_data.get('username', '') or post_data.get('email', '')
        email = email.lower() if email else ''
        password = post_data.get('password')
        # Default pin to password as fallback for old android versions
        pin = post_data.get('pin', password)
        tfa_token = post_data.get('tfa_token')

        password_empty = password == '' or password is None
        pin_empty = pin == '' or pin is None

        ratelimit_key = email or post_data.get('phone')
        if ratelimit_key:
            limit = rate_limit("login_"+ratelimit_key, 25)
            if limit:
                response_object = {
                    'status': 'fail',
                    'message': f'Please try again in {limit} minutes'
                }
                return make_response(jsonify(response_object)), 403

        # First try to match email
        if email:
            user = User.query.filter(func.lower(User.email)==email).execution_options(show_all=True).first()

        # Now try to match the public serial number (comes in under the phone)
        if not user:
            public_serial_number_or_phone = post_data.get('phone')

            user = User.query.filter_by(public_serial_number=public_serial_number_or_phone).execution_options(
                show_all=True).first()

        # Now try to match the phone
        if not user:
            try:
                phone = proccess_phone_number(post_data.get('phone'), region=post_data.get('region'))
            except NumberParseException as e:
                response_object = {'message': 'Invalid Phone Number: ' + str(e)}
                return make_response(jsonify(response_object)), 401

            if phone:
                user = User.query.filter_by(phone=phone).execution_options(show_all=True).first()

        # mobile user doesn't exist so default to creating a new wallet!
        if user is None and phone and current_app.config['ALLOW_SELF_SIGN_UP']:
            # this is a registration from a mobile device THUS a vendor or recipient.
            response_object, response_code = UserUtils.proccess_create_or_modify_user_request(
                dict(phone=phone, deviceInfo=post_data.get('deviceInfo')),
                is_self_sign_up=True,
            )

            if response_code == 200:
                db.session.commit()

            return make_response(jsonify(response_object)), response_code
        no_password_or_pin_hash = user and not user.password_hash and not user.pin_hash
        if post_data.get('phone') and user and user.one_time_code and (not user.is_activated or not user.pin_hash):
            # vendor sign up with one time code or OTP verified
            if user.one_time_code == pin:
                response_object = {
                    'status': 'success',
                    'pin_must_be_set': True,
                    'message': 'Please set your pin.'
                }
                return make_response(jsonify(attach_host(response_object))), 200

            if not user.is_phone_verified or no_password_or_pin_hash:
                if user.is_self_sign_up:
                    # self sign up, resend phone verification code
                    user.set_pin(None, False)  # resets PIN
                    UserUtils.send_one_time_code(phone=phone, user=user)
                db.session.commit()

                if not password_empty:
                    # The user provided a password, so probably not going through incremental login
                    # This is a hacky way to get past the incremental-login multi-org split
                    response_object = {
                        'status': 'fail',
                        'otp_verify': True,
                        'message': 'Please verify phone number.',
                        'error_message': 'Incorrect One Time Code.'
                    }
                    return make_response(jsonify(attach_host(response_object))), 200

                response_object = {'message':  'Please verify phone number.', 'otp_verify': True}
                return make_response(jsonify(attach_host(response_object))), 200

        if user and user.is_activated and post_data.get('phone') and (password_empty and pin_empty):
            # user already exists, is activated. no password or pin provided, thus request PIN screen.
            # todo: this should check if device exists, if no, resend OTP to verify login is real.
            response_object = {
                'status': 'success',
                'login_with_pin': True,
                'message': 'Login with PIN'
            }
            return make_response(jsonify(attach_host(response_object))), 200

        if not (email or post_data.get('phone')):
            response_object = {
                'status': 'fail',
                'message': 'No username supplied'
            }
            return make_response(jsonify(response_object)), 401
    

        try:
            if not (user and (pin and user.verify_pin(pin) or password and user.verify_password(password))):
                response_object = {
                    'status': 'fail',
                    'message': 'Invalid username or password'
                }

                return make_response(jsonify(response_object)), 401

            if not user.is_activated:
                response_object = {
                    'status': 'fail',
                    'is_activated': False,
                    'message': 'Account has not been activated. Please check your emails.'
                }
                return make_response(jsonify(response_object)), 401
            if post_data.get('deviceInfo'):
                deviceInfo = post_data.get('deviceInfo')
                UserUtils.save_device_info(deviceInfo, user)

            auth_token = user.encode_auth_token()

            if not auth_token:
                response_object = {
                    'status': 'fail',
                    'message': 'Invalid username or password'
                }
                return make_response(jsonify(response_object)), 401

            # Possible Outcomes:
            # TFA required, but not set up
            # TFA enabled, and user does not have valid TFA token
            # TFA enabled, and user has valid TFA token
            # TFA not required

            tfa_response_oject = tfa_logic(user, tfa_token)
            if tfa_response_oject:
                tfa_response_oject['auth_token'] = auth_token.decode()

                return make_response(jsonify(tfa_response_oject)), 401

            # Update the last_seen TS for this user
            user.update_last_seen_ts()

            response_object = create_user_response_object(user, auth_token, 'Successfully logged in.')

            db.session.commit()

            return make_response(jsonify(attach_host(response_object))), 200

        except Exception as e:
            sentry_sdk.capture_exception(e)
            raise e
コード例 #14
0
    def post(self):
        # get the post data
        post_data = request.get_json()

        activation_token = post_data.get('activation_token')

        if activation_token and activation_token != 'null':
            auth_token = activation_token.split(" ")[0]
        else:
            auth_token = ''
        if auth_token:

            validity_check = User.decode_single_use_JWS(activation_token, 'A')

            if not validity_check['success']:
                response_object = {
                    'status': 'fail',
                    'message': validity_check['message']
                }

                return make_response(jsonify(response_object)), 401

            user = validity_check['user']

            if user.is_activated:
                response_object = {
                    'status': 'fail',
                    'message': 'Already activated.'
                }

                return make_response(jsonify(response_object)), 401

            user.is_activated = True

            auth_token = user.encode_auth_token()

            db.session.flush()

            # Possible Outcomes:
            # TFA required, but not set up
            # TFA not required

            tfa_response_oject = tfa_logic(user, tfa_token=None)
            if tfa_response_oject:
                tfa_response_oject['auth_token'] = auth_token.decode()

                db.session.commit()  # need to commit here so that is_activated = True

                return make_response(jsonify(tfa_response_oject)), 401

            # Update the last_seen TS for this user
            user.update_last_seen_ts()

            response_object = create_user_response_object(user, auth_token, 'Successfully activated.')

            db.session.commit()

            return make_response(jsonify(attach_host(response_object))), 201

        else:
            response_object = {
                'status': 'fail',
                'message': 'Provide a valid auth token.'
            }
            return make_response(jsonify(response_object)), 401
コード例 #15
0
    def get(self):
        tfa_url = g.user.tfa_url
        response_object = {'data': {"tfa_url": tfa_url}}

        return make_response(jsonify(attach_host(response_object))), 200