#!/bin/bash
###############################################################################
# Cowrie RPM Package Builder
#
# Project : Cowrie SSH/Telnet Honeypot
# Package : cowrie
# Install : /var/lib/cowrie
# User    : cowrie
#
# Build:
#   chmod +x build-rpm
#   ./build-rpm
#
# Install:
#   sudo rpm -ivh dist/cowrie-VERSION-RELEASE.ARCH.rpm
#
# Run:
#   cowrie status
#   sudo -u cowrie cowrie foreground
#
###############################################################################

set -e

###############################################################################
# Configuration
###############################################################################

PROJECT="cowrie"

INSTALL_DIR="/var/lib/cowrie"
COWRIE_USER="cowrie"
COWRIE_GROUP="cowrie"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

BUILD_DIR="${SCRIPT_DIR}/.rpm-build"
RPMBUILD="${BUILD_DIR}/rpmbuild"
DIST_DIR="${SCRIPT_DIR}/dist"

APP_DIR="${INSTALL_DIR}/app"
VENV_DIR="${INSTALL_DIR}/venv"
ETC_DIR="${INSTALL_DIR}/etc"
LOG_DIR="${INSTALL_DIR}/log"
LIB_DIR="${INSTALL_DIR}/lib"
RUN_DIR="${INSTALL_DIR}/run"

###############################################################################
# Architecture detection
###############################################################################

RPM_ARCH="$(uname -m)"

case "${RPM_ARCH}" in
    x86_64|aarch64|ppc64le|s390x)
        ;;
    i386|i486|i586|i686)
        RPM_ARCH="i686"
        ;;
    *)
        ;;
esac

###############################################################################
# Version detection
###############################################################################

VERSION="1.0.0"
RELEASE="1"

if git rev-parse --git-dir >/dev/null 2>&1; then

    GIT_VERSION="$(git describe --tags --always 2>/dev/null || true)"

    if [ -n "${GIT_VERSION}" ]; then

        GIT_VERSION="${GIT_VERSION#v}"

        # Remove git commit suffix.
        GIT_VERSION="$(
            printf '%s' "${GIT_VERSION}" |
            sed -E 's/-g[0-9a-fA-F]+$//'
        )"

        # Only accept clean numeric semantic versions.
        if printf '%s' "${GIT_VERSION}" |
            grep -Eq '^[0-9]+(\.[0-9]+)*$'; then

            VERSION="${GIT_VERSION}"

        fi

    fi

fi

PKG_NAME="${PROJECT}-${VERSION}"

OUTPUT="${DIST_DIR}/${PROJECT}-${VERSION}-${RELEASE}.${RPM_ARCH}.rpm"

MAINTAINER="KYGnus"
URL="https://github.com/cowrie/cowrie"
LICENSE="BSD"

###############################################################################
# Header
###############################################################################

echo
echo "============================================================"
echo "          Cowrie RPM Package Builder"
echo "============================================================"
echo
echo " Package : ${PROJECT}"
echo " Version : ${VERSION}"
echo " Release : ${RELEASE}"
echo " Arch    : ${RPM_ARCH}"
echo " Install : ${INSTALL_DIR}"
echo " User    : ${COWRIE_USER}"
echo
echo "============================================================"
echo

###############################################################################
# Check source tree
###############################################################################

echo "[INFO] Checking Cowrie source..."

if [ ! -f "pyproject.toml" ]; then
    echo "[ERROR] pyproject.toml not found."
    echo "[ERROR] Run this script from the Cowrie source directory."
    exit 1
fi

if [ ! -d "src/cowrie" ]; then
    echo "[ERROR] src/cowrie directory not found."
    exit 1
fi

if [ ! -f "requirements.txt" ]; then
    echo "[ERROR] requirements.txt not found."
    exit 1
fi

echo "[OK] Cowrie source detected."

###############################################################################
# Build dependencies
###############################################################################

echo "[INFO] Checking build dependencies..."

REQUIRED_COMMANDS="
rpm
rpmbuild
python3
git
rsync
sed
grep
head
tar
find
"

for cmd in ${REQUIRED_COMMANDS}; do

    if ! command -v "${cmd}" >/dev/null 2>&1; then
        echo "[ERROR] Missing command: ${cmd}"
        echo
        echo "Install build tools:"
        echo "  openSUSE: sudo zypper install rpm-build python3 python3-devel python3-virtualenv python3-pip git rsync tar"
        echo "  Fedora:   sudo dnf install rpm-build python3 python3-devel python3-virtualenv python3-pip git rsync tar"
        exit 1
    fi

done

if ! python3 -m venv --help >/dev/null 2>&1; then

    echo "[ERROR] Python venv module is unavailable."
    echo
    echo "Install it with:"
    echo
    echo "  openSUSE: sudo zypper install python3-virtualenv"
    echo "  Fedora:   sudo dnf install python3-virtualenv"
    echo

    exit 1

fi

echo "[OK] Build dependencies available."

###############################################################################
# Clean previous build
###############################################################################

echo "[INFO] Cleaning previous build..."

rm -rf "${BUILD_DIR}"
mkdir -p "${DIST_DIR}"

mkdir -p "${RPMBUILD}/BUILD"
mkdir -p "${RPMBUILD}/BUILDROOT"
mkdir -p "${RPMBUILD}/RPMS"
mkdir -p "${RPMBUILD}/SOURCES"
mkdir -p "${RPMBUILD}/SPECS"
mkdir -p "${RPMBUILD}/SRPMS"

###############################################################################
# Create source tree for tarball
###############################################################################

echo "[INFO] Copying Cowrie application into tarball tree..."

TARBALL_DIR="${BUILD_DIR}/${PKG_NAME}"
mkdir -p "${TARBALL_DIR}"

rsync -a \
    --exclude=".git" \
    --exclude=".rpm-build" \
    --exclude=".deb-build" \
    --exclude="dist" \
    --exclude="build" \
    --exclude="venv" \
    --exclude=".venv" \
    --exclude="__pycache__" \
    --exclude="*.pyc" \
    --exclude="*.egg-info" \
    ./ \
    "${TARBALL_DIR}/"

###############################################################################
# Create helper files inside the tarball
###############################################################################

echo "[INFO] Creating Cowrie launcher inside tarball..."

mkdir -p "${TARBALL_DIR}/pkgfiles"

cat > "${TARBALL_DIR}/pkgfiles/cowrie-launcher.sh" <<'EOF'
#!/bin/bash

###############################################################################
# Cowrie launcher
###############################################################################

set -e

COWRIE_HOME="/var/lib/cowrie"
COWRIE_VENV="${COWRIE_HOME}/venv"

export COWRIE_HOME
export PYTHONPATH="${COWRIE_HOME}/app/src${PYTHONPATH:+:${PYTHONPATH}}"

cd "${COWRIE_HOME}"

#
# Cowrie must never run as root.
#

if [ "$(id -u)" -eq 0 ]; then

    echo
    echo "ERROR: You must not run cowrie as root!"
    echo
    echo "Run it as the cowrie user:"
    echo
    echo "  sudo -u cowrie cowrie foreground"
    echo

    exit 1

fi

case "${1:-}" in

    start)
        exec "${COWRIE_VENV}/bin/twistd" \
            --pidfile "${COWRIE_HOME}/run/cowrie.pid" \
            cowrie
        ;;

    stop)
        if [ -f "${COWRIE_HOME}/run/cowrie.pid" ]; then
            PID="$(cat "${COWRIE_HOME}/run/cowrie.pid")"
            if kill -0 "${PID}" 2>/dev/null; then
                kill "${PID}" 2>/dev/null || true
            fi
        else
            echo "Cowrie is not running."
        fi
        ;;

    restart)
        "$0" stop
        sleep 1
        exec "$0" start
        ;;

    status)
        if [ -f "${COWRIE_HOME}/run/cowrie.pid" ]; then
            PID="$(cat "${COWRIE_HOME}/run/cowrie.pid")"
            if kill -0 "${PID}" 2>/dev/null; then
                echo "Cowrie is running."
                echo "PID: ${PID}"
                exit 0
            fi
        fi
        echo "Cowrie is not running."
        exit 1
        ;;

    foreground)
        exec "${COWRIE_VENV}/bin/twistd" \
            --nodaemon \
            cowrie
        ;;

    *)
        echo
        echo "Cowrie Honeypot"
        echo
        echo "Usage:"
        echo "  cowrie start"
        echo "  cowrie stop"
        echo "  cowrie restart"
        echo "  cowrie status"
        echo "  cowrie foreground"
        echo
        exit 1
        ;;
esac
EOF

chmod 0755 "${TARBALL_DIR}/pkgfiles/cowrie-launcher.sh"

# /usr/bin/cowrie wrapper
cat > "${TARBALL_DIR}/pkgfiles/cowrie-wrapper.sh" <<'EOF'
#!/bin/bash

exec /var/lib/cowrie/app/bin/cowrie "$@"
EOF

chmod 0755 "${TARBALL_DIR}/pkgfiles/cowrie-wrapper.sh"

# Default cowrie.cfg
cat > "${TARBALL_DIR}/pkgfiles/cowrie.cfg.default" <<'EOF'
[honeypot]
hostname = srv
download_limit_size = 10485760

[ssh]
enabled = true
listen_endpoints = tcp:2222:interface=0.0.0.0

[telnet]
enabled = true
listen_endpoints = tcp:2223:interface=0.0.0.0

[output_jsonlog]
enabled = true
logfile = ${COWRIE_HOME}/var/log/cowrie/cowrie.json
EOF

# systemd unit
cat > "${TARBALL_DIR}/pkgfiles/cowrie.service" <<'EOF'
[Unit]
Description=Cowrie SSH/Telnet Honeypot
After=network.target

[Service]

Type=simple

User=cowrie
Group=cowrie

WorkingDirectory=/var/lib/cowrie

Environment=COWRIE_HOME=/var/lib/cowrie
Environment=PYTHONPATH=/var/lib/cowrie/app/src

ExecStart=/var/lib/cowrie/venv/bin/twistd --nodaemon cowrie

Restart=on-failure
RestartSec=5

UMask=0027

NoNewPrivileges=true
PrivateTmp=true

ProtectSystem=full
ProtectHome=true

ReadWritePaths=/var/lib/cowrie

[Install]
WantedBy=multi-user.target
EOF

###############################################################################
# Create source tarball
###############################################################################

echo "[INFO] Creating source tarball..."

cd "${BUILD_DIR}"
tar -czf "${RPMBUILD}/SOURCES/${PKG_NAME}.tar.gz" "${PKG_NAME}"
cd "${SCRIPT_DIR}"

###############################################################################
# Generate RPM spec file
###############################################################################

echo "[INFO] Generating RPM spec file..."

SPEC_FILE="${RPMBUILD}/SPECS/${PROJECT}.spec"

cat > "${SPEC_FILE}" <<SPEC_EOF
###############################################################################
# Cowrie SSH/Telnet Honeypot — RPM spec file
###############################################################################

Name:           ${PROJECT}
Version:        ${VERSION}
Release:        ${RELEASE}%{?dist}
Summary:        Cowrie SSH and Telnet honeypot

# Disable debug package generation — we are a Python-only package and
# do not want rpmbuild to create cowrie-debuginfo / cowrie-debugsource.
%global debug_package %{nil}

License:        ${LICENSE}
URL:            ${URL}
Source0:        %{name}-%{version}.tar.gz

BuildArch:      ${RPM_ARCH}

Requires:       python3 >= 3.11
Requires:       python3-devel
Requires:       python3-virtualenv
Requires:       python3-pip
Requires:       shadow-utils

%description
Cowrie is a medium to high interaction SSH and Telnet honeypot
designed to log brute-force attacks and shell interaction.

This package installs Cowrie under ${INSTALL_DIR} with a dedicated
non-root service account and an isolated Python virtual environment.


###############################################################################
# PREP
###############################################################################

%prep
%setup -q -n %{name}-%{version}


###############################################################################
# BUILD
###############################################################################

%build
# Create the virtual environment inside the source tree so it gets
# picked up by the %install step.

python3 -m venv --copies venv

VENV_PYTHON="\${PWD}/venv/bin/python"
VENV_PIP="\${PWD}/venv/bin/pip"

# Upgrade packaging tools
"\${VENV_PYTHON}" -m pip install --upgrade pip setuptools wheel setuptools-scm

# Install Cowrie dependencies
"\${VENV_PIP}" install --no-cache-dir -r requirements.txt

# Install Cowrie package itself
export SETUPTOOLS_SCM_PRETEND_VERSION="%{version}"
"\${VENV_PIP}" install --no-cache-dir --no-deps .
unset SETUPTOOLS_SCM_PRETEND_VERSION


###############################################################################
# INSTALL
###############################################################################

%install
rm -rf %{buildroot}

# ------------------------------------------------------------
# Directories
# ------------------------------------------------------------

install -d -m 0755 %{buildroot}${INSTALL_DIR}
install -d -m 0755 %{buildroot}${INSTALL_DIR}/app
install -d -m 0750 %{buildroot}${INSTALL_DIR}/etc
install -d -m 0750 %{buildroot}${INSTALL_DIR}/log
install -d -m 0750 %{buildroot}${INSTALL_DIR}/run
install -d -m 0755 %{buildroot}${INSTALL_DIR}/lib

install -d -m 0755 %{buildroot}/usr/bin
install -d -m 0755 %{buildroot}/etc/systemd/system

# ------------------------------------------------------------
# Application files
#
# Exclude development artifacts that should not ship in a
# production honeypot package.
# ------------------------------------------------------------

rsync -a \
    --exclude='venv' \
    --exclude='.github' \
    --exclude='.git' \
    --exclude='.gitignore' \
    --exclude='.gitattributes' \
    --exclude='.dockerignore' \
    --exclude='.hadolint.yaml' \
    --exclude='.pre-commit-config.yaml' \
    --exclude='.pyre_configuration' \
    --exclude='.readthedocs.yml' \
    --exclude='.yamllint.yml' \
    --exclude='__pycache__' \
    --exclude='*.pyc' \
    --exclude='*.egg-info' \
    ./ %{buildroot}${INSTALL_DIR}/app/

# ------------------------------------------------------------
# Virtual environment
# ------------------------------------------------------------

cp -a venv %{buildroot}${INSTALL_DIR}/venv

# ------------------------------------------------------------
# Cowrie launcher
# ------------------------------------------------------------

install -d -m 0755 %{buildroot}${INSTALL_DIR}/app/bin
install -m 0755 pkgfiles/cowrie-launcher.sh %{buildroot}${INSTALL_DIR}/app/bin/cowrie

# ------------------------------------------------------------
# Global wrapper
# ------------------------------------------------------------

install -m 0755 pkgfiles/cowrie-wrapper.sh %{buildroot}/usr/bin/cowrie

# ------------------------------------------------------------
# Configuration
# ------------------------------------------------------------

install -m 0640 pkgfiles/cowrie.cfg.default %{buildroot}${INSTALL_DIR}/etc/cowrie.cfg

# ------------------------------------------------------------
# systemd unit
# ------------------------------------------------------------

install -m 0644 pkgfiles/cowrie.service %{buildroot}/etc/systemd/system/cowrie.service


###############################################################################
# %post
###############################################################################

%post
# ------------------------------------------------------------
# Rewrite Python shebangs to point to the installed venv
# ------------------------------------------------------------

FINAL_PY="${INSTALL_DIR}/venv/bin/python"

for script in ${INSTALL_DIR}/venv/bin/*; do
    [ -f "\${script}" ] || continue

    base="\$(basename "\${script}")"

    case "\${base}" in
        activate|activate.csh|activate.fish|Activate.ps1)
            continue
            ;;
    esac

    # Skip binary files
    if ! LC_ALL=C grep -Iq . "\${script}" 2>/dev/null; then
        continue
    fi

    shebang="\$(sed -n '1p' "\${script}" 2>/dev/null || true)"

    case "\${shebang}" in
        '#!'*python*)
            sed -i "1c#!\${FINAL_PY}" "\${script}"
            ;;
    esac
done

# ------------------------------------------------------------
# Create group
# ------------------------------------------------------------

if ! getent group ${COWRIE_USER} >/dev/null 2>&1; then
    groupadd --system ${COWRIE_GROUP}
fi

# ------------------------------------------------------------
# Create user
# ------------------------------------------------------------

if ! getent passwd ${COWRIE_USER} >/dev/null 2>&1; then
    useradd \\
        --system \\
        --gid ${COWRIE_GROUP} \\
        --home-dir ${INSTALL_DIR} \\
        --no-create-home \\
        --shell /usr/sbin/nologin \\
        ${COWRIE_USER}
fi

# ------------------------------------------------------------
# Runtime directories
# ------------------------------------------------------------

mkdir -p \\
    ${INSTALL_DIR} \\
    ${INSTALL_DIR}/etc \\
    ${INSTALL_DIR}/log \\
    ${INSTALL_DIR}/run \\
    ${INSTALL_DIR}/lib

# ------------------------------------------------------------
# Ownership
# ------------------------------------------------------------

chown -R ${COWRIE_USER}:${COWRIE_GROUP} ${INSTALL_DIR}

# ------------------------------------------------------------
# Permissions
# ------------------------------------------------------------

chmod 0750 ${INSTALL_DIR}
chmod 0750 ${INSTALL_DIR}/etc ${INSTALL_DIR}/log ${INSTALL_DIR}/run
chmod 0640 ${INSTALL_DIR}/etc/cowrie.cfg 2>/dev/null || true

# ------------------------------------------------------------
# Remove stale PID
# ------------------------------------------------------------

rm -f ${INSTALL_DIR}/run/cowrie.pid

# ------------------------------------------------------------
# systemd
# ------------------------------------------------------------

if command -v systemctl >/dev/null 2>&1; then
    systemctl daemon-reload || true
fi

echo
echo "============================================================"
echo " Cowrie installed successfully"
echo "============================================================"
echo
echo "Application : ${INSTALL_DIR}/app"
echo "Python      : ${INSTALL_DIR}/venv"
echo "Config      : ${INSTALL_DIR}/etc/cowrie.cfg"
echo "Data        : ${INSTALL_DIR}"
echo
echo "Run foreground:"
echo "  sudo -u ${COWRIE_USER} cowrie foreground"
echo
echo "Check status:"
echo "  sudo -u ${COWRIE_USER} cowrie status"
echo
echo "============================================================"
echo
exit 0


###############################################################################
# %preun
###############################################################################

%preun
# Stop the service on uninstall (not upgrade)
if [ \$1 -eq 0 ]; then
    if command -v systemctl >/dev/null 2>&1; then
        systemctl stop cowrie.service 2>/dev/null || true
        systemctl disable cowrie.service 2>/dev/null || true
    fi
fi
exit 0


###############################################################################
# %postun
###############################################################################

%postun
if command -v systemctl >/dev/null 2>&1; then
    systemctl daemon-reload 2>/dev/null || true
fi
exit 0


###############################################################################
# FILES
#
# Every file in %%{buildroot} must be claimed by %%files.
# Development artifacts (.github, .gitignore, ...) have been excluded
# in the %%install step, so a simple wildcard is enough here.
###############################################################################

%files
%defattr(-,root,root,-)

# --- Top-level directories ---
%dir ${INSTALL_DIR}
%dir ${INSTALL_DIR}/app
%dir ${INSTALL_DIR}/etc
%dir ${INSTALL_DIR}/log
%dir ${INSTALL_DIR}/run
%dir ${INSTALL_DIR}/lib

# --- Application tree ---
${INSTALL_DIR}/app

# --- Virtual environment ---
${INSTALL_DIR}/venv

# --- Global launcher ---
/usr/bin/cowrie

# --- Configuration (preserved on upgrade) ---
%config(noreplace) %attr(0640,${COWRIE_USER},${COWRIE_GROUP}) ${INSTALL_DIR}/etc/cowrie.cfg

# --- systemd unit ---
/etc/systemd/system/cowrie.service


###############################################################################
# CHANGELOG
###############################################################################

%changelog
* $(LC_ALL=C date '+%a %b %d %Y') ${MAINTAINER} - ${VERSION}-${RELEASE}
- Initial RPM package for Cowrie SSH/Telnet honeypot
SPEC_EOF

echo "[INFO] Spec file created:"
echo "       ${SPEC_FILE}"

###############################################################################
# Build RPM
###############################################################################

echo "[INFO] Building RPM package..."

rpmbuild \
    --define "_topdir ${RPMBUILD}" \
    --define "_sourcedir ${RPMBUILD}/SOURCES" \
    --define "_builddir ${RPMBUILD}/BUILD" \
    --define "_rpmdir ${RPMBUILD}/RPMS" \
    --define "_srcrpmdir ${RPMBUILD}/SRPMS" \
    --define "_specdir ${RPMBUILD}/SPECS" \
    -bb "${SPEC_FILE}"

###############################################################################
# Collect output
###############################################################################

echo "[INFO] Collecting RPM package..."

rm -f "${OUTPUT}"

FOUND_RPM="$(find "${RPMBUILD}/RPMS" -name "*.rpm" -type f | head -n 1)"

if [ -z "${FOUND_RPM}" ]; then
    echo "[ERROR] RPM package was not created."
    exit 1
fi

cp -f "${FOUND_RPM}" "${OUTPUT}"

###############################################################################
# Verify resulting package
###############################################################################

echo "[INFO] Verifying generated package..."

rpm -qip "${OUTPUT}" >/dev/null
rpm -qlp "${OUTPUT}" >/dev/null

###############################################################################
# Final output
###############################################################################

echo
echo "============================================================"
echo "                 BUILD SUCCESSFUL"
echo "============================================================"
echo
echo "Package:"
echo
echo "  ${OUTPUT}"
echo
echo "Architecture:"
echo
echo "  ${RPM_ARCH}"
echo
echo "Install:"
echo
echo "  openSUSE:"
echo "      sudo zypper install ${OUTPUT}"
echo
echo "  Fedora / RHEL:"
echo "      sudo dnf install ${OUTPUT}"
echo
echo "  Generic RPM:"
echo "      sudo rpm -ivh ${OUTPUT}"
echo
echo "Run foreground:"
echo
echo "  sudo -u cowrie cowrie foreground"
echo
echo "Check status:"
echo
echo "  sudo -u cowrie cowrie status"
echo
echo "Global command:"
echo
echo "  cowrie status"
echo
echo "============================================================"
echo
