Merge branch '2.4' into feature/remote-user-authenticate

This commit is contained in:
James Brooks
2019-06-23 09:04:25 +01:00
committed by GitHub
136 changed files with 5378 additions and 2760 deletions

View File

@@ -73,7 +73,8 @@ class ScheduleController extends AbstractApiController
Binput::get('status'),
Binput::get('scheduled_at'),
Binput::get('completed_at'),
Binput::get('components', [])
Binput::get('components', []),
Binput::get('notify', false)
));
} catch (QueryException $e) {
throw new BadRequestHttpException();

View File

@@ -17,6 +17,7 @@ use CachetHQ\Cachet\Bus\Events\User\UserLoggedOutEvent;
use CachetHQ\Cachet\Bus\Events\User\UserPassedTwoAuthEvent;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Session;
@@ -47,9 +48,9 @@ class AuthController extends Controller
// Login with username or email.
$loginKey = filter_var($loginData['username'], FILTER_VALIDATE_EMAIL) ? 'email' : 'username';
$loginData[$loginKey] = array_pull($loginData, 'username');
$loginData[$loginKey] = Arr::pull($loginData, 'username');
$rememberUser = array_pull($loginData, 'remember_me') === '1';
$rememberUser = Arr::pull($loginData, 'remember_me') === '1';
// Validate login credentials.
if (Auth::validate($loginData)) {

View File

@@ -21,6 +21,7 @@ use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\View;
@@ -73,7 +74,7 @@ class ComponentController extends Controller
*/
public function showComponents()
{
$components = Component::orderBy('order')->orderBy('created_at')->get();
$components = Component::with('group')->orderBy('order')->orderBy('created_at')->get();
$this->subMenu['components']['active'] = true;
@@ -112,7 +113,7 @@ class ComponentController extends Controller
public function updateComponentAction(Component $component)
{
$componentData = Binput::get('component');
$tags = array_pull($componentData, 'tags');
$tags = Arr::pull($componentData, 'tags');
try {
$component = execute(new UpdateComponentCommand(
@@ -169,7 +170,7 @@ class ComponentController extends Controller
public function createComponentAction()
{
$componentData = Binput::get('component');
$tags = array_pull($componentData, 'tags');
$tags = Arr::pull($componentData, 'tags');
try {
$component = execute(new CreateComponentCommand(

View File

@@ -106,7 +106,9 @@ class DashboardController extends Controller
$entries = null;
if ($feed = $this->feed->latest()) {
$entries = array_slice($feed->channel->item, 0, 5);
if (is_object($feed)) {
$entries = array_slice($feed->channel->item, 0, 5);
}
}
return View::make('dashboard.index')

View File

@@ -75,7 +75,7 @@ class IncidentController extends Controller
*/
public function showIncidents()
{
$incidents = Incident::orderBy('created_at', 'desc')->get();
$incidents = Incident::with('user')->orderBy('created_at', 'desc')->get();
return View::make('dashboard.incidents.index')
->withPageTitle(trans('dashboard.incidents.incidents').' - '.trans('dashboard.dashboard'))
@@ -128,7 +128,8 @@ class IncidentController extends Controller
Binput::get('stickied', false),
Binput::get('occurred_at'),
null,
[]
[],
['seo' => Binput::get('seo', [])]
));
} catch (ValidationException $e) {
return cachet_redirect('dashboard.incidents.create')
@@ -258,7 +259,8 @@ class IncidentController extends Controller
Binput::get('stickied', false),
Binput::get('occurred_at'),
null,
[]
[],
['seo' => Binput::get('seo', [])]
));
} catch (ValidationException $e) {
return cachet_redirect('dashboard.incidents.edit', ['id' => $incident->id])

View File

@@ -15,6 +15,7 @@ use AltThree\Validator\ValidationException;
use CachetHQ\Cachet\Bus\Commands\Schedule\CreateScheduleCommand;
use CachetHQ\Cachet\Bus\Commands\Schedule\DeleteScheduleCommand;
use CachetHQ\Cachet\Bus\Commands\Schedule\UpdateScheduleCommand;
use CachetHQ\Cachet\Integrations\Contracts\System;
use CachetHQ\Cachet\Models\IncidentTemplate;
use CachetHQ\Cachet\Models\Schedule;
use GrahamCampbell\Binput\Facades\Binput;
@@ -35,13 +36,21 @@ class ScheduleController extends Controller
*/
protected $subMenu = [];
/**
* The system instance.
*
* @var \CachetHQ\Cachet\Integrations\Contracts\System
*/
protected $system;
/**
* Creates a new schedule controller instance.
*
* @return void
*/
public function __construct()
public function __construct(System $system)
{
$this->system = $system;
View::share('subTitle', trans('dashboard.schedule.title'));
}
@@ -70,7 +79,8 @@ class ScheduleController extends Controller
return View::make('dashboard.maintenance.add')
->withPageTitle(trans('dashboard.schedule.add.title').' - '.trans('dashboard.dashboard'))
->withIncidentTemplates($incidentTemplates);
->withIncidentTemplates($incidentTemplates)
->withNotificationsEnabled($this->system->canNotifySubscribers());
}
/**
@@ -87,7 +97,8 @@ class ScheduleController extends Controller
Binput::get('status', Schedule::UPCOMING),
Binput::get('scheduled_at'),
Binput::get('completed_at'),
Binput::get('components', [])
Binput::get('components', []),
Binput::get('notify', false)
));
} catch (ValidationException $e) {
return cachet_redirect('dashboard.schedule.create')

View File

@@ -18,6 +18,7 @@ use CachetHQ\Cachet\Bus\Events\User\UserRegeneratedApiTokenEvent;
use CachetHQ\Cachet\Models\User;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\View;
use PragmaRX\Google2FA\Vendor\Laravel\Facade as Google2FA;
@@ -44,7 +45,7 @@ class UserController extends Controller
{
$userData = array_filter(Binput::only(['username', 'email', 'password', 'google2fa']));
$enable2FA = (bool) array_pull($userData, 'google2fa');
$enable2FA = (bool) Arr::pull($userData, 'google2fa');
// Let's enable/disable auth
if ($enable2FA && !Auth::user()->hasTwoFactor) {

View File

@@ -16,6 +16,7 @@ use CachetHQ\Cachet\Models\User;
use CachetHQ\Cachet\Settings\Repository;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Request;
@@ -199,7 +200,7 @@ class SetupController extends Controller
});
$v->sometimes(['env.mail_username'], 'required', function ($input) {
return !in_array($input->env['mail_username'], ['sendmail']);
return !in_array($input->env['mail_driver'], ['sendmail', 'log']);
});
if ($v->passes()) {
@@ -240,7 +241,7 @@ class SetupController extends Controller
if ($v->passes()) {
// Pull the user details out.
$userDetails = array_pull($postData, 'user');
$userDetails = Arr::pull($postData, 'user');
$user = User::create([
'username' => $userDetails['username'],
@@ -253,13 +254,13 @@ class SetupController extends Controller
$setting = app(Repository::class);
$settings = array_pull($postData, 'settings');
$settings = Arr::pull($postData, 'settings');
foreach ($settings as $settingName => $settingValue) {
$setting->set($settingName, $settingValue);
}
$envData = array_pull($postData, 'env');
$envData = Arr::pull($postData, 'env');
// Write the env to the .env file.
execute(new UpdateConfigCommand($envData));

View File

@@ -96,7 +96,8 @@ class StatusPageController extends AbstractApiController
$nextDate = $startDate->copy()->addDays($appIncidentDays)->toDateString();
}
$allIncidents = Incident::where('visible', '>=', (int) !Auth::check())->whereBetween('occurred_at', [
$allIncidents = Incident::with('component')->with('updates.incident')
->where('visible', '>=', (int) !Auth::check())->whereBetween('occurred_at', [
$endDate->format('Y-m-d').' 00:00:00',
$startDate->format('Y-m-d').' 23:59:59',
])->orderBy('occurred_at', 'desc')->get()->groupBy(function (Incident $incident) {

View File

@@ -213,6 +213,6 @@ class SubscribeController extends Controller
}
return cachet_redirect('subscribe.manage', $subscriber->verify_code)
->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.subscribed')));
->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.updated-subscribe')));
}
}

View File

@@ -11,16 +11,18 @@
namespace CachetHQ\Cachet\Http;
use AltThree\Throttle\ThrottlingMiddleware;
use Barryvdh\Cors\HandleCors;
use CachetHQ\Cachet\Http\Middleware\Admin;
use CachetHQ\Cachet\Http\Middleware\ApiAuthentication;
use CachetHQ\Cachet\Http\Middleware\Authenticate;
use CachetHQ\Cachet\Http\Middleware\CacheControl;
use CachetHQ\Cachet\Http\Middleware\Localize;
use CachetHQ\Cachet\Http\Middleware\ReadyForUse;
use CachetHQ\Cachet\Http\Middleware\RedirectIfAuthenticated;
use CachetHQ\Cachet\Http\Middleware\RemoteUserAuthenticate;
use CachetHQ\Cachet\Http\Middleware\SetupAlreadyCompleted;
use CachetHQ\Cachet\Http\Middleware\SubscribersConfigured;
use CachetHQ\Cachet\Http\Middleware\Throttler;
use CachetHQ\Cachet\Http\Middleware\TrustProxies;
use Illuminate\Auth\Middleware\Authorize;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
@@ -44,16 +46,18 @@ class Kernel extends HttpKernel
* @var array
*/
protected $routeMiddleware = [
'admin' => Admin::class,
'can' => Authorize::class,
'auth' => Authenticate::class,
'auth.api' => ApiAuthentication::class,
'admin' => Admin::class,
'auth.api' => ApiAuthentication::class,
'auth.remoteuser' => RemoteUserAuthenticate::class,
'guest' => RedirectIfAuthenticated::class,
'localize' => Localize::class,
'ready' => ReadyForUse::class,
'setup' => SetupAlreadyCompleted::class,
'subscribers' => SubscribersConfigured::class,
'throttle' => ThrottlingMiddleware::class,
'auth' => Authenticate::class,
'cache' => CacheControl::class,
'can' => Authorize::class,
'cors' => HandleCors::class,
'guest' => RedirectIfAuthenticated::class,
'localize' => Localize::class,
'ready' => ReadyForUse::class,
'setup' => SetupAlreadyCompleted::class,
'subscribers' => SubscribersConfigured::class,
'throttle' => Throttler::class,
];
}

View File

@@ -18,7 +18,7 @@ use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
/**
* This is the acceptable middleware class.
*
* @author Graham Campbell <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
* @author James Brooks <james@alt-three.com>
*/
class Acceptable

View File

@@ -20,7 +20,7 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
* This is the admin middleware class.
*
* @author Joseph Cohen <joe@alt-three.com>
* @author Graham Campbell <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
* @author James Brooks <james@alt-three.com>
*/
class Admin

View File

@@ -22,7 +22,7 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
* This is the api authentication middleware class.
*
* @author Joseph Cohen <joe@alt-three.com>
* @author Graham Campbell <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
* @author James Brooks <james@alt-three.com>
*/
class ApiAuthentication

View File

@@ -20,7 +20,7 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
* This is the authenticate middleware class.
*
* @author Joseph Cohen <joe@alt-three.com>
* @author Graham Campbell <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
* @author James Brooks <james@alt-three.com>
*/
class Authenticate

View File

@@ -0,0 +1,37 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CacheControl
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
$response = $next($request);
$maxAge = time() + 30;
$response->header('Cache-Control', 'public,max-age='.$maxAge);
return $response;
}
}

View File

@@ -22,7 +22,7 @@ use Jenssegers\Date\Date;
*
* @author James Brooks <james@alt-three.com>
* @author Joseph Cohen <joe@alt-three.com>
* @author Graham Campbell <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
*/
class Localize
{

View File

@@ -18,7 +18,7 @@ use Illuminate\Http\Request;
/**
* This is the ready for use middleware class.
*
* @author Graham Campbell <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
* @author James Brooks <james@alt-three.com>
* @author Joseph Cohen <joe@alt-three.com>
*/

View File

@@ -18,7 +18,7 @@ use Illuminate\Http\Request;
/**
* This is the redirect if authenticated middleware class.
*
* @author Graham Campbell <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
* @author Joseph Cohen <joe@alt-three.com>
* @author James Brooks <james@alt-three.com>
*/

View File

@@ -19,7 +19,7 @@ use Illuminate\Http\Request;
/**
* This is the setup already completed middelware class.
*
* @author Graham Campbell <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
* @author James Brooks <james@alt-three.com>
* @author Joseph Cohen <joe@alt-three.com>
*/

View File

@@ -19,7 +19,7 @@ use Illuminate\Http\Request;
* This is the subscribers configured middleware class.
*
* @author James Brooks <james@alt-three.com>
* @author Graham Campbell <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
*/
class SubscribersConfigured
{

View File

@@ -0,0 +1,125 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use Closure;
use Illuminate\Cache\RateLimiter;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
/**
* This is the throttler middleware class.
*
* @author Graham Campbell <graham@alt-three.com>
*/
class Throttler
{
/**
* The rate limiter instance.
*
* @var \Illuminate\Cache\RateLimiter
*/
protected $limiter;
/**
* Create a new throttler middleware instance.
*
* @param \Illuminate\Cache\RateLimiter $limiter
*
* @return void
*/
public function __construct(RateLimiter $limiter)
{
$this->limiter = $limiter;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param int|string $limit
* @param int|string $decay
*
* @throws \Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException
*
* @return mixed
*/
public function handle(Request $request, Closure $next, $limit = 60, $decay = 1)
{
return $this->safeHandle($request, $next, (int) $limit, (int) $decay);
}
/**
* Handle an incoming request, with correct types.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param int $limit
* @param int $decay
*
* @throws \Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException
*
* @return mixed
*/
protected function safeHandle(Request $request, Closure $next, int $limit, int $decay)
{
$key = $request->fingerprint();
if ($this->limiter->tooManyAttempts($key, $limit, $decay)) {
throw $this->buildException($key, $limit);
}
$this->limiter->hit($key, $decay);
$response = $next($request);
$response->headers->add($this->getHeaders($key, $limit));
return $response;
}
/**
* Create a too many requests http exception.
*
* @param string $key
* @param int $limit
*
* @return \Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException
*/
protected function buildException(string $key, int $limit)
{
$after = $this->limiter->availableIn($key);
$exception = new TooManyRequestsHttpException($after, 'Rate limit exceeded.');
$exception->setHeaders($this->getHeaders($key, $limit, $after, $exception->getHeaders()));
return $exception;
}
/**
* Get the limit header information.
*
* @param string $key
* @param int $limit
* @param int|null $after
* @param array $merge
*
* @return array
*/
protected function getHeaders(string $key, int $limit, int $after = null, array $merge = [])
{
$remaining = $after === null ? $this->limiter->retriesLeft($key, $limit) : 0;
$headers = ['X-RateLimit-Limit' => $limit, 'X-RateLimit-Remaining' => $remaining];
return array_merge($headers, $merge);
}
}

View File

@@ -19,7 +19,7 @@ use Illuminate\Http\Request;
* This is the timezone middleware class.
*
* @author James Brooks <james@alt-three.com>
* @author Graham Campbell <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
*/
class Timezone
{

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
/**
* This is the verify csrf token middleware class.
*
* @author James Brooks <james@alt-three.com>
*/
class VerifyCsrfToken extends Middleware
{
/**
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
*
* @var bool
*/
protected $addHttpCookie = true;
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
'/api/*',
];
}

View File

@@ -40,7 +40,7 @@ class ApiRoutes
'namespace' => 'Api',
'prefix' => 'api/v1',
], function (Registrar $router) {
$router->group(['middleware' => ['auth.api']], function (Registrar $router) {
$router->group(['middleware' => ['auth.api', 'cors']], function (Registrar $router) {
$router->get('components', 'ComponentController@index');
$router->get('components/groups', 'ComponentGroupController@index');
$router->get('components/groups/{component_group}', 'ComponentGroupController@show');

View File

@@ -43,7 +43,7 @@ class ApiSystemRoutes
$router->group(['middleware' => ['auth.api']], function (Registrar $router) {
$router->get('ping', 'GeneralController@ping');
$router->get('version', 'GeneralController@version');
$router->get('status', 'GeneralController@status');
$router->get('status', ['uses' => 'GeneralController@status', 'middleware' => ['cache']]);
});
});
}