### Quick Start Docker Compose Deployment Source: https://context7.com/marat2509/nod32-mirror/llms.txt This bash script provides a quick start guide for deploying nod32-mirror. It involves downloading the docker-compose.yml and nod32ms.conf files, editing the configuration, and then starting the services in detached mode. ```bash # Quick start wget https://raw.githubusercontent.com/marat2509/nod32-mirror/main/docker-compose.yml wget https://raw.githubusercontent.com/marat2509/nod32-mirror/main/nod32ms.conf # Edit nod32ms.conf, then: docker-compose up -d # Status page available at http://localhost:8084/ ``` -------------------------------- ### Run Docker Compose Source: https://github.com/marat2509/nod32-mirror/blob/main/README.md Execute this command to start the ESET Nod32 mirror services in detached mode. ```sh docker-compose up -d ``` -------------------------------- ### Version Configuration Handling Source: https://context7.com/marat2509/nod32-mirror/llms.txt The `VersionConfig` class manages per-version settings from the configuration file, including enabling versions and filtering by platform and channel. It provides methods to get all enabled versions, check if a specific version is enabled, and retrieve platform and channel filters. ```php 'WINDOWS_NT_AMD64']); // Clean up after processing a version Mirror::destruct(); ?> ``` -------------------------------- ### Download Configuration File Source: https://github.com/marat2509/nod32-mirror/blob/main/README.md Download the nod32ms.conf file to configure the mirror. This file is essential for the mirror's operation. ```sh wget https://raw.githubusercontent.com/marat2509/nod32-mirror/main/nod32ms.conf ``` -------------------------------- ### Orchestrate Full Mirror Run with Nod32ms Class Source: https://context7.com/marat2509/nod32-mirror/llms.txt Instantiate the `Nod32ms` class to trigger a complete mirror update cycle. The constructor automatically handles initialization for enabled versions, license key management, downloading signatures, and generating HTML/JSON outputs. Catch exceptions for logging. ```php getMessage(), 0); } // __destruct() logs total working time and sends mailer summary ?> ``` -------------------------------- ### PHP Update Script Initialization Source: https://context7.com/marat2509/nod32-mirror/llms.txt The main PHP script (`worker/core/update.php`) initializes logging, language, and configuration subsystems. It then instantiates the `Nod32ms` class, which triggers the mirror update cycle. Exception handling is included for various potential errors during initialization and execution. ```php getMessage(), 0); } catch (ConfigException $e) { Log::write_log($e->getMessage(), 0); } catch (phpmailerException $e) { Log::write_log($e->getMessage(), 0); } catch (Exception $e) { Log::write_log($e->getMessage(), 0); } // Debug mode (all errors visible): // Use worker/core/debuging_run.php instead ``` -------------------------------- ### Download Docker Compose File Source: https://github.com/marat2509/nod32-mirror/blob/main/README.md Use this command to download the docker-compose.yml file, which defines the services for the mirror. ```sh wget https://raw.githubusercontent.com/marat2509/nod32-mirror/main/docker-compose.yml ``` -------------------------------- ### Import ESET license keys with import_key.py Source: https://context7.com/marat2509/nod32-mirror/llms.txt Use this Python 3 script to manually add validated ESET license keys to the `nod_keys.valid` file. It allows adding single or multiple keys and specifying a custom keys file path. Ensure the configuration file and keys file paths are correct. ```bash # Add a single key for all enabled versions python3 tools/import_key.py \ --config nod32ms.conf \ --keys_file docker-data/log/nod_keys.valid \ --key "EAV-0123456789:abcdefghij" ``` ```bash # Add multiple keys at once python3 tools/import_key.py \ -k "EAV-0123456789:abcdefghij" \ -k "EAV-9876543210:zyxwvutsrq" ``` ```bash # Custom keys file path python3 tools/import_key.py \ --keys_file /custom/path/nod_keys.valid \ --key "TRIAL-0123456789:abcdefghij" ``` ```bash # Output example: ``` -------------------------------- ### Mirror Class Methods Source: https://context7.com/marat2509/nod32-mirror/llms.txt The Mirror class provides static methods to manage ESET product versions, handle mirror probing, download update files, parse them, and clean up stale data. ```APIDOC ## Mirror::init(string $version, string $dir) ### Description Initializes the Mirror class for a specific ESET product version and directory. ### Method `Mirror::init` ### Parameters - **version** (string) - The product version to initialize (e.g., 'ep9'). - **dir** (string) - The directory path for the version. ### Request Example ```php Mirror::init('ep9', $DIRECTORIES['ep9']); ``` ``` ```APIDOC ## Mirror::set_key(array $credentials) ### Description Sets the license key credentials (login and password) for authentication with ESET update servers. ### Method `Mirror::set_key` ### Parameters - **credentials** (array) - An array containing the login and password strings. - **login** (string) - The license key login. - **password** (string) - The license key password. ### Request Example ```php Mirror::set_key(['EAV-0123456789', 'abcdefghij']); ``` ``` ```APIDOC ## Mirror::test_key(): bool ### Description Tests the currently set license key against all configured mirrors to find those with the latest database version. Populates `Mirror::$mirrors` with valid mirrors. ### Method `Mirror::test_key` ### Returns - **bool** - True if the key is valid and at least one mirror is found, false otherwise. ``` ```APIDOC ## Mirror::check_mirror(string $mirror_url): ?int ### Description Checks a specific mirror to determine its current database version. ### Method `Mirror::check_mirror` ### Parameters - **mirror_url** (string) - The URL of the mirror to check. ### Returns - **?int** - The integer database version ID if successful, or null if the mirror is unreachable or invalid. ``` ```APIDOC ## Mirror::download_update_ver(string $mirror_url): void ### Description Downloads the `update.ver` file from a specified mirror and saves it to a temporary file. ### Method `Mirror::download_update_ver` ### Parameters - **mirror_url** (string) - The URL of the mirror from which to download `update.ver`. ``` ```APIDOC ## Mirror::download_signature(): array ### Description Performs a full download cycle: parses `update.ver`, compares against local files, downloads missing files, cleans up stale files, and fixes timestamps. ### Method `Mirror::download_signature` ### Returns - **array** - An array containing: - **totalSize** (int) - Total size in bytes of downloaded files. - **totalDownloads** (int) - Total number of files downloaded. - **avgSpeed** (int|null) - Average download speed in bytes per second, or null if not applicable. ``` ```APIDOC ## Mirror::get_DB_version(string $update_ver_path): int ### Description Retrieves the database version ID from a local `update.ver` file. ### Method `Mirror::get_DB_version` ### Parameters - **update_ver_path** (string) - The file path to the local `update.ver` file. ### Returns - **int** - The integer database version ID, or 0/null if the file is missing. ``` ```APIDOC ## Mirror::matches_platform(array $platform_info): bool ### Description Checks if a given platform information matches the configured platforms for the current mirror instance. ### Method `Mirror::matches_platform` ### Parameters - **platform_info** (array) - An array containing platform details, e.g., `['platform' => 'WINDOWS_NT_AMD64']`. ### Returns - **bool** - True if the platform matches, false otherwise. ``` ```APIDOC ## Mirror::destruct(): void ### Description Cleans up resources and performs necessary actions after processing a specific product version. ### Method `Mirror::destruct` ``` -------------------------------- ### ESET Product Version Configuration Source: https://context7.com/marat2509/nod32-mirror/llms.txt This PHP array defines the supported ESET product versions, their display names, and the available update channels (production, deferred, pre-release). It also specifies the relative paths for update verification files. ```php ['name' => 'ESET NOD32 Endpoint 6', 'channels' => [ 'production' => ['file' => 'eset_upd/ep6.6/update.ver', 'dll' => 'eset_upd/ep6.6/dll/update.ver'], 'deferred' => ['file' => 'deferred/eset_upd/ep6.6/update.ver', 'dll' => 'deferred/eset_upd/ep6.6/dll/update.ver'], ]], 'ep8' => ['name' => 'ESET NOD32 Endpoint 7-8', /* production + deferred */ ], 'ep9' => ['name' => 'ESET NOD32 Endpoint 9', /* production + deferred + pre-release */ ], 'ep10' => ['name' => 'ESET NOD32 Endpoint 10-11', /* dll only, production + deferred + pre-release */ ], 'ep12' => ['name' => 'ESET NOD32 Endpoint 12', /* dll only */ ], 'v3' => ['name' => 'ESET NOD32 3-9', /* file only, production + deferred */ ], 'v10' => ['name' => 'ESET NOD32 10-13', /* file only, production + pre-release */ ], 'v16' => ['name' => 'ESET NOD32 14-19', /* dll only, production + pre-release */ ], ]; // Enable a version in nod32ms.conf: // [ESET.VERSIONS.ep9] // mirror = 1 // Resulting local file layout under www/ after a successful run: // www/eset_upd/ep9/production/update.ver // www/eset_upd/ep9/production/dll/update.ver // www/eset_upd/ep9/deferred/update.ver // www/ep9-XXXX/.nup ``` -------------------------------- ### Logging and Notification with Log Class Source: https://context7.com/marat2509/nod32-mirror/llms.txt Utilize the static `Log` class for configurable logging to files or stdout, with support for log rotation and levels 0-5. Use `write_log` for general entries, `informer` for update notifications (level 1+ triggers email), and `write_to_file` for raw data. Ensure `init()` is called before logging and `destruct()` at the end. ```php ``` -------------------------------- ### Download files and format data with Tools class Source: https://context7.com/marat2509/nod32-mirror/llms.txt Utilize the Tools class for various file and data manipulation tasks. It supports cURL downloads, archive extraction, human-readable formatting of byte sizes and durations, path joining, and parsing comma-separated lists. Ensure the unrar executable path is correct for archive extraction. ```php 'http://update.eset.com/eset_upd/ep9/update.ver', CURLOPT_USERPWD => 'EAV-0123456789:abcdefghij', CURLOPT_FILE => '/tmp/update.ver', CURLOPT_CONNECTTIMEOUT => 5, ], $headers); // $headers['http_code'] == 200 on success ``` ```php // Retrieve page content (RETURNTRANSFER) $html = Tools::download_file([ CURLOPT_URL => 'http://example.com', CURLOPT_RETURNTRANSFER => 1, CURLOPT_NOBODY => 0, ], $headers); ``` ```php // Extract a .rar archive (Linux/macOS uses system unrar) Tools::extract_file('/usr/bin/unrar', '/tmp/update.rar', '/tmp/'); ``` ```php // Human-readable byte sizes echo Tools::bytesToSize1024(157286400); // "150 MBytes" echo Tools::secondsToHumanReadable(3723); // "01:02:03" ``` ```php // Convert human size string to bytes $bytes = Tools::human2bytes('100K'); // 102400 ``` ```php // Cross-platform path join $path = Tools::ds('www', 'eset_upd', 'ep9', 'update.ver'); // "/app/www/eset_upd/ep9/update.ver" (OS-appropriate separator) ``` ```php // Parse comma-separated config string $mirrors = Tools::parse_comma_list('update.eset.com, um01.eset.com, um02.eset.com'); // ['update.eset.com', 'um01.eset.com', 'um02.eset.com'] ``` ```php // Compare two files by size (used to avoid redundant downloads) $same = Tools::compare_files(stat('/tmp/em000.nup'), ['size' => 10240]); ``` -------------------------------- ### Configuration Class Usage Source: https://context7.com/marat2509/nod32-mirror/llms.txt The static `Config` class parses the `nod32ms.conf` file and provides access to configuration settings. It can retrieve entire sections as associative arrays or specific version configurations. It also provides a method to build cURL options for outbound connections. ```php '1','platforms'=>'','channels'=>''] // Build cURL options array for outbound connections $curlOpts = Config::getConnectionInfo(); // Returns array with CURLOPT_CONNECTTIMEOUT, CURLOPT_PROXY, etc. ``` -------------------------------- ### Docker Compose for Nod32 Mirror Deployment Source: https://context7.com/marat2509/nod32-mirror/llms.txt This Docker Compose configuration sets up a two-container stack for Nod32 Mirror. It includes a PHP worker for downloading updates and an nginx server for serving them, sharing a volume for immediate access. ```yaml services: nod32-mirror-worker: image: marat2509/nod32-mirror:latest container_name: nod32-mirror-worker restart: unless-stopped volumes: - ./docker-data/www:/app/www - ./nod32ms.conf:/app/nod32ms.conf environment: - TZ=Europe/Moscow - MEMORY_LIMIT=128M - DOWNLOAD_THREADS=32 - USE_MULTIDOWNLOAD=1 - LINK_METHOD=hardlink - GENERATE_HTML=1 - GENERATE_JSON=1 - SHOW_LOGIN_PASSWORD=0 - LOG_TYPE=2 - LOG_LEVEL=4 - LOG_ROTATE=1 - LOG_ROTATE_SIZE=100K - LOG_ROTATE_QTY=5 - FIND_AUTO=1 - FIND_NUMBER_ATTEMPTS=5 - FIND_COUNT_KEYS=1 - FIND_REMOVE_INVALID_KEYS=1 - FIND_QUERY="nod32+username+password" - FIND_PAGEINDEX=1 - FIND_PAGE_QTY=5 - FIND_PATTERN="((EAV|TRIAL)-[0-9]{10}).+?([a-z0-9]{10})" - FIND_RECURSION_LEVEL=2 - FIND_ERRORS_QUANTITY=5 - ESET_MIRROR="update.eset.com, um01.eset.com, um02.eset.com" - ESET_PLATFORMS="" - ESET_CHANNELS="" - ESET_VERSIONS_EP6_MIRROR=1 - ESET_VERSIONS_EP9_MIRROR=1 - ESET_VERSIONS_EP9_PLATFORMS="WINDOWS_NT_X86, WINDOWS_NT_AMD64" - ESET_VERSIONS_EP9_CHANNELS="production, deferred" - ESET_VERSIONS_V10_MIRROR=1 nod32-mirror-nginx: image: nginx:alpine container_name: nod32-mirror-nginx restart: unless-stopped ports: - "80:80" volumes: - ./docker-data/www:/usr/share/nginx/html/nod32 - ./nginx.conf:/etc/nginx/conf.d/default.conf ``` -------------------------------- ### Configure Nod32 Mirror Worker Settings Source: https://context7.com/marat2509/nod32-mirror/llms.txt This INI-format configuration file controls the behavior of the Nod32 Mirror worker container. Adjust settings for language, memory limits, download methods, and output generation. ```ini [SCRIPT] language = "en" ; en, ru, ukr codepage = "utf-8" timezone = "Europe/Moscow" memory_limit = '32M' link_method = "hardlink" ; hardlink | symlink | copy generate_html = 1 ; write www/index.html status page generate_json = 1 ; write www/index.json metadata generate_only_table = 0 ; embed-only table (no full HTML wrapper) show_login_password = 0 ; expose credentials in HTML/JSON output filename_html = "index.html" filename_json = "index.json" html_codepage = "utf-8" debug_html = 0 ; dump parsed pages to debug/ dir debug_update = 0 ; keep timestamped update.ver snapshots [CONNECTION] use_multidownload = 0 ; 1 = parallel curl_multi downloads download_speed_limit = 0 ; bytes/s, 0 = unlimited download_threads = 32 timeout = 5 ; connection timeout in seconds proxy = 0 ; 1 = enable proxy type = 'http' ; http | socks4 | socks4a | socks5 server = 'proxy.example.com' port = 3128 user = 'username' password = 'pass' [MAILER] enable = 0 smtp = 0 host = "smtp.gmail.com" port = 587 auth = 0 secure = "tls" login = "login@gmail.com" password = "password" subject = "NOD32 script informer" sender = "sender@gmail.com" recipient = "receiver@gmail.com" log_level = 1 ; 0=disabled 1=errors+fail 2=success+errors 3=all days = 3 [LOG] type = 2 ; 0=off 1=file 2=stdout 3=file+stdout level = 4 ; 0-5 verbosity dir = "log" rotate = 1 rotate_size = "100K" rotate_qty = 5 [FIND] auto = 1 ; auto-search for ESET license keys online number_attempts = 5 system = "" ; blank = use all patterns in patterns/ dir count_keys = 1 remove_invalid_keys = 1 query = "nod32+username+password" pageindex = 1 page_qty = 5 pattern = "((EAV|TRIAL)-[0-9]{10}).+?([a-z0-9]{10})" recursion_level = 2 errors_quantity = 5 [ESET] mirror = "update.eset.com, um01.eset.com, um02.eset.com" [ESET.VERSIONS] platforms = "" ; global fallback – empty = all platforms channels = "" ; global fallback – empty = all channels ; Per-version blocks – mirror=1 enables that version [ESET.VERSIONS.ep6] mirror = 1 platforms = "" channels = "" [ESET.VERSIONS.ep9] mirror = 1 platforms = "WINDOWS_NT_X86, WINDOWS_NT_AMD64" channels = "production, deferred" [ESET.VERSIONS.v10] mirror = 1 platforms = "" channels = "" ``` -------------------------------- ### Nginx version routing configuration Source: https://context7.com/marat2509/nod32-mirror/llms.txt This nginx configuration uses `map` directives to route update requests based on User-Agent and X-ESET-Spread-Control headers. It determines the product version and channel, then rewrites the URL to the appropriate versioned path. Ensure the ESET client's update URL points to the correct mirror host. ```nginx # User-Agent examples: # "ESET Endpoint Antivirus Update BPC 9.1.2060.0 ..." → ver=ep9 # "ESET NOD32 Antivirus Update BPC 10.1.219.0 ..." → ver=v10 map $http_user_agent $ver { "~^.*(EEA|EES|EFSW|EMSX|ESFW)+\s+Update.*BPC\s+(\d+)\..*$" "ep$2"; "~^.*Update.*BPC\s+(\d+)\..*$" "v$1"; } ``` ```nginx # X-ESET-Spread-Control: domain=deferred → channel=deferred map $http_eset_spread_control $raw_channel { default production; "~domain=(?P[^;]+)" $d; } ``` ```nginx # ep6 does not support pre-release; override it to production map "$ver:$raw_channel" $channel { "ep6:pre-release" "production"; default $raw_channel; } ``` ```nginx # Rewrite rules route to www/eset_upd/{version}/{channel}/[dll/]update.ver # ep6 → eset_upd/ep6.6/$channel/[dll/]update.ver # ep7, ep8 → eset_upd/ep8/$channel/[dll/]update.ver # ep9 → eset_upd/ep9/$channel/[dll/]update.ver # ep10, ep11 → eset_upd/ep10/$channel/[dll/]update.ver (ep11 not in PHP) # ep12 → eset_upd/ep12/$channel/[dll/]update.ver # v3 – v9 → eset_upd/v3/$channel/update.ver # v10 – v13 → eset_upd/v10/$channel/update.ver # v14 – v18 → eset_upd/v16/$channel/dll/update.ver ``` -------------------------------- ### Nod32ms Class Usage Source: https://context7.com/marat2509/nod32-mirror/llms.txt The Nod32ms class acts as an orchestrator, triggering the entire mirror update process by iterating through enabled versions, managing license keys, and generating output files. ```APIDOC ## new Nod32ms() ### Description Instantiating the Nod32ms class automatically triggers a full mirror update cycle. This includes initializing mirrors for enabled versions, handling license key validation and discovery, downloading signatures, and generating HTML and JSON output files. ### Constructor `__construct()` ### Behavior - Initializes `Mirror` for each enabled version. - Reads and validates license keys. - Attempts to find license keys via web search if not found locally. - Calls `Mirror::download_signature()` if a valid key is available. - Generates `www/index.html` via `generate_html()`. - Generates `www/index.json` via `generate_json()`. ### Error Handling Exceptions during the process are caught and logged using `Log::write_log()`. ### Example ```php try { $nod32ms = new Nod32ms(); } catch (Exception $e) { Log::write_log($e->getMessage(), 0); } ``` ``` -------------------------------- ### Worker Entrypoint Script Source: https://context7.com/marat2509/nod32-mirror/llms.txt The worker's entrypoint script (`worker/entrypoint.sh`) runs the PHP update script in a loop. It calculates the sleep duration to ensure the total interval, including script execution time, matches the `UPDATE_INTERVAL` environment variable. Errors during script execution will cause the script to exit. ```sh #!/bin/sh # Requires /app/nod32ms.conf to be mounted UPDATE_INTERVAL=${UPDATE_INTERVAL:-3600} # default 1 hour while true; do start_time=$(date +%s) php /app/update.php # run the mirror update end_time=$(date +%s) duration=$((end_time - start_time)) sleep_time=$((UPDATE_INTERVAL - duration)) if [ "$sleep_time" -gt 0 ]; then sleep "$sleep_time" else echo "Warning: Script execution time ($duration s) exceeded UPDATE_INTERVAL." fi done # Exits with error if php update.php returns non-zero ``` -------------------------------- ### Log Class Methods Source: https://context7.com/marat2509/nod32-mirror/llms.txt The static Log class provides functionality for logging messages with different levels, managing log rotation, and optionally sending email notifications. ```APIDOC ## Log::init(): void ### Description Initializes the logging system by reading configuration from the `LOG` and `MAILER` sections of the `nod32ms.conf` file. ### Method `Log::init` ``` ```APIDOC ## Log::write_log(string $message, int $level, ?string $version_tag = null): void ### Description Writes a log entry with a specified message and log level. An optional version tag can be included for context. ### Method `Log::write_log` ### Parameters - **message** (string) - The log message to write. - **level** (int) - The log level (0-5), where 0 is for system messages and successful updates, and 5 is for full trace details. - **version_tag** (?string) - Optional. A tag representing the ESET product version (e.g., 'ep9'). ### Log Level Reference - 0: System messages + successful updates only - 1: + errors (triggers mailer) - 2: + warnings - 3: + update progress detail - 4: + file search/download detail - 5: full trace (method calls) ### Example ```php Log::write_log('Mirror started', 0); Log::write_log('Checking mirror update.eset.com', 3, 'ep9'); ``` ``` ```APIDOC ## Log::informer(string $message, string $version_tag, int $level): void ### Description Logs update or error notifications. These messages are also queued for sending via the mailer service, especially for error levels. ### Method `Log::informer` ### Parameters - **message** (string) - The notification message. - **version_tag** (string) - The ESET product version tag (e.g., 'ep9'). - **level** (int) - The severity level of the notification. Level 1 indicates an error and will trigger an email. ### Example ```php Log::informer('Database updated to 28500', 'ep9', 2); Log::informer('Database update failed!', 'ep9', 1); ``` ``` ```APIDOC ## Log::write_to_file(string $filepath, string $content): void ### Description Appends raw text content to a specified file. ### Method `Log::write_to_file` ### Parameters - **filepath** (string) - The path to the file where content will be appended. - **content** (string) - The raw text content to append. ### Example ```php Log::write_to_file('log/nod_keys.valid', "EAV-0123456789:abcdefghij:ep9\r\n"); ``` ``` ```APIDOC ## Log::destruct(): void ### Description Finalizes logging operations, sends any queued mailer summaries, and flushes log buffers. This should be called at the end of the script execution. ### Method `Log::destruct` ``` -------------------------------- ### Parse INI-like files and HTML with Parser class Source: https://context7.com/marat2509/nod32-mirror/llms.txt Use the Parser class to extract specific data from update files and HTML content. It supports parsing tag=value lines, key triplets, and extracting data using regex templates. Ensure the file exists before calling delete_parse_line_in_file. ```php