#![allow(dead_code)] use crate::{datastore, datastore::Store}; use actix_web::{ // http::StatusCode, error::ResponseError, Result, get, post, web, App, HttpResponse, HttpServer, Responder, }; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use std::sync::Arc; const HOMEPAGE: &str = r#"Welcome, b3L0v3D h4ck3r! This node is part of the DeTEE hacker-challenge, a decentralized wallet that mints the HCKT Token. The private key of the mint authority was generated within the network. The challenge is easy: Hack the network to get the private key, and all the SOL is yours. We also offer other rewards, including: - a unique NFT - token rewards at after release of the DeTEE token - a seat on the Advisory Board of DeTEE - possible employment at DeTEE The mint address of the token is: TOKEN_ADDRESS The mint authority is: MINT_AUTHORITY In order to mint, the mint authority will need some SOL. Before sending SOL, the take into consideration that DeTEE REPRESENTATIVES DON'T KNOW HOW TO GET THE SOL OUT OF THE NETWORK! Allowed operations: /nodes <- information about nodes and counters of network activity /mint (address) <- mint DHCT tokens to the address; the wallet needs sol for this operation If you are able to get the SOL out of the wallet, please contact us at https://detee.ltd The code of the challenge can be found at https://gitea.detee.cloud/ghe0/hacker-challenge "#; #[get("/")] async fn homepage(ds: web::Data>) -> impl Responder { let text = HOMEPAGE .to_string() .replace("TOKEN_ADDRESS", &ds.get_token_address()) .replace("MINT_AUTHORITY", &ds.get_pubkey_base58()); HttpResponse::Ok().body(text) } #[derive(Serialize)] pub struct NodesResp { pub ip: String, pub joined_at: String, pub last_keepalive: String, pub mint_requests: u64, pub mints: u64, pub ratls_attacks: u64, pub total_ratls_conns: u64, pub public: bool, } impl From<(String, datastore::NodeInfo)> for NodesResp { fn from((ip, node_info): (String, datastore::NodeInfo)) -> Self { let joined_at: DateTime = node_info.started_at.into(); let last_keepalive: DateTime = node_info.keepalive.into(); let joined_at = joined_at.format("%Y-%m-%d %H:%M:%S").to_string(); let last_keepalive = last_keepalive.format("%Y-%m-%d %H:%M:%S").to_string(); crate::http_server::NodesResp { ip, joined_at, last_keepalive, mints: node_info.mints, total_ratls_conns: node_info.ratls_conns, ratls_attacks: node_info.ratls_attacks, public: node_info.public, mint_requests: node_info.mint_requests, } } } #[get("/nodes")] async fn get_nodes(ds: web::Data>) -> HttpResponse { HttpResponse::Ok().json( ds.get_node_list().into_iter().map(Into::::into).collect::>(), ) } #[derive(Deserialize)] struct MintReq { wallet: String, } #[post("/mint")] async fn mint(ds: web::Data>, req: web::Json) -> impl Responder { ds.increase_mint_requests(); let result = actix_web::web::block(move || ds.mint(&req.into_inner().wallet).map_err(|e| e.to_string())) .await .unwrap(); // TODO: check if this can get a BlockingError match result { Ok(s) => HttpResponse::Ok().body(format!(r#"{{ "signature": "{s}"}}"#)), Err(e) => HttpResponse::InternalServerError().body(format!(r#"{{ "error": "{e}"}}"#)), } } pub async fn init(ds: Arc) { HttpServer::new(move || { App::new() .app_data(web::Data::new(ds.clone())) .service(homepage) .service(get_nodes) .service(mint) }) .bind("0.0.0.0:31372") .unwrap() .run() .await .unwrap(); }