add: serverside record models
chore: ui improvements fix: login modal fail to show if not logged in fix: cannot set null for nullable fields
This commit is contained in:
parent
aeab0dfdbc
commit
a4b3a57e1d
25 changed files with 405 additions and 90 deletions
|
@ -63,7 +63,7 @@
|
|||
"prefer-stable": true,
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"FoskyM\\OAuthCenter\\Tests\\": "tests/"
|
||||
"RhodesIsland\\OAuthCenter\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"archive": {
|
||||
|
|
|
@ -31,6 +31,7 @@ return [
|
|||
|
||||
(new Extend\Routes('forum'))
|
||||
->post('/oauth/authorize', 'oauth.authorize.post', Controllers\AuthorizeController::class)
|
||||
->post('/oauth/authorize/redirect', 'oauth.authorize.redirect', Controllers\AuthorizeRedirectController::class)
|
||||
->post('/oauth/token', 'oauth.token', Controllers\TokenController::class),
|
||||
|
||||
(new Extend\Routes('api'))
|
||||
|
@ -45,12 +46,16 @@ return [
|
|||
->patch('/oauth-scopes/{id}', 'oauth.scopes.update', Api\Controller\UpdateScopeController::class)
|
||||
->delete('/oauth-scopes/{id}', 'oauth.scopes.delete', Api\Controller\DeleteScopeController::class)
|
||||
|
||||
->get('/oauth-records', 'oauth.records.list', Api\Controller\ListRecordController::class)
|
||||
|
||||
->get('/user', 'user.show', Controllers\ApiUserController::class),
|
||||
|
||||
(new Extend\Settings)
|
||||
->serializeToForum('rhodes-island-oauth-center.display_mode', 'rhodes-island-oauth-center.display_mode')
|
||||
->serializeToForum('rhodes-island-oauth-center.allow_implicit', 'rhodes-island-oauth-center.allow_implicit', 'boolval')
|
||||
->serializeToForum('rhodes-island-oauth-center.enforce_state', 'rhodes-island-oauth-center.enforce_state', 'boolval')
|
||||
->serializeToForum('rhodes-island-oauth-center.require_exact_redirect_uri', 'rhodes-island-oauth-center.require_exact_redirect_uri', 'boolval'),
|
||||
->serializeToForum('rhodes-island-oauth-center.require_exact_redirect_uri', 'rhodes-island-oauth-center.require_exact_redirect_uri', 'boolval')
|
||||
->serializeToForum('rhodes-island-oauth-center.use_redirect_authorize', 'rhodes-island-oauth-center.use_redirect_authorize', 'boolval'),
|
||||
|
||||
(new Extend\Middleware('api'))
|
||||
->insertAfter(AuthenticateWithHeader::class, ResourceScopeMiddleware::class),
|
||||
|
|
|
@ -28,6 +28,11 @@ app.initializers.add('foskym/flarum-oauth-center', () => {
|
|||
setting: "rhodes-island-oauth-center.require_exact_redirect_uri",
|
||||
type: "boolean"
|
||||
})
|
||||
.registerSetting({
|
||||
label: app.translator.trans('rhodes-island-oauth-center.admin.settings.use_redirect_authorize'),
|
||||
setting: "rhodes-island-oauth-center.use_redirect_authorize",
|
||||
type: "boolean"
|
||||
})
|
||||
.registerSetting({
|
||||
label: app.translator.trans('rhodes-island-oauth-center.admin.settings.access_lifetime'),
|
||||
setting: "rhodes-island-oauth-center.access_lifetime",
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import Extend from 'flarum/common/extenders';
|
||||
import Client from "./models/Client";
|
||||
import Scope from "./models/Scope";
|
||||
import Record from './models/Record';
|
||||
|
||||
export default [
|
||||
new Extend.Store()
|
||||
.add('oauth-clients', Client)
|
||||
.add('oauth-scopes', Scope),
|
||||
.add('oauth-scopes', Scope)
|
||||
.add('oauth-records', Record),
|
||||
];
|
||||
|
|
|
@ -4,11 +4,11 @@ export default class Client extends Model {
|
|||
client_id = Model.attribute<string>('client_id');
|
||||
client_secret = Model.attribute<string>('client_secret');
|
||||
redirect_uri = Model.attribute<string>('redirect_uri');
|
||||
grant_types = Model.attribute<string>('grant_types');
|
||||
scope = Model.attribute<string>('scope');
|
||||
grant_types = Model.attribute<string | null>('grant_types');
|
||||
scope = Model.attribute<string | null>('scope');
|
||||
user_id = Model.attribute<number>('user_id');
|
||||
client_name = Model.attribute<string>('client_name');
|
||||
client_icon = Model.attribute<string>('client_icon');
|
||||
client_desc = Model.attribute<string>('client_desc');
|
||||
client_home = Model.attribute<string>('client_home');
|
||||
client_icon = Model.attribute<string | null>('client_icon');
|
||||
client_desc = Model.attribute<string | null>('client_desc');
|
||||
client_home = Model.attribute<string | null>('client_home');
|
||||
}
|
||||
|
|
8
js/src/common/models/Record.ts
Normal file
8
js/src/common/models/Record.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import Model from 'flarum/common/Model';
|
||||
import type Client from './Client';
|
||||
|
||||
export default class Record extends Model {
|
||||
client = Model.hasOne<Client>('client');
|
||||
user_id = Model.attribute<number>('user_id');
|
||||
authorized_at = Model.attribute<Date, string>('authorized_at', Model.transformDate);
|
||||
}
|
|
@ -86,7 +86,6 @@ export default class AuthorizePage extends IndexPage {
|
|||
finalScopes.push(definedScope);
|
||||
}
|
||||
}
|
||||
console.log(wantedScopes, definedScopes, finalScopes);
|
||||
|
||||
this.clientScopes = finalScopes;
|
||||
this.loading = false;
|
||||
|
@ -103,7 +102,7 @@ export default class AuthorizePage extends IndexPage {
|
|||
super.oncreate(vnode);
|
||||
|
||||
if (!app.session.user) {
|
||||
app.modal.show(LogInModal);
|
||||
setTimeout(() => app.modal.show(LogInModal)); // make sure mithril wont get double redraw
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,14 +135,14 @@ export default class AuthorizePage extends IndexPage {
|
|||
<div className="OAuth-Details">
|
||||
<div className="OAuth-App">
|
||||
<p>{app.translator.trans('rhodes-island-oauth-center.forum.authorize.app_text')}</p>
|
||||
{(clientHome && clientHome != "" ? <Tooltip text={app.translator.trans('rhodes-island-oauth-center.forum.authorize.to_app_homepage', { name: this.client!!.client_name() })}>
|
||||
{(clientHome ? <Tooltip text={app.translator.trans('rhodes-island-oauth-center.forum.authorize.to_app_homepage', { name: this.client!!.client_name() })}>
|
||||
<a href={clientHome} target="_blank" className="OAuth-App-Info">
|
||||
{clientIcon && clientIcon != "" ? <img src={clientIcon} class="OAuth-App-Icon"/> : <i class="OAuth-App-Icon fas fa-5x fa-cube"></i>}
|
||||
{clientIcon ? <img src={clientIcon} class="OAuth-App-Icon"/> : <i class="OAuth-App-Icon fas fa-5x fa-cube"></i>}
|
||||
<p>{this.client!!.client_name()}</p>
|
||||
<small>{this.client!!.client_desc()}</small>
|
||||
</a>
|
||||
</Tooltip> : <div className="OAuth-App-Info">
|
||||
{clientIcon && clientIcon != "" ? <img src={clientIcon} class="OAuth-App-Icon"/> : <i class="OAuth-App-Icon fas fa-5x fa-cube"></i>}
|
||||
{clientIcon ? <img src={clientIcon} class="OAuth-App-Icon"/> : <i class="OAuth-App-Icon fas fa-5x fa-cube"></i>}
|
||||
<p>{this.client!!.client_name()}</p>
|
||||
<small>{this.client!!.client_desc()}</small>
|
||||
</div>)}
|
||||
|
@ -176,16 +175,16 @@ export default class AuthorizePage extends IndexPage {
|
|||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="OAuth-Action">
|
||||
<Button className="Button Button--primary Button--block" onclick={() => this.submit(true)}
|
||||
loading={this.submitting}>
|
||||
{app.translator.trans('rhodes-island-oauth-center.forum.authorize.agree')}
|
||||
</Button>
|
||||
<Button className="Button Button--link Button--block" onclick={() => this.submit(false)}
|
||||
loading={this.submitting}>
|
||||
{app.translator.trans('rhodes-island-oauth-center.forum.authorize.deny')}
|
||||
</Button>
|
||||
</div>
|
||||
{this.submitting ? <LoadingIndicator/> :
|
||||
<div class="OAuth-Action">
|
||||
<Button className="Button Button--primary Button--block" onclick={() => this.submit(true)}>
|
||||
{app.translator.trans('rhodes-island-oauth-center.forum.authorize.agree')}
|
||||
</Button>
|
||||
<Button className="Button Button--link Button--block" onclick={() => this.submit(false)}>
|
||||
{app.translator.trans('rhodes-island-oauth-center.forum.authorize.deny')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -194,19 +193,37 @@ export default class AuthorizePage extends IndexPage {
|
|||
|
||||
submit(authorized: boolean) {
|
||||
this.submitting = true;
|
||||
app.request({
|
||||
method: 'POST',
|
||||
url: '/oauth/authorize',
|
||||
body: {
|
||||
response_type: this.params!!.response_type,
|
||||
client_id: this.params!!.client_id,
|
||||
redirect_uri: this.params!!.redirect_uri,
|
||||
state: this.params!!.state,
|
||||
scope: this.params!!.scope,
|
||||
is_authorized: authorized,
|
||||
const form = {
|
||||
response_type: this.params!!.response_type,
|
||||
client_id: this.params!!.client_id,
|
||||
redirect_uri: this.params!!.redirect_uri,
|
||||
state: this.params!!.state,
|
||||
scope: this.params!!.scope,
|
||||
is_authorized: authorized,
|
||||
};
|
||||
if (app.forum.attribute('rhodes-island-oauth-center.use_redirect_authorize')) {
|
||||
const formEl = document.createElement("form");
|
||||
formEl.style.display = "none";
|
||||
formEl.action = "/oauth/authorize/redirect";
|
||||
formEl.method = "POST";
|
||||
for (const k in form) {
|
||||
const el = document.createElement("input");
|
||||
el.name = k;
|
||||
el.value = (form as any)[k];
|
||||
formEl.appendChild(el);
|
||||
}
|
||||
}).then((params: any) => {
|
||||
window.location.href = params.location;
|
||||
});
|
||||
document.body.appendChild(formEl);
|
||||
formEl.submit();
|
||||
} else {
|
||||
app.request({
|
||||
method: 'POST',
|
||||
url: '/oauth/authorize',
|
||||
body: form
|
||||
}).then((params: any) => {
|
||||
window.location.href = params.redirect;
|
||||
}).catch(() => {
|
||||
// TODO: error handling
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,65 @@
|
|||
import app from "flarum/common/app";
|
||||
import LoadingIndicator from "flarum/common/components/LoadingIndicator";
|
||||
import Placeholder from "flarum/common/components/Placeholder";
|
||||
import UserPage from 'flarum/forum/components/UserPage';
|
||||
|
||||
import type Client from "src/common/models/Client";
|
||||
import type Record from "src/common/models/Record";
|
||||
|
||||
export default class AuthorizedPage extends UserPage {
|
||||
records: Record[] = [];
|
||||
loading = true;
|
||||
nomore = false;
|
||||
page = 0;
|
||||
|
||||
oninit(vnode: any) {
|
||||
super.oninit(vnode);
|
||||
|
||||
this.loadUser(m.route.param('username'));
|
||||
this.loadRecords();
|
||||
}
|
||||
|
||||
loadRecords() {
|
||||
app.store.find('oauth-records', { page: this.page } as any).then(records => {
|
||||
this.records = this.records.concat(records as unknown as Record[]);
|
||||
this.loading = false;
|
||||
if (this.records.length < 10) {
|
||||
this.nomore = true;
|
||||
}
|
||||
m.redraw();
|
||||
});
|
||||
}
|
||||
|
||||
loadMore() {
|
||||
this.loadRecords();
|
||||
this.page += 1
|
||||
}
|
||||
|
||||
content() {
|
||||
if (this.records.length == 0) {
|
||||
return <Placeholder>{app.translator.trans('rhodes-island-oauth-center.forum.authorized.no_records')}</Placeholder>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="AuthorizedPage">
|
||||
<div className="AuthorizedRecords">
|
||||
{this.records.map(record =>
|
||||
{
|
||||
const client = record.attribute("client") as Client;
|
||||
return <li className="AuthorizedRecord">
|
||||
<h3>
|
||||
{client.client_name}
|
||||
<time>
|
||||
{record.authorized_at().toLocaleString()}
|
||||
</time>
|
||||
</h3>
|
||||
<p>{client.client_desc}</p>
|
||||
<hr />
|
||||
</li>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
{this.loading && <LoadingIndicator/>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
import app from 'flarum/forum/app';
|
||||
import AuthorizePage from "./components/oauth/AuthorizePage";
|
||||
import AuthorizedPage from "./components/user/AuthorizedPage";
|
||||
app.initializers.add('foskym/flarum-oauth-center', () => {
|
||||
app.routes['oauth.authorize'] = {
|
||||
path: '/oauth/authorize',
|
||||
component: AuthorizePage
|
||||
};
|
||||
|
||||
app.routes['user.authorized'] = {
|
||||
path: '/u/:username/authorized',
|
||||
component: AuthorizedPage
|
||||
};
|
||||
});
|
28
js/src/forum/index.tsx
Normal file
28
js/src/forum/index.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import app from 'flarum/forum/app';
|
||||
import { extend } from 'flarum/common/extend';
|
||||
import AuthorizePage from "./components/oauth/AuthorizePage";
|
||||
import AuthorizedPage from "./components/user/AuthorizedPage";
|
||||
import UserPage from 'flarum/forum/components/UserPage';
|
||||
import LinkButton from "flarum/common/components/LinkButton";
|
||||
|
||||
app.initializers.add('foskym/flarum-oauth-center', () => {
|
||||
app.routes['oauth.authorize'] = {
|
||||
path: '/oauth/authorize',
|
||||
component: AuthorizePage
|
||||
};
|
||||
|
||||
app.routes['user.authorized'] = {
|
||||
path: '/u/:username/authorized',
|
||||
component: AuthorizedPage
|
||||
};
|
||||
|
||||
/*extend(UserPage.prototype, 'navItems', function (items) {
|
||||
if (app.session.user?.id() === this.user?.id()) {
|
||||
items.add(
|
||||
'authorized',
|
||||
<LinkButton href={app.route('user.authorized', { username: this.user!!.username() })} icon="fas fa-user-friends">{app.translator.trans('rhodes-island-oauth-center.forum.page.label.authorized')}</LinkButton>,
|
||||
-110
|
||||
);
|
||||
}
|
||||
});*/ // TODO: finish this
|
||||
});
|
|
@ -42,7 +42,7 @@ rhodes-island-oauth-center:
|
|||
title:
|
||||
authorize: Authorize
|
||||
label:
|
||||
authorized: Authorized Logs
|
||||
authorized: Authorization Logs
|
||||
authorize:
|
||||
title: Third party application authorization
|
||||
description: Authorize third party application to use your identity
|
||||
|
|
|
@ -11,6 +11,7 @@ rhodes-island-oauth-center:
|
|||
allow_implicit: 允许隐式授权(response_type=token)
|
||||
enforce_state: 强制状态验证(state 参数)
|
||||
require_exact_redirect_uri: 需要精确的重定向 URI
|
||||
use_redirect_authorize: 授权时直接进行跳转
|
||||
clients:
|
||||
client_id: 应用 ID
|
||||
client_secret: 应用密钥
|
||||
|
@ -52,3 +53,5 @@ rhodes-island-oauth-center:
|
|||
agree: 授权
|
||||
deny: 拒绝
|
||||
not_logged_in: 请登录后再继续操作
|
||||
authorized:
|
||||
no_records: 无授权记录
|
29
migrations/2024_02_25_create_oauth_records_table.php
Normal file
29
migrations/2024_02_25_create_oauth_records_table.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of foskym/flarum-oauth-center.
|
||||
*
|
||||
* Copyright (c) 2023 FoskyM.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE.md
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Schema\Builder;
|
||||
|
||||
return [
|
||||
'up' => function (Builder $schema) {
|
||||
if ($schema->hasTable('oauth_records')) {
|
||||
return;
|
||||
}
|
||||
$schema->create('oauth_records', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('client_id', 80);
|
||||
$table->string('user_id', 80)->nullable();
|
||||
$table->timestamp('authorized_at');
|
||||
});
|
||||
},
|
||||
'down' => function (Builder $schema) {
|
||||
$schema->dropIfExists('oauth_records');
|
||||
},
|
||||
];
|
|
@ -6,6 +6,7 @@ use Flarum\Api\Controller\AbstractCreateController;
|
|||
use Flarum\Http\RequestUtil;
|
||||
use Illuminate\Support\Arr;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use RhodesIsland\OAuthCenter\Utils;
|
||||
use Tobscure\JsonApi\Document;
|
||||
use RhodesIsland\OAuthCenter\Models\Client;
|
||||
use RhodesIsland\OAuthCenter\Api\Serializer\ClientSerializer;
|
||||
|
@ -20,17 +21,9 @@ class CreateClientController extends AbstractCreateController
|
|||
|
||||
$attributes = Arr::get($request->getParsedBody(), 'data.attributes');
|
||||
|
||||
$validAttrs = [
|
||||
'user_id' => $actor->id
|
||||
];
|
||||
$attrs = Utils::processAttributes($attributes, Utils::CLIENT_ATTRIBUTES, Utils::CLIENT_NULLABLE_ATTRIBUTES);
|
||||
$attrs["user_id"] = $actor->id;
|
||||
|
||||
collect(['client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'client_name', 'client_desc', 'client_icon', 'client_home'])
|
||||
->each(function (string $attribute) use (&$validAttrs, $attributes) {
|
||||
if (($val = Arr::get($attributes, $attribute)) !== null) {
|
||||
$validAttrs[$attribute] = $val;
|
||||
}
|
||||
});
|
||||
|
||||
return Client::create($validAttrs);
|
||||
return Client::create($attrs);
|
||||
}
|
||||
}
|
||||
|
|
33
src/Api/Controller/ListRecordController.php
Normal file
33
src/Api/Controller/ListRecordController.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace RhodesIsland\OAuthCenter\Api\Controller;
|
||||
|
||||
use Flarum\Api\Controller\AbstractListController;
|
||||
use Flarum\Http\RequestUtil;
|
||||
use Illuminate\Support\Arr;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Tobscure\JsonApi\Document;
|
||||
use RhodesIsland\OAuthCenter\Models\Record;
|
||||
use RhodesIsland\OAuthCenter\Api\Serializer\RecordSerializer;
|
||||
|
||||
class ListRecordController extends AbstractListController
|
||||
{
|
||||
public $serializer = RecordSerializer::class;
|
||||
protected function data(ServerRequestInterface $request, Document $document)
|
||||
{
|
||||
$page = Arr::get($request->getQueryParams(), 'page', 0);
|
||||
|
||||
$actor = RequestUtil::getActor($request);
|
||||
$actor->assertRegistered();
|
||||
|
||||
$pageSize = 10;
|
||||
$skip = $page * $pageSize;
|
||||
$records = Record::where('user_id', $actor->id)
|
||||
->orderBy('authorized_at', 'desc')
|
||||
->skip($skip)
|
||||
->take($pageSize)
|
||||
->get();
|
||||
|
||||
return $records;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ use Flarum\Api\Controller\AbstractListController;
|
|||
use Flarum\Http\RequestUtil;
|
||||
use Illuminate\Support\Arr;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use RhodesIsland\OAuthCenter\Utils;
|
||||
use Tobscure\JsonApi\Document;
|
||||
use RhodesIsland\OAuthCenter\Models\Client;
|
||||
use RhodesIsland\OAuthCenter\Api\Serializer\ClientSerializer;
|
||||
|
@ -23,12 +24,11 @@ class UpdateClientController extends AbstractListController
|
|||
|
||||
$attributes = Arr::get($request->getParsedBody(), 'data.attributes', []);
|
||||
|
||||
collect(['client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'client_name', 'client_desc', 'client_icon', 'client_home'])
|
||||
->each(function (string $attribute) use ($client, $attributes) {
|
||||
if (($val = Arr::get($attributes, $attribute)) !== null) {
|
||||
$client->$attribute = $val;
|
||||
}
|
||||
});
|
||||
$attrs = Utils::processAttributes($attributes, Utils::CLIENT_ATTRIBUTES, Utils::CLIENT_NULLABLE_ATTRIBUTES);
|
||||
|
||||
foreach ($attrs as $k => $v) {
|
||||
$client[$k] = $v;
|
||||
}
|
||||
|
||||
$client->save();
|
||||
|
||||
|
|
30
src/Api/Serializer/RecordSerializer.php
Normal file
30
src/Api/Serializer/RecordSerializer.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace RhodesIsland\OAuthCenter\Api\Serializer;
|
||||
|
||||
use Flarum\Api\Serializer\AbstractSerializer;
|
||||
use RhodesIsland\OAuthCenter\Models\Record;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class RecordSerializer extends AbstractSerializer
|
||||
{
|
||||
protected $type = 'oauth-records';
|
||||
|
||||
protected function getDefaultAttributes($model)
|
||||
{
|
||||
if (!($model instanceof Record)) {
|
||||
throw new InvalidArgumentException(
|
||||
get_class($this) . ' can only serialize instances of ' . Record::class
|
||||
);
|
||||
}
|
||||
|
||||
// See https://docs.flarum.org/extend/api.html#serializers for more information.
|
||||
|
||||
return [
|
||||
"id" => $model->id,
|
||||
"client" => $model->client,
|
||||
"user_id" => $model->user_id,
|
||||
"authorized_at" => $model->authorized_at
|
||||
];
|
||||
}
|
||||
}
|
|
@ -9,16 +9,12 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace RhodesIsland\OAuthCenter\Controllers;
|
||||
use Flarum\User\User;
|
||||
use Flarum\Http\RequestUtil;
|
||||
use RhodesIsland\OAuthCenter\OAuth;
|
||||
use Illuminate\Support\Arr;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Flarum\Group\Group;
|
||||
|
||||
class ApiUserController implements RequestHandlerInterface
|
||||
{
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace RhodesIsland\OAuthCenter\Controllers;
|
||||
use Flarum\User\User;
|
||||
use Flarum\Http\RequestUtil;
|
||||
use RhodesIsland\OAuthCenter\Models\Record;
|
||||
use RhodesIsland\OAuthCenter\OAuth;
|
||||
use Illuminate\Support\Arr;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
@ -18,7 +18,6 @@ use Psr\Http\Message\ServerRequestInterface;
|
|||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Flarum\Group\Group;
|
||||
|
||||
class AuthorizeController implements RequestHandlerInterface
|
||||
{
|
||||
|
@ -34,6 +33,7 @@ class AuthorizeController implements RequestHandlerInterface
|
|||
$actor->assertRegistered();
|
||||
|
||||
if (!$actor->hasPermission('rhodes-island-oauth-center.use-oauth')) {
|
||||
// TODO: i18n description
|
||||
return new JsonResponse([ 'error' => 'no_permission', 'error_description' => 'Don\'t have the permissions of oauth' ]);
|
||||
}
|
||||
|
||||
|
@ -45,18 +45,23 @@ class AuthorizeController implements RequestHandlerInterface
|
|||
$response = $oauth->response();
|
||||
|
||||
if (!$server->validateAuthorizeRequest($request, $response)) {
|
||||
return new JsonResponse(json_decode($response->getResponseBody(), true));
|
||||
return new JsonResponse($response->getParameters(), $response->getStatusCode(), $response->getHttpHeaders());
|
||||
}
|
||||
|
||||
$is_authorized = Arr::get($params, 'is_authorized', 0);
|
||||
$server->handleAuthorizeRequest($request, $response, $is_authorized, $actor->id);
|
||||
|
||||
if ($is_authorized) {
|
||||
// $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=') + 5, 40);
|
||||
/*Record::create([
|
||||
'client_id' => Arr::get($params, 'client_id'),
|
||||
'user_id' => $actor->id,
|
||||
'authorized_at' => date('Y-m-d H:i:s')
|
||||
]);*/
|
||||
return new JsonResponse([
|
||||
'location' => $response->getHttpHeader('Location')
|
||||
"redirect" => $response->getHttpHeader("Location")
|
||||
]);
|
||||
}
|
||||
|
||||
return new JsonResponse(json_decode($response->getResponseBody(), true));
|
||||
return new JsonResponse($response->getParameters(), $response->getStatusCode(), $response->getHttpHeaders());
|
||||
}
|
||||
}
|
||||
|
|
65
src/Controllers/AuthorizeRedirectController.php
Normal file
65
src/Controllers/AuthorizeRedirectController.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of foskym/flarum-oauth-center.
|
||||
*
|
||||
* Copyright (c) 2024 FoskyM.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE.md
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace RhodesIsland\OAuthCenter\Controllers;
|
||||
use Flarum\Http\RequestUtil;
|
||||
use RhodesIsland\OAuthCenter\Models\Record;
|
||||
use RhodesIsland\OAuthCenter\OAuth;
|
||||
use Illuminate\Support\Arr;
|
||||
use Laminas\Diactoros\Response\HtmlResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
|
||||
class AuthorizeRedirectController implements RequestHandlerInterface
|
||||
{
|
||||
protected $settings;
|
||||
public function __construct(SettingsRepositoryInterface $settings)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$actor = RequestUtil::getActor($request);
|
||||
$actor->assertRegistered();
|
||||
|
||||
if (!$actor->hasPermission('rhodes-island-oauth-center.use-oauth')) {
|
||||
// TODO: better error response
|
||||
return new HtmlResponse('Don\'t have the permissions of oauth');
|
||||
}
|
||||
|
||||
$params = $request->getParsedBody();
|
||||
|
||||
$oauth = new OAuth($this->settings);
|
||||
$server = $oauth->server();
|
||||
$request = $oauth->request()::createFromGlobals();
|
||||
$response = $oauth->response();
|
||||
|
||||
if (!$server->validateAuthorizeRequest($request, $response)) {
|
||||
return new JsonResponse($response->getParameters(), $response->getStatusCode(), $response->getHttpHeaders());
|
||||
}
|
||||
|
||||
$is_authorized = (bool) Arr::get($params, 'is_authorized', 0);
|
||||
$server->handleAuthorizeRequest($request, $response, $is_authorized, $actor->id);
|
||||
|
||||
if ($is_authorized) {
|
||||
/*Record::create([
|
||||
'client_id' => Arr::get($params, 'client_id'),
|
||||
'user_id' => $actor->id,
|
||||
'authorized_at' => date('Y-m-d H:i:s')
|
||||
]);*/
|
||||
}
|
||||
|
||||
return new JsonResponse($response->getParameters(), $response->getStatusCode(), $response->getHttpHeaders());
|
||||
}
|
||||
}
|
|
@ -2,28 +2,18 @@
|
|||
|
||||
namespace RhodesIsland\OAuthCenter\Middlewares;
|
||||
|
||||
use Flarum\Foundation\ErrorHandling\ExceptionHandler\IlluminateValidationExceptionHandler;
|
||||
use Flarum\Foundation\ErrorHandling\JsonApiFormatter;
|
||||
use RhodesIsland\OAuthCenter\OAuth;
|
||||
use RhodesIsland\OAuthCenter\Storage;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Flarum\Http\RequestUtil;
|
||||
use Flarum\Api\JsonApiResponse;
|
||||
use Tobscure\JsonApi\Document;
|
||||
use Tobscure\JsonApi\Exception\Handler\ResponseBag;
|
||||
|
||||
use RhodesIsland\OAuthCenter\Models\Scope;
|
||||
class UnsetCsrfMiddleware implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, RequestHandlerInterface $handler): Response
|
||||
{
|
||||
$uri = [
|
||||
'/oauth/token',
|
||||
'/oauth/authorize/redirect'
|
||||
];
|
||||
$path = $request->getUri()->getPath();
|
||||
if (in_array($path, $uri)) {
|
||||
|
|
|
@ -27,4 +27,9 @@ class Client extends AbstractModel
|
|||
|
||||
return $client;
|
||||
}
|
||||
|
||||
public function record()
|
||||
{
|
||||
return $this->hasMany(Record::class, 'client_id', 'client_id');
|
||||
}
|
||||
}
|
||||
|
|
24
src/Models/Record.php
Normal file
24
src/Models/Record.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of foskym/flarum-oauth-center.
|
||||
*
|
||||
* Copyright (c) 2023 FoskyM.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE.md
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace RhodesIsland\OAuthCenter\Models;
|
||||
|
||||
use Flarum\Database\AbstractModel;
|
||||
|
||||
class Record extends AbstractModel
|
||||
{
|
||||
protected $table = 'oauth_records';
|
||||
protected $guarded = [];
|
||||
|
||||
public function client()
|
||||
{
|
||||
return $this->belongsTo(Client::class, 'client_id', 'client_id');
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace RhodesIsland\OAuthCenter;
|
||||
use Flarum\Extend\Model;
|
||||
|
||||
use Flarum\User\User;
|
||||
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
|
||||
use OAuth2\OpenID\Storage\UserClaimsInterface;
|
||||
|
|
40
src/Utils.php
Normal file
40
src/Utils.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace RhodesIsland\OAuthCenter;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class Utils {
|
||||
public const CLIENT_ATTRIBUTES = [
|
||||
"client_id",
|
||||
"client_secret",
|
||||
"redirect_uri",
|
||||
"client_name"
|
||||
];
|
||||
public const CLIENT_NULLABLE_ATTRIBUTES = [
|
||||
"grant_types",
|
||||
"scope",
|
||||
"client_icon",
|
||||
"client_desc",
|
||||
"client_home"
|
||||
];
|
||||
|
||||
public static function nullIfEmpty(string $value): string | null {
|
||||
return $value == "" ? null : $value;
|
||||
}
|
||||
|
||||
public static function processAttributes(array $attributes, array $requiredAttributes, array $nullableAttributes): array {
|
||||
$result = [];
|
||||
collect($requiredAttributes)->each(function (string $attribute) use (&$result, $attributes) {
|
||||
if (($val = Arr::get($attributes, $attribute)) !== null) {
|
||||
$result[$attribute] = $val;
|
||||
}
|
||||
});
|
||||
collect($nullableAttributes)->each(function (string $attribute) use (&$result, $attributes) {
|
||||
if (($val = Arr::get($attributes, $attribute)) !== null) {
|
||||
$result[$attribute] = Utils::nullIfEmpty($val);
|
||||
}
|
||||
});
|
||||
return $result;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue