Exemple #1
0
def create_master_organisation(test_client, init_database, external_reserve_token):
    from server.models.organisation import Organisation
    master_organisation = Organisation.master_organisation()
    if master_organisation is None:
        print('Creating master organisation')
        master_organisation = Organisation(name='FrancineCorp', is_master=True, token=external_reserve_token,
                                           country_code='AU')
        db.session.add(master_organisation)
        db.session.commit()

    return master_organisation
Exemple #2
0
    def approve_and_disburse(self, initial_disbursement=None):
        from server.utils.access_control import AccessControl
        admin = getattr(g, 'user', None)
        active_org = getattr(g, 'active_organisation', Organisation.master_organisation())
        
        if initial_disbursement is None:
            # initial disbursement defaults to None. If initial_disbursement is set then skip this section.
            # If none, then we want to see if the active_org has a default disbursement amount
            initial_disbursement = active_org.default_disbursement

        # Baseline is NOT is_approved, and do NOT auto_resolve
        self.is_approved = False
        auto_resolve = False
        # If admin role is admin or higher, then auto-approval is contingent on being less than or 
        # equal to the default disbursement
        if (admin and AccessControl.has_sufficient_tier(admin.roles, 'ADMIN', 'admin'))or (
            g.get('auth_type') == 'external' and active_org.auto_approve_externally_created_users
        ):
            self.is_approved = True
            if initial_disbursement <= active_org.default_disbursement:
                auto_resolve = True
                
        # Accounts created by superadmins are all approved, and their disbursements are 
        # auto-resolved no matter how big they are!
        if admin and AccessControl.has_sufficient_tier(admin.roles, 'ADMIN', 'superadmin'):
            self.is_approved = True
            auto_resolve = True

        if self.is_beneficiary:
            # Initial disbursement should be pending if the account is not approved
            disbursement = self._make_initial_disbursement(initial_disbursement, auto_resolve=auto_resolve)
            return disbursement
Exemple #3
0
def create_organisation(test_client, init_database, external_reserve_token, create_master_organisation):
    from server.models.organisation import Organisation
    organisation = Organisation(name='Sempo', token=external_reserve_token, default_disbursement=400, country_code='US')
    db.session.add(organisation)
    db.session.commit()

    return organisation
def proccess_phone_number(phone_number, region=None, ignore_region=False):
    """
    Parse any given phone number.
    :param phone_number: int
    :param region: ISO 3166-1 alpha-2 codes
    :param ignore_region: Boolean. True returns original phone
    :return:
    """
    from server.models.organisation import Organisation

    if phone_number is None:
        return None

    if ignore_region:
        return phone_number

    if region is None:
        try:
            region = g.active_organisation.country_code
        except AttributeError:
            region = Organisation.master_organisation().country_code

    if not isinstance(phone_number, str):
        try:
            phone_number = str(int(phone_number))

        except ValueError:
            pass

    phone_number_object = phonenumbers.parse(phone_number, region)

    parsed_phone_number = phonenumbers.format_number(phone_number_object, phonenumbers.PhoneNumberFormat.E164)

    return parsed_phone_number
    def _make_initial_disbursement(self,
                                   initial_disbursement,
                                   auto_resolve=False):
        from server.utils.credit_transfer import make_payment_transfer

        active_org = getattr(g, 'active_organisation',
                             Organisation.master_organisation())
        initial_disbursement = initial_disbursement or active_org.default_disbursement
        if not initial_disbursement:
            return None

        user_id = get_authorising_user_id()
        if user_id is not None:
            sender = User.query.execution_options(show_all=True).get(user_id)
        else:
            sender = self.primary_user

        disbursement = make_payment_transfer(
            initial_disbursement,
            token=self.token,
            send_user=sender,
            receive_user=self.primary_user,
            transfer_subtype=TransferSubTypeEnum.DISBURSEMENT,
            is_ghost_transfer=False,
            require_sender_approved=False,
            require_recipient_approved=False,
            automatically_resolve_complete=auto_resolve)

        return disbursement
Exemple #6
0
def create_master_organisation(reserve_token):

    print_section_title('Creating/Updating Master Organisation')

    master_organisation = Organisation.master_organisation()
    if master_organisation is None:
        print('Creating master organisation')
        if reserve_token:
            print('Binding to reserve token')
        master_organisation = Organisation(name='Reserve',
                                           is_master=True,
                                           token=reserve_token)
        db.session.add(master_organisation)

        db.session.commit()

    print_section_conclusion('Done creating master organisation')
Exemple #7
0
def create_master_organisation(app, reserve_token):

    print_section_title('Creating/Updating Master Organisation')

    master_organisation = Organisation.master_organisation()
    if master_organisation is None:
        print('Creating master organisation')
        if reserve_token:
            print('Binding to reserve token')
        master_organisation = Organisation(
            name='Reserve', is_master=True,
            token=reserve_token, country_code=app.config.get('DEFAULT_COUNTRY', 'AU')
        )
        db.session.add(master_organisation)

        db.session.commit()

    print_section_conclusion('Done creating master organisation')
Exemple #8
0
def test_credit_transfer_organisation_filters(test_client, init_database,
                                              authed_sempo_admin_user,
                                              complete_admin_auth_token,
                                              create_credit_transfer,
                                              query_organisations,
                                              status_code):
    # Checks that the credit_transfer endpoint supports multiple organisations
    url = f'/api/v1/credit_transfer/?query_organisations={query_organisations}'

    from server.models.organisation import Organisation
    # master_organisation is organisation 1
    master_organisation = Organisation.master_organisation()
    create_credit_transfer.sender_user.organisation = master_organisation
    create_credit_transfer.recipient_user.organisation = master_organisation
    create_credit_transfer.sender_transfer_account.organisation = master_organisation
    create_credit_transfer.recipient_transfer_account.organisation = master_organisation
    init_database.session.commit()

    # Add master_organisation (organisation 1) to our user's organisations. admin_user already
    # is a member of organisation 2
    authed_sempo_admin_user.organisations.append(master_organisation)

    response = test_client.get(url,
                               headers=dict(
                                   Authorization=complete_admin_auth_token,
                                   Accept='application/json'))

    all_transfers = CreditTransfer.query.execution_options(show_all=True).all()

    org1 = Organisation.query.get(1)
    org2 = Organisation.query.get(2)

    org1_transfer_ids = set(t.id for t in all_transfers
                            if org1 in t.organisations)
    org2_transfer_ids = set(t.id for t in all_transfers
                            if org2 in t.organisations)

    assert response.status_code == status_code
    if status_code == 200:
        response_ids = set()
        for r in response.json['data'].get('credit_transfers', []):
            response_ids.add(r['id'])
        if '1' in query_organisations:
            assert create_credit_transfer.id in response_ids

        if query_organisations == '1':
            assert response_ids == org1_transfer_ids
        if query_organisations == '2' or query_organisations == '':
            assert response_ids == org2_transfer_ids
        if query_organisations == '1,2':
            assert response_ids == org1_transfer_ids.union(org2_transfer_ids)
Exemple #9
0
def default_token(user: User) -> Token:
    try:
        transfer_account = default_transfer_account(user)
        token = transfer_account.token
    except TransferAccountNotFoundError:
        if user.default_organisation is not None:
            token = user.default_organisation.token
        else:
            token = Organisation.master_organisation().token

        if token is None:
            raise Exception('no default token for user')

    return token
Exemple #10
0
    def add_user_to_organisation(self, organisation: Organisation, is_admin=False):
        if not self.default_organisation:
            self.default_organisation = organisation

        self.organisations.append(organisation)

        if is_admin and organisation.org_level_transfer_account_id:
            if organisation.org_level_transfer_account is None:
                organisation.org_level_transfer_account = (
                    db.session.query(server.models.transfer_account.TransferAccount)
                    .execution_options(show_all=True)
                    .get(organisation.org_level_transfer_account_id))

            self.transfer_accounts.append(organisation.org_level_transfer_account)
    def __init__(self,
                 blockchain_address: Optional[str] = None,
                 bound_entity: Optional[Union[Organisation, User]] = None,
                 account_type: Optional[TransferAccountType] = None,
                 private_key: Optional[str] = None,
                 **kwargs):

        super(TransferAccount, self).__init__(**kwargs)

        if bound_entity:
            bound_entity.transfer_accounts.append(self)

            if isinstance(bound_entity, Organisation):
                self.account_type = TransferAccountType.ORGANISATION
                self.blockchain_address = bound_entity.primary_blockchain_address

                self._bind_to_organisation(bound_entity)

            elif isinstance(bound_entity, User):
                self.account_type = TransferAccountType.USER
                self.blockchain_address = bound_entity.primary_blockchain_address

                if bound_entity.default_organisation:
                    self._bind_to_organisation(
                        bound_entity.default_organisation)

            elif isinstance(bound_entity, ExchangeContract):
                self.account_type = TransferAccountType.CONTRACT
                self.blockchain_address = bound_entity.blockchain_address
                self.is_public = True
                self.exchange_contact = self

        if not self.organisation:
            master_organisation = Organisation.master_organisation()
            if not master_organisation:
                print('master_organisation not found')
            if master_organisation:
                self._bind_to_organisation(master_organisation)

        if blockchain_address:
            self.blockchain_address = blockchain_address

        if not self.blockchain_address:
            self.blockchain_address = bt.create_blockchain_wallet(
                private_key=private_key)

        if account_type:
            self.account_type = account_type
def test_get_user(test_client, authed_sempo_admin_user, create_transfer_account_user):
    # Checks that the get_user endpoint supports multiple organisations
    from server.models.organisation import Organisation
    master_organisation = Organisation.master_organisation()
    authed_sempo_admin_user.organisations.append(master_organisation)
    create_transfer_account_user.organisations = [master_organisation]
    db.session.commit()

    authed_sempo_admin_user.set_held_role('ADMIN', 'superadmin')
    auth = get_complete_auth_token(authed_sempo_admin_user)

    def get_user_endpoint(query_organisations):
        return test_client.get(
            f"/api/v1/user/?query_organisations={query_organisations}",
            headers=dict(
                Authorization=auth,
                Accept='application/json'
            ))

    def get_transfer_account_ids(users):
        transfer_account_ids = []
        for user in users:
            transfer_account_ids.append(user['id'])
        return transfer_account_ids

    # User 1 is in both orgs
    # User 3 is in Org 2
    # User 4 is in Org 2
    # User 5 is in Org 2
    response = get_user_endpoint('1,2')
    assert response.status_code == 200
    users_list = response.json['data']['users']
    assert get_transfer_account_ids(users_list) == [5, 4, 3, 1]

    response = get_user_endpoint('1')
    assert response.status_code == 200
    users_list = response.json['data']['users']
    assert get_transfer_account_ids(users_list) == [1]


    response = get_user_endpoint('2')
    assert response.status_code == 200
    users_list = response.json['data']['users']
    assert get_transfer_account_ids(users_list) == [5, 4, 3, 1]
Exemple #13
0
    def approve_initial_disbursement(self):
        from server.utils.access_control import AccessControl

        admin = getattr(g, 'user', None)
        active_org = getattr(g, 'active_organisation', Organisation.master_organisation())

        initial_disbursement = db.session.query(server.models.credit_transfer.CreditTransfer)\
            .filter(server.models.credit_transfer.CreditTransfer.recipient_user == self.primary_user)\
            .filter(server.models.credit_transfer.CreditTransfer.is_initial_disbursement == True)\
            .first()
        
        if initial_disbursement and initial_disbursement.transfer_status == TransferStatusEnum.PENDING:
            # Must be superadmin to auto-resolve something over default disbursement
            if initial_disbursement.transfer_amount > active_org.default_disbursement:
                if admin and AccessControl.has_sufficient_tier(admin.roles, 'ADMIN', 'superadmin'):
                    return initial_disbursement.resolve_as_complete_and_trigger_blockchain(queue='high-priority')
                else:
                    return False
            else:
                return initial_disbursement.resolve_as_complete_and_trigger_blockchain(queue='high-priority')
Exemple #14
0
    def post(self):
        # get the post data
        post_data = request.get_json()

        email = post_data.get('email') or post_data.get('username')
        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(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_by(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(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(response_object)), 201
Exemple #15
0
 def get_reserve_token(self):
     # reserve token is master token for now
     return Organisation.master_organisation().token
Exemple #16
0
def create_transfer_account_user(first_name=None,
                                 last_name=None,
                                 preferred_language=None,
                                 phone=None,
                                 email=None,
                                 public_serial_number=None,
                                 organisation: Organisation = None,
                                 token=None,
                                 blockchain_address=None,
                                 transfer_account_name=None,
                                 lat=None,
                                 lng=None,
                                 use_precreated_pin=False,
                                 use_last_4_digits_of_id_as_initial_pin=False,
                                 existing_transfer_account=None,
                                 is_beneficiary=False,
                                 is_vendor=False,
                                 is_tokenagent=False,
                                 is_groupaccount=False,
                                 is_self_sign_up=False,
                                 business_usage=None,
                                 initial_disbursement=None):

    user = User(first_name=first_name,
                last_name=last_name,
                lat=lat,
                lng=lng,
                preferred_language=preferred_language,
                phone=phone,
                email=email,
                public_serial_number=public_serial_number,
                is_self_sign_up=is_self_sign_up,
                business_usage=business_usage)

    precreated_pin = None
    is_activated = False

    try:
        transfer_card = TransferCard.get_transfer_card(public_serial_number)
    except Exception as e:
        transfer_card = None

    if use_precreated_pin:
        precreated_pin = transfer_card.PIN
        is_activated = True

    elif use_last_4_digits_of_id_as_initial_pin:
        precreated_pin = str(public_serial_number or phone)[-4:]
        is_activated = False

    user.set_pin(precreated_pin, is_activated)

    if not is_vendor:
        vendor_tier = None
    elif existing_transfer_account:
        vendor_tier = 'vendor'
    else:
        vendor_tier = 'supervendor'

    user.set_held_role('VENDOR', vendor_tier)

    if is_tokenagent:
        user.set_held_role('TOKEN_AGENT', 'grassroots_token_agent')

    if is_groupaccount:
        user.set_held_role('GROUP_ACCOUNT', 'grassroots_group_account')

    if is_beneficiary:
        user.set_held_role('BENEFICIARY', 'beneficiary')

    if not organisation:
        organisation = Organisation.master_organisation()

    user.add_user_to_organisation(organisation, is_admin=False)

    db.session.add(user)

    if existing_transfer_account:
        transfer_account = existing_transfer_account
        user.transfer_accounts.append(existing_transfer_account)
    else:
        transfer_account = TransferAccount(
            bound_entity=user,
            blockchain_address=blockchain_address,
            organisation=organisation)

        transfer_account.name = transfer_account_name
        transfer_account.is_vendor = is_vendor
        transfer_account.is_beneficiary = is_beneficiary

        if transfer_card:
            transfer_account.transfer_card = transfer_card

        if token:
            transfer_account.token = token

        if not is_self_sign_up:
            transfer_account.approve_and_disburse(
                initial_disbursement=initial_disbursement)

        db.session.add(transfer_account)

    user.default_transfer_account = transfer_account

    return user
Exemple #17
0
    def post(self, organisation_id):
        post_data = request.get_json()

        organisation_name = post_data.get('organisation_name')
        custom_welcome_message_key = post_data.get(
            'custom_welcome_message_key')
        timezone = post_data.get('timezone')

        country_code = post_data.get('country_code')
        default_disbursement = post_data.get('default_disbursement')
        minimum_vendor_payout_withdrawal = post_data.get(
            'minimum_vendor_payout_withdrawal')
        require_transfer_card = post_data.get('require_transfer_card')
        default_lat = post_data.get('default_lat')
        default_lng = post_data.get('default_lng')
        account_types = post_data.get('account_types', [])

        token_id = post_data.get('token_id')
        deploy_cic = post_data.get('deploy_cic', False)

        for at in account_types:
            if at not in ASSIGNABLE_TIERS.keys():
                raise Exception(f'{at} not an assignable role')

        if organisation_name is None or country_code is None or timezone is None:
            return make_response(
                jsonify({
                    'message':
                    'Must provide organisation_name, country_code and timezone to create organisation.'
                })), 400

        existing_organisation = Organisation.query.filter_by(
            name=organisation_name).execution_options(show_all=True).first()
        if existing_organisation is not None:
            return make_response(
                jsonify({
                    'message':
                    'Must be unique name. Organisation already exists for name: {}'
                    .format(organisation_name),
                    'data': {
                        'organisation':
                        organisation_schema.dump(existing_organisation).data
                    }
                })), 400

        try:
            new_organisation = Organisation(
                name=organisation_name,
                custom_welcome_message_key=custom_welcome_message_key,
                timezone=timezone,
                country_code=country_code,
                default_disbursement=default_disbursement,
                minimum_vendor_payout_withdrawal=
                minimum_vendor_payout_withdrawal,
                require_transfer_card=require_transfer_card,
                default_lat=default_lat,
                default_lng=default_lng,
                valid_roles=account_types)
        except Exception as e:
            response_object = {
                'message': str(e),
            }
            return make_response(jsonify(response_object)), 400

        db.session.add(new_organisation)
        db.session.flush()

        response_object = {
            'message': 'Created Project',
            'data': {
                'organisation': organisation_schema.dump(new_organisation).data
            },
        }

        if token_id:
            token = Token.query.get(token_id)
            if token is None:
                return make_response(jsonify({'message':
                                              'Token not found'})), 404
            new_organisation.bind_token(token)

        elif deploy_cic:

            cic_response_object, cic_response_code = deploy_cic_token(
                post_data, new_organisation)
            if cic_response_code == 201:
                response_object['data']['token_id'] = cic_response_object[
                    'data']['token_id']
            else:
                return make_response(
                    jsonify(cic_response_object)), cic_response_code

        if AccessControl.has_suffient_role(g.user.roles,
                                           {'ADMIN': 'superadmin'}):
            g.user.add_user_to_organisation(new_organisation, is_admin=True)

        return make_response(jsonify(response_object)), 201
Exemple #18
0
    def post(self, organisation_id):
        post_data = request.get_json()

        organisation_name = post_data.get('organisation_name')
        custom_welcome_message_key = post_data.get(
            'custom_welcome_message_key')
        timezone = post_data.get('timezone')

        country_code = post_data.get('country_code')
        default_disbursement = post_data.get('default_disbursement')
        require_transfer_card = post_data.get('require_transfer_card')
        default_lat = post_data.get('default_lat')
        default_lng = post_data.get('default_lng')

        token_id = post_data.get('token_id')
        deploy_cic = post_data.get('deploy_cic', False)

        if organisation_name is None or country_code is None:
            return make_response(
                jsonify({
                    'message':
                    'Must provide name and ISO 2 country_code to create organisation.'
                })), 400

        existing_organisation = Organisation.query.filter_by(
            name=organisation_name).execution_options(show_all=True).first()
        if existing_organisation is not None:
            return make_response(
                jsonify({
                    'message':
                    'Must be unique name. Organisation already exists for name: {}'
                    .format(organisation_name),
                    'data': {
                        'organisation':
                        organisation_schema.dump(existing_organisation).data
                    }
                })), 400

        try:
            new_organisation = Organisation(
                name=organisation_name,
                custom_welcome_message_key=custom_welcome_message_key,
                timezone=timezone,
                country_code=country_code,
                default_disbursement=default_disbursement,
                require_transfer_card=require_transfer_card,
                default_lat=default_lat,
                default_lng=default_lng)
        except Exception as e:
            response_object = {
                'message': str(e),
            }
            return make_response(jsonify(response_object)), 400

        db.session.add(new_organisation)
        db.session.flush()

        response_object = {
            'message': 'Created Organisation',
            'data': {
                'organisation': organisation_schema.dump(new_organisation).data
            },
        }

        if token_id:
            token = Token.query.get(token_id)
            if token is None:
                return make_response(jsonify({'message':
                                              'Token not found'})), 404
            new_organisation.bind_token(token)

        elif deploy_cic:

            cic_response_object, cic_response_code = deploy_cic_token(
                post_data, new_organisation)
            if cic_response_code == 201:
                response_object['data']['token_id'] = cic_response_object[
                    'data']['token_id']
            else:
                return make_response(
                    jsonify(cic_response_object)), cic_response_code

        return make_response(jsonify(response_object)), 201
Exemple #19
0
def run_setup():
    app = create_app()
    ctx = app.app_context()
    ctx.push()

    # To simplify creation, we set the flask context to show all model data
    g.show_all = True

    master_organisation = Organisation.master_organisation()
    if master_organisation is None:
        print('Creating master organisation')
        master_organisation = Organisation(is_master=True)
        db.session.add(master_organisation)

    master_system_address = master_organisation.system_blockchain_address

    load_account(master_system_address, int(1e18))
    reserve_token = get_or_create_reserve_token(master_system_address, 'AUD Token', 'AUD')

    master_organisation.token = reserve_token

    print('Creating organisation')
    new_organisation = get_or_create_organisation('org1', reserve_token)
    load_account(new_organisation.system_blockchain_address, int(1e18))

    print('Creating admin user')
    amount_to_load = 1000
    admin_user = get_or_create_admin_user('*****@*****.**', 'TestPassword', new_organisation)
    admin_transfer_account = admin_user.transfer_account
    load_account(admin_transfer_account.blockchain_address, int(20e18))
    send_eth_task = bt.send_eth(
        signing_address=admin_transfer_account.blockchain_address,
        recipient_address=reserve_token.address,
        amount_wei=amount_to_load * int(1e16))

    bt.await_task_success(send_eth_task)

    admin_user.transfer_account.balance = amount_to_load

    print('Creating Transfer Usage')
    usages = list(map(
        get_or_create_transfer_usage,
        ['Broken Pencils',
         'Off Milk',
         'Stuxnet',
         'Used Playing Cards',
         '09 F9',
         'Junk Mail',
         'Cutlery',
         'Leaked Private Keys',
         'Parking Infringements',
         'Betamax Movies',
         'Hyperallergenic Soap',
         'Dioxygen Difluoride',
         'Hunter2'
         ]))

    print('Create a list of users with a different business usage id ')
    user_list = create_users_different_transer_usage(15, new_organisation)

    print('Making Bulk Transfers')
    seed_transfers(user_list, admin_user, reserve_token)

    print('Deploying Smart Token')
    smart_token, exchange_contract, registry_address = create_or_get_reserve_token(
        deploying_address=admin_transfer_account.blockchain_address,
        reserve_token=reserve_token,
        reserve_deposit_wei=5e17,
        issue_amount_wei=5e17,
        name='CIC1', symbol='CIC1', reserve_ratio_ppm=250000
    )

    print('Making exchanges')
    make_exchange(
        user=admin_user,
        from_token=reserve_token,
        to_token=smart_token,
        from_amount=2
    )

    create_transfer(
        amount=10,
        sender_user=admin_user,
        recipient_user=user_list[0],
        token=reserve_token
    )

    make_exchange(
        user=user_list[0],
        from_token=reserve_token,
        to_token=smart_token,
        from_amount=10
    )

    create_transfer(
        amount=2,
        sender_user=user_list[0],
        recipient_user=user_list[1],
        token=smart_token
    )

    db.session.commit()
    ctx.pop()
def deploy_cic_token(post_data, creating_org=None):

    name = post_data['name']
    symbol = post_data['symbol']
    decimals = post_data.get('decimals', 18)
    issue_amount_wei = int(post_data['issue_amount_wei'])
    reserve_deposit_wei = int(post_data['reserve_deposit_wei'])
    exchange_contract_id = post_data['exchange_contract_id']
    reserve_ratio_ppm = post_data.get('reserve_ratio_ppm', 250000)

    if creating_org:
        deploying_address = creating_org.primary_blockchain_address
    else:
        deploying_address = g.user.primary_blockchain_address


    if not exchange_contract_id:
        response_object = {
            'message': 'Must supply exchange contract id if deploying smart token contract'
        }

        return response_object, 400

    exchange_contract = ExchangeContract.query.get(exchange_contract_id)

    if not exchange_contract:
        response_object = {
            'message': 'Exchange contract not found for id {}'.format(exchange_contract_id)
        }

        return response_object, 400

    balance_wei = bt.get_wallet_balance(deploying_address, exchange_contract.reserve_token)

    if balance_wei < reserve_deposit_wei:

        load_amount = int((reserve_deposit_wei - balance_wei) / 1e16)

        master_org = Organisation.master_organisation()

        print(f'Insufficient reserve funds (balance in wei: {balance_wei}), loading')

        if master_org.org_level_transfer_account.balance < load_amount:
            response_object = {
                'message': f'Insufficient reserve funds for both deploying account  ({balance_wei} wei), '
                           f'and master ({master_org.org_level_transfer_account.balance * 1e16} wei)'
            }

            return response_object, 400

        load_task_uuid = bt.make_token_transfer(
            signing_address=master_org.primary_blockchain_address,
            token=exchange_contract.reserve_token,
            from_address=master_org.primary_blockchain_address,
            to_address=deploying_address,
            amount=load_amount
        )

        try:
            bt.await_task_success(load_task_uuid)
        except TimeoutError:
            response_object = {
                'message': f'Insufficient reserve funds (balance in wei: {balance_wei}), and could not load from master'
            }

            return response_object, 400

        master_org.org_level_transfer_account.balance -= load_amount

    token = Token(name=name, symbol=symbol, token_type=TokenType.LIQUID)
    db.session.add(token)
    db.session.flush()

    deploy_data = dict(
        deploying_address=deploying_address,
        name=name, symbol=symbol, decimals=decimals,
        reserve_deposit_wei=reserve_deposit_wei,
        issue_amount_wei=issue_amount_wei,
        contract_registry_address=exchange_contract.contract_registry_blockchain_address,
        reserve_token_address=exchange_contract.reserve_token.address,
        reserve_ratio_ppm=reserve_ratio_ppm
    )

    @copy_current_request_context
    def deploy(_deploy_data, _token_id, _exchange_contract_id, _creating_org_id=None):
        smart_token_result = bt.deploy_smart_token(**_deploy_data)

        address = smart_token_result['smart_token_address']
        subexchange_address = smart_token_result['subexchange_address']

        _token = Token.query.get(_token_id)
        _token.address = address

        _exchange_contract = ExchangeContract.query.get(_exchange_contract_id)
        _exchange_contract.add_token(_token, subexchange_address, reserve_ratio_ppm)

        if _creating_org_id:

            _creating_org = Organisation.query.get(_creating_org_id)
            _creating_org.bind_token(_token)
            _creating_org.org_level_transfer_account.balance = int(_deploy_data['issue_amount_wei'] / 1e16)

            bal = bt.get_wallet_balance(_creating_org.primary_blockchain_address, _token)

            print(f'Balance is {bal}')

        db.session.commit()

    if creating_org:
        creating_org_id = creating_org.id
    else:
        creating_org_id = None

    t = threading.Thread(target=deploy,
                         args=(deploy_data, token.id, exchange_contract_id, creating_org_id))
    t.daemon = True
    t.start()

    response_object = {
        'message': 'success',
        'data': {
            'token_id': token.id
        }
    }

    return response_object, 201
Exemple #21
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
Exemple #22
0
def create_transfer_account_user(first_name=None,
                                 last_name=None,
                                 preferred_language=None,
                                 phone=None,
                                 email=None,
                                 public_serial_number=None,
                                 uuid=None,
                                 organisation: Organisation = None,
                                 token=None,
                                 blockchain_address=None,
                                 transfer_account_name=None,
                                 use_precreated_pin=False,
                                 use_last_4_digits_of_id_as_initial_pin=False,
                                 existing_transfer_account=None,
                                 roles=None,
                                 is_self_sign_up=False,
                                 business_usage=None,
                                 initial_disbursement=None):

    user = User(first_name=first_name,
                last_name=last_name,
                preferred_language=preferred_language,
                blockchain_address=blockchain_address,
                phone=phone,
                email=email,
                uuid=uuid,
                public_serial_number=public_serial_number,
                is_self_sign_up=is_self_sign_up,
                business_usage=business_usage)

    precreated_pin = None
    is_activated = False

    try:
        transfer_card = TransferCard.get_transfer_card(public_serial_number)
    except Exception as e:
        transfer_card = None

    if use_precreated_pin:
        precreated_pin = transfer_card.PIN
        is_activated = True

    elif use_last_4_digits_of_id_as_initial_pin:
        precreated_pin = str(public_serial_number or phone)[-4:]
        is_activated = False

    user.set_pin(precreated_pin, is_activated)

    if roles:
        for role in roles:
            user.set_held_role(role[0], role[1])
    else:
        user.remove_all_held_roles()

    if not organisation:
        organisation = Organisation.master_organisation()

    user.add_user_to_organisation(organisation, is_admin=False)

    db.session.add(user)

    if existing_transfer_account:
        transfer_account = existing_transfer_account
        user.transfer_accounts.append(existing_transfer_account)
    else:
        transfer_account = TransferAccount(
            bound_entity=user,
            blockchain_address=blockchain_address,
            organisation=organisation)

        top_level_roles = [r[0] for r in roles or []]
        is_vendor = 'VENDOR' in top_level_roles
        is_beneficiary = 'BENEFICIARY' in top_level_roles

        transfer_account.name = transfer_account_name
        transfer_account.is_vendor = is_vendor
        transfer_account.is_beneficiary = is_beneficiary

        if transfer_card:
            transfer_account.transfer_card = transfer_card

        if token:
            transfer_account.token = token

        if not is_self_sign_up:
            transfer_account.approve_and_disburse(
                initial_disbursement=initial_disbursement)

        db.session.add(transfer_account)

    user.default_transfer_account = transfer_account

    return user