diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index d21c8d3c8..dc7837f90 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -2,7 +2,6 @@ namespace Pterodactyl\Http; -use Pterodactyl\Http\Middleware\MaintenanceMiddleware; use Pterodactyl\Models\ApiKey; use Illuminate\Auth\Middleware\Authorize; use Illuminate\Auth\Middleware\Authenticate; @@ -21,6 +20,7 @@ use Illuminate\Routing\Middleware\SubstituteBindings; use Pterodactyl\Http\Middleware\AccessingValidServer; use Pterodactyl\Http\Middleware\Api\SetSessionDriver; use Illuminate\View\Middleware\ShareErrorsFromSession; +use Pterodactyl\Http\Middleware\MaintenanceMiddleware; use Pterodactyl\Http\Middleware\RedirectIfAuthenticated; use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth; use Pterodactyl\Http\Middleware\Api\AuthenticateIPAccess; @@ -71,7 +71,7 @@ class Kernel extends HttpKernel RequireTwoFactorAuthentication::class, ], 'api' => [ - 'throttle:120,1', + 'throttle:240,1', ApiSubstituteBindings::class, SetSessionDriver::class, 'api..key:' . ApiKey::TYPE_APPLICATION, @@ -79,7 +79,9 @@ class Kernel extends HttpKernel AuthenticateIPAccess::class, ], 'client-api' => [ - 'throttle:60,1', + 'throttle:240,1', + EncryptCookies::class, + StartSession::class, SubstituteClientApiBindings::class, SetSessionDriver::class, 'api..key:' . ApiKey::TYPE_ACCOUNT, diff --git a/app/Http/Middleware/Api/AuthenticateKey.php b/app/Http/Middleware/Api/AuthenticateKey.php index 998eb378c..e5dd91159 100644 --- a/app/Http/Middleware/Api/AuthenticateKey.php +++ b/app/Http/Middleware/Api/AuthenticateKey.php @@ -5,6 +5,7 @@ namespace Pterodactyl\Http\Middleware\Api; use Closure; use Lcobucci\JWT\Parser; use Cake\Chronos\Chronos; +use Illuminate\Support\Str; use Illuminate\Http\Request; use Pterodactyl\Models\ApiKey; use Illuminate\Auth\AuthManager; @@ -63,19 +64,24 @@ class AuthenticateKey public function handle(Request $request, Closure $next, int $keyType) { if (is_null($request->bearerToken())) { - throw new HttpException(401, null, null, ['WWW-Authenticate' => 'Bearer']); + if (! Str::startsWith($request->route()->getName(), ['api.client']) && ! $request->user()) { + throw new HttpException(401, null, null, ['WWW-Authenticate' => 'Bearer']); + } } - $raw = $request->bearerToken(); + if (is_null($request->bearerToken())) { + $model = (new ApiKey)->forceFill([ + 'user_id' => $request->user()->id, + 'key_type' => ApiKey::TYPE_ACCOUNT, + ]); + } - // This is an internal JWT, treat it differently to get the correct user before passing it along. - if (strlen($raw) > ApiKey::IDENTIFIER_LENGTH + ApiKey::KEY_LENGTH) { - $model = $this->authenticateJWT($raw); - } else { + if (! isset($model)) { + $raw = $request->bearerToken(); $model = $this->authenticateApiKey($raw, $keyType); + $this->auth->guard()->loginUsingId($model->user_id); } - $this->auth->guard()->loginUsingId($model->user_id); $request->attributes->set('api_key', $model); return $next($request); diff --git a/resources/assets/scripts/app.js b/resources/assets/scripts/app.js index a8f012a68..3aa7f6979 100644 --- a/resources/assets/scripts/app.js +++ b/resources/assets/scripts/app.js @@ -3,6 +3,8 @@ import Vuex from 'vuex'; import vuexI18n from 'vuex-i18n'; import VueRouter from 'vue-router'; +require('./bootstrap'); + // Helpers import { Ziggy } from './helpers/ziggy'; import Locales from './../../../resources/lang/locales'; @@ -32,6 +34,4 @@ const router = new VueRouter({ mode: 'history', routes }); -require('./bootstrap'); - const app = new Vue({ store, router }).$mount('#pterodactyl'); diff --git a/resources/assets/scripts/bootstrap.js b/resources/assets/scripts/bootstrap.js index 05dccd8e8..35667f59a 100644 --- a/resources/assets/scripts/bootstrap.js +++ b/resources/assets/scripts/bootstrap.js @@ -1,3 +1,5 @@ +import axios from './helpers/axios'; + window._ = require('lodash'); /** @@ -10,24 +12,7 @@ try { window.$ = window.jQuery = require('jquery'); } catch (e) {} -/** - * We'll load the axios HTTP library which allows us to easily issue requests - * to our Laravel back-end. This library automatically handles sending the - * CSRF token as a header based on the value of the "XSRF" token cookie. - */ - -window.axios = require('axios'); -window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; -window.axios.defaults.headers.common['Accept'] = 'application/json'; -window.axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.token || ''; - -if (typeof phpdebugbar !== 'undefined') { - window.axios.interceptors.response.use(function (response) { - phpdebugbar.ajaxHandler.handle(response.request); - - return response; - }); -} +window.axios = axios; /** * Next we will register the CSRF Token as a common header with Axios so that diff --git a/resources/assets/scripts/components/dashboard/Dashboard.vue b/resources/assets/scripts/components/dashboard/Dashboard.vue index a34060438..ca3a5555a 100644 --- a/resources/assets/scripts/components/dashboard/Dashboard.vue +++ b/resources/assets/scripts/components/dashboard/Dashboard.vue @@ -18,7 +18,7 @@ diff --git a/resources/assets/scripts/helpers/axios.js b/resources/assets/scripts/helpers/axios.js new file mode 100644 index 000000000..376179118 --- /dev/null +++ b/resources/assets/scripts/helpers/axios.js @@ -0,0 +1,19 @@ +/** + * We'll load the axios HTTP library which allows us to easily issue requests + * to our Laravel back-end. This library automatically handles sending the + * CSRF token as a header based on the value of the "XSRF" token cookie. + */ + +let axios = require('axios'); +axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; +axios.defaults.headers.common['Accept'] = 'application/json'; + +if (typeof phpdebugbar !== 'undefined') { + axios.interceptors.response.use(function (response) { + phpdebugbar.ajaxHandler.handle(response.request); + + return response; + }); +} + +export default axios; diff --git a/resources/assets/scripts/models/server.js b/resources/assets/scripts/models/server.js index b8ebe9332..e1c933e30 100644 --- a/resources/assets/scripts/models/server.js +++ b/resources/assets/scripts/models/server.js @@ -1,3 +1,21 @@ export default class Server { - + constructor({ + identifier, + uuid, + name, + node, + description, + allocation, + limits, + feature_limits + }) { + this.identifier = identifier; + this.uuid = uuid; + this.name = name; + this.node = node; + this.description = description; + this.allocation = allocation; + this.limits = limits; + this.feature_limits = feature_limits; + } } diff --git a/resources/assets/scripts/models/user.js b/resources/assets/scripts/models/user.js index c20f9143e..8da7353ff 100644 --- a/resources/assets/scripts/models/user.js +++ b/resources/assets/scripts/models/user.js @@ -1,25 +1,21 @@ +import axios from './../helpers/axios'; + export default class User { /** * Get a new user model by hitting the Panel API using the authentication token * provided. If no user can be retrieved null will be returned. * - * @param {string} token - * @param {string} cookie * @return {User|null} */ - static fromCookie(token, cookie = 'pterodactyl_session') { - window.axios.get('/api/client/account', { - headers: { - Cookie: `${cookie}=${token}`, - } - }) + static fromCookie() { + axios.get('/api/client/account') .then(response => { return new User(response.data.attributes); }) .catch(err => { console.error(err); return null; - }) + }); } /** diff --git a/resources/assets/scripts/store/index.js b/resources/assets/scripts/store/index.js index 0435b17bb..44c02653b 100644 --- a/resources/assets/scripts/store/index.js +++ b/resources/assets/scripts/store/index.js @@ -1,6 +1,6 @@ import auth from './modules/auth'; export default { - // strict: process.env.NODE_ENV !== 'production', + strict: process.env.NODE_ENV !== 'production', modules: { auth }, }; diff --git a/resources/assets/scripts/store/modules/auth.js b/resources/assets/scripts/store/modules/auth.js index 2971f5101..fb12aaea9 100644 --- a/resources/assets/scripts/store/modules/auth.js +++ b/resources/assets/scripts/store/modules/auth.js @@ -4,11 +4,7 @@ const route = require('./../../../../../vendor/tightenco/ziggy/src/js/route').de export default { namespaced: true, state: { - user: () => { - const data = JSON.parse(localStorage.getItem('token')); - - return User.fromCookie(data.value, data.name); - } + user: null, }, getters: { /**