Add MaxMind geoipupdate and upload fallback
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
A modern web hosting control panel for WordPress and general PHP hosting. Built with Laravel 12, Filament v5, Livewire 4, and Tailwind CSS v4.
|
A modern web hosting control panel for WordPress and general PHP hosting. Built with Laravel 12, Filament v5, Livewire 4, and Tailwind CSS v4.
|
||||||
|
|
||||||
Version: 0.9-rc20 (release candidate)
|
Version: 0.9-rc21 (release candidate)
|
||||||
|
|
||||||
This is a release candidate. Expect rapid iteration and breaking changes until 1.0.
|
This is a release candidate. Expect rapid iteration and breaking changes until 1.0.
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ use App\Services\Agent\AgentClient;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use Filament\Actions\Action;
|
use Filament\Actions\Action;
|
||||||
use Filament\Actions\CreateAction;
|
use Filament\Actions\CreateAction;
|
||||||
|
use Filament\Forms\Components\FileUpload;
|
||||||
use Filament\Forms\Components\TextInput;
|
use Filament\Forms\Components\TextInput;
|
||||||
use Filament\Notifications\Notification;
|
use Filament\Notifications\Notification;
|
||||||
use Filament\Resources\Pages\ListRecords;
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class ListGeoBlockRules extends ListRecords
|
class ListGeoBlockRules extends ListRecords
|
||||||
{
|
{
|
||||||
@@ -75,6 +77,64 @@ class ListGeoBlockRules extends ListRecords
|
|||||||
->send();
|
->send();
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
Action::make('uploadGeoIpDatabase')
|
||||||
|
->label(__('Upload GeoIP Database'))
|
||||||
|
->icon('heroicon-o-arrow-up-tray')
|
||||||
|
->form([
|
||||||
|
FileUpload::make('mmdb_file')
|
||||||
|
->label(__('GeoIP .mmdb File'))
|
||||||
|
->required()
|
||||||
|
->acceptedFileTypes(['application/octet-stream', 'application/x-maxmind-db'])
|
||||||
|
->helperText(__('Upload a MaxMind GeoIP .mmdb file (GeoLite2 or GeoIP2).')),
|
||||||
|
TextInput::make('edition')
|
||||||
|
->label(__('Edition ID'))
|
||||||
|
->helperText(__('Example: GeoLite2-Country'))
|
||||||
|
->default(fn (): string => (string) (DnsSetting::get('geoip_edition_ids') ?? 'GeoLite2-Country')),
|
||||||
|
])
|
||||||
|
->action(function (array $data): void {
|
||||||
|
if (empty($data['mmdb_file'])) {
|
||||||
|
Notification::make()
|
||||||
|
->title(__('No file uploaded'))
|
||||||
|
->danger()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$edition = trim((string) ($data['edition'] ?? 'GeoLite2-Country'));
|
||||||
|
if ($edition === '') {
|
||||||
|
$edition = 'GeoLite2-Country';
|
||||||
|
}
|
||||||
|
|
||||||
|
$filePath = Storage::disk('local')->path($data['mmdb_file']);
|
||||||
|
if (! file_exists($filePath)) {
|
||||||
|
Notification::make()
|
||||||
|
->title(__('Uploaded file not found'))
|
||||||
|
->danger()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = base64_encode((string) file_get_contents($filePath));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$agent = new AgentClient;
|
||||||
|
$result = $agent->geoUploadDatabase($edition, $content);
|
||||||
|
|
||||||
|
Notification::make()
|
||||||
|
->title(__('GeoIP database uploaded'))
|
||||||
|
->body($result['path'] ?? null)
|
||||||
|
->success()
|
||||||
|
->send();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Notification::make()
|
||||||
|
->title(__('GeoIP upload failed'))
|
||||||
|
->body($e->getMessage())
|
||||||
|
->danger()
|
||||||
|
->send();
|
||||||
|
}
|
||||||
|
}),
|
||||||
CreateAction::make(),
|
CreateAction::make(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1359,6 +1359,14 @@ class AgentClient
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function geoUploadDatabase(string $edition, string $content): array
|
||||||
|
{
|
||||||
|
return $this->send('geo.upload_database', [
|
||||||
|
'edition' => $edition,
|
||||||
|
'content' => $content,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function databasePersistTuning(string $name, string $value): array
|
public function databasePersistTuning(string $name, string $value): array
|
||||||
{
|
{
|
||||||
return $this->send('database.persist_tuning', [
|
return $this->send('database.persist_tuning', [
|
||||||
|
|||||||
148
bin/jabali-agent
148
bin/jabali-agent
@@ -548,6 +548,7 @@ function handleAction(array $request): array
|
|||||||
'waf.apply' => wafApplySettings($params),
|
'waf.apply' => wafApplySettings($params),
|
||||||
'geo.apply_rules' => geoApplyRules($params),
|
'geo.apply_rules' => geoApplyRules($params),
|
||||||
'geo.update_database' => geoUpdateDatabase($params),
|
'geo.update_database' => geoUpdateDatabase($params),
|
||||||
|
'geo.upload_database' => geoUploadDatabase($params),
|
||||||
'database.persist_tuning' => databasePersistTuning($params),
|
'database.persist_tuning' => databasePersistTuning($params),
|
||||||
'database.get_variables' => databaseGetVariables($params),
|
'database.get_variables' => databaseGetVariables($params),
|
||||||
'database.set_global' => databaseSetGlobal($params),
|
'database.set_global' => databaseSetGlobal($params),
|
||||||
@@ -2926,8 +2927,9 @@ function geoUpdateDatabase(array $params): array
|
|||||||
$editionIdsRaw = $params['edition_ids'] ?? 'GeoLite2-Country';
|
$editionIdsRaw = $params['edition_ids'] ?? 'GeoLite2-Country';
|
||||||
$useExisting = !empty($params['use_existing']);
|
$useExisting = !empty($params['use_existing']);
|
||||||
|
|
||||||
if (!toolExists('geoipupdate')) {
|
$toolError = ensureGeoIpUpdateTool();
|
||||||
return ['success' => false, 'error' => 'geoipupdate is not installed'];
|
if ($toolError !== null) {
|
||||||
|
return ['success' => false, 'error' => $toolError];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$useExisting && ($accountId === '' || $licenseKey === '')) {
|
if (!$useExisting && ($accountId === '' || $licenseKey === '')) {
|
||||||
@@ -3002,6 +3004,148 @@ function geoUpdateDatabase(array $params): array
|
|||||||
return ['success' => false, 'error' => 'GeoIP database not found after update'];
|
return ['success' => false, 'error' => 'GeoIP database not found after update'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function geoUploadDatabase(array $params): array
|
||||||
|
{
|
||||||
|
$edition = trim((string) ($params['edition'] ?? 'GeoLite2-Country'));
|
||||||
|
$content = (string) ($params['content'] ?? '');
|
||||||
|
|
||||||
|
if ($content === '') {
|
||||||
|
return ['success' => false, 'error' => 'No database content provided'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match('/^[A-Za-z0-9._-]+$/', $edition)) {
|
||||||
|
return ['success' => false, 'error' => 'Invalid edition name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = base64_decode($content, true);
|
||||||
|
if ($decoded === false) {
|
||||||
|
return ['success' => false, 'error' => 'Invalid database content'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$targetDir = '/usr/share/GeoIP';
|
||||||
|
if (!is_dir($targetDir)) {
|
||||||
|
@mkdir($targetDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$target = $targetDir . '/' . $edition . '.mmdb';
|
||||||
|
if (file_put_contents($target, $decoded) === false) {
|
||||||
|
return ['success' => false, 'error' => 'Failed to write GeoIP database'];
|
||||||
|
}
|
||||||
|
|
||||||
|
@chmod($target, 0644);
|
||||||
|
|
||||||
|
return ['success' => true, 'path' => $target];
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureGeoIpUpdateTool(): ?string
|
||||||
|
{
|
||||||
|
if (toolExists('geoipupdate')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$error = installGeoIpUpdateBinary();
|
||||||
|
if ($error !== null) {
|
||||||
|
return $error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!toolExists('geoipupdate')) {
|
||||||
|
return 'geoipupdate is not installed';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function installGeoIpUpdateBinary(): ?string
|
||||||
|
{
|
||||||
|
$arch = php_uname('m');
|
||||||
|
$archMap = [
|
||||||
|
'x86_64' => 'amd64',
|
||||||
|
'amd64' => 'amd64',
|
||||||
|
'aarch64' => 'arm64',
|
||||||
|
'arm64' => 'arm64',
|
||||||
|
];
|
||||||
|
$archToken = $archMap[$arch] ?? $arch;
|
||||||
|
|
||||||
|
$apiUrl = 'https://api.github.com/repos/maxmind/geoipupdate/releases/latest';
|
||||||
|
$metadata = @shell_exec('curl -fsSL ' . escapeshellarg($apiUrl) . ' 2>/dev/null');
|
||||||
|
if (!$metadata) {
|
||||||
|
$metadata = @shell_exec('wget -qO- ' . escapeshellarg($apiUrl) . ' 2>/dev/null');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$metadata) {
|
||||||
|
return 'Failed to download geoipupdate release metadata';
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = json_decode($metadata, true);
|
||||||
|
if (!is_array($data)) {
|
||||||
|
return 'Invalid geoipupdate release metadata';
|
||||||
|
}
|
||||||
|
|
||||||
|
$downloadUrl = null;
|
||||||
|
foreach (($data['assets'] ?? []) as $asset) {
|
||||||
|
$name = strtolower((string) ($asset['name'] ?? ''));
|
||||||
|
$url = (string) ($asset['browser_download_url'] ?? '');
|
||||||
|
if ($name === '' || $url === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strpos($name, 'linux') === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strpos($name, $archToken) === false) {
|
||||||
|
if (!($archToken === 'amd64' && strpos($name, 'x86_64') !== false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!str_ends_with($name, '.tar.gz') && !str_ends_with($name, '.tgz')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$downloadUrl = $url;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$downloadUrl) {
|
||||||
|
return 'No suitable geoipupdate binary found for ' . $arch;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmpDir = sys_get_temp_dir() . '/jabali-geoipupdate-' . bin2hex(random_bytes(4));
|
||||||
|
@mkdir($tmpDir, 0755, true);
|
||||||
|
$archive = $tmpDir . '/geoipupdate.tgz';
|
||||||
|
|
||||||
|
$downloadCmd = toolExists('curl')
|
||||||
|
? 'curl -fsSL ' . escapeshellarg($downloadUrl) . ' -o ' . escapeshellarg($archive)
|
||||||
|
: 'wget -qO ' . escapeshellarg($archive) . ' ' . escapeshellarg($downloadUrl);
|
||||||
|
|
||||||
|
exec($downloadCmd . ' 2>&1', $output, $code);
|
||||||
|
if ($code !== 0) {
|
||||||
|
return 'Failed to download geoipupdate binary';
|
||||||
|
}
|
||||||
|
|
||||||
|
exec('tar -xzf ' . escapeshellarg($archive) . ' -C ' . escapeshellarg($tmpDir) . ' 2>&1', $output, $code);
|
||||||
|
if ($code !== 0) {
|
||||||
|
return 'Failed to extract geoipupdate archive';
|
||||||
|
}
|
||||||
|
|
||||||
|
$binary = null;
|
||||||
|
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($tmpDir, FilesystemIterator::SKIP_DOTS));
|
||||||
|
foreach ($iterator as $file) {
|
||||||
|
if ($file->isFile() && $file->getFilename() === 'geoipupdate') {
|
||||||
|
$binary = $file->getPathname();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$binary) {
|
||||||
|
return 'geoipupdate binary not found in archive';
|
||||||
|
}
|
||||||
|
|
||||||
|
exec('install -m 0755 ' . escapeshellarg($binary) . ' /usr/local/bin/geoipupdate 2>&1', $output, $code);
|
||||||
|
if ($code !== 0) {
|
||||||
|
return 'Failed to install geoipupdate';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function ensureGeoIpModuleEnabled(): ?string
|
function ensureGeoIpModuleEnabled(): ?string
|
||||||
{
|
{
|
||||||
$modulePaths = [
|
$modulePaths = [
|
||||||
|
|||||||
71
install.sh
71
install.sh
@@ -12,7 +12,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Version - will be read from VERSION file after clone, this is fallback
|
# Version - will be read from VERSION file after clone, this is fallback
|
||||||
JABALI_VERSION="0.9-rc20"
|
JABALI_VERSION="0.9-rc21"
|
||||||
|
|
||||||
# Colors
|
# Colors
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
@@ -720,6 +720,74 @@ install_packages() {
|
|||||||
log "System packages installed"
|
log "System packages installed"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_geoipupdate_binary() {
|
||||||
|
if command -v geoipupdate &>/dev/null; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
info "geoipupdate not found, installing from MaxMind releases..."
|
||||||
|
|
||||||
|
local arch
|
||||||
|
arch="$(uname -m)"
|
||||||
|
local arch_token="$arch"
|
||||||
|
if [[ "$arch" == "x86_64" ]]; then
|
||||||
|
arch_token="amd64"
|
||||||
|
elif [[ "$arch" == "aarch64" || "$arch" == "arm64" ]]; then
|
||||||
|
arch_token="arm64"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local api_url="https://api.github.com/repos/maxmind/geoipupdate/releases/latest"
|
||||||
|
local metadata
|
||||||
|
metadata=$(curl -fsSL "$api_url" 2>/dev/null || true)
|
||||||
|
if [[ -z "$metadata" ]]; then
|
||||||
|
metadata=$(wget -qO- "$api_url" 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$metadata" ]]; then
|
||||||
|
warn "Failed to download geoipupdate release metadata"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local download_url
|
||||||
|
download_url=$(echo "$metadata" | grep -Eo "https://[^\"]+${arch_token}[^\"]+\\.tar\\.gz" | head -n1)
|
||||||
|
if [[ -z "$download_url" && "$arch_token" == "amd64" ]]; then
|
||||||
|
download_url=$(echo "$metadata" | grep -Eo "https://[^\"]+x86_64[^\"]+\\.tar\\.gz" | head -n1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$download_url" ]]; then
|
||||||
|
warn "No suitable geoipupdate binary found for ${arch}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local tmp_dir
|
||||||
|
tmp_dir=$(mktemp -d)
|
||||||
|
local archive="${tmp_dir}/geoipupdate.tgz"
|
||||||
|
|
||||||
|
if command -v curl &>/dev/null; then
|
||||||
|
curl -fsSL "$download_url" -o "$archive" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
wget -qO "$archive" "$download_url" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -s "$archive" ]]; then
|
||||||
|
warn "Failed to download geoipupdate binary"
|
||||||
|
rm -rf "$tmp_dir"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
tar -xzf "$archive" -C "$tmp_dir" 2>/dev/null || true
|
||||||
|
local binary
|
||||||
|
binary=$(find "$tmp_dir" -type f -name geoipupdate | head -n1)
|
||||||
|
if [[ -z "$binary" ]]; then
|
||||||
|
warn "geoipupdate binary not found in archive"
|
||||||
|
rm -rf "$tmp_dir"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
install -m 0755 "$binary" /usr/local/bin/geoipupdate 2>/dev/null || true
|
||||||
|
rm -rf "$tmp_dir"
|
||||||
|
}
|
||||||
|
|
||||||
# Install Composer
|
# Install Composer
|
||||||
install_composer() {
|
install_composer() {
|
||||||
header "Installing Composer"
|
header "Installing Composer"
|
||||||
@@ -3248,6 +3316,7 @@ main() {
|
|||||||
|
|
||||||
add_repositories
|
add_repositories
|
||||||
install_packages
|
install_packages
|
||||||
|
install_geoipupdate_binary
|
||||||
install_composer
|
install_composer
|
||||||
clone_jabali
|
clone_jabali
|
||||||
configure_php
|
configure_php
|
||||||
|
|||||||
Reference in New Issue
Block a user