9 Commits

Author SHA1 Message Date
anoracleofra-code 0edc84c997 bump: release v0.2.0
Former-commit-id: 15f1a1dc3c
2026-03-08 14:27:54 -06:00
anoracleofra-code 0519ed040b fix: make test_trace.py curl commands OS-agnostic
Former-commit-id: b57830c1a6
2026-03-08 14:24:36 -06:00
anoracleofra-code 80fedc103a fix: make dev scripts cross-platform compatible
Former-commit-id: 9802fe55a3
2026-03-08 14:20:28 -06:00
anoracleofra-code 5cefd8f8d5 feat: add Docker publishing via GitHub Actions
Former-commit-id: 36c92881c8
2026-03-08 14:04:52 -06:00
Shadowbroker 75537a8570 Update README.md
Former-commit-id: 313aa32a9b
2026-03-08 12:23:56 -06:00
Shadowbroker bc13706311 Update README.md
Former-commit-id: b5f3b08dee
2026-03-08 12:23:39 -06:00
Shadowbroker 3711c84ebe Update README.md
Former-commit-id: e1acd44e43
2026-03-04 23:39:43 -07:00
Shadowbroker 8e79c03d88 Update README.md
Former-commit-id: 65a8c836c4
2026-03-04 23:38:27 -07:00
Shadowbroker 9419ed9883 Update README.md
Former-commit-id: 955907c056
2026-03-04 23:38:05 -07:00
10 changed files with 242 additions and 48 deletions
+92
View File
@@ -0,0 +1,92 @@
name: Docker Publish
on:
push:
branches: ["main"]
tags: ["v*.*.*"]
pull_request:
branches: ["main"]
env:
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push-frontend:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-frontend
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v5.0.0
with:
context: ./frontend
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-and-push-backend:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-backend
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v5.0.0
with:
context: ./backend
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
+74 -29
View File
@@ -2,12 +2,12 @@
<h1 align="center">🛰️ S H A D O W B R O K E R</h1> <h1 align="center">🛰️ S H A D O W B R O K E R</h1>
<p align="center"><strong>Global Threat Intercept — Real-Time Geospatial Intelligence Platform</strong></p> <p align="center"><strong>Global Threat Intercept — Real-Time Geospatial Intelligence Platform</strong></p>
<p align="center"> <p align="center">
<code>TOP SECRET // SI TK // NOFORN</code>
</p> </p>
</p> </p>
--- ---
![Shadowbroker1](https://github.com/user-attachments/assets/000b94eb-bf33-4e8b-8c60-15ca4a723c68)
**ShadowBroker** is a real-time, full-spectrum geospatial intelligence dashboard that aggregates live data from dozens of open-source intelligence (OSINT) feeds and renders them on a unified dark-ops map interface. It tracks aircraft, ships, satellites, earthquakes, conflict zones, CCTV networks, GPS jamming, and breaking geopolitical events — all updating in real time. **ShadowBroker** is a real-time, full-spectrum geospatial intelligence dashboard that aggregates live data from dozens of open-source intelligence (OSINT) feeds and renders them on a unified dark-ops map interface. It tracks aircraft, ships, satellites, earthquakes, conflict zones, CCTV networks, GPS jamming, and breaking geopolitical events — all updating in real time.
Built with **Next.js**, **MapLibre GL**, **FastAPI**, and **Python**, it's designed for analysts, researchers, and enthusiasts who want a single-pane-of-glass view of global activity. Built with **Next.js**, **MapLibre GL**, **FastAPI**, and **Python**, it's designed for analysts, researchers, and enthusiasts who want a single-pane-of-glass view of global activity.
@@ -83,33 +83,34 @@ Built with **Next.js**, **MapLibre GL**, **FastAPI**, and **Python**, it's desig
## 🏗️ Architecture ## 🏗️ Architecture
``` ```
┌──────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────
FRONTEND (Next.js) │ │ FRONTEND (Next.js)
│ │
│ ┌─────────────┐ ┌──────────┐ ┌─────────────────┐ │ │ ┌─────────────┐ ┌──────────┐ ┌───────────────┐
│ │ MapLibre GL │ │ NewsFeed │ Control Panels │ │ │ │ MapLibre GL │ │ NewsFeed │ Control Panels│
│ │ 2D WebGL │ │ SIGINT │ │ Layers/Filters │ │ │ │ 2D WebGL │ │ SIGINT │ │ Layers/Filters│
│ │ Map Render │ Intel │ │ Markets/Radio │ │ │ │ Map Render │ Intel │ │ Markets/Radio │
│ └──────┬──────┘ └────┬─────┘ └────────┬────────┘ │ │ └──────┬──────┘ └────┬─────┘ └──────────────┘
│ └───────────────────────────────┘ │ └────────────────┼──────────────────┘ │
│ │ REST API (15s fast / 60s slow │ REST API (15s / 60s)
├────────────────────────┼─────────────────────────────┤ ├──────────────────────────┼─────────────────────────────┤
│ BACKEND (FastAPI) │ │ BACKEND (FastAPI) │
│ │ │ │
│ ┌──────────────────────────────────────────────┐ │ ┌───────────────────────┼──────────────────────────┐ │
│ │ Data Fetcher (Scheduler) │ │ │ Data Fetcher (Scheduler) │ │
│ │ ┌──────────┬──────────┬──────────┬─────────┐ │ │ │
│ │ │ OpenSky │ adsb.lol │ N2YO │ USGS │ │ │ ┌──────────┬──────────┬──────────┬───────────┐ │ │
│ │ │ Flights │ Military │ Sats │ Quakes │ │ │ │ │ OpenSky │ adsb.lol │ N2YO │ USGS
│ │ ├──────────┼──────────┼──────────┼─────────┤ │ │ │ │ Flights │ Military │ Sats │ Quakes │ │
│ │ │ AIS WS │ Carrier │ GDELT │ CCTV │ │ │ ├──────────┼──────────┼──────────┼───────────┤ │ │
│ │ │ Ships │ Tracker │ Conflict │ Cameras │ │ │ │ │ │ AIS WS │ Carrier │ GDELT │ CCTV
│ │ ├──────────┼──────────┼──────────┼─────────┤ │ │ │ │ Ships │ Tracker │ Conflict │ Cameras │ │
│ │ │ DeepState│ RSS │ Region │ GPS │ │ │ ├──────────┼──────────┼──────────┼───────────┤ │ │
│ │ │ Frontline│ Intel │ Dossier │ Jamming │ │ │ │ │ DeepState│ RSS │ Region │ GPS │ │
│ │ └──────────┴──────────┴──────────┴─────────┘ │ │ │ │ Frontline│ Intel │ Dossier │ Jamming │ │
│ └─────────────────────────────────────────────┘ │ │ └─────────────────────────────────────────┘
└────────────────────────────────────────────────────── └──────────────────────────────────────────────────┘
└────────────────────────────────────────────────────────┘
``` ```
--- ---
@@ -138,12 +139,56 @@ Built with **Next.js**, **MapLibre GL**, **FastAPI**, and **Python**, it's desig
## 🚀 Getting Started ## 🚀 Getting Started
### 🐳 Docker Setup (Recommended for Self-Hosting)
You can run the dashboard easily using the pre-built Docker images hosted on GitHub Container Registry (GHCR).
1. Create a `docker-compose.yml` file:
```yaml
version: '3.8'
services:
backend:
image: ghcr.io/<your-username>/live-risk-dashboard-backend:main
container_name: shadowbroker-backend
ports:
- "8000:8000"
environment:
- AISSTREAM_API_KEY=${AISSTREAM_API_KEY}
- N2YO_API_KEY=${N2YO_API_KEY}
# Add other required environment variables here
volumes:
- backend_data:/app/data
restart: unless-stopped
frontend:
image: ghcr.io/<your-username>/live-risk-dashboard-frontend:main
container_name: shadowbroker-frontend
ports:
- "3000:3000"
environment:
- NEXT_PUBLIC_API_URL=http://localhost:8000
depends_on:
- backend
restart: unless-stopped
volumes:
backend_data:
```
1. Create a `.env` file in the same directory with your API keys.
2. Run `docker-compose up -d`.
3. Access the dashboard at `http://localhost:3000`.
---
### 📦 Quick Start (No Code Required) ### 📦 Quick Start (No Code Required)
If you just want to run the dashboard without dealing with terminal commands: If you just want to run the dashboard without dealing with terminal commands:
1. Go to the **[Releases](../../releases)** tab on the right side of this GitHub page. 1. Go to the **[Releases](../../releases)** tab on the right side of this GitHub page.
2. Download the `ShadowBroker_v0.1.zip` file. 2. Download the `ShadowBroker_v0.2.zip` file.
3. Extract the folder to your computer. 3. Extract the folder to your computer.
4. **Windows:** Double-click `start.bat`. 4. **Windows:** Double-click `start.bat`.
**Mac/Linux:** Open terminal, type `chmod +x start.sh`, and run `./start.sh`. **Mac/Linux:** Open terminal, type `chmod +x start.sh`, and run `./start.sh`.
+10
View File
@@ -0,0 +1,10 @@
venv/
__pycache__/
*.pyc
.env
.pytest_cache/
.coverage
cctv.db
*.json
*.txt
!requirements.txt
+7
View File
@@ -9,6 +9,13 @@ RUN pip install --no-cache-dir -r requirements.txt
# Copy source code # Copy source code
COPY . . COPY . .
# Create a non-root user for security
RUN adduser --system --uid 1001 backenduser \
&& chown -R backenduser /app
# Switch to the non-root user
USER backenduser
# Expose port # Expose port
EXPOSE 8000 EXPOSE 8000
+4 -4
View File
@@ -11,7 +11,7 @@ hex_prefix = hex_code[-2:]
# Test 1: adsb.fi trace_full # Test 1: adsb.fi trace_full
url1 = f"https://globe.adsb.fi/data/traces/{date_str}/{hex_prefix}/trace_full_{hex_code}.json" url1 = f"https://globe.adsb.fi/data/traces/{date_str}/{hex_prefix}/trace_full_{hex_code}.json"
print(f"URL1: {url1}") print(f"URL1: {url1}")
r = subprocess.run(["curl.exe", "-s", "--max-time", "10", url1], capture_output=True, text=True, timeout=15) r = subprocess.run(["curl", "-s", "--max-time", "10", url1], capture_output=True, text=True, timeout=15)
if r.stdout.strip().startswith("{"): if r.stdout.strip().startswith("{"):
data = json.loads(r.stdout) data = json.loads(r.stdout)
print(f"SUCCESS! Keys: {list(data.keys())}") print(f"SUCCESS! Keys: {list(data.keys())}")
@@ -28,7 +28,7 @@ else:
# Test 2: adsb.lol hex lookup # Test 2: adsb.lol hex lookup
url2 = f"https://api.adsb.lol/v2/hex/{hex_code}" url2 = f"https://api.adsb.lol/v2/hex/{hex_code}"
print(f"\nURL2: {url2}") print(f"\nURL2: {url2}")
r2 = subprocess.run(["curl.exe", "-s", "--max-time", "10", url2], capture_output=True, text=True, timeout=15) r2 = subprocess.run(["curl", "-s", "--max-time", "10", url2], capture_output=True, text=True, timeout=15)
if r2.stdout.strip().startswith("{"): if r2.stdout.strip().startswith("{"):
data = json.loads(r2.stdout) data = json.loads(r2.stdout)
if 'ac' in data and data['ac']: if 'ac' in data and data['ac']:
@@ -41,13 +41,13 @@ else:
# Test 3: Try adsb.lol trace # Test 3: Try adsb.lol trace
url3 = f"https://api.adsb.lol/trace/{hex_code}" url3 = f"https://api.adsb.lol/trace/{hex_code}"
print(f"\nURL3: {url3}") print(f"\nURL3: {url3}")
r3 = subprocess.run(["curl.exe", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", "10", url3], capture_output=True, text=True, timeout=15) r3 = subprocess.run(["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", "10", url3], capture_output=True, text=True, timeout=15)
print(f"HTTP status: {r3.stdout}") print(f"HTTP status: {r3.stdout}")
# Test 4: Try globe.adsb.lol format # Test 4: Try globe.adsb.lol format
url4 = f"https://globe.adsb.lol/data/traces/{date_str}/{hex_prefix}/trace_full_{hex_code}.json" url4 = f"https://globe.adsb.lol/data/traces/{date_str}/{hex_prefix}/trace_full_{hex_code}.json"
print(f"\nURL4: {url4}") print(f"\nURL4: {url4}")
r4 = subprocess.run(["curl.exe", "-s", "--max-time", "10", url4], capture_output=True, text=True, timeout=15) r4 = subprocess.run(["curl", "-s", "--max-time", "10", url4], capture_output=True, text=True, timeout=15)
if r4.stdout.strip().startswith("{"): if r4.stdout.strip().startswith("{"):
data = json.loads(r4.stdout) data = json.loads(r4.stdout)
print(f"SUCCESS! Keys: {list(data.keys())}") print(f"SUCCESS! Keys: {list(data.keys())}")
+13
View File
@@ -0,0 +1,13 @@
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git
.env
.env.local
.env.*
eslint.config.mjs
postcss.config.mjs
tailwind.config.ts
+30 -11
View File
@@ -1,19 +1,38 @@
FROM node:18-alpine FROM node:18-alpine AS base
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app WORKDIR /app
# Install dependencies
COPY package*.json ./ COPY package*.json ./
RUN npm install RUN npm ci
# Copy source code FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . . COPY . .
ENV NEXT_TELEMETRY_DISABLED 1
RUN npm run build
# Expose port FROM base AS runner
EXPOSE 3000 WORKDIR /app
ENV NODE_ENV production
# Next.js telemetry disable
ENV NEXT_TELEMETRY_DISABLED 1 ENV NEXT_TELEMETRY_DISABLED 1
# Start development server RUN addgroup --system --gid 1001 nodejs
CMD ["npm", "run", "dev:frontend"] RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
RUN mkdir .next
RUN chown nextjs:nodejs .next
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
+7
View File
@@ -2,6 +2,13 @@ import type { NextConfig } from "next";
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
transpilePackages: ['react-map-gl', 'mapbox-gl', 'maplibre-gl'], transpilePackages: ['react-map-gl', 'mapbox-gl', 'maplibre-gl'],
output: "standalone",
typescript: {
ignoreBuildErrors: true,
},
eslint: {
ignoreDuringBuilds: true,
},
}; };
export default nextConfig; export default nextConfig;
+4 -3
View File
@@ -1,16 +1,17 @@
{ {
"name": "frontend", "name": "frontend",
"version": "0.1.0", "version": "0.2.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "concurrently \"npm run dev:frontend\" \"cd ../backend && python -m uvicorn main:app --reload\"", "dev": "concurrently \"npm run dev:frontend\" \"npm run dev:backend\"",
"dev:frontend": "next dev", "dev:frontend": "next dev",
"dev:backend": "cd ../backend && venv\\Scripts\\python.exe main.py", "dev:backend": "cd ../backend && python -m uvicorn main:app --reload",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "eslint" "lint": "eslint"
}, },
"dependencies": { "dependencies": {
"@mapbox/point-geometry": "^1.1.0",
"@types/leaflet": "^1.9.21", "@types/leaflet": "^1.9.21",
"@types/mapbox-gl": "^3.4.1", "@types/mapbox-gl": "^3.4.1",
"framer-motion": "^12.34.3", "framer-motion": "^12.34.3",
+1 -1
View File
@@ -2,7 +2,7 @@ import os
import zipfile import zipfile
def create_clean_zip(): def create_clean_zip():
zip_name = 'ShadowBroker_v0.1.zip' zip_name = 'ShadowBroker_v0.2.zip'
exclude_dirs = {'.git', 'node_modules', 'venv', '.next', '__pycache__'} exclude_dirs = {'.git', 'node_modules', 'venv', '.next', '__pycache__'}
exclude_files = {zip_name, 'zip_repo.py', '.env', '.env.local'} exclude_files = {zip_name, 'zip_repo.py', '.env', '.env.local'}