diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index fae18efab..e970f5c24 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -2,7 +2,13 @@ namespace App\Exceptions; +use GuzzleHttp\Exception\ConnectException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; +use Illuminate\Http\Client\ConnectionException; +use Illuminate\Http\Exceptions\HttpResponseException; +use Illuminate\Http\Request; +use Illuminate\Http\Response; +use Illuminate\Validation\ValidationException; use League\OAuth2\Server\Exception\OAuthServerException; use Throwable; @@ -15,8 +21,8 @@ class Handler extends ExceptionHandler */ protected $dontReport = [ OAuthServerException::class, - \GuzzleHttp\Exception\ConnectException::class, - \Illuminate\Http\Client\ConnectionException::class, + ConnectException::class, + ConnectionException::class, ]; /** @@ -51,7 +57,7 @@ class Handler extends ExceptionHandler return app()->environment() !== 'production'; }); - $this->reportable(function (\Illuminate\Http\Client\ConnectionException $e) { + $this->reportable(function (ConnectionException $e) { return app()->environment() !== 'production'; }); } @@ -59,24 +65,30 @@ class Handler extends ExceptionHandler /** * Render an exception into an HTTP response. * - * @param \Illuminate\Http\Request $request + * @param Request $request * @param \Exception $exception - * @return \Illuminate\Http\Response + * @return Response */ public function render($request, Throwable $exception) { - if ($exception instanceof \Illuminate\Validation\ValidationException && $request->wantsJson()) { - return response()->json( - [ + if ($request->wantsJson()) { + if ($exception instanceof HttpResponseException) { + return $exception->getResponse(); + } + + if ($exception instanceof ValidationException) { + return response()->json([ 'message' => $exception->getMessage(), 'errors' => $exception->validator->getMessageBag(), - ], - method_exists($exception, 'getStatusCode') ? $exception->getStatusCode() : 500 - ); - } elseif ($request->wantsJson()) { + ], $exception->status); + } + + $isHttp = $this->isHttpException($exception); + return response()->json( ['error' => $exception->getMessage()], - method_exists($exception, 'getStatusCode') ? $exception->getStatusCode() : 500 + $isHttp ? $exception->getStatusCode() : 500, + $isHttp ? $exception->getHeaders() : [], ); } diff --git a/app/Http/Controllers/PersonalAccessTokenController.php b/app/Http/Controllers/PersonalAccessTokenController.php index cbb2e69c8..13f287817 100644 --- a/app/Http/Controllers/PersonalAccessTokenController.php +++ b/app/Http/Controllers/PersonalAccessTokenController.php @@ -78,6 +78,34 @@ class PersonalAccessTokenController extends Controller ]); } + public function renew(Request $request, string $token_id): JsonResponse + { + $oldToken = $request->user() + ->tokens() + ->with('client') + ->whereKey($token_id) + ->firstOrFail(); + + abort_unless($this->isPersonalAccessToken($oldToken), 404); + + abort_if($oldToken->revoked, 422, 'This token has already been revoked.'); + + $scopes = array_values(array_unique($oldToken->scopes ?? [])); + + $result = $request->user()->createToken( + $oldToken->name, + $scopes + ); + + $oldToken->revoke(); + + return response()->json([ + 'accessToken' => $result->accessToken, + 'token' => $this->serializeToken($result->token), + 'renewedTokenId' => $oldToken->id, + ]); + } + public function destroy(Request $request, string $token) { $token = $request->user() diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index f0e703080..ed20ce853 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -2,7 +2,37 @@ namespace App\Http; +use App\Http\Middleware\AccountInterstitial; +use App\Http\Middleware\Admin; +use App\Http\Middleware\DangerZone; +use App\Http\Middleware\EmailVerificationCheck; +use App\Http\Middleware\EncryptCookies; +use App\Http\Middleware\FrameGuard; +use App\Http\Middleware\Localization; +use App\Http\Middleware\RedirectIfAuthenticated; +use App\Http\Middleware\TrimStrings; +use App\Http\Middleware\TrustProxies; +use App\Http\Middleware\TwoFactorAuth; +use App\Http\Middleware\VerifyCsrfToken; +use Illuminate\Auth\Middleware\Authenticate; +use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth; +use Illuminate\Auth\Middleware\Authorize; +use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Illuminate\Foundation\Http\Kernel as HttpKernel; +use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode; +use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull; +use Illuminate\Foundation\Http\Middleware\ValidatePostSize; +use Illuminate\Http\Middleware\HandleCors; +use Illuminate\Http\Middleware\SetCacheHeaders; +use Illuminate\Routing\Middleware\SubstituteBindings; +use Illuminate\Routing\Middleware\ThrottleRequests; +use Illuminate\Routing\Middleware\ValidateSignature; +use Illuminate\Session\Middleware\AuthenticateSession; +use Illuminate\Session\Middleware\StartSession; +use Illuminate\View\Middleware\ShareErrorsFromSession; +use Laravel\Passport\Http\Middleware\CheckForAnyScope; +use Laravel\Passport\Http\Middleware\CheckScopes; +use Laravel\Passport\Http\Middleware\CreateFreshApiToken; class Kernel extends HttpKernel { @@ -14,12 +44,12 @@ class Kernel extends HttpKernel * @var array */ protected $middleware = [ - \Illuminate\Http\Middleware\HandleCors::class, - \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class, - \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, - \App\Http\Middleware\TrustProxies::class, - \App\Http\Middleware\TrimStrings::class, - \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, + HandleCors::class, + CheckForMaintenanceMode::class, + ValidatePostSize::class, + TrustProxies::class, + TrimStrings::class, + ConvertEmptyStringsToNull::class, ]; /** @@ -29,18 +59,29 @@ class Kernel extends HttpKernel */ protected $middlewareGroups = [ 'web' => [ - \App\Http\Middleware\EncryptCookies::class, - \App\Http\Middleware\FrameGuard::class, - \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, - \Illuminate\Session\Middleware\StartSession::class, - \Illuminate\Session\Middleware\AuthenticateSession::class, - \Illuminate\View\Middleware\ShareErrorsFromSession::class, - \App\Http\Middleware\VerifyCsrfToken::class, - \Illuminate\Routing\Middleware\SubstituteBindings::class, - \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class, + EncryptCookies::class, + FrameGuard::class, + AddQueuedCookiesToResponse::class, + StartSession::class, + AuthenticateSession::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + SubstituteBindings::class, + CreateFreshApiToken::class, // 'restricted', ], + 'oauth-web' => [ + EncryptCookies::class, + FrameGuard::class, + AddQueuedCookiesToResponse::class, + StartSession::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + SubstituteBindings::class, + CreateFreshApiToken::class, + ], + 'api' => [ 'bindings', ], @@ -54,23 +95,23 @@ class Kernel extends HttpKernel * @var array */ protected $routeMiddleware = [ - 'api.admin' => \App\Http\Middleware\Api\Admin::class, - 'admin' => \App\Http\Middleware\Admin::class, - 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, - 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, - 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, - 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, - 'can' => \Illuminate\Auth\Middleware\Authorize::class, - 'dangerzone' => \App\Http\Middleware\DangerZone::class, - 'localization' => \App\Http\Middleware\Localization::class, - 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, - 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, - 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, - 'twofactor' => \App\Http\Middleware\TwoFactorAuth::class, - 'validemail' => \App\Http\Middleware\EmailVerificationCheck::class, - 'interstitial' => \App\Http\Middleware\AccountInterstitial::class, - 'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class, - 'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class, + 'api.admin' => Middleware\Api\Admin::class, + 'admin' => Admin::class, + 'auth' => Authenticate::class, + 'auth.basic' => AuthenticateWithBasicAuth::class, + 'bindings' => SubstituteBindings::class, + 'cache.headers' => SetCacheHeaders::class, + 'can' => Authorize::class, + 'dangerzone' => DangerZone::class, + 'localization' => Localization::class, + 'guest' => RedirectIfAuthenticated::class, + 'signed' => ValidateSignature::class, + 'throttle' => ThrottleRequests::class, + 'twofactor' => TwoFactorAuth::class, + 'validemail' => EmailVerificationCheck::class, + 'interstitial' => AccountInterstitial::class, + 'scopes' => CheckScopes::class, + 'scope' => CheckForAnyScope::class, // 'restricted' => \App\Http\Middleware\RestrictedAccess::class, ]; } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 4c6e79683..e71ad7680 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -112,6 +112,36 @@ class AppServiceProvider extends ServiceProvider return Limit::perDay(50)->by($request->ip()); }); + RateLimiter::for('oauth-pat', function (Request $request) { + $user = $request->user('web'); + + $actor = $user + ? 'u:'.$user->getAuthIdentifier() + : 'ip:'.$request->ip(); + + $tooMany = function (Request $request, array $headers) { + return response()->json([ + 'message' => 'Too many requests', + 'retry_after' => isset($headers['Retry-After']) + ? (int) $headers['Retry-After'] + : null, + 'debug' => 'oauth-pat limiter hit', + 'headers' => $headers, + ], 429)->withHeaders($headers)->header('X-Debug-Limiter', 'oauth-pat'); + }; + + return [ + Limit::perMinute(3) + ->by("minute:{$actor}"), + + Limit::perHour(15) + ->by("hour:{$actor}"), + + Limit::perDay(20) + ->by("day:{$actor}"), + ]; + }); + Passport::useTokenModel(OAuthToken::class); Passport::tokensExpireIn(now()->addDays(config('instance.oauth.token_expiration', 356))); Passport::refreshTokensExpireIn(now()->addDays(config('instance.oauth.refresh_expiration', 400))); diff --git a/public/js/developers.js b/public/js/developers.js index b568822a4..49d50e1d2 100644 --- a/public/js/developers.js +++ b/public/js/developers.js @@ -1 +1 @@ -(self.webpackChunkpixelfed=self.webpackChunkpixelfed||[]).push([[755],{60621(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>a});const a={data:function(){return{tokens:[]}},ready:function(){this.prepareComponent()},mounted:function(){this.prepareComponent()},methods:{prepareComponent:function(){this.getTokens()},getTokens:function(){var t=this;axios.get("/oauth/tokens").then(function(e){t.tokens=e.data})},revoke:function(t){var e=this;axios.delete("/oauth/tokens/"+t.id).then(function(t){e.getTokens()})}}}},76860(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(74692);function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}const o={data:function(){return{clients:[],createForm:{errors:[],name:"",redirect:""},editForm:{errors:[],name:"",redirect:""}}},ready:function(){this.prepareComponent()},mounted:function(){this.prepareComponent()},methods:{prepareComponent:function(){this.getClients(),a("#modal-create-client").on("shown.bs.modal",function(){a("#create-client-name").focus()}),a("#modal-edit-client").on("shown.bs.modal",function(){a("#edit-client-name").focus()})},getClients:function(){var t=this;axios.get("/oauth/clients").then(function(e){t.clients=e.data})},showCreateClientForm:function(){a("#modal-create-client").modal("show")},store:function(){this.persistClient("post","/oauth/clients",this.createForm,"#modal-create-client")},edit:function(t){this.editForm.id=t.id,this.editForm.name=t.name,this.editForm.redirect=t.redirect,a("#modal-edit-client").modal("show")},update:function(){this.persistClient("put","/oauth/clients/"+this.editForm.id,this.editForm,"#modal-edit-client")},persistClient:function(t,e,s,o){var r=this;s.errors=[],axios[t](e,s).then(function(t){r.getClients(),s.name="",s.redirect="",s.errors=[],a(o).modal("hide")}).catch(function(t){"object"===n(t.response.data)?s.errors=_.flatten(_.toArray(t.response.data.errors)):s.errors=["Something went wrong. Please try again."]})},destroy:function(t){var e=this;axios.delete("/oauth/clients/"+t.id).then(function(t){e.getClients()})}}}},88838(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(74692);function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}const o={data:function(){return{accessToken:null,tokens:[],scopes:[],form:{name:"",scopes:[],errors:[]}}},mounted:function(){this.prepareComponent()},methods:{prepareComponent:function(){this.getTokens(),this.getScopes(),a("#modal-create-token").on("shown.bs.modal",function(){a("#create-token-name").focus()})},getScopeBadge:function(t){switch(t){case"*":case"write":case"follow":case"admin:read":case"admin:read:domain_blocks":case"admin:write":case"admin:write:domain_blocks":return"badge-danger";case"read":return"badge-secondary";case"push":return"badge-info"}},getTokens:function(){var t=this;axios.get("/oauth/personal-access-tokens").then(function(e){t.tokens=e.data})},getScopes:function(){var t=this;axios.get("/oauth/scopes").then(function(e){t.scopes=e.data})},showCreateTokenForm:function(){a("#modal-create-token").modal("show")},store:function(){var t=this;this.accessToken=null,this.form.errors=[],axios.post("/oauth/personal-access-tokens",this.form).then(function(e){t.form.name="",t.form.scopes=[],t.form.errors=[],t.tokens.push(e.data.token),t.showAccessToken(e.data.accessToken)}).catch(function(e){"object"===n(e.response.data)?t.form.errors=_.flatten(_.toArray(e.response.data.errors)):t.form.errors=["Something went wrong. Please try again."]})},toggleScope:function(t){this.scopeIsAssigned(t)?this.form.scopes=_.reject(this.form.scopes,function(e){return e===t}):this.form.scopes.push(t)},scopeIsAssigned:function(t){return _.indexOf(this.form.scopes,t)>=0},showAccessToken:function(t){a("#modal-create-token").modal("hide"),this.accessToken=t,a("#modal-access-token").modal("show")},revoke:function(t){var e=this;window.confirm("Delete this token? Any applications using it will stop working immediately.")&&axios.delete("/oauth/personal-access-tokens/"+t.id).then(function(){e.getTokens()})},formatDate:function(t){if(!t)return"";var e=new Date(t);return isNaN(e.getTime())?t:e.toLocaleString(void 0,{year:"numeric",month:"short",day:"numeric"})},isExpired:function(t){return!!t.expires_at&&new Date(t.expires_at).getTime()a,staticRenderFns:()=>n});var a=function(){var t=this,e=t._self._c;return e("div",[t.tokens.length>0?e("div",[e("div",{staticClass:"card card-default mb-4"},[e("div",{staticClass:"card-header font-weight-bold bg-white"},[t._v("Authorized Applications")]),t._v(" "),e("div",{staticClass:"card-body"},[e("table",{staticClass:"table table-borderless mb-0"},[t._m(0),t._v(" "),e("tbody",t._l(t.tokens,function(s){return e("tr",[e("td",{staticStyle:{"vertical-align":"middle"}},[t._v("\n "+t._s(s.client.name)+"\n ")]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[s.scopes.length>0?e("span",[t._v("\n "+t._s(s.scopes.join(", "))+"\n ")]):t._e()]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[e("a",{staticClass:"action-link text-danger",on:{click:function(e){return t.revoke(s)}}},[t._v("\n Revoke\n ")])])])}),0)])])])]):t._e()])},n=[function(){var t=this,e=t._self._c;return e("thead",[e("tr",[e("th",[t._v("Name")]),t._v(" "),e("th",[t._v("Scopes")]),t._v(" "),e("th")])])}]},47665(t,e,s){"use strict";s.r(e),s.d(e,{render:()=>a,staticRenderFns:()=>n});var a=function(){var t=this,e=t._self._c;return e("div",[e("div",{staticClass:"card card-default mb-4"},[e("div",{staticClass:"card-header font-weight-bold bg-white"},[e("div",{staticStyle:{display:"flex","justify-content":"space-between","align-items":"center"}},[e("span",[t._v("\n OAuth Clients\n ")]),t._v(" "),e("a",{staticClass:"action-link",attrs:{tabindex:"-1"},on:{click:t.showCreateClientForm}},[t._v("\n Create New Client\n ")])])]),t._v(" "),e("div",{staticClass:"card-body"},[0===t.clients.length?e("p",{staticClass:"mb-0 font-weight-bold text-center lead p-5"},[t._v("\n You have not created any OAuth clients.\n ")]):t._e(),t._v(" "),t.clients.length>0?e("table",{staticClass:"table table-borderless mb-0"},[t._m(0),t._v(" "),e("tbody",t._l(t.clients,function(s){return e("tr",[e("td",{staticStyle:{"vertical-align":"middle"}},[t._v("\n "+t._s(s.id)+"\n ")]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[t._v("\n "+t._s(s.name)+"\n ")]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[e("code",[t._v(t._s(s.secret))])]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[e("a",{staticClass:"btn btn-outline-secondary btn-sm py-1",attrs:{tabindex:"-1"},on:{click:function(e){return t.edit(s)}}},[t._v("\n Edit\n ")])]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[e("a",{staticClass:"btn btn-outline-danger btn-sm py-1",attrs:{href:""},on:{click:function(e){return t.destroy(s)}}},[t._v("\n Delete\n ")])])])}),0)]):t._e()])]),t._v(" "),e("div",{staticClass:"modal fade",attrs:{id:"modal-create-client",tabindex:"-1",role:"dialog"}},[e("div",{staticClass:"modal-dialog"},[e("div",{staticClass:"modal-content"},[t._m(1),t._v(" "),e("div",{staticClass:"modal-body"},[t.createForm.errors.length>0?e("div",{staticClass:"alert alert-danger"},[t._m(2),t._v(" "),e("br"),t._v(" "),e("ul",t._l(t.createForm.errors,function(s){return e("li",[t._v("\n "+t._s(s)+"\n ")])}),0)]):t._e(),t._v(" "),e("form",{attrs:{role:"form"}},[e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Name")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.createForm.name,expression:"createForm.name"}],staticClass:"form-control",attrs:{id:"create-client-name",type:"text",autocomplete:"off"},domProps:{value:t.createForm.name},on:{keyup:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.store.apply(null,arguments)},input:function(e){e.target.composing||t.$set(t.createForm,"name",e.target.value)}}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Something your users will recognize and trust.\n ")])])]),t._v(" "),t._m(3),t._v(" "),t._m(4),t._v(" "),e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Redirect URL")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.createForm.redirect,expression:"createForm.redirect"}],staticClass:"form-control",attrs:{type:"text",name:"redirect"},domProps:{value:t.createForm.redirect},on:{keyup:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.store.apply(null,arguments)},input:function(e){e.target.composing||t.$set(t.createForm,"redirect",e.target.value)}}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Your application's authorization callback URL.\n ")])])]),t._v(" "),t._m(5)])]),t._v(" "),e("div",{staticClass:"modal-footer"},[e("button",{staticClass:"btn btn-secondary font-weight-bold",attrs:{type:"button","data-dismiss":"modal"}},[t._v("Close")]),t._v(" "),e("button",{staticClass:"btn btn-primary font-weight-bold",attrs:{type:"button"},on:{click:t.store}},[t._v("\n Create\n ")])])])])]),t._v(" "),e("div",{staticClass:"modal fade",attrs:{id:"modal-edit-client",tabindex:"-1",role:"dialog"}},[e("div",{staticClass:"modal-dialog"},[e("div",{staticClass:"modal-content"},[t._m(6),t._v(" "),e("div",{staticClass:"modal-body"},[t.editForm.errors.length>0?e("div",{staticClass:"alert alert-danger"},[t._m(7),t._v(" "),e("br"),t._v(" "),e("ul",t._l(t.editForm.errors,function(s){return e("li",[t._v("\n "+t._s(s)+"\n ")])}),0)]):t._e(),t._v(" "),e("form",{attrs:{role:"form"}},[e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Name")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.editForm.name,expression:"editForm.name"}],staticClass:"form-control",attrs:{id:"edit-client-name",type:"text"},domProps:{value:t.editForm.name},on:{keyup:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.update.apply(null,arguments)},input:function(e){e.target.composing||t.$set(t.editForm,"name",e.target.value)}}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Something your users will recognize and trust.\n ")])])]),t._v(" "),e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Redirect URL")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.editForm.redirect,expression:"editForm.redirect"}],staticClass:"form-control",attrs:{type:"text",name:"redirect"},domProps:{value:t.editForm.redirect},on:{keyup:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.update.apply(null,arguments)},input:function(e){e.target.composing||t.$set(t.editForm,"redirect",e.target.value)}}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Your application's authorization callback URL.\n ")])])])])]),t._v(" "),e("div",{staticClass:"modal-footer"},[e("button",{staticClass:"btn btn-secondary",attrs:{type:"button","data-dismiss":"modal"}},[t._v("Close")]),t._v(" "),e("button",{staticClass:"btn btn-primary",attrs:{type:"button"},on:{click:t.update}},[t._v("\n Save Changes\n ")])])])])])])},n=[function(){var t=this,e=t._self._c;return e("thead",[e("tr",[e("th",[t._v("Client ID")]),t._v(" "),e("th",[t._v("Name")]),t._v(" "),e("th",[t._v("Secret")]),t._v(" "),e("th"),t._v(" "),e("th")])])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"modal-header"},[e("h4",{staticClass:"modal-title"},[t._v("\n Create Client\n ")]),t._v(" "),e("button",{staticClass:"close",attrs:{type:"button","data-dismiss":"modal","aria-hidden":"true"}},[t._v("×")])])},function(){var t=this,e=t._self._c;return e("p",{staticClass:"mb-0"},[e("strong",[t._v("Whoops!")]),t._v(" Something went wrong!")])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Description")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("textarea",{staticClass:"form-control",attrs:{rows:"3"}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n A brief description of your app\n ")])])])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Website")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("input",{staticClass:"form-control",attrs:{type:"text",autocomplete:"off"}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Your website url\n ")])])])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Scopes")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("div",{staticClass:"custom-control custom-switch"},[e("input",{staticClass:"custom-control-input",attrs:{type:"checkbox",id:"customSwitch1"}}),t._v(" "),e("label",{staticClass:"custom-control-label",attrs:{for:"customSwitch1"}},[t._v("Read")])]),t._v(" "),e("div",{staticClass:"custom-control custom-switch"},[e("input",{staticClass:"custom-control-input",attrs:{type:"checkbox",id:"customSwitch2"}}),t._v(" "),e("label",{staticClass:"custom-control-label",attrs:{for:"customSwitch2"}},[t._v("Write")])]),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Your application's scopes.\n ")])])])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"modal-header"},[e("h4",{staticClass:"modal-title"},[t._v("\n Edit Client\n ")]),t._v(" "),e("button",{staticClass:"close",attrs:{type:"button","data-dismiss":"modal","aria-hidden":"true"}},[t._v("×")])])},function(){var t=this,e=t._self._c;return e("p",{staticClass:"mb-0"},[e("strong",[t._v("Whoops!")]),t._v(" Something went wrong!")])}]},10118(t,e,s){"use strict";s.r(e),s.d(e,{render:()=>a,staticRenderFns:()=>n});var a=function(){var t=this,e=t._self._c;return e("div",[e("div",[e("div",{staticClass:"card card-default mb-4"},[e("div",{staticClass:"card-header font-weight-bold bg-white"},[e("div",{staticStyle:{display:"flex","justify-content":"space-between","align-items":"center"}},[e("span",[t._v("\n Personal Access Tokens\n ")]),t._v(" "),e("a",{staticClass:"action-link",attrs:{tabindex:"-1"},on:{click:t.showCreateTokenForm}},[t._v("\n Create New Token\n ")])])]),t._v(" "),e("div",{staticClass:"card-body"},[0===t.tokens.length?e("p",{staticClass:"mb-0"},[t._v("\n You have not created any personal access tokens.\n ")]):t._e(),t._v(" "),t.tokens.length>0?e("table",{staticClass:"table table-borderless mb-0"},[t._m(0),t._v(" "),e("tbody",t._l(t.tokens,function(s){return e("tr",{key:s.id},[e("td",{staticStyle:{"vertical-align":"middle"}},[e("div",{staticClass:"font-weight-bold"},[t._v(t._s(s.name))]),t._v(" "),s.created_at?e("small",{staticClass:"text-muted",staticStyle:{"font-size":"12px"}},[t._v("\n Created "+t._s(t.formatDate(s.created_at))+"\n ")]):t._e()]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[s.scopes&&s.scopes.length>0?t._l(s.scopes,function(s){return e("span",{key:s,staticClass:"badge mr-1 mb-1",class:t.getScopeBadge(s)},[t._v("\n "+t._s("*"===s?"all scopes":s)+"\n ")])}):e("span",{staticClass:"text-muted"},[t._v("—")])],2),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[s.expires_at?e("span",{class:{"text-danger":t.isExpired(s)},staticStyle:{"font-size":"12px"},attrs:{title:t.formatDate(s.expires_at)}},[t._v("\n "+t._s(t.formatDate(s.expires_at))+"\n "),t.isExpired(s)?e("span",{staticClass:"font-weight-bold"},[t._v("(expired)")]):t._e()]):e("span",{staticClass:"text-muted text-xs"},[t._v("\n Never\n ")])]),t._v(" "),e("td",{staticClass:"text-right",staticStyle:{"vertical-align":"middle"}},[e("a",{staticClass:"btn btn-danger btn-sm",staticStyle:{"font-weight":"bold"},on:{click:function(e){return t.revoke(s)}}},[t._v("\n Delete\n ")])])])}),0)]):t._e()])])]),t._v(" "),e("div",{staticClass:"modal fade",attrs:{id:"modal-create-token",tabindex:"-1",role:"dialog"}},[e("div",{staticClass:"modal-dialog"},[e("div",{staticClass:"modal-content"},[t._m(1),t._v(" "),e("div",{staticClass:"modal-body"},[t.form.errors.length>0?e("div",{staticClass:"alert alert-danger"},[t._m(2),t._v(" "),e("br"),t._v(" "),e("ul",t._l(t.form.errors,function(s,a){return e("li",{key:a},[t._v("\n "+t._s(s)+"\n ")])}),0)]):t._e(),t._v(" "),e("form",{attrs:{role:"form"},on:{submit:function(e){return e.preventDefault(),t.store.apply(null,arguments)}}},[e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-4 col-form-label"},[t._v("Name")]),t._v(" "),e("div",{staticClass:"col-md-6"},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.form.name,expression:"form.name"}],staticClass:"form-control",attrs:{id:"create-token-name",type:"text",name:"name",autocomplete:"off"},domProps:{value:t.form.name},on:{input:function(e){e.target.composing||t.$set(t.form,"name",e.target.value)}}})])]),t._v(" "),t.scopes.length>0?e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-4 col-form-label"},[t._v("Scopes")]),t._v(" "),e("div",{staticClass:"col-md-6"},t._l(t.scopes,function(s){return e("div",{key:s.id},[e("div",{staticClass:"checkbox"},[e("label",[e("input",{attrs:{type:"checkbox"},domProps:{checked:t.scopeIsAssigned(s.id)},on:{click:function(e){return t.toggleScope(s.id)}}}),t._v("\n\n "+t._s(s.id)+"\n ")]),t._v(" "),s.description?e("small",{staticClass:"text-muted d-block ml-4"},[t._v("\n "+t._s(s.description)+"\n ")]):t._e()])])}),0)]):t._e()])]),t._v(" "),e("div",{staticClass:"modal-footer"},[e("button",{staticClass:"btn btn-secondary font-weight-bold",attrs:{type:"button","data-dismiss":"modal"}},[t._v("Close")]),t._v(" "),e("button",{staticClass:"btn btn-primary font-weight-bold",attrs:{type:"button"},on:{click:t.store}},[t._v("\n Create\n ")])])])])]),t._v(" "),e("div",{staticClass:"modal fade",attrs:{id:"modal-access-token",tabindex:"-1",role:"dialog"}},[e("div",{staticClass:"modal-dialog"},[e("div",{staticClass:"modal-content"},[t._m(3),t._v(" "),e("div",{staticClass:"modal-body"},[e("p",[t._v("\n Here is your new personal access token. This is the only time it will be shown so don't lose it!\n You may now use this token to make API requests.\n ")]),t._v(" "),e("textarea",{staticClass:"form-control",attrs:{rows:"10",readonly:""}},[t._v(t._s(t.accessToken))])]),t._v(" "),t._m(4)])])])])},n=[function(){var t=this,e=t._self._c;return e("thead",[e("tr",[e("th",[t._v("Name")]),t._v(" "),e("th",[t._v("Scopes")]),t._v(" "),e("th",[t._v("Expires")]),t._v(" "),e("th")])])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"modal-header"},[e("h4",{staticClass:"modal-title"},[t._v("\n Create Token\n ")]),t._v(" "),e("button",{staticClass:"close",attrs:{type:"button","data-dismiss":"modal","aria-hidden":"true"}},[t._v("×")])])},function(){var t=this,e=t._self._c;return e("p",{staticClass:"mb-0"},[e("strong",[t._v("Whoops!")]),t._v(" Something went wrong!")])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"modal-header"},[e("h4",{staticClass:"modal-title"},[t._v("\n Personal Access Token\n ")]),t._v(" "),e("button",{staticClass:"close",attrs:{type:"button","data-dismiss":"modal","aria-hidden":"true"}},[t._v("×")])])},function(){var t=this._self._c;return t("div",{staticClass:"modal-footer"},[t("button",{staticClass:"btn btn-secondary",attrs:{type:"button","data-dismiss":"modal"}},[this._v("Close")])])}]},15905(t,e,s){Vue.component("passport-clients",s(19308).default),Vue.component("passport-authorized-clients",s(22593).default),Vue.component("passport-personal-access-tokens",s(87036).default)},13025(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(76798),n=s.n(a)()(function(t){return t[1]});n.push([t.id,".action-link[data-v-1b737fda]{cursor:pointer}",""]);const o=n},49921(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(76798),n=s.n(a)()(function(t){return t[1]});n.push([t.id,".action-link[data-v-d71fe564]{cursor:pointer}",""]);const o=n},1420(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(76798),n=s.n(a)()(function(t){return t[1]});n.push([t.id,".action-link[data-v-4f2aff84]{cursor:pointer}",""]);const o=n},19318(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>i});var a=s(85072),n=s.n(a),o=s(13025),r={insert:"head",singleton:!1};n()(o.default,r);const i=o.default.locals||{}},37622(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>i});var a=s(85072),n=s.n(a),o=s(49921),r={insert:"head",singleton:!1};n()(o.default,r);const i=o.default.locals||{}},10621(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>i});var a=s(85072),n=s.n(a),o=s(1420),r={insert:"head",singleton:!1};n()(o.default,r);const i=o.default.locals||{}},22593(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>r});var a=s(93638),n=s(83382),o={};for(const t in n)"default"!==t&&(o[t]=()=>n[t]);s.d(e,o);s(703);const r=(0,s(14486).default)(n.default,a.render,a.staticRenderFns,!1,null,"1b737fda",null).exports},19308(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>r});var a=s(28004),n=s(71991),o={};for(const t in n)"default"!==t&&(o[t]=()=>n[t]);s.d(e,o);s(54019);const r=(0,s(14486).default)(n.default,a.render,a.staticRenderFns,!1,null,"d71fe564",null).exports},87036(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>r});var a=s(69969),n=s(38335),o={};for(const t in n)"default"!==t&&(o[t]=()=>n[t]);s.d(e,o);s(54946);const r=(0,s(14486).default)(n.default,a.render,a.staticRenderFns,!1,null,"4f2aff84",null).exports},83382(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(60621),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n);const o=a.default},71991(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(76860),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n);const o=a.default},38335(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(88838),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n);const o=a.default},93638(t,e,s){"use strict";s.r(e);var a=s(41671),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)},28004(t,e,s){"use strict";s.r(e);var a=s(47665),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)},69969(t,e,s){"use strict";s.r(e);var a=s(10118),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)},703(t,e,s){"use strict";s.r(e);var a=s(19318),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)},54019(t,e,s){"use strict";s.r(e);var a=s(37622),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)},54946(t,e,s){"use strict";s.r(e);var a=s(10621),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)}},t=>{t.O(0,[3660],()=>{return e=15905,t(t.s=e);var e});t.O()}]); \ No newline at end of file +(self.webpackChunkpixelfed=self.webpackChunkpixelfed||[]).push([[755],{60621(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>a});const a={data:function(){return{tokens:[]}},ready:function(){this.prepareComponent()},mounted:function(){this.prepareComponent()},methods:{prepareComponent:function(){this.getTokens()},getTokens:function(){var t=this;axios.get("/oauth/tokens").then(function(e){t.tokens=e.data})},revoke:function(t){var e=this;axios.delete("/oauth/tokens/"+t.id).then(function(t){e.getTokens()})}}}},76860(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(74692);function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}const o={data:function(){return{clients:[],createForm:{errors:[],name:"",redirect:""},editForm:{errors:[],name:"",redirect:""}}},ready:function(){this.prepareComponent()},mounted:function(){this.prepareComponent()},methods:{prepareComponent:function(){this.getClients(),a("#modal-create-client").on("shown.bs.modal",function(){a("#create-client-name").focus()}),a("#modal-edit-client").on("shown.bs.modal",function(){a("#edit-client-name").focus()})},getClients:function(){var t=this;axios.get("/oauth/clients").then(function(e){t.clients=e.data})},showCreateClientForm:function(){a("#modal-create-client").modal("show")},store:function(){this.persistClient("post","/oauth/clients",this.createForm,"#modal-create-client")},edit:function(t){this.editForm.id=t.id,this.editForm.name=t.name,this.editForm.redirect=t.redirect,a("#modal-edit-client").modal("show")},update:function(){this.persistClient("put","/oauth/clients/"+this.editForm.id,this.editForm,"#modal-edit-client")},persistClient:function(t,e,s,o){var r=this;s.errors=[],axios[t](e,s).then(function(t){r.getClients(),s.name="",s.redirect="",s.errors=[],a(o).modal("hide")}).catch(function(t){"object"===n(t.response.data)?s.errors=_.flatten(_.toArray(t.response.data.errors)):s.errors=["Something went wrong. Please try again."]})},destroy:function(t){var e=this;axios.delete("/oauth/clients/"+t.id).then(function(t){e.getClients()})}}}},88838(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(74692);function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}const o={data:function(){return{accessToken:null,tokens:[],scopes:[],form:{name:"",scopes:[],errors:[]}}},mounted:function(){this.prepareComponent()},methods:{prepareComponent:function(){this.getTokens(),this.getScopes(),a("#modal-create-token").on("shown.bs.modal",function(){a("#create-token-name").focus()})},getScopeBadge:function(t){switch(t){case"*":case"write":case"follow":case"admin:read":case"admin:read:domain_blocks":case"admin:write":case"admin:write:domain_blocks":return"badge-danger";case"read":return"badge-secondary";case"push":return"badge-info"}},getTokens:function(){var t=this;axios.get("/oauth/personal-access-tokens").then(function(e){t.tokens=e.data})},getScopes:function(){var t=this;axios.get("/oauth/scopes").then(function(e){t.scopes=e.data})},showCreateTokenForm:function(){a("#modal-create-token").modal("show")},store:function(){var t=this;this.accessToken=null,this.form.errors=[],axios.post("/oauth/personal-access-tokens",this.form).then(function(e){t.form.name="",t.form.scopes=[],t.form.errors=[],t.tokens.push(e.data.token),t.showAccessToken(e.data.accessToken)}).catch(function(e){"object"===n(e.response.data)?t.form.errors=_.flatten(_.toArray(e.response.data.errors)):t.form.errors=["Something went wrong. Please try again."]})},toggleScope:function(t){this.scopeIsAssigned(t)?this.form.scopes=_.reject(this.form.scopes,function(e){return e===t}):this.form.scopes.push(t)},scopeIsAssigned:function(t){return _.indexOf(this.form.scopes,t)>=0},showAccessToken:function(t){a("#modal-create-token").modal("hide"),this.accessToken=t,a("#modal-access-token").modal("show")},revoke:function(t){var e=this;swal({title:"Confirm token deletion",text:"Are you sure you want to delete this token? Any applications using it will stop working immediately.",icon:"warning",dangerMode:!0,buttons:!0}).then(function(s){s&&axios.delete("/oauth/personal-access-tokens/"+t.id).then(function(){e.getTokens()})})},renew:function(t){var e=this;swal({title:"Confirm token renewal",text:"Are you sure you want to renew this token? Any applications using it will stop working immediately, a new token will be generated and only shown once.",icon:"warning",dangerMode:!0,buttons:!0}).then(function(s){s&&(e.accessToken=null,axios.post("/oauth/personal-access-tokens/"+t.id+"/renew").then(function(t){e.tokens=e.tokens.filter(function(e){return e.id!==t.data.renewedTokenId}),e.tokens.push(t.data.token),e.showAccessToken(t.data.accessToken)}).catch(function(t){alert("Unable to renew this token. Please try again.")}))})},formatDate:function(t){if(!t)return"";var e=new Date(t);return isNaN(e.getTime())?t:e.toLocaleString(void 0,{year:"numeric",month:"short",day:"numeric"})},isExpired:function(t){return!!t.expires_at&&new Date(t.expires_at).getTime()a,staticRenderFns:()=>n});var a=function(){var t=this,e=t._self._c;return e("div",[t.tokens.length>0?e("div",[e("div",{staticClass:"card card-default mb-4"},[e("div",{staticClass:"card-header font-weight-bold bg-white"},[t._v("Authorized Applications")]),t._v(" "),e("div",{staticClass:"card-body"},[e("table",{staticClass:"table table-borderless mb-0"},[t._m(0),t._v(" "),e("tbody",t._l(t.tokens,function(s){return e("tr",[e("td",{staticStyle:{"vertical-align":"middle"}},[t._v("\n "+t._s(s.client.name)+"\n ")]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[s.scopes.length>0?e("span",[t._v("\n "+t._s(s.scopes.join(", "))+"\n ")]):t._e()]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[e("a",{staticClass:"action-link text-danger",on:{click:function(e){return t.revoke(s)}}},[t._v("\n Revoke\n ")])])])}),0)])])])]):t._e()])},n=[function(){var t=this,e=t._self._c;return e("thead",[e("tr",[e("th",[t._v("Name")]),t._v(" "),e("th",[t._v("Scopes")]),t._v(" "),e("th")])])}]},47665(t,e,s){"use strict";s.r(e),s.d(e,{render:()=>a,staticRenderFns:()=>n});var a=function(){var t=this,e=t._self._c;return e("div",[e("div",{staticClass:"card card-default mb-4"},[e("div",{staticClass:"card-header font-weight-bold bg-white"},[e("div",{staticStyle:{display:"flex","justify-content":"space-between","align-items":"center"}},[e("span",[t._v("\n OAuth Clients\n ")]),t._v(" "),e("a",{staticClass:"action-link",attrs:{tabindex:"-1"},on:{click:t.showCreateClientForm}},[t._v("\n Create New Client\n ")])])]),t._v(" "),e("div",{staticClass:"card-body"},[0===t.clients.length?e("p",{staticClass:"mb-0 font-weight-bold text-center lead p-5"},[t._v("\n You have not created any OAuth clients.\n ")]):t._e(),t._v(" "),t.clients.length>0?e("table",{staticClass:"table table-borderless mb-0"},[t._m(0),t._v(" "),e("tbody",t._l(t.clients,function(s){return e("tr",[e("td",{staticStyle:{"vertical-align":"middle"}},[t._v("\n "+t._s(s.id)+"\n ")]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[t._v("\n "+t._s(s.name)+"\n ")]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[e("code",[t._v(t._s(s.secret))])]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[e("a",{staticClass:"btn btn-outline-secondary btn-sm py-1",attrs:{tabindex:"-1"},on:{click:function(e){return t.edit(s)}}},[t._v("\n Edit\n ")])]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[e("a",{staticClass:"btn btn-outline-danger btn-sm py-1",attrs:{href:""},on:{click:function(e){return t.destroy(s)}}},[t._v("\n Delete\n ")])])])}),0)]):t._e()])]),t._v(" "),e("div",{staticClass:"modal fade",attrs:{id:"modal-create-client",tabindex:"-1",role:"dialog"}},[e("div",{staticClass:"modal-dialog"},[e("div",{staticClass:"modal-content"},[t._m(1),t._v(" "),e("div",{staticClass:"modal-body"},[t.createForm.errors.length>0?e("div",{staticClass:"alert alert-danger"},[t._m(2),t._v(" "),e("br"),t._v(" "),e("ul",t._l(t.createForm.errors,function(s){return e("li",[t._v("\n "+t._s(s)+"\n ")])}),0)]):t._e(),t._v(" "),e("form",{attrs:{role:"form"}},[e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Name")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.createForm.name,expression:"createForm.name"}],staticClass:"form-control",attrs:{id:"create-client-name",type:"text",autocomplete:"off"},domProps:{value:t.createForm.name},on:{keyup:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.store.apply(null,arguments)},input:function(e){e.target.composing||t.$set(t.createForm,"name",e.target.value)}}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Something your users will recognize and trust.\n ")])])]),t._v(" "),t._m(3),t._v(" "),t._m(4),t._v(" "),e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Redirect URL")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.createForm.redirect,expression:"createForm.redirect"}],staticClass:"form-control",attrs:{type:"text",name:"redirect"},domProps:{value:t.createForm.redirect},on:{keyup:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.store.apply(null,arguments)},input:function(e){e.target.composing||t.$set(t.createForm,"redirect",e.target.value)}}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Your application's authorization callback URL.\n ")])])]),t._v(" "),t._m(5)])]),t._v(" "),e("div",{staticClass:"modal-footer"},[e("button",{staticClass:"btn btn-secondary font-weight-bold",attrs:{type:"button","data-dismiss":"modal"}},[t._v("Close")]),t._v(" "),e("button",{staticClass:"btn btn-primary font-weight-bold",attrs:{type:"button"},on:{click:t.store}},[t._v("\n Create\n ")])])])])]),t._v(" "),e("div",{staticClass:"modal fade",attrs:{id:"modal-edit-client",tabindex:"-1",role:"dialog"}},[e("div",{staticClass:"modal-dialog"},[e("div",{staticClass:"modal-content"},[t._m(6),t._v(" "),e("div",{staticClass:"modal-body"},[t.editForm.errors.length>0?e("div",{staticClass:"alert alert-danger"},[t._m(7),t._v(" "),e("br"),t._v(" "),e("ul",t._l(t.editForm.errors,function(s){return e("li",[t._v("\n "+t._s(s)+"\n ")])}),0)]):t._e(),t._v(" "),e("form",{attrs:{role:"form"}},[e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Name")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.editForm.name,expression:"editForm.name"}],staticClass:"form-control",attrs:{id:"edit-client-name",type:"text"},domProps:{value:t.editForm.name},on:{keyup:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.update.apply(null,arguments)},input:function(e){e.target.composing||t.$set(t.editForm,"name",e.target.value)}}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Something your users will recognize and trust.\n ")])])]),t._v(" "),e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Redirect URL")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.editForm.redirect,expression:"editForm.redirect"}],staticClass:"form-control",attrs:{type:"text",name:"redirect"},domProps:{value:t.editForm.redirect},on:{keyup:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.update.apply(null,arguments)},input:function(e){e.target.composing||t.$set(t.editForm,"redirect",e.target.value)}}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Your application's authorization callback URL.\n ")])])])])]),t._v(" "),e("div",{staticClass:"modal-footer"},[e("button",{staticClass:"btn btn-secondary",attrs:{type:"button","data-dismiss":"modal"}},[t._v("Close")]),t._v(" "),e("button",{staticClass:"btn btn-primary",attrs:{type:"button"},on:{click:t.update}},[t._v("\n Save Changes\n ")])])])])])])},n=[function(){var t=this,e=t._self._c;return e("thead",[e("tr",[e("th",[t._v("Client ID")]),t._v(" "),e("th",[t._v("Name")]),t._v(" "),e("th",[t._v("Secret")]),t._v(" "),e("th"),t._v(" "),e("th")])])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"modal-header"},[e("h4",{staticClass:"modal-title"},[t._v("\n Create Client\n ")]),t._v(" "),e("button",{staticClass:"close",attrs:{type:"button","data-dismiss":"modal","aria-hidden":"true"}},[t._v("×")])])},function(){var t=this,e=t._self._c;return e("p",{staticClass:"mb-0"},[e("strong",[t._v("Whoops!")]),t._v(" Something went wrong!")])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Description")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("textarea",{staticClass:"form-control",attrs:{rows:"3"}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n A brief description of your app\n ")])])])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Website")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("input",{staticClass:"form-control",attrs:{type:"text",autocomplete:"off"}}),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Your website url\n ")])])])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-3 col-form-label"},[t._v("Scopes")]),t._v(" "),e("div",{staticClass:"col-md-9"},[e("div",{staticClass:"custom-control custom-switch"},[e("input",{staticClass:"custom-control-input",attrs:{type:"checkbox",id:"customSwitch1"}}),t._v(" "),e("label",{staticClass:"custom-control-label",attrs:{for:"customSwitch1"}},[t._v("Read")])]),t._v(" "),e("div",{staticClass:"custom-control custom-switch"},[e("input",{staticClass:"custom-control-input",attrs:{type:"checkbox",id:"customSwitch2"}}),t._v(" "),e("label",{staticClass:"custom-control-label",attrs:{for:"customSwitch2"}},[t._v("Write")])]),t._v(" "),e("span",{staticClass:"form-text text-muted"},[t._v("\n Your application's scopes.\n ")])])])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"modal-header"},[e("h4",{staticClass:"modal-title"},[t._v("\n Edit Client\n ")]),t._v(" "),e("button",{staticClass:"close",attrs:{type:"button","data-dismiss":"modal","aria-hidden":"true"}},[t._v("×")])])},function(){var t=this,e=t._self._c;return e("p",{staticClass:"mb-0"},[e("strong",[t._v("Whoops!")]),t._v(" Something went wrong!")])}]},29834(t,e,s){"use strict";s.r(e),s.d(e,{render:()=>a,staticRenderFns:()=>n});var a=function(){var t=this,e=t._self._c;return e("div",[e("div",[e("div",{staticClass:"card card-default mb-4"},[e("div",{staticClass:"card-header font-weight-bold bg-white"},[e("div",{staticStyle:{display:"flex","justify-content":"space-between","align-items":"center"}},[e("span",[t._v("\n Personal Access Tokens\n ")]),t._v(" "),e("a",{staticClass:"action-link",attrs:{tabindex:"-1"},on:{click:t.showCreateTokenForm}},[t._v("\n Create New Token\n ")])])]),t._v(" "),e("div",{staticClass:"card-body"},[0===t.tokens.length?e("p",{staticClass:"mb-0"},[t._v("\n You have not created any personal access tokens.\n ")]):t._e(),t._v(" "),t.tokens.length>0?e("table",{staticClass:"table table-borderless mb-0"},[t._m(0),t._v(" "),e("tbody",t._l(t.tokens,function(s){return e("tr",{key:s.id},[e("td",{staticStyle:{"vertical-align":"middle"}},[e("div",{staticClass:"font-weight-bold"},[t._v(t._s(s.name))]),t._v(" "),s.created_at?e("small",{staticClass:"text-muted",staticStyle:{"font-size":"12px"}},[t._v("\n Created "+t._s(t.formatDate(s.created_at))+"\n ")]):t._e()]),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[s.scopes&&s.scopes.length>0?t._l(s.scopes,function(s){return e("span",{key:s,staticClass:"badge mr-1 mb-1",class:t.getScopeBadge(s)},[t._v("\n "+t._s("*"===s?"all scopes":s)+"\n ")])}):e("span",{staticClass:"text-muted"},[t._v("—")])],2),t._v(" "),e("td",{staticStyle:{"vertical-align":"middle"}},[s.expires_at?e("span",{class:{"text-danger":t.isExpired(s)},staticStyle:{"font-size":"12px"},attrs:{title:t.formatDate(s.expires_at)}},[t._v("\n "+t._s(t.formatDate(s.expires_at))+"\n "),t.isExpired(s)?e("span",{staticClass:"font-weight-bold"},[t._v("(expired)")]):t._e()]):e("span",{staticClass:"text-muted text-xs"},[t._v("\n Never\n ")])]),t._v(" "),e("td",{staticClass:"d-flex"},[e("a",{staticClass:"btn btn-warning btn-sm",staticStyle:{"font-weight":"bold"},on:{click:function(e){return t.renew(s)}}},[t._v("\n Renew\n ")]),t._v(" "),e("span",{staticClass:"mx-1"}),t._v(" "),e("a",{staticClass:"btn btn-danger btn-sm",staticStyle:{"font-weight":"bold"},on:{click:function(e){return t.revoke(s)}}},[t._v("\n Delete\n ")])])])}),0)]):t._e()])])]),t._v(" "),e("div",{staticClass:"modal fade",attrs:{id:"modal-create-token",tabindex:"-1",role:"dialog"}},[e("div",{staticClass:"modal-dialog"},[e("div",{staticClass:"modal-content"},[t._m(1),t._v(" "),e("div",{staticClass:"modal-body"},[t.form.errors.length>0?e("div",{staticClass:"alert alert-danger"},[t._m(2),t._v(" "),e("br"),t._v(" "),e("ul",t._l(t.form.errors,function(s,a){return e("li",{key:a},[t._v("\n "+t._s(s)+"\n ")])}),0)]):t._e(),t._v(" "),e("form",{attrs:{role:"form"},on:{submit:function(e){return e.preventDefault(),t.store.apply(null,arguments)}}},[e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-4 col-form-label"},[t._v("Name")]),t._v(" "),e("div",{staticClass:"col-md-6"},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.form.name,expression:"form.name"}],staticClass:"form-control",attrs:{id:"create-token-name",type:"text",name:"name",autocomplete:"off"},domProps:{value:t.form.name},on:{input:function(e){e.target.composing||t.$set(t.form,"name",e.target.value)}}})])]),t._v(" "),t.scopes.length>0?e("div",{staticClass:"form-group row"},[e("label",{staticClass:"col-md-4 col-form-label"},[t._v("Scopes")]),t._v(" "),e("div",{staticClass:"col-md-6"},t._l(t.scopes,function(s){return e("div",{key:s.id},[e("div",{staticClass:"checkbox"},[e("label",[e("input",{attrs:{type:"checkbox"},domProps:{checked:t.scopeIsAssigned(s.id)},on:{click:function(e){return t.toggleScope(s.id)}}}),t._v("\n\n "+t._s(s.id)+"\n ")]),t._v(" "),s.description?e("small",{staticClass:"text-muted d-block ml-4"},[t._v("\n "+t._s(s.description)+"\n ")]):t._e()])])}),0)]):t._e()])]),t._v(" "),e("div",{staticClass:"modal-footer"},[e("button",{staticClass:"btn btn-secondary font-weight-bold",attrs:{type:"button","data-dismiss":"modal"}},[t._v("Close")]),t._v(" "),e("button",{staticClass:"btn btn-primary font-weight-bold",attrs:{type:"button"},on:{click:t.store}},[t._v("\n Create\n ")])])])])]),t._v(" "),e("div",{staticClass:"modal fade",attrs:{id:"modal-access-token",tabindex:"-1",role:"dialog"}},[e("div",{staticClass:"modal-dialog"},[e("div",{staticClass:"modal-content"},[t._m(3),t._v(" "),e("div",{staticClass:"modal-body"},[e("p",[t._v("\n Here is your new personal access token. This is the only time it will be shown so don't lose it!\n You may now use this token to make API requests.\n ")]),t._v(" "),e("textarea",{staticClass:"form-control",attrs:{rows:"10",readonly:""}},[t._v(t._s(t.accessToken))])]),t._v(" "),t._m(4)])])])])},n=[function(){var t=this,e=t._self._c;return e("thead",[e("tr",[e("th",[t._v("Name")]),t._v(" "),e("th",[t._v("Scopes")]),t._v(" "),e("th",[t._v("Expires")]),t._v(" "),e("th")])])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"modal-header"},[e("h4",{staticClass:"modal-title"},[t._v("\n Create Token\n ")]),t._v(" "),e("button",{staticClass:"close",attrs:{type:"button","data-dismiss":"modal","aria-hidden":"true"}},[t._v("×")])])},function(){var t=this,e=t._self._c;return e("p",{staticClass:"mb-0"},[e("strong",[t._v("Whoops!")]),t._v(" Something went wrong!")])},function(){var t=this,e=t._self._c;return e("div",{staticClass:"modal-header"},[e("h4",{staticClass:"modal-title"},[t._v("\n Personal Access Token\n ")]),t._v(" "),e("button",{staticClass:"close",attrs:{type:"button","data-dismiss":"modal","aria-hidden":"true"}},[t._v("×")])])},function(){var t=this._self._c;return t("div",{staticClass:"modal-footer"},[t("button",{staticClass:"btn btn-secondary",attrs:{type:"button","data-dismiss":"modal"}},[this._v("Close")])])}]},15905(t,e,s){Vue.component("passport-clients",s(19308).default),Vue.component("passport-authorized-clients",s(22593).default),Vue.component("passport-personal-access-tokens",s(87036).default)},13025(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(76798),n=s.n(a)()(function(t){return t[1]});n.push([t.id,".action-link[data-v-1b737fda]{cursor:pointer}",""]);const o=n},49921(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(76798),n=s.n(a)()(function(t){return t[1]});n.push([t.id,".action-link[data-v-d71fe564]{cursor:pointer}",""]);const o=n},44180(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(76798),n=s.n(a)()(function(t){return t[1]});n.push([t.id,".action-link[data-v-58e8e72c]{cursor:pointer}",""]);const o=n},19318(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>i});var a=s(85072),n=s.n(a),o=s(13025),r={insert:"head",singleton:!1};n()(o.default,r);const i=o.default.locals||{}},37622(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>i});var a=s(85072),n=s.n(a),o=s(49921),r={insert:"head",singleton:!1};n()(o.default,r);const i=o.default.locals||{}},13181(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>i});var a=s(85072),n=s.n(a),o=s(44180),r={insert:"head",singleton:!1};n()(o.default,r);const i=o.default.locals||{}},22593(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>r});var a=s(93638),n=s(83382),o={};for(const t in n)"default"!==t&&(o[t]=()=>n[t]);s.d(e,o);s(703);const r=(0,s(14486).default)(n.default,a.render,a.staticRenderFns,!1,null,"1b737fda",null).exports},19308(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>r});var a=s(28004),n=s(71991),o={};for(const t in n)"default"!==t&&(o[t]=()=>n[t]);s.d(e,o);s(54019);const r=(0,s(14486).default)(n.default,a.render,a.staticRenderFns,!1,null,"d71fe564",null).exports},87036(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>r});var a=s(98433),n=s(38335),o={};for(const t in n)"default"!==t&&(o[t]=()=>n[t]);s.d(e,o);s(88798);const r=(0,s(14486).default)(n.default,a.render,a.staticRenderFns,!1,null,"58e8e72c",null).exports},83382(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(60621),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n);const o=a.default},71991(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(76860),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n);const o=a.default},38335(t,e,s){"use strict";s.r(e),s.d(e,{default:()=>o});var a=s(88838),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n);const o=a.default},93638(t,e,s){"use strict";s.r(e);var a=s(41671),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)},28004(t,e,s){"use strict";s.r(e);var a=s(47665),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)},98433(t,e,s){"use strict";s.r(e);var a=s(29834),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)},703(t,e,s){"use strict";s.r(e);var a=s(19318),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)},54019(t,e,s){"use strict";s.r(e);var a=s(37622),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)},88798(t,e,s){"use strict";s.r(e);var a=s(13181),n={};for(const t in a)"default"!==t&&(n[t]=()=>a[t]);s.d(e,n)}},t=>{t.O(0,[3660],()=>{return e=15905,t(t.s=e);var e});t.O()}]); \ No newline at end of file diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 500dc70e0..3e2601621 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -9,7 +9,7 @@ "/js/compose.js": "/js/compose.js?id=026f9f5ad4c97335697df06eb89458fc", "/js/compose-classic.js": "/js/compose-classic.js?id=b335bd735825156da46bd75c881855fc", "/js/search.js": "/js/search.js?id=9dfe84a2449a214a2b0e6dd5b327e07d", - "/js/developers.js": "/js/developers.js?id=73ea3e8690ad2b28819b345cddcc347d", + "/js/developers.js": "/js/developers.js?id=710bbc2918adfccec57e74be4b2ba8b6", "/js/hashtag.js": "/js/hashtag.js?id=e379f9a05a735bd1c3b867573e6e7b78", "/js/collectioncompose.js": "/js/collectioncompose.js?id=8cc4606d6008b6a8c013462135ee958a", "/js/collections.js": "/js/collections.js?id=750737fae261565e19f49c4d373fcd83", diff --git a/resources/assets/js/components/passport/PersonalAccessTokens.vue b/resources/assets/js/components/passport/PersonalAccessTokens.vue index ea8cf4514..d3069a9fa 100644 --- a/resources/assets/js/components/passport/PersonalAccessTokens.vue +++ b/resources/assets/js/components/passport/PersonalAccessTokens.vue @@ -69,7 +69,12 @@ - + + + Renew + + + Delete @@ -299,14 +304,49 @@ }, revoke(token) { - if (! window.confirm('Delete this token? Any applications using it will stop working immediately.')) { - return; - } + swal({ + title: 'Confirm token deletion', + text: 'Are you sure you want to delete this token? Any applications using it will stop working immediately.', + icon: "warning", + dangerMode: true, + buttons: true, + }) + .then((val) => { + if (val) { + axios.delete('/oauth/personal-access-tokens/' + token.id) + .then(() => { + this.getTokens(); + }); + } + }); + }, - axios.delete('/oauth/personal-access-tokens/' + token.id) - .then(() => { - this.getTokens(); - }); + renew(token) { + swal({ + title: 'Confirm token renewal', + text: 'Are you sure you want to renew this token? Any applications using it will stop working immediately, a new token will be generated and only shown once.', + icon: "warning", + dangerMode: true, + buttons: true + }) + .then((val) => { + if (val) { + this.accessToken = null; + + axios.post('/oauth/personal-access-tokens/' + token.id + '/renew') + .then(response => { + this.tokens = this.tokens + .filter(t => t.id !== response.data.renewedTokenId); + + this.tokens.push(response.data.token); + + this.showAccessToken(response.data.accessToken); + }) + .catch(error => { + alert('Unable to renew this token. Please try again.'); + }); + } + }); }, formatDate(value) { diff --git a/routes/web.php b/routes/web.php index 645d52026..325ad2d5d 100644 --- a/routes/web.php +++ b/routes/web.php @@ -54,6 +54,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::group([ 'as' => 'passport.', 'prefix' => 'oauth', + 'middleware' => ['oauth-web'], ], function () { Route::post('/token', [ 'uses' => '\App\Http\Controllers\OAuth\ApiTokenController@issueToken', @@ -64,10 +65,10 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::get('/authorize', [ 'uses' => '\Laravel\Passport\Http\Controllers\AuthorizationController@authorize', 'as' => 'authorizations.authorize', - 'middleware' => ['web', 'throttle:10,1'], + 'middleware' => ['throttle:10,1'], ]); - Route::middleware(['web', 'auth:web', 'validemail'])->group(function () { + Route::middleware(['auth:web', 'validemail'])->group(function () { Route::post('/token/refresh', [ 'uses' => '\Laravel\Passport\Http\Controllers\TransientTokenController@refresh', 'as' => 'token.refresh', @@ -126,14 +127,18 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::post('/personal-access-tokens', [ 'uses' => 'PersonalAccessTokenController@store', 'as' => 'personal.tokens.store', - ]); + ])->middleware(['throttle:oauth-pat']); + + Route::post('/personal-access-tokens/{token_id}/renew', [ + 'uses' => 'PersonalAccessTokenController@renew', + 'as' => 'personal.tokens.renew', + ])->middleware(['throttle:oauth-pat']); Route::delete('/personal-access-tokens/{token_id}', [ 'uses' => 'PersonalAccessTokenController@destroy', 'as' => 'personal.tokens.destroy', ]); }); - }); Route::get('discover', 'DiscoverController@home')->name('discover');