Compare commits

..

2 Commits

Author SHA1 Message Date
nolash
12db0c3ef8 Upgrade sarafu-faucet in cic-eth 2021-06-19 07:48:58 +02:00
nolash
2efe9747a8 Correct loglines 2021-06-19 07:20:39 +02:00
45 changed files with 261 additions and 668 deletions

2
.gitignore vendored
View File

@@ -11,5 +11,3 @@ build/
**/*sqlite **/*sqlite
**/.nyc_output **/.nyc_output
**/coverage **/coverage
**/.venv
.idea

View File

@@ -16,7 +16,7 @@ moolb~=0.1.1b2
eth-address-index~=0.1.1a11 eth-address-index~=0.1.1a11
chainlib~=0.0.3rc2 chainlib~=0.0.3rc2
hexathon~=0.0.1a7 hexathon~=0.0.1a7
chainsyncer[sql]==0.0.2a5 chainsyncer[sql]~=0.0.2a5
chainqueue~=0.0.2b3 chainqueue~=0.0.2b3
sarafu-faucet~=0.0.3a3 sarafu-faucet~=0.0.3a3
erc20-faucet~=0.2.1a5 erc20-faucet~=0.2.1a5

View File

@@ -87,18 +87,10 @@ for key in config.store.keys():
module = importlib.import_module(config.store[key]) module = importlib.import_module(config.store[key])
if key == 'TASKS_AFRICASTALKING': if key == 'TASKS_AFRICASTALKING':
africastalking_notifier = module.AfricasTalkingNotifier africastalking_notifier = module.AfricasTalkingNotifier
api_sender_id = config.get('AFRICASTALKING_API_SENDER_ID')
logg.debug(f'SENDER ID VALUE IS: {api_sender_id}')
if not api_sender_id:
api_sender_id = None
logg.debug(f'SENDER ID RESOLVED TO NONE: {api_sender_id}')
africastalking_notifier.initialize( africastalking_notifier.initialize(
config.get('AFRICASTALKING_API_USERNAME'), config.get('AFRICASTALKING_API_USERNAME'),
config.get('AFRICASTALKING_API_KEY'), config.get('AFRICASTALKING_API_KEY'),
api_sender_id config.get('AFRICASTALKING_API_SENDER_ID')
) )

View File

@@ -275,18 +275,6 @@
"display_key": "ussd.kenya.new_pin_confirmation", "display_key": "ussd.kenya.new_pin_confirmation",
"name": "new_pin_confirmation", "name": "new_pin_confirmation",
"parent": "metadata_management" "parent": "metadata_management"
},
"47": {
"description": "Year of birth entry menu.",
"display_key": "ussd.kenya.enter_date_of_birth",
"name": "enter_date_of_birth",
"parent": "metadata_management"
},
"48": {
"description": "Pin entry menu for changing year of birth data.",
"display_key": "ussd.kenya.dob_edit_pin_authorization",
"name": "dob_edit_pin_authorization",
"parent": "metadata_management"
} }
} }

View File

@@ -1,12 +0,0 @@
# standard imports
# external imports
# local imports
from .base import MetadataRequestsHandler
class CustomMetadata(MetadataRequestsHandler):
def __init__(self, identifier: bytes):
super().__init__(cic_type=':cic.custom', identifier=identifier)

View File

@@ -1,12 +0,0 @@
# standard imports
# external imports
# local imports
from .base import MetadataRequestsHandler
class PreferencesMetadata(MetadataRequestsHandler):
def __init__(self, identifier: bytes):
super().__init__(cic_type=':cic.preferences', identifier=identifier)

View File

@@ -8,10 +8,6 @@ import phonenumbers
from cic_ussd.db.models.account import Account from cic_ussd.db.models.account import Account
class E164Format:
region = None
def process_phone_number(phone_number: str, region: str): def process_phone_number(phone_number: str, region: str):
"""This function parses any phone number for the provided region """This function parses any phone number for the provided region
:param phone_number: A string with a phone number. :param phone_number: A string with a phone number.
@@ -42,7 +38,7 @@ def get_user_by_phone_number(phone_number: str) -> Optional[Account]:
:rtype: Account|None :rtype: Account|None
""" """
# consider adding region to user's metadata # consider adding region to user's metadata
phone_number = process_phone_number(phone_number=phone_number, region=E164Format.region) phone_number = process_phone_number(phone_number=phone_number, region='KE')
user = Account.session.query(Account).filter_by(phone_number=phone_number).first() user = Account.session.query(Account).filter_by(phone_number=phone_number).first()
return user return user

View File

@@ -1,5 +1,4 @@
# standard imports # standard imports
import datetime
import logging import logging
import json import json
import re import re
@@ -258,10 +257,6 @@ def process_display_user_metadata(user: Account, display_key: str):
contact_data = get_contact_data_from_vcard(vcard=user_metadata.get('vcard')) contact_data = get_contact_data_from_vcard(vcard=user_metadata.get('vcard'))
logg.debug(f'{contact_data}') logg.debug(f'{contact_data}')
full_name = f'{contact_data.get("given")} {contact_data.get("family")}' full_name = f'{contact_data.get("given")} {contact_data.get("family")}'
date_of_birth = user_metadata.get('date_of_birth')
year_of_birth = date_of_birth.get('year')
present_year = datetime.datetime.now().year
age = present_year - year_of_birth
gender = user_metadata.get('gender') gender = user_metadata.get('gender')
products = ', '.join(user_metadata.get('products')) products = ', '.join(user_metadata.get('products'))
location = user_metadata.get('location').get('area_name') location = user_metadata.get('location').get('area_name')
@@ -270,7 +265,6 @@ def process_display_user_metadata(user: Account, display_key: str):
key=display_key, key=display_key,
preferred_language=user.preferred_language, preferred_language=user.preferred_language,
full_name=full_name, full_name=full_name,
age=age,
gender=gender, gender=gender,
location=location, location=location,
products=products products=products
@@ -295,6 +289,7 @@ def process_display_user_metadata(user: Account, display_key: str):
) )
def process_account_statement(user: Account, display_key: str, ussd_session: dict): def process_account_statement(user: Account, display_key: str, ussd_session: dict):
""" """
:param user: :param user:
@@ -428,6 +423,12 @@ def process_request(user_input: str, user: Account, ussd_session: Optional[dict]
:return: A ussd menu's corresponding text value. :return: A ussd menu's corresponding text value.
:rtype: Document :rtype: Document
""" """
# retrieve metadata before any transition
key = generate_metadata_pointer(
identifier=blockchain_address_to_metadata_pointer(blockchain_address=user.blockchain_address),
cic_type=':cic.person'
)
person_metadata = get_cached_data(key=key)
if ussd_session: if ussd_session:
if user_input == "0": if user_input == "0":
@@ -451,7 +452,7 @@ def process_request(user_input: str, user: Account, ussd_session: Optional[dict]
'exit_pin_mismatch', 'exit_pin_mismatch',
'exit_invalid_request', 'exit_invalid_request',
'exit_successful_transaction' 'exit_successful_transaction'
]: ] and person_metadata is not None:
return UssdMenu.find_by_name(name='start') return UssdMenu.find_by_name(name='start')
else: else:
return UssdMenu.find_by_name(name=last_state) return UssdMenu.find_by_name(name=last_state)

View File

@@ -26,7 +26,7 @@ from cic_ussd.metadata.base import Metadata
from cic_ussd.operations import (define_response_with_content, from cic_ussd.operations import (define_response_with_content,
process_menu_interaction_requests, process_menu_interaction_requests,
define_multilingual_responses) define_multilingual_responses)
from cic_ussd.phone_number import process_phone_number, Support, E164Format from cic_ussd.phone_number import process_phone_number, Support
from cic_ussd.processor import get_default_token_data from cic_ussd.processor import get_default_token_data
from cic_ussd.redis import cache_data, create_cached_data_key, InMemoryStore from cic_ussd.redis import cache_data, create_cached_data_key, InMemoryStore
from cic_ussd.requests import (get_request_endpoint, from cic_ussd.requests import (get_request_endpoint,
@@ -126,7 +126,6 @@ else:
valid_service_codes = config.get('APP_SERVICE_CODE').split(",") valid_service_codes = config.get('APP_SERVICE_CODE').split(",")
E164Format.region = config.get('PHONE_NUMBER_REGION')
Support.phone_number = config.get('APP_SUPPORT_PHONE_NUMBER') Support.phone_number = config.get('APP_SUPPORT_PHONE_NUMBER')
@@ -146,7 +145,7 @@ def application(env, start_response):
if get_request_method(env=env) == 'POST' and get_request_endpoint(env=env) == '/': if get_request_method(env=env) == 'POST' and get_request_endpoint(env=env) == '/':
if env.get('CONTENT_TYPE') != 'application/x-www-form-urlencoded': if env.get('CONTENT_TYPE') != 'application/x-www-form-urlencoded':
start_response('405 Urlencoded, please', errors_headers) start_response('405 Play by the rules', errors_headers)
return [] return []
post_data = env.get('wsgi.input').read() post_data = env.get('wsgi.input').read()
@@ -169,7 +168,7 @@ def application(env, start_response):
# add validation for phone number # add validation for phone number
if phone_number: if phone_number:
phone_number = process_phone_number(phone_number=phone_number, region=E164Format.region) phone_number = process_phone_number(phone_number=phone_number, region=config.get('PHONE_NUMBER_REGION'))
# validate ip address # validate ip address
if not check_ip(config=config, env=env): if not check_ip(config=config, env=env):
@@ -214,9 +213,6 @@ def application(env, start_response):
return [response_bytes] return [response_bytes]
else: else:
logg.error('invalid query {}'.format(env))
for r in env:
logg.debug('{}: {}'.format(r, env))
start_response('405 Play by the rules', errors_headers) start_response('405 Play by the rules', errors_headers)
return [] return []

View File

@@ -66,18 +66,6 @@ def menu_five_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
return user_input == '5' return user_input == '5'
def menu_six_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
"""
This function checks that user input matches a string with value '6'
:param state_machine_data: A tuple containing user input, a ussd session and user object.
:type state_machine_data: tuple
:return: A user input's match with '6'
:rtype: bool
"""
user_input, ussd_session, user = state_machine_data
return user_input == '6'
def menu_zero_zero_selected(state_machine_data: Tuple[str, dict, Account]) -> bool: def menu_zero_zero_selected(state_machine_data: Tuple[str, dict, Account]) -> bool:
""" """
This function checks that user input matches a string with value '00' This function checks that user input matches a string with value '00'

View File

@@ -11,7 +11,7 @@ from cic_ussd.balance import BalanceManager, compute_operational_balance
from cic_ussd.chain import Chain from cic_ussd.chain import Chain
from cic_ussd.db.models.account import AccountStatus, Account from cic_ussd.db.models.account import AccountStatus, Account
from cic_ussd.operations import save_to_in_memory_ussd_session_data from cic_ussd.operations import save_to_in_memory_ussd_session_data
from cic_ussd.phone_number import get_user_by_phone_number, process_phone_number, E164Format from cic_ussd.phone_number import get_user_by_phone_number, process_phone_number
from cic_ussd.processor import retrieve_token_symbol from cic_ussd.processor import retrieve_token_symbol
from cic_ussd.redis import create_cached_data_key, get_cached_data from cic_ussd.redis import create_cached_data_key, get_cached_data
from cic_ussd.transactions import OutgoingTransactionProcessor from cic_ussd.transactions import OutgoingTransactionProcessor
@@ -29,9 +29,8 @@ def is_valid_recipient(state_machine_data: Tuple[str, dict, Account]) -> bool:
:rtype: bool :rtype: bool
""" """
user_input, ussd_session, user = state_machine_data user_input, ussd_session, user = state_machine_data
phone_number = process_phone_number(user_input, E164Format.region)
recipient = get_user_by_phone_number(phone_number=user_input) recipient = get_user_by_phone_number(phone_number=user_input)
is_not_initiator = phone_number != user.phone_number is_not_initiator = process_phone_number(user_input, 'KE') != user.phone_number
has_active_account_status = user.get_account_status() == AccountStatus.ACTIVE.name has_active_account_status = user.get_account_status() == AccountStatus.ACTIVE.name
return is_not_initiator and has_active_account_status and recipient is not None return is_not_initiator and has_active_account_status and recipient is not None

View File

@@ -29,16 +29,6 @@ def change_preferred_language_to_en(state_machine_data: Tuple[str, dict, Account
Account.session.add(user) Account.session.add(user)
Account.session.commit() Account.session.commit()
preferences_data = {
'preferred_language': 'en'
}
s = celery.signature(
'cic_ussd.tasks.metadata.add_preferences_metadata',
[user.blockchain_address, preferences_data]
)
s.apply_async(queue='cic-ussd')
def change_preferred_language_to_sw(state_machine_data: Tuple[str, dict, Account]): def change_preferred_language_to_sw(state_machine_data: Tuple[str, dict, Account]):
"""This function changes the user's preferred language to swahili. """This function changes the user's preferred language to swahili.
@@ -50,16 +40,6 @@ def change_preferred_language_to_sw(state_machine_data: Tuple[str, dict, Account
Account.session.add(user) Account.session.add(user)
Account.session.commit() Account.session.commit()
preferences_data = {
'preferred_language': 'sw'
}
s = celery.signature(
'cic_ussd.tasks.metadata.add_preferences_metadata',
[user.blockchain_address, preferences_data]
)
s.apply_async(queue='cic-ussd')
def update_account_status_to_active(state_machine_data: Tuple[str, dict, Account]): def update_account_status_to_active(state_machine_data: Tuple[str, dict, Account]):
"""This function sets user's account to active. """This function sets user's account to active.
@@ -113,9 +93,6 @@ def save_metadata_attribute_to_session_data(state_machine_data: Tuple[str, dict,
if 'given_name' in current_state: if 'given_name' in current_state:
key = 'given_name' key = 'given_name'
if 'date_of_birth' in current_state:
key = 'date_of_birth'
if 'family_name' in current_state: if 'family_name' in current_state:
key = 'family_name' key = 'family_name'
@@ -153,13 +130,6 @@ def format_user_metadata(metadata: dict, user: Account):
given_name = metadata.get('given_name') given_name = metadata.get('given_name')
family_name = metadata.get('family_name') family_name = metadata.get('family_name')
if isinstance(metadata.get('date_of_birth'), dict):
date_of_birth = metadata.get('date_of_birth')
else:
date_of_birth = {
"year": int(metadata.get('date_of_birth')[:4])
}
# check whether there's existing location data # check whether there's existing location data
if isinstance(metadata.get('location'), dict): if isinstance(metadata.get('location'), dict):
location = metadata.get('location') location = metadata.get('location')
@@ -184,7 +154,6 @@ def format_user_metadata(metadata: dict, user: Account):
) )
return { return {
"date_registered": date_registered, "date_registered": date_registered,
"date_of_birth": date_of_birth,
"gender": gender, "gender": gender,
"identities": identities, "identities": identities,
"location": location, "location": location,
@@ -232,12 +201,12 @@ def edit_user_metadata_attribute(state_machine_data: Tuple[str, dict, Account]):
given_name = ussd_session.get('session_data').get('given_name') given_name = ussd_session.get('session_data').get('given_name')
family_name = ussd_session.get('session_data').get('family_name') family_name = ussd_session.get('session_data').get('family_name')
date_of_birth = ussd_session.get('session_data').get('date_of_birth')
gender = ussd_session.get('session_data').get('gender') gender = ussd_session.get('session_data').get('gender')
location = ussd_session.get('session_data').get('location') location = ussd_session.get('session_data').get('location')
products = ussd_session.get('session_data').get('products') products = ussd_session.get('session_data').get('products')
# validate user metadata # validate user metadata
person = Person()
user_metadata = json.loads(user_metadata) user_metadata = json.loads(user_metadata)
# edit specific metadata attribute # edit specific metadata attribute
@@ -245,11 +214,6 @@ def edit_user_metadata_attribute(state_machine_data: Tuple[str, dict, Account]):
user_metadata['given_name'] = given_name user_metadata['given_name'] = given_name
if family_name: if family_name:
user_metadata['family_name'] = family_name user_metadata['family_name'] = family_name
if date_of_birth and len(date_of_birth) == 4:
year = int(date_of_birth[:4])
user_metadata['date_of_birth'] = {
'year': year
}
if gender: if gender:
user_metadata['gender'] = gender user_metadata['gender'] = gender
if location: if location:

View File

@@ -56,15 +56,3 @@ def is_valid_gender_selection(state_machine_data: Tuple[str, dict, Account]):
return True return True
else: else:
return False return False
def is_valid_date(state_machine_data: Tuple[str, dict, Account]):
"""
:param state_machine_data:
:type state_machine_data:
:return:
:rtype:
"""
user_input, ussd_session, user = state_machine_data
# For MVP this value is defaulting to year
return len(user_input) == 4 and int(user_input) >= 1900

View File

@@ -53,25 +53,13 @@ def process_account_creation_callback(self, result: str, url: str, status_code:
session.add(user) session.add(user)
session.commit() session.commit()
session.close() session.close()
queue = self.request.delivery_info.get('routing_key') queue = self.request.delivery_info.get('routing_key')
s = celery.signature(
# add phone number metadata lookup
s_phone_pointer = celery.signature(
'cic_ussd.tasks.metadata.add_phone_pointer', 'cic_ussd.tasks.metadata.add_phone_pointer',
[result, phone_number] [result, phone_number]
) )
s_phone_pointer.apply_async(queue=queue) s.apply_async(queue=queue)
# add custom metadata tags
custom_metadata = {
"tags": ["ussd", "individual"]
}
s_custom_metadata = celery.signature(
'cic_ussd.tasks.metadata.add_custom_metadata',
[result, custom_metadata]
)
s_custom_metadata.apply_async(queue=queue)
# expire cache # expire cache
cache.expire(task_id, timedelta(seconds=180)) cache.expire(task_id, timedelta(seconds=180))

View File

@@ -7,10 +7,8 @@ from hexathon import strip_0x
# local imports # local imports
from cic_ussd.metadata import blockchain_address_to_metadata_pointer from cic_ussd.metadata import blockchain_address_to_metadata_pointer
from cic_ussd.metadata.custom import CustomMetadata
from cic_ussd.metadata.person import PersonMetadata from cic_ussd.metadata.person import PersonMetadata
from cic_ussd.metadata.phone import PhonePointerMetadata from cic_ussd.metadata.phone import PhonePointerMetadata
from cic_ussd.metadata.preferences import PreferencesMetadata
from cic_ussd.tasks.base import CriticalMetadataTask from cic_ussd.tasks.base import CriticalMetadataTask
celery_app = celery.current_app celery_app = celery.current_app
@@ -46,7 +44,7 @@ def create_person_metadata(blockchain_address: str, data: dict):
@celery_app.task @celery_app.task
def edit_person_metadata(blockchain_address: str, data: dict): def edit_person_metadata(blockchain_address: str, data: bytes):
identifier = blockchain_address_to_metadata_pointer(blockchain_address=blockchain_address) identifier = blockchain_address_to_metadata_pointer(blockchain_address=blockchain_address)
person_metadata_client = PersonMetadata(identifier=identifier) person_metadata_client = PersonMetadata(identifier=identifier)
person_metadata_client.edit(data=data) person_metadata_client.edit(data=data)
@@ -58,17 +56,3 @@ def add_phone_pointer(self, blockchain_address: str, phone_number: str):
stripped_address = strip_0x(blockchain_address) stripped_address = strip_0x(blockchain_address)
phone_metadata_client = PhonePointerMetadata(identifier=identifier) phone_metadata_client = PhonePointerMetadata(identifier=identifier)
phone_metadata_client.create(data=stripped_address) phone_metadata_client.create(data=stripped_address)
@celery_app.task()
def add_custom_metadata(blockchain_address: str, data: dict):
identifier = blockchain_address_to_metadata_pointer(blockchain_address=blockchain_address)
custom_metadata_client = CustomMetadata(identifier=identifier)
custom_metadata_client.create(data=data)
@celery_app.task()
def add_preferences_metadata(blockchain_address: str, data: dict):
identifier = blockchain_address_to_metadata_pointer(blockchain_address=blockchain_address)
custom_metadata_client = PreferencesMetadata(identifier=identifier)
custom_metadata_client.create(data=data)

View File

@@ -1,4 +1,4 @@
cic_base[full_graph]~=0.1.2b21 cic_base[full_graph]~=0.1.2b15
cic-eth~=0.11.0b16 cic-eth~=0.11.0b16
cic-notify~=0.4.0a5 cic-notify~=0.4.0a5
cic-types~=0.1.0a11 cic-types~=0.1.0a10

View File

@@ -7,7 +7,6 @@
"new_pin_confirmation", "new_pin_confirmation",
"display_user_metadata", "display_user_metadata",
"name_edit_pin_authorization", "name_edit_pin_authorization",
"dob_edit_pin_authorization",
"gender_edit_pin_authorization", "gender_edit_pin_authorization",
"location_edit_pin_authorization", "location_edit_pin_authorization",
"products_edit_pin_authorization", "products_edit_pin_authorization",

View File

@@ -5,6 +5,5 @@
"enter_age", "enter_age",
"enter_location", "enter_location",
"enter_products", "enter_products",
"enter_date_of_birth",
"display_metadata_pin_authorization" "display_metadata_pin_authorization"
] ]

View File

@@ -1,39 +0,0 @@
[
{
"trigger": "scan_data",
"source": "enter_date_of_birth",
"dest": "dob_edit_pin_authorization",
"after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data",
"conditions": [
"cic_ussd.state_machine.logic.validator.has_cached_user_metadata",
"cic_ussd.state_machine.logic.validator.is_valid_date"
]
},
{
"trigger": "scan_data",
"source": "enter_date_of_birth",
"dest": "enter_gender",
"conditions": "cic_ussd.state_machine.logic.validator.is_valid_date",
"after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data",
"unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata"
},
{
"trigger": "scan_data",
"source": "enter_date_of_birth",
"dest": "exit_invalid_input",
"unless": "cic_ussd.state_machine.logic.validator.is_valid_date"
},
{
"trigger": "scan_data",
"source": "dob_edit_pin_authorization",
"dest": "exit",
"conditions": "cic_ussd.state_machine.logic.pin.is_authorized_pin",
"after": "cic_ussd.state_machine.logic.user.edit_user_metadata_attribute"
},
{
"trigger": "scan_data",
"source": "dob_edit_pin_authorization",
"dest": "exit_pin_blocked",
"conditions": "cic_ussd.state_machine.logic.pin.is_locked_account"
}
]

View File

@@ -15,7 +15,7 @@
{ {
"trigger": "scan_data", "trigger": "scan_data",
"source": "enter_family_name", "source": "enter_family_name",
"dest": "enter_date_of_birth", "dest": "enter_gender",
"after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data", "after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data",
"unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata" "unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata"
}, },

View File

@@ -14,26 +14,20 @@
{ {
"trigger": "scan_data", "trigger": "scan_data",
"source": "metadata_management", "source": "metadata_management",
"dest": "enter_date_of_birth", "dest": "enter_location",
"conditions": "cic_ussd.state_machine.logic.menu.menu_three_selected" "conditions": "cic_ussd.state_machine.logic.menu.menu_three_selected"
}, },
{ {
"trigger": "scan_data", "trigger": "scan_data",
"source": "metadata_management", "source": "metadata_management",
"dest": "enter_location", "dest": "enter_products",
"conditions": "cic_ussd.state_machine.logic.menu.menu_four_selected" "conditions": "cic_ussd.state_machine.logic.menu.menu_four_selected"
}, },
{
"trigger": "scan_data",
"source": "metadata_management",
"dest": "enter_products",
"conditions": "cic_ussd.state_machine.logic.menu.menu_five_selected"
},
{ {
"trigger": "scan_data", "trigger": "scan_data",
"source": "metadata_management", "source": "metadata_management",
"dest": "display_metadata_pin_authorization", "dest": "display_metadata_pin_authorization",
"conditions": "cic_ussd.state_machine.logic.menu.menu_six_selected" "conditions": "cic_ussd.state_machine.logic.menu.menu_five_selected"
}, },
{ {
"trigger": "scan_data", "trigger": "scan_data",

View File

@@ -17,9 +17,6 @@ en:
enter_family_name: |- enter_family_name: |-
CON Enter family name CON Enter family name
0. Back 0. Back
enter_date_of_birth: |-
CON Enter year of birth
0. Back
enter_gender: |- enter_gender: |-
CON Enter gender CON Enter gender
1. Male 1. Male
@@ -55,16 +52,14 @@ en:
CON My profile CON My profile
1. Edit name 1. Edit name
2. Edit gender 2. Edit gender
3. Edit Age 3. Edit location
4. Edit location 4. Edit products
5. Edit products 5. View my profile
6. View my profile
0. Back 0. Back
display_user_metadata: |- display_user_metadata: |-
CON Your details are: CON Your details are:
Name: %{full_name} Name: %{full_name}
Gender: %{gender} Gender: %{gender}
Age: %{age}
Location: %{location} Location: %{location}
You sell: %{products} You sell: %{products}
0. Back 0. Back
@@ -122,13 +117,6 @@ en:
retry: |- retry: |-
CON Please enter your PIN. You have %{remaining_attempts} attempts remaining CON Please enter your PIN. You have %{remaining_attempts} attempts remaining
0. Back 0. Back
dob_edit_pin_authorization:
first: |-
CON Please enter your PIN
0. Back
retry: |-
CON Please enter your PIN. You have %{remaining_attempts} attempts remaining
0. Back
gender_edit_pin_authorization: gender_edit_pin_authorization:
first: |- first: |-
CON Please enter your PIN CON Please enter your PIN

View File

@@ -17,9 +17,6 @@ sw:
enter_family_name: |- enter_family_name: |-
CON Weka jina lako la mwisho CON Weka jina lako la mwisho
0. Nyuma 0. Nyuma
enter_date_of_birth: |-
CON Weka mwaka wa kuzaliwa
0. Nyuma
enter_gender: |- enter_gender: |-
CON Weka jinsia yako CON Weka jinsia yako
1. Mwanaume 1. Mwanaume
@@ -55,16 +52,14 @@ sw:
CON Wasifu wangu CON Wasifu wangu
1. Weka jina 1. Weka jina
2. Weka jinsia 2. Weka jinsia
3 Weka umri 3. Weka eneo
4. Weka eneo 4. Weka bidhaa
5. Weka bidhaa 5. Angalia wasifu wako
6. Angalia wasifu wako
0. Nyuma 0. Nyuma
display_user_metadata: |- display_user_metadata: |-
CON Wasifu wako una maelezo yafuatayo: CON Wasifu wako una maelezo yafuatayo:
Jina: %{full_name} Jina: %{full_name}
Jinsia: %{gender} Jinsia: %{gender}
Umri: %{age}
Eneo: %{location} Eneo: %{location}
Unauza: %{products} Unauza: %{products}
0. Nyuma 0. Nyuma
@@ -122,13 +117,6 @@ sw:
retry: |- retry: |-
CON Tafadhali weka PIN yako. Una majaribio %{remaining_attempts} yaliyobaki. CON Tafadhali weka PIN yako. Una majaribio %{remaining_attempts} yaliyobaki.
0. Nyuma 0. Nyuma
dob_edit_pin_authorization:
first: |-
CON Tafadhali weka PIN yako
0. Nyuma
retry: |-
CON Tafadhali weka PIN yako. Una majaribio %{remaining_attempts} yaliyobaki.
0. Nyuma
gender_edit_pin_authorization: gender_edit_pin_authorization:
first: |- first: |-
CON Tafadhali weka PIN yako CON Tafadhali weka PIN yako

View File

@@ -136,7 +136,7 @@ First, make a note of the **block height** before running anything:
To import, run to _completion_: To import, run to _completion_:
`python eth/import_users.py -v -c config -p <eth_provider> -r <cic_registry_address> -y ../contract-migration/keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c <datadir>` `python eth/import_users.py -v -c config -p <eth_provider> -r <cic_registry_address> -y ../keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c <datadir>`
After the script completes, keystore files for all generated accouts will be found in `<datadir>/keystore`, all with `foo` as password (would set it empty, but believe it or not some interfaces out there won't work unless you have one). After the script completes, keystore files for all generated accouts will be found in `<datadir>/keystore`, all with `foo` as password (would set it empty, but believe it or not some interfaces out there won't work unless you have one).
@@ -150,7 +150,7 @@ Then run:
Run in sequence, in first terminal: Run in sequence, in first terminal:
`python cic_eth/import_balance.py -v -c config -p <eth_provider> -r <cic_registry_address> --token-symbol <token_symbol> -y ../contract-migration/keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c --head out` `python cic_eth/import_balance.py -v -c config -p <eth_provider> -r <cic_registry_address> --token-symbol <token_symbol> -y ../keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c --head out`
In another terminal: In another terminal:
@@ -226,7 +226,7 @@ The connection parameters for the `cic-ussd-server` is currently _hardcoded_ in
### Step 5 - Verify ### Step 5 - Verify
`python verify.py -v -c config -r <cic_registry_address> -p <eth_provider> --token-symbol <token_symbol> <datadir>` `python verify.py -v -c config -r <cic_registry_address> -p <eth_provider> <datadir>`
Included checks: Included checks:
* Private key is in cic-eth keystore * Private key is in cic-eth keystore
@@ -262,5 +262,3 @@ Should exit with code 0 if all input data is found in the respective services.
- MacOS BigSur issue when installing psycopg2: ld: library not found for -lssl -> https://github.com/psycopg/psycopg2/issues/1115#issuecomment-831498953 - MacOS BigSur issue when installing psycopg2: ld: library not found for -lssl -> https://github.com/psycopg/psycopg2/issues/1115#issuecomment-831498953
- `cic_ussd` imports is poorly implemented, and consumes a lot of resources. Therefore it takes a long time to complete. Reducing the amount of polls for the phone pointer would go a long way to improve it. - `cic_ussd` imports is poorly implemented, and consumes a lot of resources. Therefore it takes a long time to complete. Reducing the amount of polls for the phone pointer would go a long way to improve it.
- A strict constraint is maintained insistin the use of postgresql-12.

View File

@@ -76,7 +76,6 @@ args_override = {
'CIC_CHAIN_SPEC': getattr(args, 'i'), 'CIC_CHAIN_SPEC': getattr(args, 'i'),
'ETH_PROVIDER': getattr(args, 'p'), 'ETH_PROVIDER': getattr(args, 'p'),
'CIC_REGISTRY_ADDRESS': getattr(args, 'r'), 'CIC_REGISTRY_ADDRESS': getattr(args, 'r'),
'KEYSTORE_FILE_PATH': getattr(args, 'key-file')
} }
config.dict_override(args_override, 'cli flag') config.dict_override(args_override, 'cli flag')
config.censor('PASSWORD', 'DATABASE') config.censor('PASSWORD', 'DATABASE')

View File

@@ -194,7 +194,8 @@ if __name__ == '__main__':
f.write(json.dumps(o)) f.write(json.dumps(o))
f.close() f.close()
meta_key = generate_metadata_pointer(bytes.fromhex(new_address_clean), ':cic.person') #fi.write('{},{}\n'.format(new_address, old_address))
meta_key = generate_metadata_pointer(bytes.fromhex(new_address_clean), 'cic.person')
meta_filepath = os.path.join(meta_dir, '{}.json'.format(new_address_clean.upper())) meta_filepath = os.path.join(meta_dir, '{}.json'.format(new_address_clean.upper()))
os.symlink(os.path.realpath(filepath), meta_filepath) os.symlink(os.path.realpath(filepath), meta_filepath)
@@ -220,7 +221,7 @@ if __name__ == '__main__':
# custom data # custom data
custom_key = generate_metadata_pointer(bytes.fromhex(new_address_clean), ':cic.custom') custom_key = generate_metadata_pointer(phone.encode('utf-8'), ':cic.custom')
custom_filepath = os.path.join(custom_dir, 'meta', custom_key) custom_filepath = os.path.join(custom_dir, 'meta', custom_key)
filepath = os.path.join( filepath = os.path.join(

View File

@@ -1,133 +0,0 @@
const fs = require('fs');
const path = require('path');
const http = require('http');
const cic = require('@cicnet/cic-client-meta');
const crdt = require('@cicnet/crdt-meta');
//const conf = JSON.parse(fs.readFileSync('./cic.conf'));
const config = new crdt.Config('./config');
config.process();
console.log(config);
function sendit(uid, envelope) {
const d = envelope.toJSON();
const contentLength = (new TextEncoder().encode(d)).length;
const opts = {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Content-Length': contentLength,
'X-CIC-AUTOMERGE': 'client',
},
};
let url = config.get('META_URL');
url = url.replace(new RegExp('^(.+://[^/]+)/*$'), '$1/');
console.log('posting to url: ' + url + uid);
const req = http.request(url + uid, opts, (res) => {
res.on('data', process.stdout.write);
res.on('end', () => {
console.log('result', res.statusCode, res.headers);
});
});
if (!req.write(d)) {
console.error('foo', d);
process.exit(1);
}
req.end();
}
function doOne(keystore, filePath, identifier) {
const signer = new crdt.PGPSigner(keystore);
const o = JSON.parse(fs.readFileSync(filePath).toString());
cic.Custom.toKey(identifier).then((uid) => {
const s = new crdt.Syncable(uid, o);
s.setSigner(signer);
s.onwrap = (env) => {
sendit(identifier, env);
};
s.sign();
});
}
const privateKeyPath = path.join(config.get('PGP_EXPORTS_DIR'), config.get('PGP_PRIVATE_KEY_FILE'));
const publicKeyPath = path.join(config.get('PGP_EXPORTS_DIR'), config.get('PGP_PRIVATE_KEY_FILE'));
pk = fs.readFileSync(privateKeyPath);
pubk = fs.readFileSync(publicKeyPath);
new crdt.PGPKeyStore(
config.get('PGP_PASSPHRASE'),
pk,
pubk,
undefined,
undefined,
importMetaCustom,
);
const batchSize = 16;
const batchDelay = 1000;
const total = parseInt(process.argv[3]);
const dataDir = process.argv[2];
const workDir = path.join(dataDir, 'preferences/meta');
const userDir = path.join(dataDir, 'preferences/new');
let count = 0;
let batchCount = 0;
function importMetaCustom(keystore) {
let err;
let files;
try {
err, files = fs.readdirSync(workDir);
} catch {
console.error('source directory not yet ready', workDir);
setTimeout(importMetaCustom, batchDelay, keystore);
return;
}
let limit = batchSize;
if (files.length < limit) {
limit = files.length;
}
for (let i = 0; i < limit; i++) {
const file = files[i];
if (file.length < 3) {
console.debug('skipping file', file);
continue;
}
//const identifier = file.substr(0,file.length-5);
const identifier = file;
const filePath = path.join(workDir, file);
console.log(filePath);
//const address = fs.readFileSync(filePath).toString().substring(2).toUpperCase();
const custom = JSON.parse(fs.readFileSync(filePath).toString());
const customFilePath = path.join(
userDir,
identifier.substring(0, 2),
identifier.substring(2, 4),
identifier + '.json',
);
doOne(keystore, filePath, identifier);
fs.unlinkSync(filePath);
count++;
batchCount++;
if (batchCount == batchSize) {
console.debug('reached batch size, breathing');
batchCount=0;
setTimeout(importMetaCustom, batchDelay, keystore);
return;
}
}
if (count == total) {
return;
}
setTimeout(importMetaCustom, 100, keystore);
}

View File

@@ -70,7 +70,6 @@ args_override = {
'REDIS_DB': getattr(args, 'redis_db'), 'REDIS_DB': getattr(args, 'redis_db'),
'META_HOST': getattr(args, 'meta_host'), 'META_HOST': getattr(args, 'meta_host'),
'META_PORT': getattr(args, 'meta_port'), 'META_PORT': getattr(args, 'meta_port'),
'KEYSTORE_FILE_PATH': getattr(args, 'key-file')
} }
config.dict_override(args_override, 'cli flag') config.dict_override(args_override, 'cli flag')
config.censor('PASSWORD', 'DATABASE') config.censor('PASSWORD', 'DATABASE')
@@ -115,7 +114,7 @@ def main():
conn = EthHTTPConnection(config.get('ETH_PROVIDER')) conn = EthHTTPConnection(config.get('ETH_PROVIDER'))
ImportTask.balance_processor = BalanceProcessor(conn, chain_spec, config.get('CIC_REGISTRY_ADDRESS'), signer_address, signer) ImportTask.balance_processor = BalanceProcessor(conn, chain_spec, config.get('CIC_REGISTRY_ADDRESS'), signer_address, signer)
ImportTask.balance_processor.init(token_symbol) ImportTask.balance_processor.init()
# TODO get decimals from token # TODO get decimals from token
balances = {} balances = {}
@@ -140,7 +139,6 @@ def main():
ImportTask.balances = balances ImportTask.balances = balances
ImportTask.count = i ImportTask.count = i
ImportTask.import_dir = user_dir
s = celery.signature( s = celery.signature(
'import_task.send_txs', 'import_task.send_txs',

View File

@@ -39,7 +39,6 @@ elif args.vv:
config_dir = args.c config_dir = args.c
config = confini.Config(config_dir, os.environ.get('CONFINI_ENV_PREFIX')) config = confini.Config(config_dir, os.environ.get('CONFINI_ENV_PREFIX'))
config.process() config.process()
logg.debug('config loaded from {}:\n{}'.format(args.c, config))
celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL')) celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL'))
@@ -63,6 +62,9 @@ def main():
) )
s_import_pins.apply_async() s_import_pins.apply_async()
argv = ['worker', '-Q', 'cic-import-ussd', '--loglevel=DEBUG']
celery_app.worker_main(argv)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@@ -1,7 +1,6 @@
# standard imports # standard imports
import os import os
import logging import logging
import random
import urllib.parse import urllib.parse
import urllib.error import urllib.error
import urllib.request import urllib.request
@@ -137,42 +136,6 @@ def generate_metadata(self, address, phone):
) )
os.symlink(os.path.realpath(filepath), meta_filepath) os.symlink(os.path.realpath(filepath), meta_filepath)
# write ussd data
ussd_data = {
'phone': phone,
'is_activated': 1,
'preferred_language': random.sample(['en', 'sw'], 1)[0],
'is_disabled': False
}
ussd_data_dir = os.path.join(self.import_dir, 'ussd')
ussd_data_file_path = os.path.join(ussd_data_dir, f'{old_address}.json')
f = open(ussd_data_file_path, 'w')
f.write(json.dumps(ussd_data))
f.close()
# write preferences data
preferences_dir = os.path.join(self.import_dir, 'preferences')
preferences_data = {
'preferred_language': ussd_data['preferred_language']
}
preferences_key = generate_metadata_pointer(bytes.fromhex(new_address_clean[2:]), ':cic.preferences')
preferences_filepath = os.path.join(preferences_dir, 'meta', preferences_key)
filepath = os.path.join(
preferences_dir,
'new',
preferences_key[:2].upper(),
preferences_key[2:4].upper(),
preferences_key.upper() + '.json'
)
os.makedirs(os.path.dirname(filepath), exist_ok=True)
f = open(filepath, 'w')
f.write(json.dumps(preferences_data))
f.close()
os.symlink(os.path.realpath(filepath), preferences_filepath)
logg.debug('found metadata {} for phone {}'.format(o, phone)) logg.debug('found metadata {} for phone {}'.format(o, phone))
return address return address

View File

@@ -1,21 +1,29 @@
# standard imports # standard imports
import argparse
import json
import logging
import os import os
import sys import sys
import json
import logging
import argparse
import uuid
import datetime
import time import time
import urllib.request import urllib.request
import uuid from glob import glob
from urllib.parse import urlencode
# external imports # third-party imports
import celery
import confini
import phonenumbers
import redis import redis
from chainlib.chain import ChainSpec import confini
import celery
from hexathon import (
add_0x,
strip_0x,
)
from chainlib.eth.address import to_checksum
from cic_types.models.person import Person from cic_types.models.person import Person
from cic_eth.api.api_task import Api
from chainlib.chain import ChainSpec
from cic_types.processor import generate_metadata_pointer
import phonenumbers
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger() logg = logging.getLogger()
@@ -64,12 +72,6 @@ ps = r.pubsub()
user_new_dir = os.path.join(args.user_dir, 'new') user_new_dir = os.path.join(args.user_dir, 'new')
os.makedirs(user_new_dir) os.makedirs(user_new_dir)
ussd_data_dir = os.path.join(args.user_dir, 'ussd')
os.makedirs(ussd_data_dir)
preferences_dir = os.path.join(args.user_dir, 'preferences')
os.makedirs(os.path.join(preferences_dir, 'meta'))
meta_dir = os.path.join(args.user_dir, 'meta') meta_dir = os.path.join(args.user_dir, 'meta')
os.makedirs(meta_dir) os.makedirs(meta_dir)
@@ -85,13 +87,21 @@ chain_str = str(chain_spec)
batch_size = args.batch_size batch_size = args.batch_size
batch_delay = args.batch_delay batch_delay = args.batch_delay
db_configs = {
'database': config.get('DATABASE_NAME'),
'host': config.get('DATABASE_HOST'),
'port': config.get('DATABASE_PORT'),
'user': config.get('DATABASE_USER'),
'password': config.get('DATABASE_PASSWORD')
}
def build_ussd_request(phone, host, port, service_code, username, password, ssl=False): def build_ussd_request(phone, host, port, service_code, username, password, ssl=False):
url = 'http' url = 'http'
if ssl: if ssl:
url += 's' url += 's'
url += '://{}:{}'.format(host, port) url += '://{}:{}'.format(host, port)
url += '/?username={}&password={}'.format(username, password) url += '/?username={}&password={}'.format(username, password) #config.get('USSD_USER'), config.get('USSD_PASS'))
logg.info('ussd service url {}'.format(url)) logg.info('ussd service url {}'.format(url))
logg.info('ussd phone {}'.format(phone)) logg.info('ussd phone {}'.format(phone))
@@ -104,10 +114,9 @@ def build_ussd_request(phone, host, port, service_code, username, password, ssl=
'text': service_code, 'text': service_code,
} }
req = urllib.request.Request(url) req = urllib.request.Request(url)
req.method=('POST') data_str = json.dumps(data)
data_str = urlencode(data)
data_bytes = data_str.encode('utf-8') data_bytes = data_str.encode('utf-8')
req.add_header('Content-Type', 'application/x-www-form-urlencoded') req.add_header('Content-Type', 'application/json')
req.data = data_bytes req.data = data_bytes
return req return req
@@ -117,13 +126,7 @@ def register_ussd(i, u):
phone_object = phonenumbers.parse(u.tel) phone_object = phonenumbers.parse(u.tel)
phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164) phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164)
logg.debug('tel {} {}'.format(u.tel, phone)) logg.debug('tel {} {}'.format(u.tel, phone))
req = build_ussd_request( req = build_ussd_request(phone, 'localhost', 63315, '*483*46#', '', '')
phone,
'localhost',
config.get('CIC_USER_USSD_SVC_SERVICE_PORT'),
config.get('APP_SERVICE_CODE'),
'',
'')
response = urllib.request.urlopen(req) response = urllib.request.urlopen(req)
response_data = response.read().decode('utf-8') response_data = response.read().decode('utf-8')
state = response_data[:3] state = response_data[:3]
@@ -140,57 +143,59 @@ if __name__ == '__main__':
if y[len(y)-5:] != '.json': if y[len(y)-5:] != '.json':
continue continue
# handle json containing person object # handle json containing person object
filepath = os.path.join(x[0], y) filepath = None
f = open(filepath, 'r') if y[:15] != '_ussd_data.json':
try: filepath = os.path.join(x[0], y)
o = json.load(f) f = open(filepath, 'r')
except json.decoder.JSONDecodeError as e: try:
o = json.load(f)
except json.decoder.JSONDecodeError as e:
f.close()
logg.error('load error for {}: {}'.format(y, e))
continue
f.close() f.close()
logg.error('load error for {}: {}'.format(y, e)) u = Person.deserialize(o)
continue
f.close()
u = Person.deserialize(o)
new_address = register_ussd(i, u) new_address = register_ussd(i, u)
phone_object = phonenumbers.parse(u.tel) phone_object = phonenumbers.parse(u.tel)
phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164) phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164)
s_phone = celery.signature( s_phone = celery.signature(
'import_task.resolve_phone', 'import_task.resolve_phone',
[ [
phone, phone,
], ],
queue='cic-import-ussd', queue='cic-import-ussd',
) )
s_meta = celery.signature( s_meta = celery.signature(
'import_task.generate_metadata', 'import_task.generate_metadata',
[ [
phone, phone,
], ],
queue='cic-import-ussd', queue='cic-import-ussd',
) )
s_balance = celery.signature( s_balance = celery.signature(
'import_task.opening_balance_tx', 'import_task.opening_balance_tx',
[ [
phone, phone,
i, i,
], ],
queue='cic-import-ussd', queue='cic-import-ussd',
) )
s_meta.link(s_balance) s_meta.link(s_balance)
s_phone.link(s_meta) s_phone.link(s_meta)
# block time plus a bit of time for ussd processing # block time plus a bit of time for ussd processing
s_phone.apply_async(countdown=7) s_phone.apply_async(countdown=7)
i += 1 i += 1
sys.stdout.write('imported {} {}'.format(i, u).ljust(200) + "\r") sys.stdout.write('imported {} {}'.format(i, u).ljust(200) + "\r")
j += 1 j += 1
if j == batch_size: if j == batch_size:
time.sleep(batch_delay) time.sleep(batch_delay)
j = 0 j = 0

View File

@@ -31,9 +31,9 @@ elif args.vv:
config_dir = args.c config_dir = args.c
config = Config(config_dir, os.environ.get('CONFINI_ENV_PREFIX')) config = Config(config_dir, os.environ.get('CONFINI_ENV_PREFIX'))
config.process() config.process()
logg.debug('config loaded from {}:\n{}'.format(args.c, config))
ussd_data_dir = os.path.join(args.user_dir, 'ussd') user_old_dir = os.path.join(args.user_dir, 'old')
os.stat(user_old_dir)
db_configs = { db_configs = {
'database': config.get('DATABASE_NAME'), 'database': config.get('DATABASE_NAME'),
@@ -45,15 +45,18 @@ db_configs = {
celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL')) celery_app = celery.Celery(broker=config.get('CELERY_BROKER_URL'), backend=config.get('CELERY_RESULT_URL'))
if __name__ == '__main__': if __name__ == '__main__':
for x in os.walk(ussd_data_dir): for x in os.walk(user_old_dir):
for y in x[2]: for y in x[2]:
if y[len(y) - 5:] == '.json': if y[len(y) - 5:] != '.json':
continue
# handle ussd_data json object
if y[:15] == '_ussd_data.json':
filepath = os.path.join(x[0], y) filepath = os.path.join(x[0], y)
f = open(filepath, 'r') f = open(filepath, 'r')
try: try:
ussd_data = json.load(f) ussd_data = json.load(f)
logg.debug(f'LOADING USSD DATA: {ussd_data}')
except json.decoder.JSONDecodeError as e: except json.decoder.JSONDecodeError as e:
f.close() f.close()
logg.error('load error for {}: {}'.format(y, e)) logg.error('load error for {}: {}'.format(y, e))

View File

@@ -6,7 +6,7 @@ from eth_contract_registry import Registry
from eth_token_index import TokenUniqueSymbolIndex from eth_token_index import TokenUniqueSymbolIndex
from chainlib.eth.gas import OverrideGasOracle from chainlib.eth.gas import OverrideGasOracle
from chainlib.eth.nonce import OverrideNonceOracle from chainlib.eth.nonce import OverrideNonceOracle
from eth_erc20 import ERC20 from chainlib.eth.erc20 import ERC20
from chainlib.eth.tx import ( from chainlib.eth.tx import (
count, count,
TxFormat, TxFormat,
@@ -37,7 +37,7 @@ class BalanceProcessor:
self.value_multiplier = 1 self.value_multiplier = 1
def init(self, token_symbol): def init(self):
# Get Token registry address # Get Token registry address
registry = Registry(self.chain_spec) registry = Registry(self.chain_spec)
o = registry.address_of(self.registry_address, 'TokenRegistry') o = registry.address_of(self.registry_address, 'TokenRegistry')
@@ -46,10 +46,10 @@ class BalanceProcessor:
logg.info('found token index address {}'.format(self.token_index_address)) logg.info('found token index address {}'.format(self.token_index_address))
token_registry = TokenUniqueSymbolIndex(self.chain_spec) token_registry = TokenUniqueSymbolIndex(self.chain_spec)
o = token_registry.address_of(self.token_index_address, token_symbol) o = token_registry.address_of(self.token_index_address, 'SRF')
r = self.conn.do(o) r = self.conn.do(o)
self.token_address = token_registry.parse_address_of(r) self.token_address = token_registry.parse_address_of(r)
logg.info('found {} token address {}'.format(token_symbol, self.token_address)) logg.info('found SRF token address {}'.format(self.token_address))
tx_factory = ERC20(self.chain_spec) tx_factory = ERC20(self.chain_spec)
o = tx_factory.decimals(self.token_address) o = tx_factory.decimals(self.token_address)

View File

@@ -22,6 +22,3 @@ TRANSITIONS=/usr/src/cic-ussd/transitions/
host = host =
port = port =
ssl = ssl =
[keystore]
file_path = keystore/UTC--2021-01-08T17-18-44.521011372Z--eb3907ecad74a0013c259d5874ae7f22dcbcc95c

View File

@@ -7,4 +7,3 @@ approval_escrow_address =
chain_spec = evm:bloxberg:8996 chain_spec = evm:bloxberg:8996
tx_retry_delay = tx_retry_delay =
trust_address = 0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C trust_address = 0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C
user_ussd_svc_service_port=

View File

@@ -1,10 +1,5 @@
[database] [database]
NAME=sempo name = sempo
USER=postgres host = localhost
PASSWORD= port = 5432
HOST=localhost user = postgres
PORT=5432
ENGINE=postgresql
DRIVER=psycopg2
DEBUG=0
POOL_SIZE=1

View File

@@ -3,7 +3,6 @@ import argparse
import json import json
import logging import logging
import os import os
import uuid
# third-party imports # third-party imports
import bcrypt import bcrypt
@@ -84,7 +83,7 @@ if __name__ == '__main__':
phone_object = phonenumbers.parse(u.tel) phone_object = phonenumbers.parse(u.tel)
phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164) phone = phonenumbers.format_number(phone_object, phonenumbers.PhoneNumberFormat.E164)
password_hash = uuid.uuid4().hex password_hash = generate_password_hash()
pins_file.write(f'{phone},{password_hash}\n') pins_file.write(f'{phone},{password_hash}\n')
logg.info(f'Writing phone: {phone}, password_hash: {password_hash}') logg.info(f'Writing phone: {phone}, password_hash: {password_hash}')

View File

@@ -228,6 +228,7 @@ def prepareLocalFilePath(datadir, address):
if __name__ == '__main__': if __name__ == '__main__':
base_dir = os.path.join(user_dir, 'old') base_dir = os.path.join(user_dir, 'old')
ussd_dir = os.path.join(user_dir, 'ussd')
os.makedirs(base_dir, exist_ok=True) os.makedirs(base_dir, exist_ok=True)
fa = open(os.path.join(user_dir, 'balances.csv'), 'w') fa = open(os.path.join(user_dir, 'balances.csv'), 'w')
@@ -247,11 +248,23 @@ if __name__ == '__main__':
print(o) print(o)
ussd_data = {
'phone': phone,
'is_activated': 1,
'preferred_language': random.sample(['en', 'sw'], 1)[0],
'is_disabled': False
}
d = prepareLocalFilePath(base_dir, uid) d = prepareLocalFilePath(base_dir, uid)
f = open('{}/{}'.format(d, uid + '.json'), 'w') f = open('{}/{}'.format(d, uid + '.json'), 'w')
json.dump(o.serialize(), f) json.dump(o.serialize(), f)
f.close() f.close()
d = prepareLocalFilePath(ussd_dir, uid)
x = open('{}/{}'.format(d, uid + '_ussd_data.json'), 'w')
json.dump(ussd_data, x)
x.close()
pidx = genPhoneIndex(phone) pidx = genPhoneIndex(phone)
d = prepareLocalFilePath(os.path.join(user_dir, 'phone'), pidx) d = prepareLocalFilePath(os.path.join(user_dir, 'phone'), pidx)
f = open('{}/{}'.format(d, pidx), 'w') f = open('{}/{}'.format(d, pidx), 'w')

View File

@@ -1,19 +1,43 @@
# syntax = docker/dockerfile:1.2 # syntax = docker/dockerfile:1.2
FROM python:3.8.6-slim-buster as compile-image FROM python:3.8.6-slim-buster as compile-image
WORKDIR /root
RUN apt-get update RUN apt-get update
RUN apt-get install -y --no-install-recommends git gcc g++ libpq-dev gawk jq telnet wget openssl iputils-ping gnupg socat bash procps make python2 cargo RUN apt-get install -y --no-install-recommends git gcc g++ libpq-dev gawk jq telnet wget openssl iputils-ping gnupg socat bash procps make python2 cargo
WORKDIR /root
RUN mkdir -vp /usr/local/etc/cic RUN mkdir -vp /usr/local/etc/cic
COPY data-seeding/requirements.txt . COPY data-seeding/requirements.txt .
COPY data-seeding/ .
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433" ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
RUN pip install --extra-index-url $EXTRA_INDEX_URL -r requirements.txt RUN pip install --extra-index-url $EXTRA_INDEX_URL -r requirements.txt
# -------------- begin runtime container ----------------
FROM python:3.8.6-slim-buster as runtime-image
RUN apt-get update
RUN apt-get install -y --no-install-recommends gnupg libpq-dev
RUN apt-get install -y jq bash iputils-ping socat telnet dnsutils
COPY --from=compile-image /usr/local/bin/ /usr/local/bin/
COPY --from=compile-image /usr/local/etc/cic/ /usr/local/etc/cic/
COPY --from=compile-image /usr/local/lib/python3.8/site-packages/ \
/usr/local/lib/python3.8/site-packages/
WORKDIR root/
ENV EXTRA_INDEX_URL https://pip.grassrootseconomics.net:8433
# RUN useradd -u 1001 --create-home grassroots
# RUN adduser grassroots sudo && \
# echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
# WORKDIR /home/grassroots
COPY data-seeding/ .
# we copied these from the root build container.
# this is dumb though...I guess the compile image should have the same user
# RUN chown grassroots:grassroots -R /usr/local/lib/python3.8/site-packages/
# USER grassroots
ENTRYPOINT [ ] ENTRYPOINT [ ]

View File

@@ -75,7 +75,6 @@ args_override = {
'CIC_CHAIN_SPEC': getattr(args, 'i'), 'CIC_CHAIN_SPEC': getattr(args, 'i'),
'ETH_PROVIDER': getattr(args, 'p'), 'ETH_PROVIDER': getattr(args, 'p'),
'CIC_REGISTRY_ADDRESS': getattr(args, 'r'), 'CIC_REGISTRY_ADDRESS': getattr(args, 'r'),
'KEYSTORE_FILE_PATH': getattr(args, 'key-file')
} }
config.dict_override(args_override, 'cli flag') config.dict_override(args_override, 'cli flag')
config.censor('PASSWORD', 'DATABASE') config.censor('PASSWORD', 'DATABASE')

View File

@@ -59,7 +59,6 @@ config.process()
args_override = { args_override = {
'CIC_REGISTRY_ADDRESS': getattr(args, 'r'), 'CIC_REGISTRY_ADDRESS': getattr(args, 'r'),
'CIC_CHAIN_SPEC': getattr(args, 'i'), 'CIC_CHAIN_SPEC': getattr(args, 'i'),
'KEYSTORE_FILE_PATH': getattr(args, 'key-file')
} }
config.dict_override(args_override, 'cli') config.dict_override(args_override, 'cli')
config.add(args.user_dir, '_USERDIR', True) config.add(args.user_dir, '_USERDIR', True)

View File

@@ -1 +0,0 @@
{"address":"eb3907ecad74a0013c259d5874ae7f22dcbcc95c","crypto":{"cipher":"aes-128-ctr","ciphertext":"b0f70a8af4071faff2267374e2423cbc7a71012096fd2215866d8de7445cc215","cipherparams":{"iv":"9ac89383a7793226446dcb7e1b45cdf3"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"299f7b5df1d08a0a7b7f9c9eb44fe4798683b78da3513fcf9603fd913ab3336f"},"mac":"6f4ed36c11345a9a48353cd2f93f1f92958c96df15f3112a192bc994250e8d03"},"id":"61a9dd88-24a9-495c-9a51-152bd1bfaa5b","version":3}

View File

@@ -1,5 +1,5 @@
{ {
"name": "data-seeding", "name": "scripts",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
@@ -49,20 +49,20 @@
} }
}, },
"node_modules/@ethereumjs/common": { "node_modules/@ethereumjs/common": {
"version": "2.3.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.3.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.2.0.tgz",
"integrity": "sha512-Fmi15MdVptsC85n6NcUXIFiiXCXWEfZNgPWP+OGAQOC6ZtdzoNawtxH/cYpIgEgSuIzfOeX3VKQP/qVI1wISHg==", "integrity": "sha512-PyQiTG00MJtBRkJmv46ChZL8u2XWxNBeAthznAUIUiefxPAXjbkuiCZOuncgJS34/XkMbNc9zMt/PlgKRBElig==",
"dependencies": { "dependencies": {
"crc-32": "^1.2.0", "crc-32": "^1.2.0",
"ethereumjs-util": "^7.0.10" "ethereumjs-util": "^7.0.9"
} }
}, },
"node_modules/@ethereumjs/tx": { "node_modules/@ethereumjs/tx": {
"version": "3.2.0", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.2.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.1.3.tgz",
"integrity": "sha512-D3X/XtZ3ldUg34hr99Jvj7NxW3NxVKdUKrwQnEWlAp4CmCQpvYoyn7NF4lk34rHEt7ScS+Agu01pcDHoOcd19A==", "integrity": "sha512-DJBu6cbwYtiPTFeCUR8DF5p+PF0jxs+0rALJZiEcTz2tiRPIEkM72GEbrkGuqzENLCzBrJHT43O0DxSYTqeo+g==",
"dependencies": { "dependencies": {
"@ethereumjs/common": "^2.3.0", "@ethereumjs/common": "^2.2.0",
"ethereumjs-util": "^7.0.10" "ethereumjs-util": "^7.0.10"
} }
}, },
@@ -75,9 +75,9 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "15.12.0", "version": "14.14.41",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.41.tgz",
"integrity": "sha512-+aHJvoCsVhO2ZCuT4o5JtcPrCPyDE3+1nvbDprYes+pPkEsbjH7AGUCNtjMOXS0fqH14t+B7yLzaqSz92FPWyw==" "integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g=="
}, },
"node_modules/@types/pbkdf2": { "node_modules/@types/pbkdf2": {
"version": "3.1.0", "version": "3.1.0",
@@ -115,10 +115,6 @@
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1", "json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2" "uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
} }
}, },
"node_modules/ansi-regex": { "node_modules/ansi-regex": {
@@ -138,9 +134,6 @@
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/aproba": { "node_modules/aproba": {
@@ -810,9 +803,9 @@
} }
}, },
"node_modules/glob": { "node_modules/glob": {
"version": "7.1.7", "version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dependencies": { "dependencies": {
"fs.realpath": "^1.0.0", "fs.realpath": "^1.0.0",
"inflight": "^1.0.4", "inflight": "^1.0.4",
@@ -823,9 +816,6 @@
}, },
"engines": { "engines": {
"node": "*" "node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
@@ -846,7 +836,6 @@
"version": "5.1.5", "version": "5.1.5",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"deprecated": "this library is no longer supported",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"ajv": "^6.12.3", "ajv": "^6.12.3",
@@ -920,9 +909,9 @@
} }
}, },
"node_modules/ignore-walk": { "node_modules/ignore-walk": {
"version": "3.0.4", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
"integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
"dependencies": { "dependencies": {
"minimatch": "^3.0.4" "minimatch": "^3.0.4"
} }
@@ -1048,7 +1037,6 @@
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz",
"integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==",
"hasInstallScript": true,
"dependencies": { "dependencies": {
"node-addon-api": "^2.0.0", "node-addon-api": "^2.0.0",
"node-gyp-build": "^4.2.0" "node-gyp-build": "^4.2.0"
@@ -1068,21 +1056,21 @@
} }
}, },
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.48.0", "version": "1.47.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz",
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==",
"optional": true, "optional": true,
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/mime-types": { "node_modules/mime-types": {
"version": "2.1.31", "version": "2.1.30",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz",
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"mime-db": "1.48.0" "mime-db": "1.47.0"
}, },
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -1227,7 +1215,6 @@
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz",
"integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==",
"deprecated": "Please upgrade to @mapbox/node-pre-gyp: the non-scoped node-pre-gyp package is deprecated and only the @mapbox scoped package will recieve updates in the future",
"dependencies": { "dependencies": {
"detect-libc": "^1.0.2", "detect-libc": "^1.0.2",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
@@ -1286,9 +1273,9 @@
} }
}, },
"node_modules/npm-bundled": { "node_modules/npm-bundled": {
"version": "1.1.2", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
"integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
"dependencies": { "dependencies": {
"npm-normalize-package-bin": "^1.0.1" "npm-normalize-package-bin": "^1.0.1"
} }
@@ -1439,14 +1426,6 @@
}, },
"engines": { "engines": {
"node": ">= 8.0.0" "node": ">= 8.0.0"
},
"peerDependencies": {
"pg-native": ">=2.0.0"
},
"peerDependenciesMeta": {
"pg-native": {
"optional": true
}
} }
}, },
"node_modules/pg-connection-string": { "node_modules/pg-connection-string": {
@@ -1465,10 +1444,7 @@
"node_modules/pg-pool": { "node_modules/pg-pool": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.3.0.tgz", "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.3.0.tgz",
"integrity": "sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg==", "integrity": "sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg=="
"peerDependencies": {
"pg": ">=8.0"
}
}, },
"node_modules/pg-protocol": { "node_modules/pg-protocol": {
"version": "1.5.0", "version": "1.5.0",
@@ -1620,7 +1596,6 @@
"version": "2.88.2", "version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"aws-sign2": "~0.7.0", "aws-sign2": "~0.7.0",
@@ -1695,21 +1670,7 @@
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
}, },
"node_modules/safer-buffer": { "node_modules/safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@@ -1730,7 +1691,6 @@
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz",
"integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==",
"hasInstallScript": true,
"dependencies": { "dependencies": {
"elliptic": "^6.5.2", "elliptic": "^6.5.2",
"node-addon-api": "^2.0.0", "node-addon-api": "^2.0.0",
@@ -1795,27 +1755,18 @@
"version": "5.0.2", "version": "5.0.2",
"resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.2.tgz", "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.2.tgz",
"integrity": "sha512-1SdTNo+BVU211Xj1csWa8lV6KM0CtucDwRyA0VHl91wEH1Mgh7RxUpI4rVvG7OhHrzCSGaVyW5g8vKvlrk9DJA==", "integrity": "sha512-1SdTNo+BVU211Xj1csWa8lV6KM0CtucDwRyA0VHl91wEH1Mgh7RxUpI4rVvG7OhHrzCSGaVyW5g8vKvlrk9DJA==",
"hasInstallScript": true,
"dependencies": { "dependencies": {
"node-addon-api": "^3.0.0", "node-addon-api": "^3.0.0",
"node-pre-gyp": "^0.11.0" "node-pre-gyp": "^0.11.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"node-gyp": "3.x" "node-gyp": "3.x"
},
"peerDependencies": {
"node-gyp": "3.x"
},
"peerDependenciesMeta": {
"node-gyp": {
"optional": true
}
} }
}, },
"node_modules/sqlite3/node_modules/node-addon-api": { "node_modules/sqlite3/node_modules/node-addon-api": {
"version": "3.2.1", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz",
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw=="
}, },
"node_modules/sshpk": { "node_modules/sshpk": {
"version": "1.16.1", "version": "1.16.1",
@@ -1833,6 +1784,11 @@
"safer-buffer": "^2.0.2", "safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.0" "tweetnacl": "~0.14.0"
}, },
"bin": {
"sshpk-conv": "bin/sshpk-conv",
"sshpk-sign": "bin/sshpk-sign",
"sshpk-verify": "bin/sshpk-verify"
},
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -1916,16 +1872,12 @@
"node_modules/transit-immutable-js": { "node_modules/transit-immutable-js": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/transit-immutable-js/-/transit-immutable-js-0.7.0.tgz", "resolved": "https://registry.npmjs.org/transit-immutable-js/-/transit-immutable-js-0.7.0.tgz",
"integrity": "sha1-mT4lCJtjEf9AIUD1VidtbSUwBdk=", "integrity": "sha1-mT4lCJtjEf9AIUD1VidtbSUwBdk="
"peerDependencies": {
"immutable": ">= 3",
"transit-js": ">= 0.8"
}
}, },
"node_modules/transit-js": { "node_modules/transit-js": {
"version": "0.8.874", "version": "0.8.867",
"resolved": "https://registry.npmjs.org/transit-js/-/transit-js-0.8.874.tgz", "resolved": "https://registry.npmjs.org/transit-js/-/transit-js-0.8.867.tgz",
"integrity": "sha512-IDJJGKRzUbJHmN0P15HBBa05nbKor3r2MmG6aSt0UxXIlJZZKcddTk67/U7WyAeW9Hv/VYI02IqLzolsC4sbPA==", "integrity": "sha512-rOwB4K0z/WZ+E2bV42iN9UV3mvGzmwSv/IpMOKdnFpawPAZT0d1L7f91Y+tZQF7lXSDGk+oln4XyIQXo+pyTGA==",
"engines": { "engines": {
"node": ">= 0.10.0" "node": ">= 0.10.0"
} }
@@ -1971,7 +1923,6 @@
"version": "3.4.0", "version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": { "bin": {
"uuid": "bin/uuid" "uuid": "bin/uuid"
} }
@@ -2026,9 +1977,6 @@
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
} }
}, },
"node_modules/wrap-ansi/node_modules/ansi-regex": { "node_modules/wrap-ansi/node_modules/ansi-regex": {
@@ -2203,20 +2151,20 @@
} }
}, },
"@ethereumjs/common": { "@ethereumjs/common": {
"version": "2.3.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.3.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.2.0.tgz",
"integrity": "sha512-Fmi15MdVptsC85n6NcUXIFiiXCXWEfZNgPWP+OGAQOC6ZtdzoNawtxH/cYpIgEgSuIzfOeX3VKQP/qVI1wISHg==", "integrity": "sha512-PyQiTG00MJtBRkJmv46ChZL8u2XWxNBeAthznAUIUiefxPAXjbkuiCZOuncgJS34/XkMbNc9zMt/PlgKRBElig==",
"requires": { "requires": {
"crc-32": "^1.2.0", "crc-32": "^1.2.0",
"ethereumjs-util": "^7.0.10" "ethereumjs-util": "^7.0.9"
} }
}, },
"@ethereumjs/tx": { "@ethereumjs/tx": {
"version": "3.2.0", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.2.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.1.3.tgz",
"integrity": "sha512-D3X/XtZ3ldUg34hr99Jvj7NxW3NxVKdUKrwQnEWlAp4CmCQpvYoyn7NF4lk34rHEt7ScS+Agu01pcDHoOcd19A==", "integrity": "sha512-DJBu6cbwYtiPTFeCUR8DF5p+PF0jxs+0rALJZiEcTz2tiRPIEkM72GEbrkGuqzENLCzBrJHT43O0DxSYTqeo+g==",
"requires": { "requires": {
"@ethereumjs/common": "^2.3.0", "@ethereumjs/common": "^2.2.0",
"ethereumjs-util": "^7.0.10" "ethereumjs-util": "^7.0.10"
} }
}, },
@@ -2229,9 +2177,9 @@
} }
}, },
"@types/node": { "@types/node": {
"version": "15.12.0", "version": "14.14.41",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.41.tgz",
"integrity": "sha512-+aHJvoCsVhO2ZCuT4o5JtcPrCPyDE3+1nvbDprYes+pPkEsbjH7AGUCNtjMOXS0fqH14t+B7yLzaqSz92FPWyw==" "integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g=="
}, },
"@types/pbkdf2": { "@types/pbkdf2": {
"version": "3.1.0", "version": "3.1.0",
@@ -2874,9 +2822,9 @@
} }
}, },
"glob": { "glob": {
"version": "7.1.7", "version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"requires": { "requires": {
"fs.realpath": "^1.0.0", "fs.realpath": "^1.0.0",
"inflight": "^1.0.4", "inflight": "^1.0.4",
@@ -2961,9 +2909,9 @@
} }
}, },
"ignore-walk": { "ignore-walk": {
"version": "3.0.4", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
"integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
"requires": { "requires": {
"minimatch": "^3.0.4" "minimatch": "^3.0.4"
} }
@@ -3089,18 +3037,18 @@
} }
}, },
"mime-db": { "mime-db": {
"version": "1.48.0", "version": "1.47.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz",
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==",
"optional": true "optional": true
}, },
"mime-types": { "mime-types": {
"version": "2.1.31", "version": "2.1.30",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz",
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==",
"optional": true, "optional": true,
"requires": { "requires": {
"mime-db": "1.48.0" "mime-db": "1.47.0"
} }
}, },
"minimalistic-assert": { "minimalistic-assert": {
@@ -3261,9 +3209,9 @@
} }
}, },
"npm-bundled": { "npm-bundled": {
"version": "1.1.2", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
"integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
"requires": { "requires": {
"npm-normalize-package-bin": "^1.0.1" "npm-normalize-package-bin": "^1.0.1"
} }
@@ -3402,8 +3350,7 @@
"pg-pool": { "pg-pool": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.3.0.tgz", "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.3.0.tgz",
"integrity": "sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg==", "integrity": "sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg=="
"requires": {}
}, },
"pg-protocol": { "pg-protocol": {
"version": "1.5.0", "version": "1.5.0",
@@ -3663,9 +3610,9 @@
}, },
"dependencies": { "dependencies": {
"node-addon-api": { "node-addon-api": {
"version": "3.2.1", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz",
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw=="
} }
} }
}, },
@@ -3749,13 +3696,12 @@
"transit-immutable-js": { "transit-immutable-js": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/transit-immutable-js/-/transit-immutable-js-0.7.0.tgz", "resolved": "https://registry.npmjs.org/transit-immutable-js/-/transit-immutable-js-0.7.0.tgz",
"integrity": "sha1-mT4lCJtjEf9AIUD1VidtbSUwBdk=", "integrity": "sha1-mT4lCJtjEf9AIUD1VidtbSUwBdk="
"requires": {}
}, },
"transit-js": { "transit-js": {
"version": "0.8.874", "version": "0.8.867",
"resolved": "https://registry.npmjs.org/transit-js/-/transit-js-0.8.874.tgz", "resolved": "https://registry.npmjs.org/transit-js/-/transit-js-0.8.867.tgz",
"integrity": "sha512-IDJJGKRzUbJHmN0P15HBBa05nbKor3r2MmG6aSt0UxXIlJZZKcddTk67/U7WyAeW9Hv/VYI02IqLzolsC4sbPA==" "integrity": "sha512-rOwB4K0z/WZ+E2bV42iN9UV3mvGzmwSv/IpMOKdnFpawPAZT0d1L7f91Y+tZQF7lXSDGk+oln4XyIQXo+pyTGA=="
}, },
"tunnel-agent": { "tunnel-agent": {
"version": "0.6.0", "version": "0.6.0",

View File

@@ -9,7 +9,6 @@ import sys
import urllib import urllib
import urllib.request import urllib.request
import uuid import uuid
import urllib.parse
# external imports # external imports
import celery import celery
@@ -73,7 +72,7 @@ argparser.add_argument('--ussd-provider', type=str, dest='ussd_provider', defaul
argparser.add_argument('--skip-custodial', dest='skip_custodial', action='store_true', help='skip all custodial verifications') argparser.add_argument('--skip-custodial', dest='skip_custodial', action='store_true', help='skip all custodial verifications')
argparser.add_argument('--exclude', action='append', type=str, default=[], help='skip specified verification') argparser.add_argument('--exclude', action='append', type=str, default=[], help='skip specified verification')
argparser.add_argument('--include', action='append', type=str, help='include specified verification') argparser.add_argument('--include', action='append', type=str, help='include specified verification')
argparser.add_argument('--token-symbol', default='GFT', type=str, dest='token_symbol', help='Token symbol to use for trnsactions') argparser.add_argument('--token-symbol', default='SRF', type=str, dest='token_symbol', help='Token symbol to use for trnsactions')
argparser.add_argument('-r', '--registry-address', type=str, dest='r', help='CIC Registry address') argparser.add_argument('-r', '--registry-address', type=str, dest='r', help='CIC Registry address')
argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration') argparser.add_argument('--env-prefix', default=os.environ.get('CONFINI_ENV_PREFIX'), dest='env_prefix', type=str, help='environment prefix for variables to overwrite configuration')
argparser.add_argument('-x', '--exit-on-error', dest='x', action='store_true', help='Halt exection on error') argparser.add_argument('-x', '--exit-on-error', dest='x', action='store_true', help='Halt exection on error')
@@ -186,9 +185,9 @@ def send_ussd_request(address, data_dir):
} }
req = urllib.request.Request(config.get('_USSD_PROVIDER')) req = urllib.request.Request(config.get('_USSD_PROVIDER'))
urlencoded_data = urllib.parse.urlencode(data) data_str = json.dumps(data)
data_bytes = urlencoded_data.encode('utf-8') data_bytes = data_str.encode('utf-8')
req.add_header('Content-Type', 'application/x-www-form-urlencoded') req.add_header('Content-Type', 'application/json')
req.data = data_bytes req.data = data_bytes
response = urllib.request.urlopen(req) response = urllib.request.urlopen(req)
return response.read().decode('utf-8') return response.read().decode('utf-8')
@@ -389,9 +388,10 @@ class Verifier:
def verify_ussd_pins(self, address, balance): def verify_ussd_pins(self, address, balance):
response_data = send_ussd_request(address, self.data_dir) response_data = send_ussd_request(address, self.data_dir)
if response_data[:11] != 'CON Balance' and response_data[:9] != 'CON Salio': if response_data[:11] != 'CON Balance':
raise VerifierError(response_data, 'pins') raise VerifierError(response_data, 'pins')
def verify(self, address, balance, debug_stem=None): def verify(self, address, balance, debug_stem=None):
for k in active_tests: for k in active_tests:

View File

@@ -484,7 +484,7 @@ services:
restart_policy: restart_policy:
condition: on-failure condition: on-failure
volumes: volumes:
- ./apps/contract-migration/testdata/pgp/:/tmp/cic/pgp - ${LOCAL_VOLUME_DIR:-/tmp/cic}/pgp:/tmp/cic/pgp
# command: "/root/start_server.sh -vv" # command: "/root/start_server.sh -vv"
cic-user-ussd-server: cic-user-ussd-server: