mirror of
https://github.com/LORDBABUINO/stealth.git
synced 2026-04-27 08:00:00 -07:00
Feat: Wire frontend to backend, add wallet API endpoints
- Replace frontend mock with real fetch calls to POST /api/wallet/analyze and GET /api/wallet/{id}/utxos
- Add Vite dev proxy for /api to avoid CORS in development
- Implement WalletResource.java with the two endpoints
- Add WalletMockData.java with the 5-UTXO dataset
- Configure CORS and port in application.properties
- Add backend/requests/wallet.http with kulala tests (29 assertions, all passing)
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
package org.backend.stealth.controller;
|
||||
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.backend.stealth.mocks.WalletMockData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Path("/api/wallet")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class WalletResource {
|
||||
|
||||
private static final Map<String, String> sessions = new ConcurrentHashMap<>();
|
||||
|
||||
// DTOs
|
||||
|
||||
public record AnalyzeRequest(String descriptor) {}
|
||||
|
||||
public record AnalyzeResponse(String analysisId) {}
|
||||
|
||||
public record VulnerabilityData(String type, String severity, String description) {}
|
||||
|
||||
public record UtxoData(
|
||||
String txid,
|
||||
int vout,
|
||||
String address,
|
||||
double amountBtc,
|
||||
int confirmations,
|
||||
List<VulnerabilityData> vulnerabilities
|
||||
) {}
|
||||
|
||||
public record SummaryData(int total, int clean, int vulnerable) {}
|
||||
|
||||
public record ReportResponse(String descriptor, SummaryData summary, List<UtxoData> utxos) {}
|
||||
|
||||
// Endpoints
|
||||
|
||||
@POST
|
||||
@Path("/analyze")
|
||||
public Response analyze(AnalyzeRequest req) {
|
||||
if (req == null || req.descriptor() == null || req.descriptor().isBlank()) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(Map.of("error", "descriptor is required"))
|
||||
.build();
|
||||
}
|
||||
String analysisId = UUID.randomUUID().toString();
|
||||
sessions.put(analysisId, req.descriptor());
|
||||
return Response.ok(new AnalyzeResponse(analysisId)).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{analysisId}/utxos")
|
||||
public Response getUtxos(@PathParam("analysisId") String analysisId) {
|
||||
String descriptor = sessions.get(analysisId);
|
||||
if (descriptor == null) {
|
||||
return Response.status(Response.Status.NOT_FOUND)
|
||||
.entity(Map.of("error", "analysisId not found"))
|
||||
.build();
|
||||
}
|
||||
return Response.ok(WalletMockData.buildReport(descriptor)).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.backend.stealth.mocks;
|
||||
|
||||
import org.backend.stealth.controller.WalletResource.ReportResponse;
|
||||
import org.backend.stealth.controller.WalletResource.SummaryData;
|
||||
import org.backend.stealth.controller.WalletResource.UtxoData;
|
||||
import org.backend.stealth.controller.WalletResource.VulnerabilityData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WalletMockData {
|
||||
|
||||
public static ReportResponse buildReport(String descriptor) {
|
||||
List<UtxoData> utxos = List.of(
|
||||
new UtxoData(
|
||||
"3a7f2b8c1d4e9f0a6b5c2d7e8f3a1b4c9d2e5f0a7b8c1d4e9f2a5b6c3d7e8f1",
|
||||
0,
|
||||
"bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
|
||||
0.05234891,
|
||||
1842,
|
||||
List.of()
|
||||
),
|
||||
new UtxoData(
|
||||
"b4c8e2f6a1d5b9c3e7f1a5d9b3c7e1f5a9d3b7c1e5f9a3d7b1c5e9f3a7d1b5",
|
||||
1,
|
||||
"bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
|
||||
0.00023000,
|
||||
312,
|
||||
List.of(
|
||||
new VulnerabilityData("DUST_SPEND", "medium",
|
||||
"This UTXO is near the dust threshold. Spending it may cost more in fees than its value, and dust outputs are often used as tracking vectors by chain surveillance companies."),
|
||||
new VulnerabilityData("ADDRESS_REUSE", "high",
|
||||
"This address has received funds in 3 separate transactions. Address reuse breaks the one-time-address privacy model and allows observers to link all deposits to the same wallet.")
|
||||
)
|
||||
),
|
||||
new UtxoData(
|
||||
"f9e3d7c1b5a9f3d7c1b5a9f3d7c1b5a9f3d7c1b5a9f3d7c1b5a9f3d7c1b5a9",
|
||||
0,
|
||||
"bc1q9h7garjcdkl4h5khfz2yxkhsmhep5j7g4cjtch",
|
||||
0.12000000,
|
||||
4521,
|
||||
List.of(
|
||||
new VulnerabilityData("CONSOLIDATION", "medium",
|
||||
"This UTXO was created by consolidating 7 inputs in a single transaction. Consolidation reveals that all input addresses belong to the same wallet, reducing privacy significantly.")
|
||||
)
|
||||
),
|
||||
new UtxoData(
|
||||
"2c6e0a4f8b2d6e0a4f8b2d6e0a4f8b2d6e0a4f8b2d6e0a4f8b2d6e0a4f8b2d",
|
||||
2,
|
||||
"bc1qm34mqf4vn8f5vhf0q3djg2zuzfm9aap6e3n4j",
|
||||
0.87654321,
|
||||
98,
|
||||
List.of(
|
||||
new VulnerabilityData("CIOH", "high",
|
||||
"Common Input Ownership Heuristic (CIOH): this UTXO was spent alongside UTXOs from different derivation paths in the same transaction, strongly suggesting to analysts that all inputs share a common owner."),
|
||||
new VulnerabilityData("ADDRESS_REUSE", "high",
|
||||
"This address appears in 5 transactions as both sender and receiver, a pattern that severely compromises wallet privacy and makes cluster analysis trivial.")
|
||||
)
|
||||
),
|
||||
new UtxoData(
|
||||
"7d1b5e9f3a7d1b5e9f3a7d1b5e9f3a7d1b5e9f3a7d1b5e9f3a7d1b5e9f3a7d",
|
||||
0,
|
||||
"bc1qcr8te4kr609gcawutmrza0j4xv80jy8zeqchgx",
|
||||
0.00500000,
|
||||
2103,
|
||||
List.of(
|
||||
new VulnerabilityData("DUST_SPEND", "low",
|
||||
"A small dust amount was received at this address in a prior transaction. While the dust has not been spent, its presence could be used to track this UTXO if included in a future transaction.")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
SummaryData summary = new SummaryData(5, 1, 4);
|
||||
return new ReportResponse(descriptor, summary, utxos);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user