Skip to content

Commit

Permalink
New CACHET_INTERNET_LOOKUPS option to prevent outbound HTTP requests #6
Browse files Browse the repository at this point in the history
  • Loading branch information
sedan07 committed Jan 26, 2021
1 parent 9804c62 commit c873ed0
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 4 deletions.
9 changes: 9 additions & 0 deletions app/Http/Controllers/Dashboard/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ public function __construct()
],
];

// Remove the credits link if we cannot look them up
if (Config::get('cachet.internet_lookups') === false) {
unset($this->subMenu['credits']);
}

View::share([
'subTitle' => trans('dashboard.settings.settings'),
'subMenu' => $this->subMenu,
Expand Down Expand Up @@ -244,6 +249,10 @@ public function showStylesheetView()
*/
public function showCreditsView()
{
if (Config::get('cachet.internet_lookups') === false) {
abort(403, 'Outbound Internet Lookups Disabled');
}

$this->subMenu['credits']['active'] = true;

$credits = app(Credits::class)->latest();
Expand Down
16 changes: 15 additions & 1 deletion app/Integrations/Core/Credits.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,27 @@ class Credits implements CreditsContract
*/
protected $url;

/**
* Are outbound HTTP requests to the internet allowed by
* this installation
*
* @var bool
*/
protected $enabled;

/**
* Creates a new credits instance.
*
* @param \Illuminate\Contracts\Cache\Repository $cache
* @param bool $enabled
* @param string|null $url
*
* @return void
*/
public function __construct(Repository $cache, $url = null)
public function __construct(Repository $cache, bool $enabled = true, $url = null)
{
$this->cache = $cache;
$this->enabled = $enabled;
$this->url = $url ?: static::URL;
}

Expand All @@ -73,6 +83,10 @@ public function __construct(Repository $cache, $url = null)
*/
public function latest()
{
if (!$this->enabled) {
return null;
}

$result = $this->cache->remember('credits', 2880, function () {
try {
return json_decode((new Client())->get($this->url, [
Expand Down
15 changes: 14 additions & 1 deletion app/Integrations/GitHub/Releases.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ class Releases implements ReleasesContract
*/
protected $url;

/**
* Are outbound HTTP requests to the internet allowed by
* this installation
*
* @var bool
*/
protected $enabled;

/**
* Creates a new releases instance.
*
Expand All @@ -72,10 +80,11 @@ class Releases implements ReleasesContract
*
* @return void
*/
public function __construct(Client $client, Repository $cache, $token = null, $url = null)
public function __construct(Client $client, Repository $cache, bool $enabled = true, $token = null, $url = null)
{
$this->client = $client;
$this->cache = $cache;
$this->enabled = $enabled;
$this->token = $token;
$this->url = $url ?: static::URL;
}
Expand All @@ -87,6 +96,10 @@ public function __construct(Client $client, Repository $cache, $token = null, $u
*/
public function latest()
{
if (!$this->enabled) {
return null;
}

$release = $this->cache->remember('release.latest', 720, function () {
$headers = ['Accept' => 'application/vnd.github.v3+json', 'User-Agent' => defined('CACHET_VERSION') ? 'cachet/'.constant('CACHET_VERSION') : 'cachet'];

Expand Down
6 changes: 4 additions & 2 deletions app/Providers/IntegrationServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ protected function registerCredits()
{
$this->app->singleton(CreditsContract::class, function ($app) {
$cache = $app['cache.store'];
$enabled = $app['config']->get('cachet.internet_lookups');

return new Credits($cache);
return new Credits($cache, $enabled);
});
}

Expand Down Expand Up @@ -97,9 +98,10 @@ protected function registerReleases()
$this->app->singleton(ReleasesContract::class, function ($app) {
$client = $app->make(Client::class);
$cache = $app['cache.store'];
$enabled = $app['config']->get('cachet.internet_lookups');
$token = $app['config']->get('services.github.token');

return new Releases($client, $cache, $token);
return new Releases($client, $cache, $enabled, $token);
});
}
}
12 changes: 12 additions & 0 deletions config/cachet.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,16 @@

'beacon' => env('CACHET_BEACON', true),

/*
|--------------------------------------------------------------------------
| Internet Lookups
|--------------------------------------------------------------------------
|
| Should Cachet make outbound HTTP requests to the internet to load external
| resources. Turn off if you're behind a Firewall with no HTTP(S) egress.
|
*/

'internet_lookups' => env('CACHET_INTERNET_LOOKUPS', true),

];
18 changes: 18 additions & 0 deletions tests/Integrations/GitHub/ReleasesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,28 @@
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ConnectException;

class ReleasesTest extends AbstractTestCase
{
private $request_history = [];
/**
* Creates Mock Guzzle client
*
* @param array $mock_responses list of fake response to return to HTTP requests
*/
private function createMockClient(array $mock_responses)
{
$history = Middleware::history($this->request_history);
$mock = new MockHandler($mock_responses);

$handlerStack = HandlerStack::create($mock);
$handlerStack->push($history);

$client = new Client(['handler' => $handlerStack]);
$this->app->instance(Client::class, $client);
}
Expand Down Expand Up @@ -56,4 +61,17 @@ public function test_latest_returns_empty_on_timeout()
$latest = $this->app->make(Releases::class)->latest();
$this->assertEquals(null, $latest);
}

public function test_latest_does_not_make_http_request_when_enabled_false()
{
$mock_responses = [
new Response(200),
];
$this->createMockClient($mock_responses);

Cache::tags('release.latest')->flush();
$latest = $this->app->makeWith(Releases::class, ['enabled' => false])->latest();
$this->assertEquals(null, $latest);
$this->assertEquals(0, count($this->request_history));
}
}

0 comments on commit c873ed0

Please sign in to comment.