# ============================================================
# STAGE 1 — BUILDER
# ============================================================
FROM golang:1.26-bookworm AS builder

ENV DEBIAN_FRONTEND=noninteractive \
    GOTOOLCHAIN=local \
    GO111MODULE=on \
    GOWORK=off \
    GOPROXY=https://proxy.golang.org,direct \
    GOSUMDB=sum.golang.org \
    OUT=/out

WORKDIR /build

# ------------------------------------------------------------
# Build dependencies
# ------------------------------------------------------------
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential curl git unzip ca-certificates pkg-config \
    autoconf automake libtool make file \
    libssl-dev zlib1g-dev libnghttp2-dev libidn2-0-dev libpsl-dev \
    libkrb5-dev libssh2-1-dev \
    libreadline-dev libyaml-dev libffi-dev libbz2-dev libsqlite3-dev \
    liblzma-dev libgdbm-dev libnss3-dev libncurses-dev uuid-dev \
 && rm -rf /var/lib/apt/lists/*

# ------------------------------------------------------------
# libcurl custom
# ------------------------------------------------------------
RUN set -eux; \
    CURL_VER="$(curl -fsSL https://curl.se/download/ \
      | grep -Eo 'curl-[0-9]+\.[0-9]+\.[0-9]+\.tar\.xz' \
      | head -n1 | sed 's/curl-//;s/\.tar\.xz//')"; \
    curl -fsSL https://curl.se/download/curl-${CURL_VER}.tar.xz -o curl.tar.xz; \
    tar -xf curl.tar.xz; cd curl-${CURL_VER}; \
    ./configure --prefix=${OUT}/curl \
        --with-openssl \
        --with-nghttp2 \
        --enable-http --enable-ftp --enable-file --enable-tls-srp \
        --disable-static; \
    make -j$(nproc); make install; \
    ${OUT}/curl/bin/curl --version

ENV PKG_CONFIG_PATH=${OUT}/curl/lib/pkgconfig

# ------------------------------------------------------------
# Go tools
# ------------------------------------------------------------
COPY setup.sh .
RUN chmod +x setup.sh \
 && sed -i -E 's/(apt( |-)?get install -y[^#\n]*)\s+(golang(-go|-doc|-src)?)/\1/g' setup.sh \
 && bash -x setup.sh

# ------------------------------------------------------------
# Nuclei templates
# ------------------------------------------------------------
RUN install -d ${OUT}/nuclei-templates \
 && nuclei -silent -update-templates -ut ${OUT}/nuclei-templates || true

# ------------------------------------------------------------
# Ruby 
# ------------------------------------------------------------
ARG RUBY_PREFIX=/opt/darkmoon/ruby
ARG RUBY_VERSION=3.3.5

RUN git clone https://github.com/rbenv/ruby-build.git /tmp/ruby-build \
 && /tmp/ruby-build/install.sh \
 && ruby-build ${RUBY_VERSION} ${RUBY_PREFIX} \
 && rm -rf /tmp/ruby-build

# Ruby tools
COPY setup_ruby.sh /setup_ruby.sh
RUN chmod +x /setup_ruby.sh && /setup_ruby.sh

# ------------------------------------------------------------
# Python custom
# ------------------------------------------------------------
ARG PY_VER=3.12.6
ARG PY_PREFIX=/opt/darkmoon/python
RUN curl -fsSL https://www.python.org/ftp/python/${PY_VER}/Python-${PY_VER}.tgz -o python.tgz \
 && tar -xzf python.tgz \
 && cd Python-${PY_VER} \
 && ./configure --prefix=${PY_PREFIX} --enable-optimizations --with-ensurepip=install \
 && make -j$(nproc) && make install

# ------------------------------------------------------------
# Rust
# ------------------------------------------------------------
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable \
 && . "$HOME/.cargo/env"
ENV PATH="/root/.cargo/bin:${PATH}"

# ------------------------------------------------------------
# Python tooling
# ------------------------------------------------------------
COPY setup_py.sh /setup_py.sh
RUN chmod +x /setup_py.sh && /setup_py.sh

# ------------------------------------------------------------
# SecLists — sparse: only the files actually used by agents
# ------------------------------------------------------------
RUN install -d \
      ${OUT}/seclists/Discovery/Web-Content \
      ${OUT}/seclists/Passwords \
      ${OUT}/seclists/Fuzzing \
      ${OUT}/seclists/Discovery/DNS \
 && BASE="https://raw.githubusercontent.com/danielmiessler/SecLists/master" \
 && curl -fsSL --retry 3 "${BASE}/Discovery/Web-Content/common.txt" \
      -o ${OUT}/seclists/Discovery/Web-Content/common.txt \
 && curl -fsSL --retry 3 "${BASE}/Discovery/Web-Content/big.txt" \
      -o ${OUT}/seclists/Discovery/Web-Content/big.txt \
 && curl -fsSL --retry 3 "${BASE}/Discovery/Web-Content/raft-medium-words.txt" \
      -o ${OUT}/seclists/Discovery/Web-Content/raft-medium-words.txt \
 && curl -fsSL --retry 3 "${BASE}/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt" \
      -o ${OUT}/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt \
 && curl -fsSL --retry 3 "${BASE}/Discovery/DNS/subdomains-top1million-5000.txt" \
      -o ${OUT}/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
 && curl -fsSL --retry 3 "${BASE}/Fuzzing/fuzz-Bo0oM.txt" \
      -o ${OUT}/seclists/Fuzzing/fuzz-Bo0oM.txt

# ============================================================
# STAGE 2 — CUDA DEVEL (GPU + CPU fallback)
# ============================================================
FROM nvidia/cuda:13.1.0-devel-ubuntu22.04

ENV DEBIAN_FRONTEND=noninteractive \
    DM_HOME=/opt/darkmoon

# ------------------------------------------------------------
# Runtime OS dependencies
# ------------------------------------------------------------
RUN sed -i 's|http://archive.ubuntu.com|http://fr.archive.ubuntu.com|g' /etc/apt/sources.list \
 && sed -i 's|http://security.ubuntu.com|http://fr.archive.ubuntu.com|g' /etc/apt/sources.list \
 && apt-get update -o Acquire::Retries=3 \
 && apt-get install -y --no-install-recommends \
    # base runtime
    ca-certificates tzdata bash dnsutils jq curl git \
    \
    # libs runtime générales
    libssl3 zlib1g libnghttp2-14 libidn2-0 libpsl5 \
    libkrb5-3 libssh2-1 libyaml-0-2 libreadline8 \
    libffi8 libgmp10 libncursesw6 libpcap0.8 \
    hydra snmp openssh-client inotify-tools \
    \
    # requis pour pip / wheels
    build-essential pkg-config libffi-dev libssl-dev \
    \
    # dépendances Chromium / Playwright
    libnss3 \
    libatk1.0-0 \
    libatk-bridge2.0-0 \
    libx11-xcb1 \
    libxcomposite1 \
    libxdamage1 \
    libxrandr2 \
    libgbm1 \
    libasound2 \
    libpangocairo-1.0-0 \
    libgtk-3-0 \
    \
    # OpenCL loader
    ocl-icd-libopencl1 \
    opencl-headers \
    clinfo \
    \
    # GPU backends for hashcat, one per vendor family. The image is built once and
    # runs on machines we do not control, so every backend ships and the entrypoint
    # picks whichever the host actually exposes at runtime.
    #   NVIDIA  -> CUDA comes from the base image; the driver libraries are mounted
    #              by the container runtime, which needs NVIDIA_DRIVER_CAPABILITIES
    #              (set below) plus `--gpus all` on the docker/compose side.
    #   AMD     -> Mesa rusticl/clover: works through /dev/dri without the multi-GB
    #              ROCm stack. Machines with full ROCm keep using it via /dev/kfd.
    #   Intel   -> NEO compute runtime for Arc and recent integrated graphics.
    mesa-opencl-icd \
    intel-opencl-icd \
    \
    # CPU OpenCL backend (last-resort fallback, always present)
    pocl-opencl-icd \
    \
    # tools
    wget \
    xz-utils \
    p7zip-full \
    zip \
    unzip \
    iputils-ping \
    \
    # database / cache clients (sql-databases & messaging-cache agents)
    postgresql-client \
    default-mysql-client \
    redis-tools \
    \
    # offline cracking + wordlist gen (gcp/storage encrypted-archive chain)
    cewl \
    john \
    libcompress-raw-lzma-perl \
    \
    # firmware / IoT analysis (firmware agent)
    binwalk \
    squashfs-tools \
    sqlite3 \
    arp-scan \
    netcat-openbsd \
    nfs-common \
    file \
 && rm -rf /var/lib/apt/lists/*

# ------------------------------------------------------------
# Install official hashcat (CUDA enabled build)
# ------------------------------------------------------------
RUN wget https://hashcat.net/files/hashcat-6.2.6.7z \
 && 7z x hashcat-6.2.6.7z \
 && mv hashcat-6.2.6 /opt/hashcat \
 && ln -sf /opt/hashcat/hashcat.bin /usr/local/bin/hashcat \
 && rm hashcat-6.2.6.7z

# ------------------------------------------------------------
# 7z2john for the GCS/storage encrypted-archive crack chain (7-Zip -> hashcat -m 11600)
# ------------------------------------------------------------
RUN wget -qO /usr/local/bin/7z2john.pl https://raw.githubusercontent.com/openwall/john/bleeding-jumbo/run/7z2john.pl \
 && printf '#!/bin/sh\nexec perl /usr/local/bin/7z2john.pl "$@"\n' > /usr/local/bin/7z2john \
 && chmod +x /usr/local/bin/7z2john /usr/local/bin/7z2john.pl

# ------------------------------------------------------------
# firmwalker — automated firmware filesystem secret hunter (firmware agent)
# ------------------------------------------------------------
RUN (git clone --depth 1 https://github.com/craigz28/firmwalker.git /opt/firmwalker \
      || git clone --depth 1 https://github.com/hotelzululima/firmwalker.git /opt/firmwalker) \
 && ln -sf /opt/firmwalker/firmwalker.sh /usr/local/bin/firmwalker \
 && chmod +x /opt/firmwalker/firmwalker.sh \
 || echo "[WARN] firmwalker unavailable (upstream craigz28 repo removed); continuing without it"
# ------------------------------------------------------------
# sasquatch — vendor-patched unsquashfs for the non-standard LZMA/XZ SquashFS
# images shipped by embedded vendors (firmware agent).
# Best-effort on purpose: firmware.md falls back to plain unsquashfs when it is
# absent, so a dead mirror or a new arch must never break the whole image build.
# ------------------------------------------------------------
ARG SASQUATCH_TAG=sasquatch-v4.5.1-6
RUN set -eux; \
    ARCH="$(dpkg --print-architecture)"; \
    URL="https://github.com/onekey-sec/sasquatch/releases/download/${SASQUATCH_TAG}/sasquatch_1.0_${ARCH}.deb"; \
    if curl -fsSL --retry 2 --max-time 120 "$URL" -o /tmp/sasquatch.deb; then \
      dpkg -i /tmp/sasquatch.deb || true; \
      rm -f /tmp/sasquatch.deb; \
    fi; \
    if command -v sasquatch >/dev/null 2>&1; then \
      echo "[OK] sasquatch installed"; \
    else \
      echo "[WARN] sasquatch unavailable for ${ARCH} - firmware agent will fall back to unsquashfs"; \
    fi

# ------------------------------------------------------------
# Node.js + Playwright (stable project install)
# ------------------------------------------------------------
WORKDIR /opt/darkmoon

RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
 && apt-get install -y --no-install-recommends nodejs \
 && npm init -y \
 && npm install playwright \
 && npx playwright install chromium \
 && npm cache clean --force

# ------------------------------------------------------------
# Google Cloud SDK (gcp agent): gcloud + gsutil + bq via official tarball
# az (Azure CLI) and aws are installed into /opt/darkmoon/python by setup_py.sh
# ------------------------------------------------------------
ARG GCLOUD_VERSION=490.0.0
RUN curl -fsSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${GCLOUD_VERSION}-linux-x86_64.tar.gz" -o /tmp/gcloud.tgz \
 && tar xzf /tmp/gcloud.tgz -C /opt \
 && rm -f /tmp/gcloud.tgz \
 && /opt/google-cloud-sdk/install.sh --quiet --usage-reporting false --path-update false --command-completion false \
 && ln -sf /opt/google-cloud-sdk/bin/gcloud /usr/local/bin/gcloud \
 && ln -sf /opt/google-cloud-sdk/bin/gsutil /usr/local/bin/gsutil \
 && ln -sf /opt/google-cloud-sdk/bin/bq /usr/local/bin/bq \
 && gcloud --version | head -1

# ------------------------------------------------------------
# Core artefacts copiés depuis builder
# ------------------------------------------------------------
COPY --from=builder /out /out
COPY --from=builder /opt/darkmoon /opt/darkmoon

# ------------------------------------------------------------
# Environment runtime
# ------------------------------------------------------------
ENV PATH="/opt/darkmoon/curl/bin:/opt/darkmoon/python/bin:/opt/darkmoon/ruby/bin:${PATH}" \
    LD_LIBRARY_PATH="/usr/lib/aarch64-linux-gnu:/usr/lib/x86_64-linux-gnu:/opt/darkmoon/curl/lib:/opt/darkmoon/python/lib:/opt/darkmoon/ruby/lib"

RUN ln -s /opt/darkmoon/python/bin/python3 /usr/local/bin/python \
 && ln -s /opt/darkmoon/python/bin/pip3 /usr/local/bin/pip

# ------------------------------------------------------------
# Wordlists & data
# ------------------------------------------------------------
RUN mkdir -p /usr/share/wordlists /usr/share/dirb \
 && ln -sfn /out/seclists /usr/share/seclists \
 && ln -sfn /usr/share/seclists /usr/share/wordlists/seclists \
 && ln -sfn /out/wordlists/dirb /usr/share/dirb/wordlists \
 && ln -sfn /usr/share/seclists ${DM_HOME}/seclists

# ------------------------------------------------------------
# Full rockyou.txt (134 MB) — required for hash cracking
# SecLists only ships fragments; download the real one from
# the canonical GitHub release mirror and place it where
# tools (hashcat, john, hydra) expect it.
# ------------------------------------------------------------
RUN curl -fsSL --max-redirs 5 \
      "https://github.com/brannondorsey/naive-hashcat/releases/download/data/rockyou.txt" \
      -o /usr/share/wordlists/rockyou.txt \
 && ln -sf /usr/share/wordlists/rockyou.txt \
          /usr/share/seclists/Passwords/rockyou.txt \
 && echo "[OK] rockyou.txt $(wc -l < /usr/share/wordlists/rockyou.txt) lines"

# The NVIDIA container runtime only mounts the driver libraries when these are
# declared. Without them a container started with `--gpus all` still sees no GPU,
# which is why hashcat silently fell back to CPU pthreads on every deployment.
# Harmless on hosts with no NVIDIA GPU: the runtime simply ignores them.
ENV NVIDIA_VISIBLE_DEVICES=all \
    NVIDIA_DRIVER_CAPABILITIES=compute,utility

ENV SECLISTS=/usr/share/seclists \
    NUCLEI_TEMPLATES=${DM_HOME}/nuclei-templates

# ------------------------------------------------------------
# Binary and wrapper installations
# ------------------------------------------------------------
RUN test -d /out/bin || { echo "ERROR: /out/bin directory not found"; exit 1; } \
 && test "$(ls -A /out/bin 2>/dev/null)" || { echo "ERROR: /out/bin is empty"; exit 1; }

RUN for bin in /out/bin/*; do \
      install -m 755 "$bin" "/usr/local/bin/$(basename "$bin")"; \
    done

# ------------------------------------------------------------
# Post-install validation minimale
# ------------------------------------------------------------
RUN command -v nuclei >/dev/null \
 && command -v finalrecon >/dev/null \
 && command -v node >/dev/null \
 && node -e "require('playwright')"

# ------------------------------------------------------------
# Nuclei bootstrap
# ------------------------------------------------------------
RUN mkdir -p /root/nuclei-templates \
 && cp -a ${NUCLEI_TEMPLATES}/. /root/nuclei-templates/ || true \
 && nuclei -tl >/dev/null 2>&1 || true

# ------------------------------------------------------------
# Hardening
# ------------------------------------------------------------
RUN apt-get purge -y login passwd libpam* gnupg* apt || true \
 && rm -rf /etc/apt /var/lib/apt /var/cache/apt

RUN mkdir -p /var/lib/dpkg \
 && : > /var/lib/dpkg/status \
 && rm -rf /var/lib/dpkg/info /var/lib/dpkg/updates


COPY conf/entrypoint-darkmoon.sh /entrypoint-darkmoon.sh
RUN sed -i 's/\r$//' /entrypoint-darkmoon.sh \
 && chmod +x /entrypoint-darkmoon.sh

ENTRYPOINT ["/entrypoint-darkmoon.sh"]
CMD ["bash","-lc", "sleep infinity"]
