diff --git a/.env.example b/.env.example index a6b13005..6ef2cb54 100644 --- a/.env.example +++ b/.env.example @@ -236,6 +236,8 @@ WEBAUTHN_USER_VERIFICATION=preferred # GITHUB_CLIENT_SECRET= +#### Proxy settings #### + # Use this setting to declare trusted proxied. # Supported: # '*': to trust any proxy @@ -244,6 +246,13 @@ WEBAUTHN_USER_VERIFICATION=preferred TRUSTED_PROXIES=null +# Proxy for outgoing requests like new releases detection or logo fetching. +# You can provide a proxy URL that contains a scheme, username, and password. +# For example, "http://username:password@192.168.16.1:10". + +PROXY_FOR_OUTGOING_REQUESTS=null + + # Leave the following configuration vars as is. # Unless you like to tinker and know what you're doing. diff --git a/Dockerfile b/Dockerfile index ae5be575..e8cbc820 100644 --- a/Dockerfile +++ b/Dockerfile @@ -223,6 +223,10 @@ ENV \ # '*': to trust any proxy # A comma separated IP list: The list of proxies IP to trust TRUSTED_PROXIES=null \ + # Proxy for outgoing requests like new releases detection or logo fetching. + # You can provide a proxy URL that contains a scheme, username, and password. + # For example, "http://username:password@192.168.16.1:10". + PROXY_FOR_OUTGOING_REQUESTS=null \ # Leave the following configuration vars as is. # Unless you like to tinker and know what you're doing. BROADCAST_DRIVER=log \ diff --git a/app/Models/TwoFAccount.php b/app/Models/TwoFAccount.php index 2465ff59..aad5a045 100644 --- a/app/Models/TwoFAccount.php +++ b/app/Models/TwoFAccount.php @@ -691,7 +691,9 @@ private function storeRemoteImageAsIcon(string $url) : string|null $newFilename = self::getUniqueFilename($path_parts['extension']); try { - $response = Http::retry(3, 100)->get($url); + $response = Http::withOptions([ + 'proxy' => config('2fauth.config.outgoingProxy'), + ])->retry(3, 100)->get($url); if ($response->successful()) { Storage::disk('imagesLink')->put($newFilename, $response->body()); diff --git a/app/Services/LogoService.php b/app/Services/LogoService.php index 0cb2ec83..13094a98 100644 --- a/app/Services/LogoService.php +++ b/app/Services/LogoService.php @@ -92,7 +92,9 @@ protected function setTfaCollection() : void protected function cacheTfaDirectorySource() : void { try { - $response = Http::retry(3, 100)->get(self::TFA_URL); + $response = Http::withOptions([ + 'proxy' => config('2fauth.config.outgoingProxy'), + ])->retry(3, 100)->get(self::TFA_URL); $coll = collect(json_decode(htmlspecialchars_decode($response->body()), true)) /* @phpstan-ignore-line */ ->mapWithKeys(function ($item, $key) { @@ -117,8 +119,9 @@ protected function cacheTfaDirectorySource() : void protected function fetchLogo(string $logoFile) : void { try { - $response = Http::retry(3, 100) - ->get('https://raw.githubusercontent.com/2factorauth/twofactorauth/master/img/' . $logoFile[0] . '/' . $logoFile); + $response = Http::withOptions([ + 'proxy' => config('2fauth.config.outgoingProxy'), + ])->retry(3, 100)->get('https://raw.githubusercontent.com/2factorauth/twofactorauth/master/img/' . $logoFile[0] . '/' . $logoFile); if ($response->successful()) { Storage::disk('logos')->put($logoFile, $response->body()) diff --git a/app/Services/ReleaseRadarService.php b/app/Services/ReleaseRadarService.php index 8d2d53a9..76cce36a 100644 --- a/app/Services/ReleaseRadarService.php +++ b/app/Services/ReleaseRadarService.php @@ -22,9 +22,9 @@ public static function scheduledScan() : void /** * Run a manual release scan * - * @return false|string False if no new release, the new release number otherwise + * @return string|null|false False if no new release, null if check failed, the new release number otherwise */ - public static function manualScan() : false|string + public static function manualScan() : string|null|false { return self::newRelease(); } @@ -32,13 +32,15 @@ public static function manualScan() : false|string /** * Run a release scan * - * @return false|string False if no new release, the new release number otherwise + * @return string|null|false False if no new release, null if check failed, the new release number otherwise */ - protected static function newRelease() : false|string + protected static function newRelease() : string|null|false { Log::info('Release scan started'); + $latestRelease = self::getLatestReleaseData(); - if ($latestReleaseData = json_decode(self::getLatestReleaseData())) { + if ($latestRelease) { + $latestReleaseData = json_decode($latestRelease); $githubVersion = Helpers::cleanVersionNumber($latestReleaseData->tag_name); $installedVersion = Helpers::cleanVersionNumber(config('2fauth.version')); @@ -55,7 +57,7 @@ protected static function newRelease() : false|string } } - return false; + return $latestRelease ? false : null; } /** @@ -66,8 +68,9 @@ protected static function getLatestReleaseData() : string|null $url = config('2fauth.latestReleaseUrl'); try { - $response = Http::retry(3, 100) - ->get($url); + $response = Http::withOptions([ + 'proxy' => config('2fauth.config.outgoingProxy'), + ])->retry(3, 100)->get($url); if ($response->successful()) { Settings::set('lastRadarScan', time()); diff --git a/config/2fauth.php b/config/2fauth.php index b75ae834..d3e91f30 100644 --- a/config/2fauth.php +++ b/config/2fauth.php @@ -25,6 +25,7 @@ 'isDemoApp' => env('IS_DEMO_APP', false), 'isTestingApp' => env('IS_TESTING_APP', false), 'trustedProxies' => env('TRUSTED_PROXIES', null), + 'outgoingProxy' => env('PROXY_FOR_OUTGOING_REQUESTS', ''), 'proxyLogoutUrl' => env('PROXY_LOGOUT_URL', null), 'appSubdirectory' => env('APP_SUBDIRECTORY', ''), ], diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 05313561..08e1e4e6 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -121,6 +121,10 @@ services: # '*': to trust any proxy # A comma separated IP list: The list of proxies IP to trust - TRUSTED_PROXIES=null + # Proxy for outgoing requests like new releases detection or logo fetching. + # You can provide a proxy URL that contains a scheme, username, and password. + # For example, "http://username:password@192.168.16.1:10". + - PROXY_FOR_OUTGOING_REQUESTS=null # Leave the following configuration vars as is. # Unless you like to tinker and know what you're doing. - BROADCAST_DRIVER=log diff --git a/resources/js/components/VersionChecker.vue b/resources/js/components/VersionChecker.vue index 6c3bc6ed..8040d10f 100644 --- a/resources/js/components/VersionChecker.vue +++ b/resources/js/components/VersionChecker.vue @@ -13,7 +13,7 @@ await systemService.getLastRelease({returnError: true}) .then(response => { appSettings.latestRelease = response.data.newRelease - isUpToDate.value = response.data.newRelease === false + isUpToDate.value = response.data.newRelease === null ? null : response.data.newRelease === false }) .catch(() => { isUpToDate.value = null diff --git a/tests/Feature/Services/ReleaseRadarServiceTest.php b/tests/Feature/Services/ReleaseRadarServiceTest.php index 64b34e58..b12a77a1 100644 --- a/tests/Feature/Services/ReleaseRadarServiceTest.php +++ b/tests/Feature/Services/ReleaseRadarServiceTest.php @@ -71,7 +71,7 @@ public function test_manualScan_complete_when_http_call_fails() // We do not fake the http request so an exception will be thrown Http::preventStrayRequests(); - $this->assertFalse(ReleaseRadarService::manualScan()); + $this->assertNull(ReleaseRadarService::manualScan()); } /** @@ -86,7 +86,7 @@ public function test_manualScan_succeed_when_github_is_unreachable() $url => Http::response(null, 400), ]); - $this->assertFalse(ReleaseRadarService::manualScan()); + $this->assertNull(ReleaseRadarService::manualScan()); } /**