Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replaced the old IP address database #1929

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/config-sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,16 @@
*/
'rate_limit_whitelist' => [],
],

/**
* Use these options to override the default IP address database that FOSSBilling includes which are free of licensing and also includes ASN data rather than just country data, however it does so at a loss to accuracy.
* `custom_path` will define the local path to reference when loading the database.
* `custom_url` can be set to have FOSSBilling update a database of your choosing from the provided URL once daily.
* `included` defines what data types are included in that database. For example, the default ones for FOSSBilling would be ['country', 'asn']. This isn't strictly needed, but may be used by modules to enable / disable functionality.
*/
'ip_database' => [
'custom_path' => '',
'custom_url' => '',
'included_data' => [],
]
];
8 changes: 5 additions & 3 deletions src/di.php
Original file line number Diff line number Diff line change
Expand Up @@ -765,11 +765,13 @@
};

/*
* @param void
*
* @return \GeoIp2\Database\Reader
* @deprecated You should instead invoke the IPDatabase class directly.
*/
$di['geoip'] = fn () => new GeoIp2\Database\Reader(PATH_LIBRARY . '/GeoLite2-Country.mmdb');
$di['geoip'] = function () {
error_log("Deprecated 'geoip' function called from the DI");
return FOSSBilling\IPDatabase::getReader();
};

/*
* @param void
Expand Down
129 changes: 129 additions & 0 deletions src/library/FOSSBilling/IPDatabase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php

declare(strict_types=1);
/**
* Copyright 2022-2023 FOSSBilling
* Copyright 2011-2021 BoxBilling, Inc.
* SPDX-License-Identifier: Apache-2.0
*
* @copyright FOSSBilling (https://www.fossbilling.org)
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache-2.0
*/

namespace FOSSBilling;

use GeoIp2\Database\Reader;
use Symfony\Component\Filesystem\Path;
use Symfony\Component\HttpClient\HttpClient;

final class IPDatabase
{
/**
* FOSSBilling uses databases that are licensed under the public domain (CC0 and PDDL).
* This is done to ensure that we have good enough data out of the box that's updated regularly and that can be used without a concern of licensing issues.
* @see https://github.com/HostByBelle/IP-Geolocation-DB for the database sources
*/
public const defaultSource = 'https://github.com/HostByBelle/IP-Geolocation-DB/releases/latest/download/cc0-pddl-country-asn-both-variant-1.mmdb';
public const defaultDBPath = PATH_LIBRARY . DIRECTORY_SEPARATOR . 'ipDB.mmdb';
public const customDBDownloadedPath = PATH_LIBRARY . DIRECTORY_SEPARATOR . 'customIpDB.mmdb';

/**
* Creates a new instance of the GeoIP2 reader, selecting either our default DB or the custom one as set by the system admin
*/
public static function getReader(): Reader
{
return new Reader(self::getPath());
}

/**
* Updates the currently in use DB
*/
public static function update()
{
$custom_path = Config::getProperty('ip_database.custom_path', '');
if (!empty($custom_path)) {
return;
}

$localDb = self::getPath(false, true);
if (file_exists($localDb)) {
$dbAge = time() - filemtime($localDb);
} else {
$dbAge = 86400;
}

if ($dbAge >= 86400) {
self::performUpdate($localDb, self::getDownloadUrl());
return;
}
}

/**
* Returns an array containing what type of data is included in a given IP DB.
* Relies on the user to correctly set this information for DBs they provide on their own.
*
* @return array
*/
public static function whatIsIncluded(): array
{
$custom_path = Config::getProperty('ip_database.custom_path', '');
$custom_url = Config::getProperty('ip_database.custom_url', '');

if (!empty($custom_path) && !empty($custom_url)) {
return ['country', 'asn'];
} else {
return Config::getProperty('ip_database.included_data', []);
}
}

/**
* Returns the correct path for the actively used database.
*
* @param bool $default set to true to only have the default DB paths returned
* @param bool $skipUpdate set to true to have the system skip trying to call our updater do download the DB if it doesn't exist
*/
public static function getPath(bool $default = false, bool $skipUpdate = false): string
{
$custom_path = Config::getProperty('ip_database.custom_path', '');
$custom_url = Config::getProperty('ip_database.custom_url', '');

if (!empty($custom_url) && empty($custom_path) && !$default) {
$path = self::customDBDownloadedPath;
} else if (!empty($custom_path) && !$default) {
$path = Path::canonicalize($custom_path);
$skipUpdate = true;
} else {
$path = self::defaultDBPath;
}

if (!file_exists(self::customDBDownloadedPath) && !$skipUpdate) {
self::update();
}

return $path;
}
public static function getDownloadUrl(bool $default = false)
{
$custom_url = Config::getProperty('ip_database.custom_url', '');
if (!$default && !empty($custom_url)) {
return $custom_url;
} else {
return self::defaultSource;
}
}

private static function performUpdate(string $path, string $url)
{
try {
$httpClient = HttpClient::create();
$response = $httpClient->request('GET', $url);
if ($response->getStatusCode() === 200) {
file_put_contents($path, $response->getContent());
} else {
error_log("Got a " . $response->getStatusCode() . ' status code when attempting to download ' . $url);
}
} catch (\Exception $e) {
error_log("There was an error while updating the IP address database: " . $e->getMessage());
}
}
}
6 changes: 6 additions & 0 deletions src/library/FOSSBilling/UpdatePatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ public function applyConfigPatches(): void
$newConfig['info']['instance_id'] ??= Uuid::uuid4()->toString();
$newConfig['info']['salt'] ??= $newConfig['salt'];

$newConfig['ip_database'] ??= [
'custom_path' => '',
'custom_url' => '',
'included_data' => [],
];

// Remove depreciated config keys/subkeys.
$depreciatedConfigKeys = ['guzzle', 'locale', 'locale_date_format', 'locale_time_format', 'timezone', 'sef_urls', 'salt', 'path_logs', 'log_to_db'];
$depreciatedConfigSubkeys = [
Expand Down
Binary file removed src/library/GeoLite2-Country.mmdb
Binary file not shown.
3 changes: 3 additions & 0 deletions src/modules/System/Service.php
Original file line number Diff line number Diff line change
Expand Up @@ -1713,6 +1713,9 @@ public static function onBeforeAdminCronRun(\Box_Event $event)
if ($cache->prune()) {
$di['logger']->setChannel('cron')->info('Pruned the filesystem cache');
}

// Update the IP address database
\FOSSBilling\IPDatabase::update();
} catch (\Exception $e) {
error_log($e->getMessage());
}
Expand Down