#!/bin/bash # setup-wine-csp-service.sh - Set up Wine environment for CryptoPro CSP service # # This script: # 1. Creates a dedicated Wine prefix # 2. Installs required Windows components # 3. Builds the WineCspService for Windows target # 4. Optionally installs CryptoPro CSP (if installer is provided) # # Prerequisites: # - Wine 7.0+ installed (wine, wine64, winetricks) # - .NET SDK 8.0+ installed # - CryptoPro CSP installer (optional, for full functionality) # # Usage: # ./setup-wine-csp-service.sh [--csp-installer /path/to/csp_setup.msi] # # Environment variables: # WINE_PREFIX - Wine prefix location (default: ~/.stellaops-wine-csp) # CSP_INSTALLER - Path to CryptoPro CSP installer # WINE_CSP_PORT - HTTP port for service (default: 5099) set -euo pipefail # Configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" WINE_PREFIX="${WINE_PREFIX:-$HOME/.stellaops-wine-csp}" WINE_CSP_PORT="${WINE_CSP_PORT:-5099}" SERVICE_DIR="$REPO_ROOT/src/__Tools/WineCspService" OUTPUT_DIR="$REPO_ROOT/artifacts/wine-csp-service" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # Parse arguments CSP_INSTALLER="" while [[ $# -gt 0 ]]; do case $1 in --csp-installer) CSP_INSTALLER="$2" shift 2 ;; --help) echo "Usage: $0 [--csp-installer /path/to/csp_setup.msi]" exit 0 ;; *) log_error "Unknown option: $1" exit 1 ;; esac done # Check prerequisites check_prerequisites() { log_info "Checking prerequisites..." if ! command -v wine &> /dev/null; then log_error "Wine is not installed. Please install Wine 7.0+" exit 1 fi if ! command -v winetricks &> /dev/null; then log_warn "winetricks not found. Some components may not install correctly." fi if ! command -v dotnet &> /dev/null; then log_error ".NET SDK not found. Please install .NET 8.0+" exit 1 fi log_info "Prerequisites OK" } # Initialize Wine prefix init_wine_prefix() { log_info "Initializing Wine prefix at $WINE_PREFIX..." export WINEPREFIX="$WINE_PREFIX" export WINEARCH="win64" # Create prefix if it doesn't exist if [[ ! -d "$WINE_PREFIX" ]]; then wineboot --init log_info "Wine prefix created" else log_info "Wine prefix already exists" fi # Set Windows version wine reg add "HKCU\\Software\\Wine\\Version" /v Windows /d "win10" /f 2>/dev/null || true } # Install Windows components via winetricks install_windows_components() { log_info "Installing Windows components..." if command -v winetricks &> /dev/null; then export WINEPREFIX="$WINE_PREFIX" # Install Visual C++ runtime log_info "Installing Visual C++ runtime..." winetricks -q vcrun2019 || log_warn "vcrun2019 installation may have issues" # Install core fonts (optional, for UI) # winetricks -q corefonts || true log_info "Windows components installed" else log_warn "Skipping winetricks components (winetricks not available)" fi } # Install CryptoPro CSP if installer provided install_cryptopro_csp() { if [[ -z "$CSP_INSTALLER" ]]; then log_warn "No CryptoPro CSP installer provided. Service will run in limited mode." log_warn "Provide installer with: --csp-installer /path/to/csp_setup_x64.msi" return 0 fi if [[ ! -f "$CSP_INSTALLER" ]]; then log_error "CryptoPro installer not found: $CSP_INSTALLER" return 1 fi log_info "Installing CryptoPro CSP from $CSP_INSTALLER..." export WINEPREFIX="$WINE_PREFIX" # Run MSI installer wine msiexec /i "$CSP_INSTALLER" /qn ADDLOCAL=ALL || { log_error "CryptoPro CSP installation failed" log_info "You may need to run the installer manually:" log_info " WINEPREFIX=$WINE_PREFIX wine msiexec /i $CSP_INSTALLER" return 1 } # Verify installation if wine reg query "HKLM\\SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\Crypto-Pro GOST R 34.10-2012" 2>/dev/null; then log_info "CryptoPro CSP installed successfully" else log_warn "CryptoPro CSP may not be registered correctly" fi } # Build WineCspService for Windows build_service() { log_info "Building WineCspService..." mkdir -p "$OUTPUT_DIR" # Build for Windows x64 dotnet publish "$SERVICE_DIR/WineCspService.csproj" \ -c Release \ -r win-x64 \ --self-contained true \ -o "$OUTPUT_DIR" \ || { log_error "Build failed" exit 1 } log_info "Service built: $OUTPUT_DIR/WineCspService.exe" } # Create launcher script create_launcher() { log_info "Creating launcher script..." cat > "$OUTPUT_DIR/run-wine-csp-service.sh" << EOF #!/bin/bash # Wine CSP Service Launcher # Generated by setup-wine-csp-service.sh export WINEPREFIX="$WINE_PREFIX" export WINEDEBUG="-all" # Suppress Wine debug output PORT=\${WINE_CSP_PORT:-$WINE_CSP_PORT} SERVICE_DIR="\$(dirname "\$0")" echo "Starting Wine CSP Service on port \$PORT..." echo "Wine prefix: \$WINEPREFIX" echo "" cd "\$SERVICE_DIR" exec wine WineCspService.exe --urls "http://0.0.0.0:\$PORT" EOF chmod +x "$OUTPUT_DIR/run-wine-csp-service.sh" log_info "Launcher created: $OUTPUT_DIR/run-wine-csp-service.sh" } # Create systemd service file create_systemd_service() { log_info "Creating systemd service file..." cat > "$OUTPUT_DIR/wine-csp-service.service" << EOF [Unit] Description=Wine CSP Service for CryptoPro GOST signing After=network.target [Service] Type=simple User=$USER Environment=WINEPREFIX=$WINE_PREFIX Environment=WINEDEBUG=-all Environment=WINE_CSP_PORT=$WINE_CSP_PORT WorkingDirectory=$OUTPUT_DIR ExecStart=/bin/bash $OUTPUT_DIR/run-wine-csp-service.sh Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF log_info "Systemd service file created: $OUTPUT_DIR/wine-csp-service.service" log_info "To install: sudo cp $OUTPUT_DIR/wine-csp-service.service /etc/systemd/system/" log_info "To enable: sudo systemctl enable --now wine-csp-service" } # Create Docker Compose configuration create_docker_compose() { log_info "Creating Docker Compose configuration..." cat > "$OUTPUT_DIR/docker-compose.yml" << EOF # Wine CSP Service - Docker Compose configuration # Requires: Docker with Wine support or Windows container version: '3.8' services: wine-csp-service: build: context: . dockerfile: Dockerfile.wine ports: - "${WINE_CSP_PORT}:5099" environment: - ASPNETCORE_URLS=http://+:5099 volumes: # Mount CSP installer if available - ./csp-installer:/installer:ro # Persist Wine prefix for keys/certificates - wine-prefix:/root/.wine healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5099/health"] interval: 30s timeout: 10s retries: 3 volumes: wine-prefix: EOF # Create Dockerfile cat > "$OUTPUT_DIR/Dockerfile.wine" << 'EOF' # Wine CSP Service Dockerfile FROM ubuntu:22.04 # Install Wine and dependencies RUN dpkg --add-architecture i386 && \ apt-get update && \ apt-get install -y --no-install-recommends \ wine64 \ wine32 \ winetricks \ curl \ ca-certificates \ && rm -rf /var/lib/apt/lists/* # Initialize Wine prefix RUN wineboot --init && \ winetricks -q vcrun2019 || true # Copy service WORKDIR /app COPY WineCspService.exe . COPY *.dll ./ # Expose port EXPOSE 5099 # Health check HEALTHCHECK --interval=30s --timeout=10s --retries=3 \ CMD curl -f http://localhost:5099/health || exit 1 # Run service CMD ["wine", "WineCspService.exe", "--urls", "http://0.0.0.0:5099"] EOF log_info "Docker configuration created in $OUTPUT_DIR/" } # Test the service test_service() { log_info "Testing service startup..." export WINEPREFIX="$WINE_PREFIX" export WINEDEBUG="-all" # Start service in background cd "$OUTPUT_DIR" wine WineCspService.exe --urls "http://localhost:$WINE_CSP_PORT" & SERVICE_PID=$! # Wait for startup sleep 5 # Test health endpoint if curl -s "http://localhost:$WINE_CSP_PORT/health" | grep -q "Healthy"; then log_info "Service is running and healthy" # Test status endpoint log_info "CSP Status:" curl -s "http://localhost:$WINE_CSP_PORT/status" | python3 -m json.tool 2>/dev/null || \ curl -s "http://localhost:$WINE_CSP_PORT/status" else log_warn "Service health check failed" fi # Stop service kill $SERVICE_PID 2>/dev/null || true wait $SERVICE_PID 2>/dev/null || true } # Print summary print_summary() { echo "" log_info "==========================================" log_info "Wine CSP Service Setup Complete" log_info "==========================================" echo "" echo "Wine prefix: $WINE_PREFIX" echo "Service directory: $OUTPUT_DIR" echo "HTTP port: $WINE_CSP_PORT" echo "" echo "To start the service:" echo " $OUTPUT_DIR/run-wine-csp-service.sh" echo "" echo "To test endpoints:" echo " curl http://localhost:$WINE_CSP_PORT/status" echo " curl http://localhost:$WINE_CSP_PORT/keys" echo " curl -X POST http://localhost:$WINE_CSP_PORT/hash \\" echo " -H 'Content-Type: application/json' \\" echo " -d '{\"dataBase64\":\"SGVsbG8gV29ybGQ=\"}'" echo "" if [[ -z "$CSP_INSTALLER" ]]; then echo "NOTE: CryptoPro CSP is not installed." echo " The service will report 'CSP not available'." echo " To install CSP, run:" echo " $0 --csp-installer /path/to/csp_setup_x64.msi" fi } # Main execution main() { log_info "Wine CSP Service Setup" log_info "Repository: $REPO_ROOT" check_prerequisites init_wine_prefix install_windows_components install_cryptopro_csp build_service create_launcher create_systemd_service create_docker_compose test_service print_summary } main "$@"