Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 141 additions & 10 deletions scripts/db-debug.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
# Usage:
# ./scripts/db-debug.sh # Default query (assets)
# ./scripts/db-debug.sh "SELECT TOP 10 id FROM asset" # Custom SQL query
# ./scripts/db-debug.sh --anomalies # Show invalid FinancialDataLog entries
# ./scripts/db-debug.sh --balance # Show recent balance history
# ./scripts/db-debug.sh --asset-history Yapeal/EUR 10 # Show asset balance history
#
# Environment:
# Copy .env.db-debug.sample to .env.db-debug and fill in your credentials
Expand All @@ -15,10 +18,92 @@

set -e

# --- Help (before auth) ---
if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then
echo "DFX API Debug Database Access Script"
echo ""
echo "Usage:"
echo " ./scripts/db-debug.sh [OPTIONS] [SQL_QUERY]"
echo ""
echo "Options:"
echo " -h, --help Show this help"
echo " -a, --anomalies [N] Show invalid FinancialDataLog entries (default: 20)"
echo " -b, --balance [N] Show recent total balance history (default: 20)"
echo " -s, --stats Show log statistics by system/subsystem"
echo " -A, --asset-history <ID|Blockchain/Name> [N]"
echo " Show balance history for asset (default: 10)"
echo ""
echo "Examples:"
echo " ./scripts/db-debug.sh --anomalies 50"
echo " ./scripts/db-debug.sh --balance 10"
echo " ./scripts/db-debug.sh --asset-history 405 20"
echo " ./scripts/db-debug.sh --asset-history Yapeal/EUR 20"
echo " ./scripts/db-debug.sh --asset-history MaerkiBaumann/CHF 10"
echo " ./scripts/db-debug.sh \"SELECT TOP 10 * FROM asset\""
exit 0
fi

# --- Predefined Queries ---
query_anomalies() {
local limit="${1:-20}"
echo "SELECT TOP $limit id, created, JSON_VALUE(message, '\$.balancesTotal.totalBalanceChf') as totalBalanceChf, JSON_VALUE(message, '\$.balancesTotal.plusBalanceChf') as plusBalanceChf, JSON_VALUE(message, '\$.balancesTotal.minusBalanceChf') as minusBalanceChf, valid FROM log WHERE subsystem = 'FinancialDataLog' AND valid = 0 ORDER BY id DESC"
}

query_stats() {
echo "SELECT system, subsystem, severity, COUNT(*) as count FROM log GROUP BY system, subsystem, severity ORDER BY count DESC"
}

query_balance() {
local limit="${1:-20}"
echo "SELECT TOP $limit id, created, JSON_VALUE(message, '\$.balancesTotal.totalBalanceChf') as totalBalanceChf, JSON_VALUE(message, '\$.balancesTotal.plusBalanceChf') as plusBalanceChf, JSON_VALUE(message, '\$.balancesTotal.minusBalanceChf') as minusBalanceChf, valid FROM log WHERE subsystem = 'FinancialDataLog' ORDER BY id DESC"
}

query_asset_raw() {
local limit="${1:-10}"
echo "SELECT TOP $limit id, created, message FROM log WHERE subsystem = 'FinancialDataLog' ORDER BY id DESC"
}

# --- Parse arguments FIRST ---
SQL=""
ASSET_HISTORY_MODE=""
ASSET_ID=""
ASSET_INPUT=""
ASSET_LIMIT="10"

case "${1:-}" in
-a|--anomalies)
SQL=$(query_anomalies "${2:-20}")
;;
-s|--stats)
SQL=$(query_stats)
;;
-b|--balance)
SQL=$(query_balance "${2:-20}")
;;
-A|--asset-history)
if [ -z "${2:-}" ]; then
echo "Error: --asset-history requires an asset ID or name"
echo "Usage: ./scripts/db-debug.sh --asset-history <ASSET_ID|Blockchain/Name> [LIMIT]"
echo ""
echo "Examples:"
echo " ./scripts/db-debug.sh --asset-history 405 20"
echo " ./scripts/db-debug.sh --asset-history Yapeal/EUR 20"
echo " ./scripts/db-debug.sh --asset-history MaerkiBaumann/CHF 10"
exit 1
fi
ASSET_HISTORY_MODE="1"
ASSET_INPUT="$2"
ASSET_LIMIT="${3:-10}"
;;
*)
SQL="${1:-SELECT TOP 5 id, name, blockchain FROM asset ORDER BY id DESC}"
;;
esac

# --- Load environment ---
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="$SCRIPT_DIR/.env.db-debug"

# Load environment variables
if [ -f "$ENV_FILE" ]; then
source "$ENV_FILE"
else
Expand All @@ -27,15 +112,14 @@ else
exit 1
fi

# Validate required variables
if [ -z "$DEBUG_ADDRESS" ] || [ -z "$DEBUG_SIGNATURE" ]; then
echo "Error: DEBUG_ADDRESS and DEBUG_SIGNATURE must be set in $ENV_FILE"
exit 1
fi

API_URL="${DEBUG_API_URL:-https://api.dfx.swiss/v1}"

# Get JWT Token
# --- Authenticate ---
echo "=== Authenticating to $API_URL ==="
TOKEN_RESPONSE=$(curl -s -X POST "$API_URL/auth/signIn" \
-H "Content-Type: application/json" \
Expand All @@ -49,27 +133,74 @@ if [ "$TOKEN" == "null" ] || [ -z "$TOKEN" ]; then
exit 1
fi

# Decode and show role
ROLE=$(echo "$TOKEN" | cut -d'.' -f2 | base64 -d 2>/dev/null | jq -r '.role' 2>/dev/null || echo "unknown")
echo "Authenticated with role: $ROLE"
echo ""

# Default SQL query if none provided
SQL="${1:-SELECT TOP 5 id, name, blockchain FROM asset ORDER BY id DESC}"
# --- Resolve asset ID if needed ---
if [ -n "$ASSET_HISTORY_MODE" ]; then
if [[ "$ASSET_INPUT" =~ ^[0-9]+$ ]]; then
ASSET_ID="$ASSET_INPUT"
else
# Parse Blockchain/Name format
BLOCKCHAIN=$(echo "$ASSET_INPUT" | cut -d'/' -f1)
ASSET_NAME=$(echo "$ASSET_INPUT" | cut -d'/' -f2)

echo "=== Resolving Asset: $BLOCKCHAIN/$ASSET_NAME ==="
ASSET_QUERY="SELECT id, name, blockchain FROM asset WHERE blockchain = '$BLOCKCHAIN' AND name = '$ASSET_NAME'"
ASSET_RESULT=$(curl -s -X POST "$API_URL/gs/debug" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"sql\":\"$ASSET_QUERY\"}")

ASSET_ID=$(echo "$ASSET_RESULT" | jq -r '.[0].id // empty' 2>/dev/null)

if [ -z "$ASSET_ID" ]; then
echo "Error: Asset '$ASSET_INPUT' not found"
echo "$ASSET_RESULT" | jq . 2>/dev/null
exit 1
fi
echo "Found: Asset ID $ASSET_ID"
echo ""
fi
SQL=$(query_asset_raw "$ASSET_LIMIT")
fi

# --- Execute query ---
echo "=== Executing SQL Query ==="
echo "Query: $SQL"
echo ""

# Execute debug query
RESULT=$(curl -s -X POST "$API_URL/gs/debug" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"sql\":\"$SQL\"}")

echo "=== Result ==="
if command -v jq &> /dev/null; then
echo "$RESULT" | jq .

# Special handling for asset history mode (client-side JSON parsing)
if [ -n "$ASSET_HISTORY_MODE" ]; then
if ! command -v jq &> /dev/null; then
echo "Error: jq is required for --asset-history"
exit 1
fi

echo "Asset ID: $ASSET_ID"
echo ""
echo "$RESULT" | jq -r --arg aid "$ASSET_ID" '
.[] |
(.message | fromjson) as $msg |
$msg.assets[$aid] as $asset |
if $asset then
"[\(.id)] \(.created | split("T") | .[0]) \(.created | split("T") | .[1] | split(".") | .[0]) plus: \($asset.plusBalance.total // 0 | tostring | .[0:12]) minus: \($asset.minusBalance.total // 0 | tostring | .[0:12]) price: \($asset.priceChf // 0 | tostring | .[0:10])"
else
"[\(.id)] Asset \($aid) not found in this log entry"
end
' 2>/dev/null || echo "$RESULT" | jq .
else
echo "$RESULT"
if command -v jq &> /dev/null; then
echo "$RESULT" | jq .
else
echo "$RESULT"
fi
fi
Binary file added scripts/kyc/dummy-files/additional_document.pdf
Binary file not shown.
Binary file added scripts/kyc/dummy-files/bank_statement.pdf
Binary file not shown.
Binary file added scripts/kyc/dummy-files/commercial_register.pdf
Binary file not shown.
Binary file added scripts/kyc/dummy-files/id_back.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added scripts/kyc/dummy-files/id_front.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added scripts/kyc/dummy-files/passport.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added scripts/kyc/dummy-files/proof_of_address.pdf
Binary file not shown.
Binary file added scripts/kyc/dummy-files/residence_permit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added scripts/kyc/dummy-files/selfie.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added scripts/kyc/dummy-files/source_of_funds.pdf
Binary file not shown.
63 changes: 63 additions & 0 deletions scripts/kyc/kyc-storage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* This script shows KYC files stored in the database.
* In local development mode, KYC files are loaded from scripts/kyc/dummy-files/.
*
* Usage: node scripts/kyc/kyc-storage.js
*/

const mssql = require('mssql');

const dbConfig = {
user: process.env.SQL_USERNAME || 'sa',
password: process.env.SQL_PASSWORD || 'LocalDev2026@SQL',
server: 'localhost',
port: parseInt(process.env.SQL_PORT) || 1433,
database: process.env.SQL_DB || 'dfx',
options: { encrypt: false, trustServerCertificate: true }
};

async function main() {
console.log('KYC Storage Seeder');
console.log('==================\n');

console.log('Note: In local development mode, KYC files are stored in-memory.');
console.log('They need to be uploaded via the KYC flow or manually inserted.\n');

// Get KYC file info from database
const pool = await mssql.connect(dbConfig);

const files = await pool.request().query(`
SELECT kf.id, kf.uid, kf.name, kf.type, kf.userDataId, ud.mail
FROM kyc_file kf
JOIN user_data ud ON kf.userDataId = ud.id
ORDER BY kf.id
`);

console.log('KYC Files in database:');
console.log('======================');

for (const file of files.recordset) {
const ext = file.name.split('.').pop().toLowerCase();
const contentType = ext === 'pdf' ? 'application/pdf' : ext === 'jpg' || ext === 'jpeg' ? 'image/jpeg' : 'image/png';

console.log(` ${file.name}`);
console.log(` UID: ${file.uid}`);
console.log(` Type: ${file.type}`);
console.log(` User: ${file.mail}`);
console.log(` Content-Type: ${contentType}`);
console.log('');
}

console.log('\n========================================');
console.log('Note:');
console.log('========================================');
console.log('');
console.log('In local development mode, KYC files are automatically');
console.log('loaded from scripts/kyc/dummy-files/ by the azure-storage');
console.log('service when the requested file is not in memory storage.');
console.log('');

await pool.close();
}

main().catch(console.error);
Loading
Loading