-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #22 from getyoti/AML
[SDK-250]: AML Requests
- Loading branch information
Showing
15 changed files
with
448 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,9 @@ Entry point explanation | |
1) [Handling Users](#handling-users) - | ||
How to manage users | ||
|
||
1) [AML Integration](#aml-integration) - | ||
How to integrate with Yoti's AML (Anti Money Laundering) service | ||
|
||
1) [Running the examples](#running-the-examples) - | ||
How to retrieve a Yoti profile using the token | ||
|
||
|
@@ -128,6 +131,63 @@ gender = user_profile.get('gender') | |
nationality = user_profile.get('nationality') | ||
``` | ||
|
||
## AML Integration | ||
|
||
Yoti provides an AML (Anti Money Laundering) check service to allow a deeper KYC process to prevent fraud. This is a chargeable service, so please contact [[email protected]](mailto:[email protected]) for more information. | ||
|
||
Yoti will provide a boolean result on the following checks: | ||
|
||
* PEP list - Verify against Politically Exposed Persons list | ||
* Fraud list - Verify against US Social Security Administration Fraud (SSN Fraud) list | ||
* Watch list - Verify against watch lists from the Office of Foreign Assets Control | ||
|
||
To use this functionality you must ensure your application is assigned to your Organisation in the Yoti Dashboard - please see here for further information. | ||
|
||
For the AML check you will need to provide the following: | ||
|
||
* Data provided by Yoti (please ensure you have selected the Given name(s) and Family name attributes from the Data tab in the Yoti Dashboard) | ||
* Given name(s) | ||
* Family name | ||
* Data that must be collected from the user: | ||
* Country of residence (must be an ISO 3166 3-letter code) | ||
* Social Security Number (US citizens only) | ||
* Postcode/Zip code (US citizens only) | ||
|
||
### Consent | ||
|
||
Performing an AML check on a person *requires* their consent. | ||
**You must ensure you have user consent *before* using this service.** | ||
|
||
### Code Example | ||
|
||
Given a YotiClient initialised with your SDK ID and KeyPair (see [Client Initialisation](#client-initialisation)) performing an AML check is a straightforward case of providing basic profile data. | ||
|
||
```python | ||
from yoti_python_sdk import aml | ||
from yoti_python_sdk import Client | ||
|
||
client = Client(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH) | ||
given_names = "Edward Richard George" | ||
family_name = "Heath" | ||
|
||
aml_address = aml.AmlAddress(country="GBR") | ||
aml_profile = aml.AmlProfile( | ||
given_names, | ||
family_name, | ||
aml_address | ||
) | ||
|
||
|
||
aml_result = client.perform_aml_check(aml_profile) | ||
|
||
print("AML Result for {1} {2}:", 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)) | ||
``` | ||
|
||
Additionally an [example AML application](/examples/aml/app.py) is provided in the examples folder. | ||
|
||
## Running the Examples | ||
|
||
The callback URL for both example projects will be `http://localhost:5000/yoti/auth/` | ||
|
@@ -166,6 +226,12 @@ Both example applications utilise the env variables described in [Configuration] | |
1. Run: `python manage.py runserver 0.0.0.0:5000` | ||
1. Navigate to http://localhost:5000 | ||
|
||
#### AML Example | ||
|
||
1. Change directories to the AML folder: `cd examples/aml` | ||
1. Install requirements with `pip install -r requirements.txt` | ||
1. Run: `python app.py` | ||
|
||
### Plugins ### | ||
|
||
Plugins for both Django and Flask are in the `plugins/` dir. Their purpose is to make it as easy as possible to use the Yoti SDK with those frameworks. See the [Django](/plugins/django_yoti/README.md) and [Flask](/plugins/flask_yoti/README.md) README files for further details. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
YOTI_CLIENT_SDK_ID=yourClientSdkId | ||
YOTI_KEY_FILE_PATH=yourKeyFilePath |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import sys | ||
from os import environ | ||
from os.path import join, dirname | ||
|
||
from dotenv import load_dotenv | ||
|
||
from yoti_python_sdk import Client | ||
from yoti_python_sdk import aml | ||
|
||
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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
yoti | ||
python-dotenv>=0.7.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import json | ||
|
||
|
||
class AmlResult: | ||
def __init__(self, response_text): | ||
if not response_text: | ||
raise ValueError("AML Response is not valid") | ||
|
||
try: | ||
self.on_pep_list = json.loads(response_text).get('on_pep_list') | ||
self.on_fraud_list = json.loads(response_text).get('on_fraud_list') | ||
self.on_watch_list = json.loads(response_text).get('on_watch_list') | ||
|
||
except (AttributeError, IOError, TypeError, OSError) as exc: | ||
error = 'Could not parse AML result from response: "{0}"'.format(response_text) | ||
exception = '{0}: {1}'.format(type(exc).__name__, exc) | ||
raise RuntimeError('{0}: {1}'.format(error, exception)) | ||
|
||
self.__check_for_none_values(self.on_pep_list) | ||
self.__check_for_none_values(self.on_fraud_list) | ||
self.__check_for_none_values(self.on_watch_list) | ||
|
||
@staticmethod | ||
def __check_for_none_values(arg): | ||
if arg is None: | ||
raise TypeError(str.format("{0} argument was unable to be retrieved from the response", arg)) | ||
|
||
def __iter__(self): | ||
yield 'on_pep_list', self.on_pep_list | ||
yield 'on_fraud_list', self.on_fraud_list | ||
yield 'on_watch_list', self.on_watch_list | ||
|
||
|
||
class AmlAddress: | ||
def __init__(self, country, postcode=None): | ||
self.country = country | ||
self.post_code = postcode | ||
|
||
|
||
class AmlProfile: | ||
def __init__(self, given_names, family_name, address, ssn=None): | ||
self.given_names = given_names | ||
self.family_name = family_name | ||
self.address = address.__dict__ | ||
self.ssn = ssn |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import time | ||
import uuid | ||
|
||
|
||
class Endpoint(object): | ||
def __init__(self, sdk_id): | ||
self.sdk_id = sdk_id | ||
|
||
def get_activity_details_request_path(self, decrypted_request_token): | ||
return '/profile/{0}?nonce={1}×tamp={2}&appId={3}'.format( | ||
decrypted_request_token, | ||
self.__create_nonce(), | ||
self.__create_timestamp(), | ||
self.sdk_id | ||
) | ||
|
||
def get_aml_request_url(self): | ||
return '/aml-check?appId={0}×tamp={1}&nonce={2}'.format( | ||
self.sdk_id, | ||
self.__create_timestamp(), | ||
self.__create_nonce()) | ||
|
||
@staticmethod | ||
def __create_nonce(): | ||
return uuid.uuid4() | ||
|
||
@staticmethod | ||
def __create_timestamp(): | ||
return int(time.time() * 1000) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"on_fraud_list":false,"on_pep_list":true,"on_watch_list":false} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
NDem1ujFPEEb4cP/YWp6oGm7KFTVaxyWxLmRSNNH1hJhw3JejHwGKThlWPFdvtmsJuDVxvqTI4zbiNKlo9x9QKlNim0nUO6CFrH/PlwjJ3TAYE0c6BGoZOMp1LyAshl3QSVlNHC6/QuyyJIVJcekoH3Z3UkU8KYUB7xw+WR+OmQFO/U4JqjcqWDArPZtI5EwzFJBGpd3/7OJjpEbDHnAfU44p3yTnB9ySaxbsJ3V7zzBEMHt+b4NOEbKxboTt7hfz5N5wPRHLg2cg6gAFCq1Z7OhHsGdfmwgIqGG5Pmx6qlbBFhR7boRygK0HGDtkm25tbdLEJ9fiX40DFgbWzQF9g== |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.