diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4d56a32 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +## 2.0.0 (2022-08-14) + +### Features + +- Upgrade endpoints to v6 +- New functions: + - `getApp(app: string)` + - `unusedSponsorships(app: string)`, + - `userVerificationStatus(app: string, appUserId: string, params?: { includeHash?: boolean; signed?: "eth" | "nacl"; timestamp?: "seconds" | "milliseconds"; })` + - `userSponsorshipStatus(appUserId: string)` diff --git a/README.md b/README.md index ad5e4f2..9fd40db 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ You can install or upgrade python-brightid using: Or you can install from source with: - $ git clone https://github.com/PooyaFekri/python-brightid.git + $ git clone https://github.com/BrightID/python-brightid.git $ cd python-brightid $ python3 setup.py install @@ -24,37 +24,43 @@ Or you can install from source with: Apps can use BrightID to make sure their users have no multiple accounts. To verify uniquness of a user, app should: -1. Create a unique `contextId` for the user +1. Create a unique `appUserId` for the user + ``` >>> import uuid - >>> context = 'top-up-gifter' - >>> contextId = uuid.uuid4().hex - >>> contextId + >>> app = 'top-up-gifter' + >>> appUserId = uuid.uuid4().hex + >>> app >>> 'a9ee5dc6ac114c95af50ef90225e0e53' ``` -2. Create a deep link with that `contextId` + +2. Create a deep link with that `appUserId` + ``` >>> url = 'http://node.brightid.org' - >>> deep_link = brightid.tools.create_deep_link(context, contextId, url) + >>> deep_link = brightid.tools.create_deep_link(app, appUserId, url) >>> node = brightid.Node('http://node.brightid.org/brightid/v5') >>> brightid.tools.create_qr(deep_link) >>> 'iVBORw0KGgoAAAANSUhEUgAAAggAAA...dKGIAAAAAElFTkSuQmCC' ``` -3. Ask the user to click the deep link or scan the QR code representation to link their BrightID to that `contextId` -4. Query BrightID nodes to check if the BrightID that linked the `contextId` is verified. +3. Ask the user to click the deep link or scan the QR code representation to link their BrightID to that `appUserId` + +4. Query BrightID nodes to check if the BrightID that linked the `appUserId` is verified. + ``` >>> app = 'top-up-gifter' >>> try: - ... v = node.verifications.get(app, contextId) + ... v = node.verifications.get(app, appUserId) ... except Exception as e: ... print(str(e)) ... >>> ``` + If exception is raised and `str(e)` is: -- `contextId not found`, it means that user did not link the `contextId` to the BrightID yet. The app should query again after a while in such case. +- `appUserId not found`, it means that user did not link the `appUserId` to the BrightID yet. The app should query again after a while in such case. - `user can not be verified for this app`, it means user is not verified on BrightID yet. The app should ask user to return back after [getting verified](https://brightid.gitbook.io/brightid/getting-verified) on BrightID. @@ -62,38 +68,32 @@ If exception is raised and `str(e)` is: ``` >>> import brightid + >>> import uuid >>> import time - >>> node = brightid.Node('http://node.brightid.org/brightid/v5') - >>> op = { - ... 'name': 'Sponsor', - ... 'app': app, - ... 'contextId': contextId, - ... 'timestamp': int(time.time()*1000), - ... 'v': 5 - ... } + + >>> node = brightid.Node() + >>> app = "Gitcoin" + >>> app_user_id = uuid.uuid4().hex >>> sponsor_private_key = 'rXSGf0ka3WsvsX...ZKwujpNH51Q==' - >>> op['sig'] = brightid.tools.sign(op, sponsor_private_key) - >>> op['sig'] - '7wOmXH1ivk104a9kO5mWkslWstYnWnRtnS/jtXEz3P1PyxhTh06i3H0yZpIrST/iiYpd15iscCuyGJpghnOXDw==' - >>> node.operations.post(op) - 'rFT1ASgPQuxUx0XfMq9EjBbuzCOaoOw_sdklaDamPXw' + >>> node.sponsorships.sponsor(sponsor_private_key, app, app_user_id) >>> time.sleep(10) >>> try: - ... v = node.verifications.get(app, contextId) + ... v = node.sponsorships.sponsorshipsStatus(app_user_id) ... except Exception as e: ... print(str(e)) ... >>> v - {'unique': True, 'app': 'top-up-gifter', 'context': 'top-up-gifter', 'contextIds': ['a9ee5dc6ac114c95af50ef90225e0e53', '6e85ac7a7a1945d352de5c422db69f72']} + {'unique': True, 'app': 'Gitcoin', 'appUserIds': ['a9ee5dc6ac114c95af50ef90225e0e53', '6e85ac7a7a1945d352de5c422db69f72']} ``` -5. check its database to ensure none of linked `contextId`s by this user got the service supposed to be provided once for each user before. The response has a list of all `contextIds` the BrightID user linked under this context which can be used by app for this purpose. +5. check its database to ensure none of linked `appUserId`s by this user got the service supposed to be provided once for each user before. The response has a list of all `appUserIds` the BrightID user linked under this app which can be used by app for this purpose. ## Using API Check [BrightID API documentation](https://dev.brightid.org/docs/node-api) to find more details. #### Connecting to Node + ``` >>> import brightid >>> node = brightid.Node('http://node.brightid.org/brightid/v5') @@ -102,7 +102,9 @@ Check [BrightID API documentation](https://dev.brightid.org/docs/node-api) to fi >>> node.ip() '68.183.76.106' ``` + #### Getting users data with brightid + ``` >>> id = 'kwQyKj5RS5DzPq9bvaNTKv0E6JxYIorylnF0ACUFbH0' >>> node.users.get(id) @@ -116,39 +118,30 @@ Check [BrightID API documentation](https://dev.brightid.org/docs/node-api) to fi >>> node.users.verifications(id) [{'name': 'BrightID', 'timestamp': 1604002284314}, {'name': 'Yekta', 'rank': 1, 'timestamp': 1608280959867, 'raw_rank': 4.596579161873709}, ...] ``` + #### Getting apps data + ``` >>> node.apps.get() - [{'id': '1hive', 'name': '1Hive Honey Faucet', 'context': '1hive', 'verification': 'BrightID', 'logo': 'data:image/png;base64,iVBoAYFAw...rkJggg==', 'url': 'https://1hive.org/', 'assignedSponsorships': 7775, 'unusedSponsorships': 701}, ...] + [{'id': '1hive', 'name': '1Hive Honey Faucet', 'app': '1hive', 'verification': 'BrightID', 'logo': 'data:image/png;base64,iVBoAYFAw...rkJggg==', 'url': 'https://1hive.org/', 'assignedSponsorships': 7775, 'unusedSponsorships': 701}, ...] >>> app = 'top-up-gifter' >>> node.apps.get(app) - {'id': 'top-up-gifter', 'name': 'Top-up Gifter', 'context': 'top-up-gifter', 'verification': 'BrightID', 'logo': 'data:image/png;base64,iVBORF...YII=', 'url': 'https://t.me/top_up_gifter_bot', 'assignedSponsorships': 100, 'unusedSponsorships': 95} + {'id': 'top-up-gifter', 'name': 'Top-up Gifter', 'app': 'top-up-gifter', 'verification': 'BrightID', 'logo': 'data:image/png;base64,iVBORF...YII=', 'url': 'https://t.me/top_up_gifter_bot', 'assignedSponsorships': 100, 'unusedSponsorships': 95} ``` + #### Getting verifications data + ``` >>> node.verifications.get(app) - {'count': 68, 'contextIds': ['6847e75f4351f70836c2e6330fb3d8ac', '6e85ac7a7a1945d352de5c422db69f72', ...]} + {'count': 68, 'appUserIds': ['6847e75f4351f70836c2e6330fb3d8ac', '6e85ac7a7a1945d352de5c422db69f72', ...]} >>> node.verifications.get(app, count_only=True) 68 - >>> node.verifications.get(app, contextId, singed='eth', timestamp='seconds') - {'unique': True, 'app': 'top-up-gifter', 'context': 'top-up-gifter', 'contextIds': ['dc100f7d468b232e65aa5545d718caa3', '386039e2db5916e1375b6227bf900b58'], 'timestamp': 1608282563} -``` -#### Blocking verification for test -``` - >>> action='sponsorship' # sponsorship/link/verification are valid actions - >>> testing_key='a8...OtD' - >>> node.testblocks.put(app, action, contextId, testing_key) - >>> try: - ... node.verifications.get(app, contextId, singed='eth', timestamp='seconds') - ... except Exception as e: - ... print(str(e)) - ... - user is not sponsored - >>> node.testblocks.delete(app, action, contextId, testing_key) - >>> node.verifications.get(app, contextId, singed='eth', timestamp='seconds') - {'unique': True, 'app': 'top-up-gifter', 'context': 'top-up-gifter', 'contextIds': ['dc100f7d468b232e65aa5545d718caa3', '386039e2db5916e1375b6227bf900b58'], 'timestamp': 1608282714} + >>> node.verifications.get(app, appUserId, singed='eth', timestamp='seconds') + {'unique': True, 'app': 'top-up-gifter', 'app': 'top-up-gifter', 'appUserIds': ['dc100f7d468b232e65aa5545d718caa3', '386039e2db5916e1375b6227bf900b58'], 'timestamp': 1608282563} ``` + #### Posting operations + ``` >>> import time >>> user = brightid.tools.create_bright_id() diff --git a/brightid/apps.py b/brightid/apps.py index 603e582..a6d41c7 100644 --- a/brightid/apps.py +++ b/brightid/apps.py @@ -10,3 +10,9 @@ def get(self, app=''): res = response.json() self.node.check_error(res) return res.get('data').get('apps') or res.get('data') + + def unusedSponsorships(self, app=''): + response = requests.get(f'{self.node.url}/apps/{app}') + res = response.json() + self.node.check_error(res) + return res.get('data').get('apps').get('unusedSponsorships') diff --git a/brightid/groups.py b/brightid/groups.py index d79556f..01aa75b 100644 --- a/brightid/groups.py +++ b/brightid/groups.py @@ -10,3 +10,4 @@ def get(self, group): res = response.json() self.node.check_error(res) return res.get('data') + diff --git a/brightid/node.py b/brightid/node.py index 5db1959..5759f24 100644 --- a/brightid/node.py +++ b/brightid/node.py @@ -4,8 +4,8 @@ class Node: - def __init__(self, url='http://node.brightid.org/brightid/v5'): - self.url = url + def __init__(self): + self.url = "http://node.brightid.org/brightid/v6" self.users = users.Users(self) self.groups = groups.Groups(self) self.operations = operations.Operations(self) @@ -13,12 +13,6 @@ def __init__(self, url='http://node.brightid.org/brightid/v5'): self.testblocks = testblocks.Testblocks(self) self.apps = apps.Apps(self) - def ip(self): - response = requests.get(f'{self.url}/ip') - res = response.json() - self.check_error(res) - return res.get('data').get('ip') - def state(self): response = requests.get(f'{self.url}/state') res = response.json() diff --git a/brightid/operations.py b/brightid/operations.py index 483244f..c58e04b 100644 --- a/brightid/operations.py +++ b/brightid/operations.py @@ -1,4 +1,5 @@ import requests +import time class Operations: diff --git a/brightid/sponsorships.py b/brightid/sponsorships.py new file mode 100644 index 0000000..28723ef --- /dev/null +++ b/brightid/sponsorships.py @@ -0,0 +1,28 @@ +import requests +import time + + +class Sponsorships: + def __init__(self, node): + self.node = node + + def sponsorshipStatus(self, app_user_id): + response = requests.get( + f'{self.node.url}/sponsorships/{app_user_id}') + res = response.json() + self.node.check_error(res) + return res.get('data') + + def sponsor(self, key, app, app_user_id): + unusedSponsorships = self.node.apps.unusedSponsorships(app) + if (unusedSponsorships < 1): + raise RuntimeError(app + ' does not have any unused sponsorships') + op = { + 'name': 'Sponsor', + 'app': app, + 'appUserId': app_user_id, + 'timestamp': int(time.time()*1000), + 'v': 6 + } + op['sig'] = self.node.tools.sign(op, key) + self.node.operations.post(op) diff --git a/brightid/testblocks.py b/brightid/testblocks.py deleted file mode 100644 index 1de5987..0000000 --- a/brightid/testblocks.py +++ /dev/null @@ -1,26 +0,0 @@ -import requests - - -class Testblocks: - def __init__(self, node): - self.node = node - - def put(self, app, action, context_id, testing_key): - params = ( - ('testingKey', testing_key), - ) - response = requests.put( - f'{self.node.url}/testblocks/{app}/{action}/{context_id}', params=params) - if not response.ok: - res = response.json() - self.node.check_error(res) - - def delete(self, app, action, context_id, testing_key): - params = ( - ('testingKey', testing_key), - ) - response = requests.delete( - f'{self.node.url}/testblocks/{app}/{action}/{context_id}', params=params) - if not response.ok: - res = response.json() - self.node.check_error(res) diff --git a/brightid/tools.py b/brightid/tools.py index 9c06c00..1e93cda 100644 --- a/brightid/tools.py +++ b/brightid/tools.py @@ -4,12 +4,9 @@ import pyqrcode -def create_deep_link(context, context_id, url='http://node.brightid.org', schema='https'): - url = url.replace('/', '%2f') - if schema == 'brightid': - deep_link = f'brightid://link-verification/{url}/{context}/{context_id}' - else: - deep_link = f'https://app.brightid.org/link-verification/{url}/{context}/{context_id}/' +def create_deep_link(app, app_user_id): + url = "http://node.brightid.org".replace('/', '%2f') + deep_link = f'brightid://link-verification/{url}/{app}/{app_user_id}' return deep_link diff --git a/brightid/users.py b/brightid/users.py index dc2877f..781bb8f 100644 --- a/brightid/users.py +++ b/brightid/users.py @@ -1,5 +1,6 @@ import requests + class Users: def __init__(self, node): self.node = node @@ -25,7 +26,7 @@ def connections(self, user, direction): self.node.check_error(res) return res.get('data').get('connections') - def profile(self, user, requestor): + def profile(self, user, requestor=""): response = requests.get( f'{self.node.url}/users/{user}/profile/{requestor}') res = response.json() diff --git a/brightid/verifications.py b/brightid/verifications.py index 64f5b6e..1bc6ac1 100644 --- a/brightid/verifications.py +++ b/brightid/verifications.py @@ -5,13 +5,13 @@ class Verifications: def __init__(self, node): self.node = node - def get(self, app, context_id='', **kwargs): + def get(self, app, app_user_id='', **kwargs): params = ( ('timestamp', kwargs.get('timestamp')), ('signed', kwargs.get('signed')), ('count_only', kwargs.get('count_only')) ) - response = requests.get(f'{self.node.url}/verifications/{app}/{context_id}', params=params) + response = requests.get(f'{self.node.url}/verifications/{app}/{app_user_id}', params=params) res = response.json() self.node.check_error(res) if res.get('data').get('count') and kwargs.get('count_only'): diff --git a/setup.py b/setup.py index a9c7f3d..31f9545 100644 --- a/setup.py +++ b/setup.py @@ -2,13 +2,13 @@ setup( name = 'python_brightid', packages = ['brightid'], - version = '1.2.0', + version = '2.0.0', license='MIT', description = 'SDK for integrating with BrightId!', - author = 'Pooya Fekri', - author_email = 'pooyafekri79@gmail.com', - url = 'https://github.com/PooyaFekri/python-brightid', - download_url = 'https://github.com/PooyaFekri/python-brightid/archive/main.zip', + author = 'Pooya Fekri, Victor Ginelli (@youngkidwarrior)', + author_email = 'pooyafekri79@gmail.com, victor@she.energy', + url = 'https://github.com/BrightID/python-brightid', + download_url = 'https://github.com/BrightID/python-brightid/archive/main.zip', keywords = ['Brightid'], install_requires=[ 'requests', @@ -19,7 +19,7 @@ classifiers=[ # Optional # How mature is this project? Common values are # 3 - Alpha - # 4 - Beta + # 4 - Beta`` # 5 - Production/Stable 'Development Status :: 4 - Beta',