diff --git a/.env.example b/.env.example index 970b9d8..3c35daf 100644 --- a/.env.example +++ b/.env.example @@ -15,6 +15,8 @@ DB_DATABASE=online.tbbank.gov.tm DB_USERNAME=root DB_PASSWORD= +MAXMIND_LICENSE_KEY= + BROADCAST_DRIVER=log CACHE_DRIVER=file FILESYSTEM_DISK=local diff --git a/app/Events/EventType.php b/app/Events/EventType.php index 7ea5698..b23fb4f 100644 --- a/app/Events/EventType.php +++ b/app/Events/EventType.php @@ -54,7 +54,7 @@ class EventType return [ 'Illuminate\\Auth\\Events\\Attempting' => self::ATTEMPTING, 'Illuminate\\Auth\\Events\\Failed' => self::FAILED, - 'Illuminate\Auth\Events\Lockout' => self::LOCKOUT, + 'Illuminate\\Auth\\Events\\Lockout' => self::LOCKOUT, ]; } @@ -87,4 +87,22 @@ class EventType return self::laravelDefaultEvents()[$event] ?? ''; } + + /** + * Log type + */ + public static function logType(string $name): string + { + return match ($name) { + self::REGISTER => 'notice', + self::LOGIN => 'notice', + self::PHONE_VERIFICATION => 'info', + self::LOGOUT => 'notice', + self::PASSWORD_RESET => 'info', + self::FAILED => 'warning', + self::ATTEMPTING => 'info', + self::LOCKOUT => 'alert', + default => 'info', + }; + } } diff --git a/app/Helpers/helpers.php b/app/Helpers/helpers.php index 4c8a8ec..07aed67 100644 --- a/app/Helpers/helpers.php +++ b/app/Helpers/helpers.php @@ -6,6 +6,17 @@ use GuzzleHttp\Client; use GuzzleHttp\Psr7\Request as GuzzleRequest; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; +use Stevebauman\Location\Facades\Location; + +/** + * Check if a client IP is in our Server subnet + * + * @param string $server_ip + */ +function isLocalIp(string $ip = ''): bool +{ + return ! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); +} /** * Un mask phone from "+(993)-xx-xx-xx-xx" @@ -67,7 +78,7 @@ function sendSMSVerification(string|int $phone_number): ?Verification function storeAuthEvent(string $name, Request $request): void { Log::channel('auth_activity') - ->info(sprintf( + ->{EventType::logType($name)}(sprintf( '%s, APP_NAME: %s, REQUEST_TYPE: %s, SOURCE_IP: %s, SOURCE_PORT: %s, SOURCE_URL: %s, DESTINATION_IP: %s, DESTINATION_PORT: %s, DESTINATION_COUNTRY: %s, USER_ID: %s', $name, config('app.name'), @@ -77,7 +88,7 @@ function storeAuthEvent(string $name, Request $request): void $request->url(), $request->host(), $request->getPort(), - 'tk', + isLocalIp($request->ip()) ? 'TM' : Location::get($request->ip()), $request->user()->id ?? '-', )); } @@ -100,7 +111,7 @@ function storeResourceEvent(string $name, array $data, Request $request): void } Log::channel('resource_activity') - ->info(sprintf( + ->{EventType::logType($name)}(sprintf( '%s, APP_NAME: %s, REQUEST_TYPE: %s, SOURCE_IP: %s, SOURCE_PORT: %s, SOURCE_URL: %s, DESTINATION_IP: %s, DESTINATION_PORT: %s, DESTINATION_COUNTRY: %s, USER_ID: %s, MODEL_NAME: %s, BEFORE: %s, AFTER: %s', $name, config('app.name'), @@ -110,7 +121,7 @@ function storeResourceEvent(string $name, array $data, Request $request): void $request->url(), $request->host(), $request->getPort(), - 'tk', + isLocalIp($request->ip()) ? 'TM' : Location::get($request->ip()), $request->user()->id ?? '-', get_class($data[0]), json_encode($before), diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 077d921..d6bce18 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -23,8 +23,9 @@ class AppServiceProvider extends ServiceProvider { Model::shouldBeStrict(! app()->isProduction()); - Event::listen(['eloquent.created: *', 'eloquent.updated: *', 'eloquent.deleted: *'], function (string $eventName, array $data) { - storeResourceEvent($eventName, $data, request()); - }); + Event::listen( + events: ['eloquent.created: *', 'eloquent.updated: *', 'eloquent.deleted: *'], + listener: fn (string $eventName, array $data) => storeResourceEvent($eventName, $data, request()) + ); } } diff --git a/composer.json b/composer.json index 4ef5381..826fcfa 100644 --- a/composer.json +++ b/composer.json @@ -8,6 +8,7 @@ "php": "^8.1", "denniseilander/pulse-about-application": "^0.1.1", "eolica/nova-locale-switcher": "dev-support-nova-4", + "geoip2/geoip2": "~2.0", "guzzlehttp/guzzle": "^7.2", "konsulting/nova-target": "^1.0", "laravel/framework": "^10.10", @@ -26,6 +27,7 @@ "spatie/laravel-translatable": "^6.5", "spatie/nova-backup-tool": "^5.0", "stepanenko3/nova-logs-tool": "^2.1", + "stevebauman/location": "^7.1", "trin4ik/nova-switcher": "^0.4.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index dd3ce86..2c7658a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e85848a2ef7c35d8eff644ed1eb79219", + "content-hash": "94d89f05d5b7cc398c40b439b1a49a7e", "packages": [ { "name": "brick/math", @@ -188,6 +188,82 @@ ], "time": "2023-12-11T17:09:12+00:00" }, + { + "name": "composer/ca-bundle", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "b66d11b7479109ab547f9405b97205640b17d385" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/b66d11b7479109ab547f9405b97205640b17d385", + "reference": "b66d11b7479109ab547f9405b97205640b17d385", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.55", + "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", + "symfony/process": "^2.5 || ^3.0 || ^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.4.0" + }, + "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": "2023-12-18T12:05:55+00:00" + }, { "name": "denniseilander/pulse-about-application", "version": "0.1.1", @@ -1148,6 +1224,60 @@ ], "time": "2023-10-12T05:21:21+00:00" }, + { + "name": "geoip2/geoip2", + "version": "v2.13.0", + "source": { + "type": "git", + "url": "git@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": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "https://www.maxmind.com/" + } + ], + "description": "MaxMind GeoIP2 PHP API", + "homepage": "https://github.com/maxmind/GeoIP2-php", + "keywords": [ + "IP", + "geoip", + "geoip2", + "geolocation", + "maxmind" + ], + "time": "2022-08-05T20:32:58+00:00" + }, { "name": "graham-campbell/result-type", "version": "v1.1.2", @@ -3119,6 +3249,118 @@ }, "time": "2023-12-10T21:55:46+00:00" }, + { + "name": "maxmind-db/reader", + "version": "v1.11.1", + "source": { + "type": "git", + "url": "git@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" + ], + "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": "monolog/monolog", "version": "3.5.0", @@ -5823,6 +6065,74 @@ }, "time": "2024-01-15T10:38:09+00:00" }, + { + "name": "stevebauman/location", + "version": "v7.1.4", + "source": { + "type": "git", + "url": "https://github.com/stevebauman/location.git", + "reference": "b9cadaf84322d19c08deac82ffded86c7a07dfb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stevebauman/location/zipball/b9cadaf84322d19c08deac82ffded86c7a07dfb0", + "reference": "b9cadaf84322d19c08deac82ffded86c7a07dfb0", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "geoip2/geoip2": "^2.0", + "illuminate/support": "^8.0|^9.0|^10.0", + "php": ">=8.1" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "orchestra/testbench": "^6.0|^7.0|^8.0", + "pestphp/pest": "^1.21" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Stevebauman\\Location\\LocationServiceProvider" + ], + "aliases": { + "Location": "Stevebauman\\Location\\Facades\\Location" + } + } + }, + "autoload": { + "psr-4": { + "Stevebauman\\Location\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Steve Bauman", + "email": "steven_bauman@outlook.com" + } + ], + "description": "Retrieve a user's location by their IP Address", + "keywords": [ + "IP", + "geo", + "geo-location", + "geoip", + "laravel", + "location", + "php" + ], + "support": { + "issues": "https://github.com/stevebauman/location/issues", + "source": "https://github.com/stevebauman/location/tree/v7.1.4" + }, + "time": "2024-01-29T04:42:48+00:00" + }, { "name": "symfony/console", "version": "v6.4.2", diff --git a/config/location.php b/config/location.php new file mode 100644 index 0000000..4ebb780 --- /dev/null +++ b/config/location.php @@ -0,0 +1,125 @@ + Stevebauman\Location\Drivers\MaxMind::class, + + /* + |-------------------------------------------------------------------------- + | Driver Fallbacks + |-------------------------------------------------------------------------- + | + | The drivers you want to use to retrieve the user's location + | if the above selected driver is unavailable. + | + | These will be called upon in order (first to last). + | + */ + + 'fallbacks' => [ + Stevebauman\Location\Drivers\Ip2locationio::class, + Stevebauman\Location\Drivers\IpInfo::class, + Stevebauman\Location\Drivers\GeoPlugin::class, + Stevebauman\Location\Drivers\MaxMind::class, + ], + + /* + |-------------------------------------------------------------------------- + | Position + |-------------------------------------------------------------------------- + | + | Here you may configure the position instance that is created + | and returned from the above drivers. The instance you + | create must extend the built-in Position class. + | + */ + + 'position' => Stevebauman\Location\Position::class, + + /* + |-------------------------------------------------------------------------- + | Localhost Testing + |-------------------------------------------------------------------------- + | + | If your running your website locally and want to test different + | IP addresses to see location detection, set 'enabled' to true. + | + | The testing IP address is a Google host in the United-States. + | + */ + + 'testing' => [ + 'ip' => '66.102.0.0', + 'enabled' => env('LOCATION_TESTING', true), + ], + + /* + |-------------------------------------------------------------------------- + | MaxMind Configuration + |-------------------------------------------------------------------------- + | + | If web service is enabled, you must fill in your user ID and license key. + | + | If web service is disabled, it will try and retrieve the user's location + | from the MaxMind database file located in the local path below. + | + | The MaxMind database file can be either City (default) or Country (smaller). + | + */ + + 'maxmind' => [ + 'web' => [ + 'enabled' => false, + 'user_id' => env('MAXMIND_USER_ID'), + 'license_key' => env('MAXMIND_LICENSE_KEY'), + 'options' => ['host' => 'geoip.maxmind.com'], + ], + + 'local' => [ + 'type' => 'city', + 'path' => database_path('maxmind/GeoLite2-City.mmdb'), + 'url' => sprintf('https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=%s&suffix=tar.gz', env('MAXMIND_LICENSE_KEY')), + ], + ], + + 'ip_api' => [ + 'token' => env('IP_API_TOKEN'), + ], + + 'ipinfo' => [ + 'token' => env('IPINFO_TOKEN'), + ], + + 'ipdata' => [ + 'token' => env('IPDATA_TOKEN'), + ], + + 'ip2locationio' => [ + 'token' => env('IP2LOCATIONIO_TOKEN'), + ], + + /* + |-------------------------------------------------------------------------- + | Kloudend ~ ipapi.co Configuration + |-------------------------------------------------------------------------- + | + | The configuration for the Kloudend driver. + | + */ + + 'kloudend' => [ + + 'token' => env('KLOUDEND_TOKEN'), + + ], + +]; diff --git a/database/maxmind/GeoLite2-City.mmdb b/database/maxmind/GeoLite2-City.mmdb new file mode 100644 index 0000000..badab33 Binary files /dev/null and b/database/maxmind/GeoLite2-City.mmdb differ diff --git a/database/maxmind/GeoLite2-City_20240202/GeoLite2-City.mmdb b/database/maxmind/GeoLite2-City_20240202/GeoLite2-City.mmdb new file mode 100644 index 0000000..badab33 Binary files /dev/null and b/database/maxmind/GeoLite2-City_20240202/GeoLite2-City.mmdb differ