BrightID SDK for Python
This library provides a Python interface for the BrightID API. It's compatible with Python 3 and supports BrightID API 5. In addition to the API implementation, this library provides required tools to make BrightID integration easy and straightforward for app developers.
Visit dev.brightid.org to find out more developer guides and documents.
You can install or upgrade python-brightid using:
$ pip3 install python-brightid --upgrade
Or you can install from source with:
$ git clone https://github.com/PooyaFekri/python-brightid.git
$ cd python-brightid
$ python3 setup.py install
Apps can use BrightID to make sure their users have no multiple accounts. To verify uniquness of a user, app should:
- Create a unique
contextId
for the user
>>> import uuid
>>> context = 'top-up-gifter'
>>> contextId = uuid.uuid4().hex
>>> contextId
>>> 'a9ee5dc6ac114c95af50ef90225e0e53'
- Create a deep link with that
contextId
>>> url = 'http://node.brightid.org'
>>> deep_link = brightid.tools.create_deep_link(context, contextId, url)
>>> node = brightid.Node('http://node.brightid.org/brightid/v5')
>>> brightid.tools.create_qr(deep_link)
>>> 'iVBORw0KGgoAAAANSUhEUgAAAggAAA...dKGIAAAAAElFTkSuQmCC'
-
Ask the user to click the deep link or scan the QR code representation to link their BrightID to that
contextId
-
Query BrightID nodes to check if the BrightID that linked the
contextId
is verified.
>>> app = 'top-up-gifter'
>>> try:
... v = node.verifications.get(app, contextId)
... 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 thecontextId
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 on BrightID. -
user is not sponsored
, it means that user is not sponsored and app should sponsor the user by signing and sending aSponsor
operation, wait about 10 seconds for the operation to get applied, and then query again.
>>> import brightid
>>> 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
... }
>>> 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'
>>> time.sleep(10)
>>> try:
... v = node.verifications.get(app, contextId)
... except Exception as e:
... print(str(e))
...
>>> v
{'unique': True, 'app': 'top-up-gifter', 'context': 'top-up-gifter', 'contextIds': ['a9ee5dc6ac114c95af50ef90225e0e53', '6e85ac7a7a1945d352de5c422db69f72']}
- 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 allcontextIds
the BrightID user linked under this context which can be used by app for this purpose.
Check BrightID API documentation to find more details.
>>> import brightid
>>> node = brightid.Node('http://node.brightid.org/brightid/v5')
>>> node.state()
{'lastProcessedBlock': 3946366, 'verificationsBlock': 3946320, 'initOp': 0, 'sentOp': 248}
>>> node.ip()
'68.183.76.106'
>>> id = 'kwQyKj5RS5DzPq9bvaNTKv0E6JxYIorylnF0ACUFbH0'
>>> node.users.get(id)
{'createdAt': 1553249775161, 'flaggers': {}, 'connections': [...], 'groups': [...], 'invites': [...], 'isSponsored': True, 'trusted': [...], 'verifications': [...]}
>>> # direction can be 'inbound'/'outbound'
>>> node.users.connections(id, direction='inbound')
[{'id': '33Vo27uqL0KGRTytjV9ScJbSTJj1YskRZUjGk-DuO0A', 'level': 'already known', 'timestamp': 1553265996463}, ...]
>>> requestor='0wT96mjCAje7If7qjUyrzkVYBPoLPu3tfOzesdT3ShE'
>>> node.users.profile(id, requestor)
{'connectionsNum': 6, 'groupsNum': 3, 'mutualConnections': ['hPAwqCeceA8quMdvo9TYU996iNBByuc65SrnXSvHgMs'], 'mutualGroups': ['IXDLiaHwMXKKHjSYUdOXMHPG1tJRTCa_Y0FjvSszEDE'], 'connectedAt': 1589978985397, 'createdAt': 1553249775161, 'reports': [], 'verifications': [{'name': 'BrightID', 'timestamp': 1604002284314}, ...]}
>>> node.users.verifications(id)
[{'name': 'BrightID', 'timestamp': 1604002284314}, {'name': 'Yekta', 'rank': 1, 'timestamp': 1608280959867, 'raw_rank': 4.596579161873709}, ...]
>>> 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}, ...]
>>> 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}
>>> node.verifications.get(app)
{'count': 68, 'contextIds': ['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}
>>> 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}
>>> import time
>>> user = brightid.tools.create_bright_id()
>>> user
{'id': 'Coh5IsaAGakYssl6_97nVN2MjLigOCAv_-OjWRpb4BY', 'private': '4ZiWpKli3PTW2CSlf7nqp4gp0H9ifxfSMGc0E5QCTogKiHkixoAZqRiyyXr/3udU3YyMuKA4IC//46NZGlvgFg==', 'public': 'Coh5IsaAGakYssl6/97nVN2MjLigOCAv/+OjWRpb4BY='}
>>> op = {
... 'name': 'Connect',
... 'id1': user['id'],
... 'id2': id,
... 'level': 'just met',
... 'timestamp': int(time.time() * 1000),
... 'v': 5
... }
>>> op['sig1'] = brightid.tools.sign(op, user['private'])
>>> op['sig1']
'JMx1erPZh+P0/en033JT7CgRycsO70WQCRHW+QADt22HzI5PK8zMUfzui1rXf9NJJm9eEtsYIYhqQa96AWJPDQ=='
>>> op_hash = node.operations.post(op)
>>> op_hash
'ZB6LCV21fg2yDJPM8yqX_gZrsAU5ee9rrkP8u8YKS5s'
>>> node.operations.get(op_hash)
{'state': 'applied', 'result': None}