diff --git a/.gitignore b/.gitignore index 850117a..4891d0b 100644 --- a/.gitignore +++ b/.gitignore @@ -47,7 +47,8 @@ volumes/postgres volumes/servers.json volumes/pgadmin -services/backend_api/tini-amd64 +# install compatible version (tini-amd64/tini-arm64/..) +services/backend_api/tini !services/tx_root_publisher/src/app/lib !services/pg_tx_fetcher/src/app/lib diff --git a/README.md b/README.md index 5b5bafc..b5197bc 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,31 @@ _example output:_ } ``` +### read approved interactions +`GET http://localhost:5000/api/v1/interaction/approve -H "X-Token: "` +_example output:_ +```json +{ + "data": [ + [ + 1, + "0x3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", + "0xA024A8ec4D9F2F26Add18E999E79648DcCd805CF", + "0x7b22696e746572616374696f6e5f6964223a22307833613938356461373466653232356232303435633137326436626433393062643835356630383665336539643532356234366266653234353131343331353332222c227369676e6572223a22307841303234413865633444394632463236416464313845393939453739363438446343643830354346227d", + "0xe9ba02d1c8397078cbe858e292814211376526cb5ee55634c349511d05f2eb40631eb2501aa8b588cbaf57aa0e0867ec46e374bac0a0529667664b907db5924b1b" + ], + [ + 2, + "0x3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", + "0x7f322968701F6e2388A3deBF8E2547104bc5105C", + "0x7b22696e746572616374696f6e5f6964223a22307833613938356461373466653232356232303435633137326436626433393062643835356630383665336539643532356234366266653234353131343331353332222c227369676e6572223a22307837663332323936383730314636653233383841336465424638453235343731303462633531303543227d", + "0x117a7635c6e4afc40f2f192fa46c104f7a17b5cd59ca3560848d1fafe515b0a019766663931c7cb211f2f10eea0ab81c472831dbca630fdd1af0d01753d0da511b" + ] + ], + "success": true +} +``` + ## cheatsheet gen private key diff --git a/docker-compose.yml b/docker-compose.yml index ec83970..94500a9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,16 +14,16 @@ services: - ./docker/backend_api/dev.env - ./docker/postgres/dev.env ports: - - "5000:5000" + - "5050:5050" command: ["python", "-m", "app"] networks: - backend - tx_root_publisher: - build: - context: services/tx_root_publisher - dockerfile: ./../../docker/tx_root_publisher/Dockerfile - env_file: - - ./docker/postgres/dev.env - - ./docker/pg_root_publiser - networks: - - backend + # tx_root_publisher: + # build: + # context: services/tx_root_publisher + # dockerfile: ./../../docker/tx_root_publisher/Dockerfile + # env_file: + # - ./docker/postgres/dev.env + # - ./docker/pg_root_publiser + # networks: + # - backend diff --git a/docker/backend_api/Dockerfile b/docker/backend_api/Dockerfile index 0461036..547cc97 100644 --- a/docker/backend_api/Dockerfile +++ b/docker/backend_api/Dockerfile @@ -5,8 +5,10 @@ WORKDIR /usr/src/ RUN useradd -m -r user && chown user . RUN export readonly TINI_VERSION="v0.19.0" +# --> https://github.com/krallin/tini/releases/tag/v0.19.0 + ARG TINI_VERSION="$(echo \$TINI_VERSION)" -COPY ./tini-amd64 ./tini +COPY ./tini ./tini RUN chmod +x ./tini RUN apt-get update && \ @@ -21,7 +23,7 @@ RUN pip install -U \ RUN pip install --disable-pip-version-check -r requirements.txt -COPY source/app /usr/src/app +COPY src/app /usr/src/app ENV PYTHONPATH "${PYTHONPATH}:/usr/src/app:/usr/src" diff --git a/docker/postgres/initdb.sql b/docker/postgres/initdb.sql index b259fb5..3321c0b 100644 --- a/docker/postgres/initdb.sql +++ b/docker/postgres/initdb.sql @@ -66,3 +66,13 @@ create index interaction_tx_block_id on public.interaction_tx using btree (block_id) ; + +-- ** test data ** + +insert into public.interaction (interaction_hash, chain_id, selector, tx_to) + values ( + '0x3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532', + 12345, + 'abcdef', + '0x447E286EEdfeAA6DD043Afe0B9274A1F9223669A' + ); diff --git a/services/backend_api/.dockerignore b/services/backend_api/.dockerignore new file mode 100644 index 0000000..2bfa6a4 --- /dev/null +++ b/services/backend_api/.dockerignore @@ -0,0 +1 @@ +tests/ diff --git a/services/backend_api/src/app/__init__.py b/services/backend_api/src/app/__init__.py index 2cfdd3a..a6d3f63 100644 --- a/services/backend_api/src/app/__init__.py +++ b/services/backend_api/src/app/__init__.py @@ -1,6 +1,7 @@ from flask import Flask -from app.config import PgConfig +from app.config import PostgresClientConfig + def create_app(): app = Flask(__name__) @@ -8,15 +9,19 @@ def create_app(): from app.routes import bp as blueprint app.register_blueprint(blueprint) - from app.config import Config + from app.config import BackendApiConfig app.config.from_mapping({ - "SECRET_KEY": Config.SECRET_KEY, - "AUTH_TOKEN_DURATION": Config.AUTH_TOKEN_DURATION, - "AUTH_BEGIN_TIMESTAMP": Config.AUTH_BEGIN_TIMESTAMP + "SECRET_KEY": BackendApiConfig.SECRET_KEY, + "AUTH_TOKEN_DURATION": BackendApiConfig.AUTH_TOKEN_DURATION, + "AUTH_BEGIN_TIMESTAMP": BackendApiConfig.AUTH_BEGIN_TIMESTAMP }) - app.config.from_object(PgConfig()) + app.config.from_object(PostgresClientConfig()) return app + app = create_app() + + +__all__ = app, diff --git a/services/backend_api/src/app/__main__.py b/services/backend_api/src/app/__main__.py index 3cc7a0a..6ac4b55 100644 --- a/services/backend_api/src/app/__main__.py +++ b/services/backend_api/src/app/__main__.py @@ -1,4 +1,5 @@ from . import app + if __name__ == '__main__': - app.run(host='0.0.0.0', port=5000) + app.run(host='0.0.0.0', port=5050) diff --git a/services/backend_api/src/app/config.py b/services/backend_api/src/app/config.py index 0d376f3..b6ebc6b 100644 --- a/services/backend_api/src/app/config.py +++ b/services/backend_api/src/app/config.py @@ -7,9 +7,11 @@ class BackendApiConfig: AUTH_BEGIN_TIMESTAMP = int(os.getenv("AUTH_BEGIN_TIMESTAMP")) -# pylint: disable=duplicate-code -class PgConfig: +class PostgresClientConfig: # POSTGRES_PASSWORD = os.getenv("POSTGRES_PASSWORD") POSTGRES_DB = os.getenv("POSTGRES_DB") POSTGRES_USER = os.getenv("POSTGRES_USER") POSTGRES_HOST = "postgres" + + +__all__ = BackendApiConfig, PostgresClientConfig, diff --git a/services/backend_api/src/app/db.py b/services/backend_api/src/app/database.py similarity index 79% rename from services/backend_api/src/app/db.py rename to services/backend_api/src/app/database.py index 934655f..425e191 100644 --- a/services/backend_api/src/app/db.py +++ b/services/backend_api/src/app/database.py @@ -1,11 +1,13 @@ from flask import g, current_app import psycopg2 + def get_db(): if 'db' not in g: g.db = psycopg2.connect(host=current_app.config['POSTGRES_HOST'], database=current_app.config['POSTGRES_DB'], user=current_app.config['POSTGRES_USER']) - #password=current_app.config['POSTGRES_PASSWORD']) - return g.db + + +__all__ = get_db, diff --git a/services/backend_api/src/app/routes.py b/services/backend_api/src/app/routes.py index 610fe82..188dacc 100644 --- a/services/backend_api/src/app/routes.py +++ b/services/backend_api/src/app/routes.py @@ -9,7 +9,7 @@ from web3 import Web3, EthereumTesterProvider from eth_account.messages import encode_defunct from psycopg2.extensions import connection as pg_conn -from app.db import get_db +from app.database import get_db bp = Blueprint('v1', __name__, url_prefix='/api/v1') @@ -116,11 +116,8 @@ def process_interaction_approve_request(): if signer != signer_recovered: return jsonify(error="signer address missmatch"), 403 - sql = f'''insert into public.interaction_approve(interaction_hash, eth_address, message_, signature_hex) -values('{interaction_id}', '{signer}', '{Web3.to_hex(text=json.dumps(message, separators=(",", ":")))}', '{signature}') -on conflict do update set -message_ = EXCLUDED.message_, -signature_hex = EXCLUDED.signature_hex;''' + sql = f'''insert into public.interaction_approve (interaction_hash, eth_address, message_, signature_hex) +values('{interaction_id}', '{signer}', '{Web3.to_hex(text=json.dumps(message, separators=(",", ":")))}', '{signature}');''' # todo: move to common/misc/utils connection: pg_conn = get_db() @@ -135,9 +132,25 @@ def process_interaction_approve_request(): return jsonify(success=True), 200 -@bp.get('/interactions/approve') +@bp.get('/interaction/approve') def get_approved_interactions(): - _sql = '''select from public.interaction_approve(interaction_hash);''' + token = request.headers.get('X-Token') + if token is None: + return jsonify(error="x-token header should be set"), 400 + + sender: str = None + try: + payload = jwt.decode( + token, + current_app.config["SECRET_KEY"], + algorithms=['ES256K'], + audience='urn:autlabs:autid:holder' + ) + sender = payload['sub'] + except jwt.PyJWTError as e: + return jsonify(error=f"token validation failed with {repr(e)}"), 403 + + _sql = f'''select * from public.interaction_approve where eth_address = '{sender}';''' data = list() connection: pg_conn = get_db() diff --git a/services/backend_api/src/tests/test_auth.curl.sh b/services/backend_api/src/tests/test_auth.curl.sh index 3069d2c..0ee02ec 100755 --- a/services/backend_api/src/tests/test_auth.curl.sh +++ b/services/backend_api/src/tests/test_auth.curl.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -readonly _port=5000 +readonly _port=5050 readonly _host="localhost" readonly _version="v1" readonly _api_base_url="http://${_host}:${_port}/api/${_version}" @@ -22,7 +22,7 @@ function main { local json_fmt='{"message":%s,"signature":"%s"}' local json_msg_fmt='{"timestamp":%s,"signer":"%s","domain":"%s"}' - local msg_text=$(printf $json_msg_fmt $(date +%s) "${eth_address}" localhost:5000 | jq -c .) + local msg_text=$(printf $json_msg_fmt $(date +%s) "${eth_address}" $_host:$_port | jq -c .) local sig_text=$(python3 sign_message.py "${msg_text}" "0x${private_key}") local json=$(printf $json_fmt $msg_text $sig_text | jq -c .) @@ -55,16 +55,18 @@ function main { local sig_text_inter=$(python3 sign_message.py $msg_text_inter "0x${private_key}") local json_inter=$(printf $json_fmt_inter $msg_text_inter $sig_text_inter) - echo $digest_inter - echo $msg_text_inter - echo $json_inter + # echo $digest_inter + # echo $msg_text_inter + # echo $json_inter local data_inter=$(curl -s -XPOST "${_api_base_url}/interaction/approve" -H "Content-Type: application/json" -d $json_inter) - echo $data_inter -} + echo ">> approve result:" + echo $data_inter | jq . -set -e + local approves=$(curl -s -XGET "${_api_base_url}/interaction/approve" -H "Content-Type: application/json" -H "X-Token: ${token}") + echo ">> approves:" + echo $approves | jq . +} main $@ - exit $? diff --git a/services/backend_api/tini-arm64.sha256sum b/services/backend_api/tini-arm64.sha256sum new file mode 100644 index 0000000..0b87d0f --- /dev/null +++ b/services/backend_api/tini-arm64.sha256sum @@ -0,0 +1 @@ +07952557df20bfd2a95f9bef198b445e006171969499a1d361bd9e6f8e5e0e81 tini-arm64 diff --git a/services/tx_root_publisher/src/app/cfg/__init__.py b/services/tx_root_publisher/src/app/cfg/__init__.py index cf99054..c28464b 100644 --- a/services/tx_root_publisher/src/app/cfg/__init__.py +++ b/services/tx_root_publisher/src/app/cfg/__init__.py @@ -1,2 +1,5 @@ from .contracts_relayer import ContractsRelayer as ContractsRelayerConfig from .postgres_client import PostgresClient as PostgresClientConfig + + +__all__ = ContractsRelayerConfig, PostgresClientConfig,