From 3d36b418746953df156cdb545354fadd9c0b08d0 Mon Sep 17 00:00:00 2001 From: IvanKhrol Date: Sat, 7 Jun 2025 21:19:57 +0300 Subject: [PATCH 1/9] add WAF --- docker-compose.yaml | 13 ++++++++++--- nginx/conf.d/app.conf | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 1ef1280..5c6457c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -59,16 +59,23 @@ services: - gamehub-net reverse-proxy: - image: nginx:1.25-alpine + image: owasp/modsecurity-crs:nginx-alpine container_name: gamehub-rp ports: - "80:80" - "443:443" volumes: - - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/conf.d/app.conf:/etc/nginx/conf.d/app.conf:ro - ./nginx/certs:/etc/nginx/certs:ro - - ./nginx/conf.d:/etc/nginx/conf.d:ro - ./nginx/snippets:/etc/nginx/snippets:ro + - ./nginx_logs:/var/log/nginx + environment: + # On - блокировать, DetectionOnly - только обнаруживать, Off - выключить. + MODSEC_RULE_ENGINE: "On" + # Уровень паранойи от 1 до 4. + PARANOIA_LEVEL: "1" + # Уровень логирования (error, warn, notice, info, debug) + LOG_LEVEL: "warn" depends_on: - store-service - bank-service diff --git a/nginx/conf.d/app.conf b/nginx/conf.d/app.conf index d3b0034..f6d1a4d 100644 --- a/nginx/conf.d/app.conf +++ b/nginx/conf.d/app.conf @@ -20,6 +20,8 @@ server { server_name gamehub.local www.gamehub.local; + modsecurity on; + ssl_certificate /etc/nginx/certs/gamehub.local.crt; ssl_certificate_key /etc/nginx/certs/gamehub.local.key; From 86c0e9f692a7beb82ca7fe07fe70adaffdfc3cc5 Mon Sep 17 00:00:00 2001 From: IvanKhrol Date: Mon, 9 Jun 2025 02:16:49 +0300 Subject: [PATCH 2/9] test adding suricata --- docker-compose.yaml | 18 +++++++++++ suricata/conf/suricata.yaml | 41 ++++++++++++++++++++++++++ suricata/suricata_rules/rules/my.rules | 1 + 3 files changed, 60 insertions(+) create mode 100644 suricata/conf/suricata.yaml create mode 100644 suricata/suricata_rules/rules/my.rules diff --git a/docker-compose.yaml b/docker-compose.yaml index 5c6457c..dc7173e 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -83,8 +83,26 @@ services: - gamehub-net restart: always + ips: + image: jasonish/suricata:latest + container_name: gamehub-suricata + cap_add: + - NET_ADMIN + - NET_RAW + - SYS_NICE + command: -i eth0 + volumes: + - ./suricata/conf/suricata.yaml:/etc/suricata/suricata.yaml + - ./suricata/suricata_rules:/var/lib/suricata/rules + - suricata_logs:/var/log/suricata + networks: + - gamehub-net + networks: gamehub-net: volumes: postgres_data: + suricata_rules: + suricata_logs: + diff --git a/suricata/conf/suricata.yaml b/suricata/conf/suricata.yaml new file mode 100644 index 0000000..0c65734 --- /dev/null +++ b/suricata/conf/suricata.yaml @@ -0,0 +1,41 @@ +%YAML 1.1 +--- + +# Include the default configuration file. +#include: /etc/suricata/suricata.yaml-default + +# Overrides for this Docker container. +outputs: + - eve-log: + enabled: yes + filetype: regular + filename: eve.json + types: + - alert: + payload: yes + packet: yes + http: yes + - http: + extended: yes + - dns + - tls: + extended: yes + - files: + force-magic: yes + force-md5: yes + - ssh + - flow + - netflow + - stats: + enabled: yes + filename: stats.log + interval: 8 + +af-packet: + # Just define the default as we don't know what interface we will be + # run on. + - interface: default + threads: auto + use-mmap: yes + cluster-id: 99 + cluster-type: cluster_flow diff --git a/suricata/suricata_rules/rules/my.rules b/suricata/suricata_rules/rules/my.rules new file mode 100644 index 0000000..b2d922a --- /dev/null +++ b/suricata/suricata_rules/rules/my.rules @@ -0,0 +1 @@ +alert icmp $HOME_NET any -> 8.8.8.8 any (msg:"TEST ping google"; classtype:not-suspicious; sid:1; rev:1;) From fe5957d3c1044c33fee1f422fca801e2d5e95f5a Mon Sep 17 00:00:00 2001 From: IvanKhrol Date: Mon, 9 Jun 2025 02:41:46 +0300 Subject: [PATCH 3/9] added cringe rules --- suricata/rules/another.rules | 37 ++++++++++++++++++++++++++++++++++++ suricata/rules/my.rules | 1 + 2 files changed, 38 insertions(+) create mode 100644 suricata/rules/another.rules create mode 100644 suricata/rules/my.rules diff --git a/suricata/rules/another.rules b/suricata/rules/another.rules new file mode 100644 index 0000000..957c9a0 --- /dev/null +++ b/suricata/rules/another.rules @@ -0,0 +1,37 @@ +# Custom Suricata rules for GameHub + +# Web application security rules +alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: SQL Injection attempt detected"; flow:established,to_server; content:"SELECT"; nocase; content:"FROM"; nocase; distance:0; within:100; classtype:web-application-attack; sid:1000001; rev:1;) + +alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: XSS attempt detected"; flow:established,to_server; content:" $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Path traversal attempt"; flow:established,to_server; content:"../"; classtype:web-application-attack; sid:1000003; rev:1;) + +alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Command injection attempt"; flow:established,to_server; content:"|3B|"; content:"rm"; nocase; distance:0; within:50; classtype:web-application-attack; sid:1000004; rev:1;) + +# Banking service specific rules +alert http $EXTERNAL_NET any -> $HOME_NET 5001 (msg:"GameHub Bank: Unauthorized API access attempt"; flow:established,to_server; content:"POST"; http_method; content:"/api/transfer"; http_uri; content:!"Authorization:"; http_header; classtype:policy-violation; sid:1000010; rev:1;) + +alert http $EXTERNAL_NET any -> $HOME_NET 5001 (msg:"GameHub Bank: Large transaction attempt"; flow:established,to_server; content:"amount"; http_client_body; content:"|22|1000000"; http_client_body; distance:0; within:20; classtype:policy-violation; sid:1000011; rev:1;) + +# Store service specific rules +alert http $EXTERNAL_NET any -> $HOME_NET 5000 (msg:"GameHub Store: Price manipulation attempt"; flow:established,to_server; content:"price"; http_client_body; content:"|22|0"; http_client_body; distance:0; within:20; classtype:policy-violation; sid:1000020; rev:1;) + +alert http $EXTERNAL_NET any -> $HOME_NET 5000 (msg:"GameHub Store: Inventory manipulation"; flow:established,to_server; content:"quantity"; http_client_body; content:"|22|-"; http_client_body; distance:0; within:20; classtype:policy-violation; sid:1000021; rev:1;) + +# Database protection rules +alert tcp $EXTERNAL_NET any -> $HOME_NET $DB_PORT (msg:"GameHub DB: Direct database access attempt"; flow:established,to_server; classtype:policy-violation; sid:1000030; rev:1;) + +# Brute force protection +alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Brute force login attempt"; flow:established,to_server; content:"POST"; http_method; content:"/login"; http_uri; detection_filter:track by_src, count 5, seconds 60; classtype:attempted-recon; sid:1000040; rev:1;) + +# DDoS protection +alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Potential DDoS attack"; flow:established,to_server; detection_filter:track by_src, count 100, seconds 10; classtype:attempted-dos; sid:1000050; rev:1;) + +# Suspicious user agents +alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Suspicious bot activity"; flow:established,to_server; content:"User-Agent|3A 20|"; http_header; content:"bot"; nocase; http_header; classtype:policy-violation; sid:1000060; rev:1;) + +# File upload security +alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Malicious file upload attempt"; flow:established,to_server; content:"Content-Type|3A 20|application/x-executable"; http_header; classtype:trojan-activity; sid:1000070; rev:1;) + +alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: PHP file upload attempt"; flow:established,to_server; content:"filename|3D 22|"; http_header; content:".php"; nocase; http_header; distance:0; within:100; classtype:web-application-attack; sid:1000071; rev:1;) diff --git a/suricata/rules/my.rules b/suricata/rules/my.rules new file mode 100644 index 0000000..b2d922a --- /dev/null +++ b/suricata/rules/my.rules @@ -0,0 +1 @@ +alert icmp $HOME_NET any -> 8.8.8.8 any (msg:"TEST ping google"; classtype:not-suspicious; sid:1; rev:1;) From c577c416c38541aa550f393f948316dc73c2c8cf Mon Sep 17 00:00:00 2001 From: IvanKhrol Date: Mon, 9 Jun 2025 02:45:19 +0300 Subject: [PATCH 4/9] UPDATE README.md --- README.md | 14 +++++--------- suricata/suricata_rules/rules/my.rules | 1 - 2 files changed, 5 insertions(+), 10 deletions(-) delete mode 100644 suricata/suricata_rules/rules/my.rules diff --git a/README.md b/README.md index 418c3fc..ae9e8c4 100644 --- a/README.md +++ b/README.md @@ -112,15 +112,11 @@ curl --insecure -X POST -H 'Content-Type: application/json' -u "test:test" -d '{ # create test data (optional) python tools/deGenerator.py -# store.crt and store.key files for store service -cd store-service/ -openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout store.key -out store.crt -cd .. - -# bank.crt and bank.key files for bank service -cd bank-service/ -openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout bank.key -out bank.crt -cd .. +# create cerificates for reverse-proxy +cd nginx/certs/ +openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout gamehub.local.key -out gamehub.local.crt +openssl dhparam -out dhparam.pem 2048 +cd ../.. # run containers in daemon mode docker compose up --build -d diff --git a/suricata/suricata_rules/rules/my.rules b/suricata/suricata_rules/rules/my.rules deleted file mode 100644 index b2d922a..0000000 --- a/suricata/suricata_rules/rules/my.rules +++ /dev/null @@ -1 +0,0 @@ -alert icmp $HOME_NET any -> 8.8.8.8 any (msg:"TEST ping google"; classtype:not-suspicious; sid:1; rev:1;) From 2f62fc6e5638b1cf84265cfde33008c2c9057a5c Mon Sep 17 00:00:00 2001 From: gubanovpm Date: Mon, 9 Jun 2025 14:01:16 +0300 Subject: [PATCH 5/9] trying to view in bank service --- bank-service/bank/database/db.py | 31 ++++++++++++++---------- database/init-scripts/10-bank-schema.sql | 24 +++++++++++++++++- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/bank-service/bank/database/db.py b/bank-service/bank/database/db.py index 9933d23..e17e1e2 100644 --- a/bank-service/bank/database/db.py +++ b/bank-service/bank/database/db.py @@ -93,34 +93,39 @@ def transfer(id_from:int, uuid_to:str, amount:int): try: cursor.execute('BEGIN TRANSACTION') cursor.execute( - 'SELECT id FROM bank.accounts WHERE uuid = %s;', + 'SELECT id, uuid FROM bank.accounts WHERE uuid = %s;', (uuid_to,) ) id_to = cursor.fetchone() if not id_to: raise ValueError(f'No recver uuid={uuid_to} in database') - id_to = id_to['id'] + id_to = id_to['id'] + uuid_to = id_to['uuid'] cursor.execute( - 'SELECT balance FROM bank.accounts WHERE id = %s;', + 'SELECT id, uuid, balance FROM bank.accounts WHERE id = %s;', (id_from,) ) - sender_balance = cursor.fetchone() - if not sender_balance or sender_balance['balance'] < amount: + + from_data = cursor.fetchone() + if not from_data: + raise ValueError(f'No sender with id={id_from} in database') + uuid_from = from_data['uuid'] + + if id_from == id_to: + raise ValueError('Why you need to send money for yourself???') + + if from_data['balance'] < amount: raise ValueError('Not enough money :(') cursor.execute( - 'UPDATE bank.accounts SET balance = balance - %s WHERE id = %s;', - (amount, id_from,) - ) - cursor.execute( - 'UPDATE bank.accounts SET balance = balance + %s WHERE id = %s;', - (amount, id_to,) + 'INSERT INTO bank.transactions (account_id, amount, account_uuid_snapshot) VALUES (%s, %s, %s);', + (id_from, -amount, uuid_from) ) cursor.execute( - 'INSERT INTO bank.transactions (user_id, amount) VALUES (%s, %s), (%s, %s);', - (id_from, -amount, id_to, amount) + 'INSERT INTO bank.transactions (account_id, amount, account_uuid_snapshot) VALUES (%s, %s, %s);', + (id_to, amount, uuid_to) ) conn.commit() diff --git a/database/init-scripts/10-bank-schema.sql b/database/init-scripts/10-bank-schema.sql index 61a883f..725d8b3 100644 --- a/database/init-scripts/10-bank-schema.sql +++ b/database/init-scripts/10-bank-schema.sql @@ -11,7 +11,29 @@ CREATE TABLE IF NOT EXISTS bank.transactions ( id SERIAL PRIMARY KEY, ts TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, amount INTEGER NOT NULL, - user_id INTEGER NOT NULL REFERENCES bank.accounts (id), + user_id INTEGER REFERENCES bank.accounts (id) ON DELETE SET NULL, + account_uuid_snapshot TEXT NOT NULL, FOREIGN KEY (user_id) REFERENCES bank.accounts ); + +CREATE OR REPLACE VIEW bank.current_balance AS +SELECT + a.id, + a.uuid, + COALESCE(SUM(t.amount), 0) AS balance +FROM bank.accounts.a +LEFT JOIN bank.transactions t ON a.id = t.user_id +GROUP BY a.id, a.uuid; + +CREATE OR REPLACE VIEW bank.all_transactions_view AS +SELECT + t.id, + t.ts, + t.amount, + t.user_id + COALESCE(a.uuid, t.account_uuid_snapshot) AS related_account_uuid, + CASE WHEN a.id IS NULL THEN TRUE ELSE FALSE END AS is_acount_deleted +FROM bank.transactions t +LEFT JOIN bank.account a ON t.account_id = a.id; + From ecdbad7960d63912007e28f0fbc768cf00e43f9a Mon Sep 17 00:00:00 2001 From: gubanovpm Date: Mon, 9 Jun 2025 16:11:13 +0300 Subject: [PATCH 6/9] fixing bank-service --- bank-service/bank/__init__.py | 4 ++++ bank-service/uwsgi.ini | 2 +- database/init-scripts/10-bank-schema.sql | 6 +++--- docker-compose.yaml | 5 +++-- nginx/conf.d/app.conf | 1 + 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/bank-service/bank/__init__.py b/bank-service/bank/__init__.py index b5eb831..c7c344c 100644 --- a/bank-service/bank/__init__.py +++ b/bank-service/bank/__init__.py @@ -9,6 +9,10 @@ app.register_blueprint(routes_blueprint) app.secret_key = os.environ.get('SECRET_KEY', base64.b64encode(os.urandom(24))) +@app.errorhandler(404) +def page_not_found(e): + return str(e) + # run flask application if __name__ == '__main__': ssl_context = ('bank.crt', 'bank.key') diff --git a/bank-service/uwsgi.ini b/bank-service/uwsgi.ini index 9d31f03..ff2e7ac 100644 --- a/bank-service/uwsgi.ini +++ b/bank-service/uwsgi.ini @@ -7,7 +7,7 @@ processes = 4 threads = 2 enable-threads = true -http = 0.0.0.0:5000 +http = 0.0.0.0:5001 vacuum = true buffer-size = 32768 diff --git a/database/init-scripts/10-bank-schema.sql b/database/init-scripts/10-bank-schema.sql index 725d8b3..35c4b21 100644 --- a/database/init-scripts/10-bank-schema.sql +++ b/database/init-scripts/10-bank-schema.sql @@ -22,7 +22,7 @@ SELECT a.id, a.uuid, COALESCE(SUM(t.amount), 0) AS balance -FROM bank.accounts.a +FROM bank.accounts a LEFT JOIN bank.transactions t ON a.id = t.user_id GROUP BY a.id, a.uuid; @@ -31,9 +31,9 @@ SELECT t.id, t.ts, t.amount, - t.user_id + t.user_id, COALESCE(a.uuid, t.account_uuid_snapshot) AS related_account_uuid, CASE WHEN a.id IS NULL THEN TRUE ELSE FALSE END AS is_acount_deleted FROM bank.transactions t -LEFT JOIN bank.account a ON t.account_id = a.id; +LEFT JOIN bank.accounts a ON t.user_id = a.id; diff --git a/docker-compose.yaml b/docker-compose.yaml index dc7173e..dad8006 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -68,10 +68,10 @@ services: - ./nginx/conf.d/app.conf:/etc/nginx/conf.d/app.conf:ro - ./nginx/certs:/etc/nginx/certs:ro - ./nginx/snippets:/etc/nginx/snippets:ro - - ./nginx_logs:/var/log/nginx + - nginx_logs:/var/log/nginx environment: # On - блокировать, DetectionOnly - только обнаруживать, Off - выключить. - MODSEC_RULE_ENGINE: "On" + MODSEC_RULE_ENGINE: "Off" # Уровень паранойи от 1 до 4. PARANOIA_LEVEL: "1" # Уровень логирования (error, warn, notice, info, debug) @@ -105,4 +105,5 @@ volumes: postgres_data: suricata_rules: suricata_logs: + nginx_logs: diff --git a/nginx/conf.d/app.conf b/nginx/conf.d/app.conf index f6d1a4d..1e81133 100644 --- a/nginx/conf.d/app.conf +++ b/nginx/conf.d/app.conf @@ -46,6 +46,7 @@ server { location / { proxy_pass http://store_service_upstream/; + proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; From 04618d98f99081a614bd93830630124a8ef6d115 Mon Sep 17 00:00:00 2001 From: gubanovpm Date: Mon, 9 Jun 2025 16:44:30 +0300 Subject: [PATCH 7/9] fixing address bank service --- README.md | 2 ++ bank-service/bank/__init__.py | 7 +------ docker-compose.yaml | 6 ++++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ae9e8c4..1a395d8 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,12 @@ DB_NAME=study-project STORE_DB_NAME=store-db STORE_DB_PSWD=store-pswd STORE_DB_USER=store-user +STORE_SEC_KEY=store-secret-key BANK_DB_NAME=bank-db BANK_DB_PSWD=bank-store BANK_DB_USER=bank-user +BANK_SEC_KEY=bank-secret-key DB_PORT=51488 ``` diff --git a/bank-service/bank/__init__.py b/bank-service/bank/__init__.py index c7c344c..9f14287 100644 --- a/bank-service/bank/__init__.py +++ b/bank-service/bank/__init__.py @@ -9,11 +9,6 @@ app.register_blueprint(routes_blueprint) app.secret_key = os.environ.get('SECRET_KEY', base64.b64encode(os.urandom(24))) -@app.errorhandler(404) -def page_not_found(e): - return str(e) - # run flask application if __name__ == '__main__': - ssl_context = ('bank.crt', 'bank.key') - app.run('0.0.0.0', port=5001, debug=True, ssl_context=ssl_context) + app.run('0.0.0.0', port=5001, debug=True) diff --git a/docker-compose.yaml b/docker-compose.yaml index dad8006..7df5f40 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -38,6 +38,7 @@ services: DB_NAME: ${DB_NAME} DB_USER: ${STORE_DB_USER} DB_PSWD: ${STORE_DB_PSWD} + SECRET_KEY: ${STORE_SEC_KEY} volumes: - ./database/store-init-csvs:/tmp/init-csvs/ networks: @@ -47,14 +48,15 @@ services: build: bank-service depends_on: - db + ports: + - "5001:5001" environment: DB_HOST: db DB_PORT: ${DB_PORT} DB_NAME: ${DB_NAME} DB_USER: ${BANK_DB_USER} DB_PSWD: ${BANK_DB_PSWD} - ports: - - "5001:5001" + SECRET_KEY: ${BANK_SEC_KEY} networks: - gamehub-net From fb77430c8a789ac13b079976929582688d1f300f Mon Sep 17 00:00:00 2001 From: gubanovpm Date: Mon, 9 Jun 2025 17:10:45 +0300 Subject: [PATCH 8/9] Fixes #71, #68 --- README.md | 8 ++++---- bank-service/bank/database/db.py | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1a395d8..2eefd15 100644 --- a/README.md +++ b/README.md @@ -68,25 +68,25 @@ DB_PORT=51488 ### How to get user balance ( example ) ``` -curl --insecure -X GET -H 'Content-Type: application/json' -u "seregga:seregga" "https://127.0.0.1:5001/api/balance" +curl --insecure -X GET -H 'Content-Type: application/json' -u "seregga:seregga" "https://127.0.0.1/api/bank/api/balance" ``` ### How to add account in our great bank ( example ) ``` -curl --insecure -X POST -H 'Content-Type: application/json' -d '{"uuid" : "test", "password" : "test"}' "https://127.0.0.1:5001/api/add-account" +curl --insecure -X POST -H 'Content-Type: application/json' -d '{"uuid" : "test", "password" : "test"}' "https://127.0.0.1/api/bank/api/add-account" ``` ### How to delete bank account ( example ) ``` -curl --insecure -X POST -H 'Content-Type: application/json' -u "test:test" "https://127.0.0.1:5001/api/delete-account" +curl --insecure -X POST -H 'Content-Type: application/json' -u "test:test" "https://127.0.0.1/api/bank/api/delete-account" ``` ### How to transfer money from one account to another ( example ) ``` -curl --insecure -X POST -H 'Content-Type: application/json' -u "test:test" -d '{"uuid_to" : "seregga", "amount" : 500 }' "https://127.0.0.1:5001/api/transfer" +curl --insecure -X POST -H 'Content-Type: application/json' -u "test:test" -d '{"uuid_to" : "seregga", "amount" : 500 }' "https://127.0.0.1/api/bank/api/transfer" ``` ### Return codes for bank api service diff --git a/bank-service/bank/database/db.py b/bank-service/bank/database/db.py index e17e1e2..1f3b486 100644 --- a/bank-service/bank/database/db.py +++ b/bank-service/bank/database/db.py @@ -54,7 +54,7 @@ def add_account(uuid:str, password:str): phash = bcrypt.hashpw( password.encode('utf-8'), bcrypt.gensalt(rounds = 12) - ).hexdigest() + ).decode('utf-8') conn = get_db() try: cursor = conn.cursor() @@ -93,14 +93,13 @@ def transfer(id_from:int, uuid_to:str, amount:int): try: cursor.execute('BEGIN TRANSACTION') cursor.execute( - 'SELECT id, uuid FROM bank.accounts WHERE uuid = %s;', + 'SELECT id FROM bank.accounts WHERE uuid = %s;', (uuid_to,) ) id_to = cursor.fetchone() if not id_to: raise ValueError(f'No recver uuid={uuid_to} in database') id_to = id_to['id'] - uuid_to = id_to['uuid'] cursor.execute( 'SELECT id, uuid, balance FROM bank.accounts WHERE id = %s;', @@ -119,12 +118,12 @@ def transfer(id_from:int, uuid_to:str, amount:int): raise ValueError('Not enough money :(') cursor.execute( - 'INSERT INTO bank.transactions (account_id, amount, account_uuid_snapshot) VALUES (%s, %s, %s);', + 'INSERT INTO bank.transactions (user_id, amount, account_uuid_snapshot) VALUES (%s, %s, %s);', (id_from, -amount, uuid_from) ) cursor.execute( - 'INSERT INTO bank.transactions (account_id, amount, account_uuid_snapshot) VALUES (%s, %s, %s);', + 'INSERT INTO bank.transactions (user_id, amount, account_uuid_snapshot) VALUES (%s, %s, %s);', (id_to, amount, uuid_to) ) From b5c9fe1f679baabe9bc2c8e3d7620c936565414c Mon Sep 17 00:00:00 2001 From: gubanovpm Date: Mon, 9 Jun 2025 17:22:05 +0300 Subject: [PATCH 9/9] fixing linter issues --- database/init-scripts/10-bank-schema.sql | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/database/init-scripts/10-bank-schema.sql b/database/init-scripts/10-bank-schema.sql index 35c4b21..1b29a4f 100644 --- a/database/init-scripts/10-bank-schema.sql +++ b/database/init-scripts/10-bank-schema.sql @@ -22,8 +22,8 @@ SELECT a.id, a.uuid, COALESCE(SUM(t.amount), 0) AS balance -FROM bank.accounts a -LEFT JOIN bank.transactions t ON a.id = t.user_id +FROM bank.accounts AS a +LEFT JOIN bank.transactions AS t ON a.id = t.user_id GROUP BY a.id, a.uuid; CREATE OR REPLACE VIEW bank.all_transactions_view AS @@ -33,7 +33,6 @@ SELECT t.amount, t.user_id, COALESCE(a.uuid, t.account_uuid_snapshot) AS related_account_uuid, - CASE WHEN a.id IS NULL THEN TRUE ELSE FALSE END AS is_acount_deleted -FROM bank.transactions t -LEFT JOIN bank.accounts a ON t.user_id = a.id; - + (a.id IS NULL) AS is_account_deleted +FROM bank.transactions AS t +LEFT JOIN bank.accounts AS a ON t.user_id = a.id;