import hmac import mimetypes import os from pathlib import Path from fastapi import FastAPI, Header, HTTPException, Query from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from app import db from app.admin import create_admin from app.verify import DappVerifier, TokenVerifier BASE_DIR = Path(__file__).resolve().parent ICON_DIR = BASE_DIR / "static" / "icons" SECRET = os.environ.get("IDRS_SECRET", "") token_verifier = TokenVerifier() dapp_verifier = DappVerifier() app = FastAPI(title="IDRS API") app.mount("/static", StaticFiles(directory=str(BASE_DIR / "static")), name="static") create_admin(app) @app.get("/api/getTokenInfo") def get_token_info(): tokens = [] for t in db.list_tokens(): tokens.append( { "idfToken": t.idfToken, "position": t.position, "typeBlockchain": t.typeBlockchain, "name": t.name, "symbol": t.symbol, "contractAddr": t.contractAddr, "decimals": t.decimals, "iconUrl": t.iconUrl, "filename": t.filename, "is_live": bool(t.is_live), } ) return {"tokenList": tokens} @app.get("/api/version/android") def get_version_android(): v = db.get_version() return { "idVersion": v.idVersion, "appName": v.appName, "acceptableVersion": v.acceptableVersion, "latestVersion": v.latestVersion, } def _serve_icon(filename: str): token_dir = ICON_DIR / "token" path = (token_dir / filename).resolve() if not path.is_file() or token_dir.resolve() not in path.parents: raise HTTPException(status_code=404, detail="not found") return FileResponse(path, media_type="image/png") def _serve_dapp_image(filename: str): dapp_dir = ICON_DIR / "dapps" path = (dapp_dir / filename).resolve() if not path.is_file() or dapp_dir.resolve() not in path.parents: raise HTTPException(status_code=404, detail="not found") return FileResponse(path, media_type=mimetypes.guess_type(path.name)[0] or "application/octet-stream") @app.get("/img/token/{filename}") def get_icon(filename: str): return _serve_icon(filename) @app.get("/public/img/token/{filename}") def get_public_icon(filename: str): return _serve_icon(filename) @app.get("/img/dapps/{filename}") def get_dapp_image(filename: str): return _serve_dapp_image(filename) @app.get("/public/img/dapps/{filename}") def get_public_dapp_image(filename: str): return _serve_dapp_image(filename) @app.get("/api/getDapps") def get_dapps(): dapps = [] for d in db.list_dapps(): dapps.append( { "id": d.id, "name": d.name, "description": d.description, "link": d.link, "image": d.image, "is_live": bool(d.is_live), "counter": d.counter, "category_id": d.category_id, "is_available_indonesia": d.is_available_indonesia, "is_new_version": bool(d.is_new_version), "created_at": d.created_at, "updated_at": d.updated_at, } ) return {"dappList": dapps} @app.post("/api/increaseDappCounter") def increase_dapp_counter(id: int = Query(...), x_api_key: str = Header(default="")): if not SECRET or not hmac.compare_digest(SECRET.encode(), x_api_key.encode()): raise HTTPException(status_code=401, detail="unauthorized") new_counter = db.increment_dapp_counter(id) if new_counter is None: raise HTTPException(status_code=404, detail="dapp not found") return {"id": id, "counter": new_counter} @app.get("/api/getWhitelist") def get_whitelist(): return {"walletList": db.list_wallets()} @app.on_event("startup") def startup(): db.init_db() token_verifier.start() dapp_verifier.start()