diff --git a/README.md b/README.md index 2c7001be8..7f8e4348e 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,30 @@ Docker Vichan comes with a Dockerfile and docker-compose configuration, the latter aimed primarily at development and testing. See the `docker/doc.md` file for more information. +MaxMind support +------------ +We use MaxMind to retrieve flags for posts. Previously, the country database was stored in `inc/lib/geoip`, but updating it in that location became unmanageable. Now, a MaxMind account is required to download the country database. + +### How to Set It Up + +1. Follow these instructions to create a free account for using GeoLite2: + [Create an Account on MaxMind](https://support.maxmind.com/hc/en-us/articles/4407099783707-Create-an-Account#h_01G4G4NV169TJWFCJ1KGFAM1CD) + +2. Download the database using maxmind website + +3. (Optional) Install `geoipupdate` to download the database using CLI: + [GeoIP Update Installation Guide](https://github.com/maxmind/geoipupdate) + + 1. Edit the `/etc/GeoIP.conf` file to add your API key. + 2. Run `geoipupdate` + +5. Update path in `$config['maxmind']['db_path']` + +6. (Optional) Set up a cron job to automatically update the database: + ``` + 0 0 * * 2,5 geoipupdate + ``` + vichan API ---------- vichan provides by default a 4chan-compatible JSON API. For documentation on this, see: diff --git a/composer.json b/composer.json index 4d020047d..4661b165e 100644 --- a/composer.json +++ b/composer.json @@ -17,9 +17,9 @@ "lifo/ip": "^1.0", "gettext/gettext": "^5.5", "mrclay/minify": "^2.1.6", - "geoip/geoip": "^1.17", "dapphp/securimage": "^4.0", - "erusev/parsedown": "^1.7.4" + "erusev/parsedown": "^1.7.4", + "geoip2/geoip2": "^2.13" }, "autoload": { "classmap": ["inc/"], @@ -39,6 +39,7 @@ "inc/functions/net.php", "inc/functions/num.php", "inc/functions/theme.php", + "inc/functions/ip.php", "inc/context.php" ] }, diff --git a/composer.lock b/composer.lock index 742c3cfce..77f01bbcf 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,84 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "72e79f203581eea6e6b0455147b25878", + "content-hash": "5fc42e63c61b5d69693a300f026d7d58", "packages": [ + { + "name": "composer/ca-bundle", + "version": "1.5.3", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "3b1fc3f0be055baa7c6258b1467849c3e8204eb2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/3b1fc3f0be055baa7c6258b1467849c3e8204eb2", + "reference": "3b1fc3f0be055baa7c6258b1467849c3e8204eb2", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8 || ^9", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.5.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-04T10:15:26+00:00" + }, { "name": "dapphp/securimage", "version": "4.0.2", @@ -64,58 +140,112 @@ "time": "2020-05-30T10:05:48+00:00" }, { - "name": "geoip/geoip", - "version": "v1.17", + "name": "erusev/parsedown", + "version": "1.7.4", "source": { "type": "git", - "url": "https://github.com/maxmind/geoip-api-php.git", - "reference": "2053a85c2ed3e7adcbaf0117e26832f57366e370" + "url": "https://github.com/erusev/parsedown.git", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/geoip-api-php/zipball/2053a85c2ed3e7adcbaf0117e26832f57366e370", - "reference": "2053a85c2ed3e7adcbaf0117e26832f57366e370", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", "shasum": "" }, - "conflict": { - "ext-geoip": "*" + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" }, "require-dev": { - "phpunit/phpunit": "3.7.*", - "satooshi/php-coveralls": "1.0.*" + "phpunit/phpunit": "^4.8.35" }, "type": "library", "autoload": { - "files": [ - "src/geoip.inc", - "src/geoipcity.inc", - "src/timezone.php" - ] + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "support": { + "issues": "https://github.com/erusev/parsedown/issues", + "source": "https://github.com/erusev/parsedown/tree/1.7.x" + }, + "time": "2019-12-30T22:54:17+00:00" + }, + { + "name": "geoip2/geoip2", + "version": "v2.13.0", + "source": { + "type": "git", + "url": "https://github.com/maxmind/GeoIP2-php.git", + "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/6a41d8fbd6b90052bc34dff3b4252d0f88067b23", + "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23", + "shasum": "" + }, + "require": { + "ext-json": "*", + "maxmind-db/reader": "~1.8", + "maxmind/web-service-common": "~0.8", + "php": ">=7.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^8.0 || ^9.0", + "squizlabs/php_codesniffer": "3.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "GeoIp2\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL 2.1+" + "Apache-2.0" ], "authors": [ { - "name": "MaxMind, Inc.", - "email": "support@maxmind.com", - "homepage": "http://www.maxmind.com/" + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "https://www.maxmind.com/" } ], - "description": "MaxMind GeoIP PHP API", - "homepage": "http://dev.maxmind.com/geoip/legacy/downloadable", + "description": "MaxMind GeoIP2 PHP API", + "homepage": "https://github.com/maxmind/GeoIP2-php", "keywords": [ + "IP", "geoip", + "geoip2", "geolocation", "maxmind" ], "support": { - "issues": "https://github.com/maxmind/geoip-api-php/issues", - "source": "https://github.com/maxmind/geoip-api-php/tree/master" + "issues": "https://github.com/maxmind/GeoIP2-php/issues", + "source": "https://github.com/maxmind/GeoIP2-php/tree/v2.13.0" }, - "abandoned": "geoip2/geoip2", - "time": "2016-05-16T19:06:50+00:00" + "time": "2022-08-05T20:32:58+00:00" }, { "name": "gettext/gettext", @@ -312,6 +442,122 @@ }, "time": "2022-07-12T15:45:54+00:00" }, + { + "name": "maxmind-db/reader", + "version": "v1.11.1", + "source": { + "type": "git", + "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git", + "reference": "1e66f73ffcf25e17c7a910a1317e9720a95497c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/1e66f73ffcf25e17c7a910a1317e9720a95497c7", + "reference": "1e66f73ffcf25e17c7a910a1317e9720a95497c7", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "conflict": { + "ext-maxminddb": "<1.11.1,>=2.0.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "php-coveralls/php-coveralls": "^2.1", + "phpstan/phpstan": "*", + "phpunit/phpcov": ">=6.0.0", + "phpunit/phpunit": ">=8.0.0,<10.0.0", + "squizlabs/php_codesniffer": "3.*" + }, + "suggest": { + "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups" + }, + "type": "library", + "autoload": { + "psr-4": { + "MaxMind\\Db\\": "src/MaxMind/Db" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "https://www.maxmind.com/" + } + ], + "description": "MaxMind DB Reader API", + "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php", + "keywords": [ + "database", + "geoip", + "geoip2", + "geolocation", + "maxmind" + ], + "support": { + "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues", + "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.11.1" + }, + "time": "2023-12-02T00:09:23+00:00" + }, + { + "name": "maxmind/web-service-common", + "version": "v0.9.0", + "source": { + "type": "git", + "url": "https://github.com/maxmind/web-service-common-php.git", + "reference": "4dc5a3e8df38aea4ca3b1096cee3a038094e9b53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/4dc5a3e8df38aea4ca3b1096cee3a038094e9b53", + "reference": "4dc5a3e8df38aea4ca3b1096cee3a038094e9b53", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0.3", + "ext-curl": "*", + "ext-json": "*", + "php": ">=7.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^8.0 || ^9.0", + "squizlabs/php_codesniffer": "3.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "MaxMind\\Exception\\": "src/Exception", + "MaxMind\\WebService\\": "src/WebService" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory Oschwald", + "email": "goschwald@maxmind.com" + } + ], + "description": "Internal MaxMind Web Service API", + "homepage": "https://github.com/maxmind/web-service-common-php", + "support": { + "issues": "https://github.com/maxmind/web-service-common-php/issues", + "source": "https://github.com/maxmind/web-service-common-php/tree/v0.9.0" + }, + "time": "2022-03-28T17:43:20+00:00" + }, { "name": "mrclay/minify", "version": "2.3.3", @@ -748,10 +994,14 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "ext-mbstring": ">=5.4", - "ext-gd": ">=5.4", - "ext-pdo": ">=5.4" + "php": ">=7.4", + "ext-mbstring": ">=7.4", + "ext-gd": ">=7.4", + "ext-pdo": ">=7.4" }, "platform-dev": [], + "platform-overrides": { + "php": "7.4" + }, "plugin-api-version": "2.3.0" } diff --git a/inc/config.php b/inc/config.php index c111b7623..454cae4f7 100644 --- a/inc/config.php +++ b/inc/config.php @@ -699,6 +699,19 @@ // Attach country flags to posts. $config['country_flags'] = false; + // Maxmind configuration for country_flags + $config['maxmind'] = [ + // Path to the MaxMind GeoLite2 City database file used for IP geolocation. + 'db_path' => '/usr/share/GeoIP/GeoLite2-City.mmdb', + // Array of preferred locales to use when fetching location data. + // The first locale in the array will be prioritized. + 'locale' => ['en'], + // Default country name to use if no geolocation data is found for the IP address. + 'country_fallback' => 'Unknown', + // Default country code to use if no geolocation data is found. + 'code_fallback' => 'xx', + ]; + // Allow the user to decide whether or not he wants to display his country $config['allow_no_country'] = false; diff --git a/inc/functions/ip.php b/inc/functions/ip.php new file mode 100644 index 000000000..0b2f1a5c8 --- /dev/null +++ b/inc/functions/ip.php @@ -0,0 +1,28 @@ +city($ip); + $countryCode = strtolower($record->country->isoCode); + } catch (Exception $e) { + return [ + $config['maxmind']['code_fallback'], + $config['maxmind']['country_fallback'], + ]; + } + + $countryName = $record->country->name; + + if (empty($countryName)) { + $countryName = $config['maxmind']['country_fallback']; + $countryCode = $config['maxmind']['code_fallback']; + } + + return [$countryCode, $countryName]; +} \ No newline at end of file diff --git a/inc/lib/geoip/GeoIPv6.dat b/inc/lib/geoip/GeoIPv6.dat deleted file mode 100644 index c2f3f11bf..000000000 Binary files a/inc/lib/geoip/GeoIPv6.dat and /dev/null differ diff --git a/post.php b/post.php index 644be70d4..62b929d10 100644 --- a/post.php +++ b/post.php @@ -8,7 +8,7 @@ use Vichan\{Context, WebDependencyFactory}; use Vichan\Data\Driver\{LogDriver, HttpDriver}; use Vichan\Service\{RemoteCaptchaQuery, SecureImageCaptchaQuery}; -use Vichan\Functions\Format; +use Vichan\Functions\{Format, IP}; /** * Utility functions @@ -976,25 +976,11 @@ function delete_cyclical_posts(string $boardUri, int $threadId, int $cycleLimit) if (!$dropped_post) if (($config['country_flags'] && !$config['allow_no_country']) || ($config['country_flags'] && $config['allow_no_country'] && !isset($_POST['no_country']))) { - $gi=geoip_open('inc/lib/geoip/GeoIPv6.dat', GEOIP_STANDARD); - function ipv4to6($ip) { - if (strpos($ip, ':') !== false) { - if (strpos($ip, '.') > 0) - $ip = substr($ip, strrpos($ip, ':')+1); - else return $ip; //native ipv6 - } - $iparr = array_pad(explode('.', $ip), 4, 0); - $part7 = base_convert(($iparr[0] * 256) + $iparr[1], 10, 16); - $part8 = base_convert(($iparr[2] * 256) + $iparr[3], 10, 16); - return '::ffff:'.$part7.':'.$part8; - } + list($flagCode, $flagName) = IP\fetch_maxmind($_SERVER['REMOTE_ADDR']); - if ($country_code = geoip_country_code_by_addr_v6($gi, ipv4to6($_SERVER['REMOTE_ADDR']))) { - if (!in_array(strtolower($country_code), array('eu', 'ap', 'o1', 'a1', 'a2'))) - $post['body'] .= "\n".strtolower($country_code)."". - "\n".geoip_country_name_by_addr_v6($gi, ipv4to6($_SERVER['REMOTE_ADDR'])).""; - } + $post['body'] .= "\n".strtolower($flagCode)."". + "\n".$flagName.""; } if ($config['user_flag'] && isset($_POST['user_flag']) && !empty($_POST['user_flag'])) {