def login_callback():
    client = Client(current_app.config['YOTI_CLIENT_SDK_ID'],
                    current_app.config['YOTI_KEY_FILE_PATH'])
    token = request.args.get('token')
    if token:
        activity_details = client.get_activity_details(token)
        user_profile = activity_details.user_profile
        email_address = user_profile.get('email_address')
        user_details_res = requests.get(
            current_app.config['CASE_MANAGEMENT_API_URL'] + '/users',
            params={"email_address": email_address.lower()},
            headers={'Accept': 'application/json'})
        user_details = json.loads(user_details_res.text)
        if user_details:
            for user in user_details:
                session[
                    'user_name'] = user['first_name'] + " " + user['last_name']
                session['user_id'] = user['identity']
                session['email'] = user['email_address']
                return redirect(request.args.get('next'))
        else:
            redirect_url = request.args.get('next')
            return render_template('app/yoti_login.html',
                                   next=redirect_url,
                                   error_message="User not found")
    else:
        # in case of missing Yoti token, the previous redirect url is
        # lost so pass it back to the login form in a new variable
        redirect_url = request.args.get('next')
        return render_template('app/yoti_login.html',
                               next=redirect_url,
                               error_message="Token not found.")
Exemplo n.º 2
0
def auth():
    client = Client(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH)
    activity_details = client.get_activity_details(request.args["token"])
    profile = activity_details.profile
    profile_dict = vars(profile)

    context = profile_dict.get("attributes")
    context["base64_selfie_uri"] = getattr(activity_details, "base64_selfie_uri")
    context["remember_me_id"] = getattr(activity_details, "remember_me_id")
    context["parent_remember_me_id"] = getattr(
        activity_details, "parent_remember_me_id"
    )
    context["receipt_id"] = getattr(activity_details, "receipt_id")
    context["timestamp"] = getattr(activity_details, "timestamp")

    # change this number according to the age condition defined in Yoti Hub
    age_verified = profile.find_age_over_verification(18)

    # Age verification objects don't have the same properties as an attribute,
    # so for this example we had to mock an object with the same properties
    if age_verified is not None:
        context["age_verified"] = {
            "name": "age_verified",
            "value": age_verified,
            "sources": age_verified.attribute.sources,
            "verifiers": age_verified.attribute.verifiers,
        }

    selfie = context.get("selfie")
    if selfie is not None:
        save_image(selfie.value)
    return render_template("profile.html", **context)
def register_callback():
    client = Client(current_app.config['YOTI_CLIENT_SDK_ID'],
                    current_app.config['YOTI_KEY_FILE_PATH'])
    token = request.args.get('token')
    if token:
        try:
            activity_details = client.get_activity_details(token)
            user_profile = activity_details.user_profile

            user_request = {
                'identity':
                activity_details.user_id,
                # if given_names or family_name are missing, get the first/last name in full_name respectively
                'first_name':
                user_profile.get('given_names',
                                 user_profile.get('full_name').split()[0]),
                'last_name':
                user_profile.get('family_name',
                                 user_profile.get('full_name').split()[-1]),
                'email_address':
                user_profile.get('email_address'),
                'phone_number':
                user_profile.get('phone_number'),
                'address': {
                    'house_name_number': '',
                    'street': '',
                    'town_city': '',
                    'county': '',
                    'country': '',
                    'postcode': 'BS2 8EN'
                }
            }
            user_details_res = requests.post(
                current_app.config['CASE_MANAGEMENT_API_URL'] + '/users',
                data=json.dumps(user_request),
                headers={
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                })
            user_details = user_details_res.json()
            if user_details:
                session['user_name'] = user_details[
                    'first_name'] + " " + user_details['last_name']
                session['user_id'] = user_details['identity']
                session['email'] = user_details['email_address']
                return redirect(
                    url_for('conveyancer_user.registration_complete'))
            else:
                return redirect(
                    url_for('auth.register_yoti',
                            error_message="User not found"))
        except Exception as e:
            return redirect(url_for('auth.register_yoti',
                                    error_message=str(e)))
    else:
        # in case of missing Yoti token, the previous redirect url is
        # lost so pass it back to the login form in a new variable
        return render_template('app/register_yoti.html',
                               error_message="Token not found.")
Exemplo n.º 4
0
def auth(request):
    token = request.GET.get('token')
    if not token:
        return render(request, 'yoti_auth.html')

    client = Client(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH)
    activity_details = client.get_activity_details(token)
    request.session['activity_details'] = dict(activity_details)
    return redirect(reverse(YOTI_REDIRECT_TO))
Exemplo n.º 5
0
def test_creating_client_instance_with_valid_key_file_env_but_invalid_key_file_arg():
    environ['YOTI_KEY_FILE_PATH'] = PEM_FILE_PATH
    with pytest.raises(RuntimeError) as exc:
        Client(YOTI_CLIENT_SDK_ID, INVALID_KEY_FILE_PATH)
    expected_error = 'Could not read private key file'
    assert expected_error in str(exc)
    assert str(INVALID_KEY_FILE_PATH) in str(exc)
Exemplo n.º 6
0
def auth():
    token = request.args.get('token')
    if not token:
        return render_template('yoti_auth.html')

    client_sdk_id = get_config_value('YOTI_CLIENT_SDK_ID')
    key_file_path = get_config_value('YOTI_KEY_FILE_PATH')
    client = Client(client_sdk_id, key_file_path)
    activity_details = client.get_activity_details(token)
    session['yoti_user_id'] = activity_details.user_id
    if not is_cookie_session(session):
        session['activity_details'] = dict(activity_details)
    else:
        activity_details_storage.save(activity_details)
    redirect_to = get_config_value('YOTI_REDIRECT_TO')
    return redirect(url_for(redirect_to))
Exemplo n.º 7
0
def test_creating_client_instance_with_invalid_key_file_env(key_file):
    environ['YOTI_KEY_FILE_PATH'] = str(key_file)
    with pytest.raises(RuntimeError) as exc:
        Client(YOTI_CLIENT_SDK_ID)
    expected_error = 'Could not read private key file'
    expected_error_source = 'specified by the YOTI_KEY_FILE_PATH env variable'
    assert expected_error in str(exc)
    assert expected_error_source in str(exc)
    assert str(key_file) in str(exc)
Exemplo n.º 8
0
def dynamic_share():
    client = Client(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH)
    policy = (
        DynamicPolicyBuilder().with_full_name().with_age_over(18).with_email().build()
    )
    scenario = (
        DynamicScenarioBuilder()
        .with_policy(policy)
        .with_callback_endpoint("/yoti/auth")
        .build()
    )
    share = create_share_url(client, scenario)
    return render_template(
        "dynamic-share.html",
        yoti_client_sdk_id=YOTI_CLIENT_SDK_ID,
        yoti_share_url=share.share_url,
    )
Exemplo n.º 9
0
    def __init__(self, **kwargs: Any) -> None:
        """
        Initialize a connection to an SDK or API.

        :param configuration: the connection configuration.
        :param crypto_store: object to access the connection crypto objects.
        :param identity: the identity object.
        """
        super().__init__(**kwargs)
        yoti_client_sdk_id = cast(
            Optional[str], self.configuration.config.get("yoti_client_sdk_id")
        )
        yoti_key_file_path = cast(
            Optional[str], self.configuration.config.get("yoti_key_file_path")
        )
        if yoti_client_sdk_id is None or yoti_key_file_path is None:
            raise ValueError("Missing configuration.")
        self._client = YotiClient(yoti_client_sdk_id, yoti_key_file_path)
        self.dialogues = YotiDialogues()
Exemplo n.º 10
0
 def get(self, request, *args, **kwargs):
     client = Client(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH)
     policy = (
         DynamicPolicyBuilder()
         .with_full_name()
         .with_age_over(18)
         .with_email()
         .build()
     )
     scenario = (
         DynamicScenarioBuilder()
         .with_policy(policy)
         .with_callback_endpoint("/yoti/auth")
         .build()
     )
     share = create_share_url(client, scenario)
     context = {
         "yoti_client_sdk_id": YOTI_CLIENT_SDK_ID,
         "yoti_share_url": share.share_url,
     }
     return self.render_to_response(context)
Exemplo n.º 11
0
def source_constraints():
    client = Client(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH)
    constraint = (
        SourceConstraintBuilder().with_driving_licence().with_passport().build()
    )
    policy = (
        DynamicPolicyBuilder()
        .with_full_name(constraints=constraint)
        .with_structured_postal_address(constraints=constraint)
        .build()
    )
    scenario = (
        DynamicScenarioBuilder()
        .with_policy(policy)
        .with_callback_endpoint("/yoti/auth")
        .build()
    )
    share = create_share_url(client, scenario)
    return render_template(
        "dynamic-share.html",
        yoti_client_sdk_id=YOTI_CLIENT_SDK_ID,
        yoti_share_url=share.share_url,
    )
Exemplo n.º 12
0
 def get(self, request, *args, **kwargs):
     client = Client(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH)
     constraint = (
         SourceConstraintBuilder().with_driving_licence().with_passport().build()
     )
     policy = (
         DynamicPolicyBuilder()
         .with_full_name(constraints=constraint)
         .with_structured_postal_address(constraints=constraint)
         .build()
     )
     scenario = (
         DynamicScenarioBuilder()
         .with_policy(policy)
         .with_callback_endpoint("/yoti/auth")
         .build()
     )
     share = create_share_url(client, scenario)
     context = {
         "yoti_client_sdk_id": YOTI_CLIENT_SDK_ID,
         "yoti_share_url": share.share_url,
     }
     return self.render_to_response(context)
Exemplo n.º 13
0
class YotiConnection(BaseSyncConnection):
    """Proxy to the functionality of the SDK or API."""

    MAX_WORKER_THREADS = 5

    connection_id = PublicId.from_str("fetchai/yoti:0.1.0")

    def __init__(self, **kwargs: Any) -> None:
        """
        Initialize a connection to an SDK or API.

        :param configuration: the connection configuration.
        :param crypto_store: object to access the connection crypto objects.
        :param identity: the identity object.
        """
        super().__init__(**kwargs)
        yoti_client_sdk_id = cast(
            Optional[str], self.configuration.config.get("yoti_client_sdk_id")
        )
        yoti_key_file_path = cast(
            Optional[str], self.configuration.config.get("yoti_key_file_path")
        )
        if yoti_client_sdk_id is None or yoti_key_file_path is None:
            raise ValueError("Missing configuration.")
        self._client = YotiClient(yoti_client_sdk_id, yoti_key_file_path)
        self.dialogues = YotiDialogues()

    def on_connect(self) -> None:
        """Run on connect."""

    def on_disconnect(self) -> None:
        """Run on disconnect."""

    def on_send(self, envelope: Envelope) -> None:
        """
        Send an envelope.

        :param envelope: the envelope to send.
        :return: None
        """
        self.dispatch(envelope)

    def dispatch(self, envelope: Envelope) -> None:
        """
        Dispatch the request to the right sender handler.

        :param envelope: the envelope.
        :return: an awaitable.
        """
        if not isinstance(envelope.message, Message):  # pragma: nocover
            raise ValueError("Yoti connection expects non-serialized messages.")
        message = cast(YotiMessage, envelope.message)
        dialogue = cast(Optional[YotiDialogue], self.dialogues.update(message))
        if dialogue is None:
            raise ValueError(  # pragma: nocover
                "No dialogue created. Message={} not valid.".format(message)
            )
        performative = message.performative
        handler = self.get_handler(performative.value)
        response_message = handler(message, dialogue)

        if not response_message:
            self.logger.warning(f"Construct no response messge for {envelope}")
            return

        response_envelope = Envelope(
            to=envelope.sender,
            sender=envelope.to,
            message=response_message,
            context=envelope.context,
        )
        self.put_envelope(response_envelope)

    def get_handler(self, performative: str) -> Callable[[Message, Dialogue], Message]:
        """
        Get the handler method, given the message performative.

        :param performative_name: the message performative.
        :return: the method that will send the request.
        """
        handler = getattr(self, performative, None)
        if handler is None:
            raise Exception("Performative not recognized.")
        return handler

    def get_profile(self, message: YotiMessage, dialogue: YotiDialogue) -> YotiMessage:
        """
        Send the request 'get_request'.

        :param message: the Yoti message
        :param dialogue: the Yoti dialogue
        :return: None
        """
        activity_details = self._client.get_activity_details(message.token)
        if activity_details is None:
            response = self.get_error_message(
                ValueError("No activity_details returned"), message, dialogue
            )
            return response
        try:
            remember_me_id = activity_details.user_id
            profile = activity_details.profile
            if message.dotted_path == "":
                attributes = {
                    key: value.value
                    if isinstance(value.value, str)
                    else json.dumps(value.value)
                    for key, value in profile.attributes.items()
                }
                result = {"remember_me_id": remember_me_id, **attributes}
            else:
                callable_ = rgetattr(profile, message.dotted_path, *message.args)
                if len(message.args) != 0:
                    intermediate = callable_(*message.args)
                else:
                    intermediate = callable_
                result = {
                    "remember_me_id": remember_me_id,
                    "name": intermediate.name,
                    "value": intermediate.value,
                    "sources": ",".join(
                        [source.value for source in intermediate.sources]
                    ),
                    "verifiers": ",".join(
                        [verifier.value for verifier in intermediate.verifiers]
                    ),
                }
            response = cast(
                YotiMessage,
                dialogue.reply(
                    performative=YotiMessage.Performative.PROFILE,
                    target_message=message,
                    info=result,
                ),
            )
        except Exception as e:  # pylint: disable=broad-except
            response = self.get_error_message(e, message, dialogue)
            if self._logger:
                self._logger.exception("Error during envelope handling")
        return response

    @staticmethod
    def get_error_message(
        e: Exception, message: YotiMessage, dialogue: YotiDialogue,
    ) -> YotiMessage:
        """
        Build an error message.

        :param e: the exception
        :param message: the received message.
        :param dialogue: the dialogue.
        :return: an error message response.
        """
        response = cast(
            YotiMessage,
            dialogue.reply(
                performative=YotiMessage.Performative.ERROR,
                target_message=message,
                error_code=500,
                error_msg=str(e),
            ),
        )
        return response
Exemplo n.º 14
0
dotenv_path = join(dirname(__file__), ".env")
load_dotenv(dotenv_path)

YOTI_CLIENT_SDK_ID = environ.get("YOTI_CLIENT_SDK_ID")
YOTI_KEY_FILE_PATH = environ.get("YOTI_KEY_FILE_PATH")


# The following exits cleanly on Ctrl-C,
# while treating other exceptions as before.
def cli_exception(exception_type, value, tb):
    if not issubclass(exception_type, KeyboardInterrupt):
        sys.__excepthook__(exception_type, value, tb)


given_names = "Edward Richard George"
family_name = "Heath"

aml_address = aml.AmlAddress(country="GBR")
aml_profile = aml.AmlProfile(given_names, family_name, aml_address)

if sys.stdin.isatty():
    sys.excepthook = cli_exception

client = Client(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH)

aml_result = client.perform_aml_check(aml_profile)
print("AML Result for {0} {1}:".format(given_names, family_name))
print("On PEP list: " + str(aml_result.on_pep_list))
print("On fraud list: " + str(aml_result.on_fraud_list))
print("On watchlist: " + str(aml_result.on_watch_list))
Exemplo n.º 15
0
 def get(self, request, *args, **kwargs):
     client = Client(YOTI_CLIENT_SDK_ID, YOTI_FULL_KEY_FILE_PATH)
     activity_details = client.get_activity_details(request.GET['token'])
     context = activity_details.user_profile
     self.save_image(context.get('selfie'))
     return self.render_to_response(context)
Exemplo n.º 16
0
def client():
    return Client(YOTI_CLIENT_SDK_ID, PEM_FILE_PATH)
Exemplo n.º 17
0
def auth():
    client = Client(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH)
    activity_details = client.get_activity_details(request.args['token'])
    user_profile = activity_details.user_profile
    user_profile['user_id'] = activity_details.user_id
    return render_template('profile.html', **user_profile)
Exemplo n.º 18
0
def test_creating_client_instance_with_invalid_key_file_env_but_valid_key_file_arg(
):
    environ['YOTI_KEY_FILE_PATH'] = INVALID_KEY_FILE_PATH
    Client(YOTI_CLIENT_SDK_ID, PEM_FILE_PATH)
Exemplo n.º 19
0
def test_creating_client_instance_with_invalid_key_file_arg(key_file):
    with pytest.raises(RuntimeError) as exc:
        Client(YOTI_CLIENT_SDK_ID, key_file)
    expected_error = 'Could not read private key file'
    assert expected_error in str(exc)
    assert str(key_file) in str(exc)
Exemplo n.º 20
0
def test_creating_client_instance_without_private_key_file():
    if environ.get('YOTI_KEY_FILE_PATH'):
        del environ['YOTI_KEY_FILE_PATH']
    with pytest.raises(RuntimeError) as exc:
        Client(YOTI_CLIENT_SDK_ID)
    assert str(exc.value) == NO_KEY_FILE_SPECIFIED_ERROR
Exemplo n.º 21
0
def test_creating_client_instance_with_valid_key_file_env():
    environ['YOTI_KEY_FILE_PATH'] = PEM_FILE_PATH
    Client(YOTI_CLIENT_SDK_ID)
def sign_callback():
    yoti_client = Client(current_app.config['YOTI_CLIENT_SDK_ID'],
                         current_app.config['YOTI_KEY_FILE_PATH'])
    token = request.args.get('token')
    if token:
        try:
            activity_details = yoti_client.get_activity_details(token)

            title_number = str(session['title_id'])

            # API to fetch seller's details
            url = current_app.config['CASE_MANAGEMENT_API_URL'] + '/cases'
            case_details_res = requests.get(
                url,
                params={
                    "title_number": title_number,
                    "embed": "client"
                },
                headers={'Accept': 'application/json'})

            # Response
            case_details_obj = case_details_res.json()
            client = {}
            for case in case_details_obj:
                client = case['client']
            client['type'] = "individual"

            # Check that the current user is authorised to sign the agreement
            if client['identity'] == activity_details.user_id:

                url = current_app.config['CONVEYANCER_API_URL'] + '/me'
                signatory_res = requests.get(
                    url, headers={'Accept': 'application/json'})
                signatory = signatory_res.json()
                agreement_approval_data = {
                    "action": "sign",
                    "signatory": signatory['me']['x500'],
                    "signatory_individual": client
                }

                # Sign contract
                url = current_app.config[
                    'CONVEYANCER_API_URL'] + '/titles/' + title_number + "/sales-agreement"
                response = requests.put(
                    url,
                    data=json.dumps(agreement_approval_data),
                    headers={
                        'Accept': 'Application/JSON',
                        'Content-Type': 'Application/JSON'
                    })

                # Output
                if response.status_code == 200:
                    return redirect(
                        url_for('conveyancer_user.agreement_signed'))
                else:
                    return "Something went wrong:<br>" + response.text.replace(
                        "\n", "<br/>")

            else:
                error_message = "User not authorised to sign"
                redirect_url = request.args.get('next')
                return redirect(
                    url_for('conveyancer_user.agreement_signing',
                            redirect_url=redirect_url,
                            error_message=error_message))

        except Exception as e:
            error_message = str(e)
            redirect_url = request.args.get('next')
            return redirect(
                url_for('conveyancer_user.agreement_signing',
                        redirect_url=redirect_url,
                        error_message=error_message))
    else:
        return 'Yoti token missing'