rewrite: frontend
This commit is contained in:
parent
bd4402f98c
commit
64d36a111b
44 changed files with 950 additions and 926 deletions
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "foskym/flarum-oauth-center",
|
"name": "rhodes-island/flarum-oauth-center",
|
||||||
"description": "Allow user to authorize the third clients",
|
"description": "Allow user to authorize the third-party clients",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"flarum",
|
"flarum",
|
||||||
"user",
|
"user",
|
||||||
|
@ -19,6 +19,10 @@
|
||||||
"email": "i@fosky.top",
|
"email": "i@fosky.top",
|
||||||
"role": "Developer",
|
"role": "Developer",
|
||||||
"homepage": "https://fosky.top"
|
"homepage": "https://fosky.top"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rain",
|
||||||
|
"role": "Developer"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
|
|
@ -48,9 +48,9 @@ return [
|
||||||
->get('/user', 'user.show', Controllers\ApiUserController::class),
|
->get('/user', 'user.show', Controllers\ApiUserController::class),
|
||||||
|
|
||||||
(new Extend\Settings)
|
(new Extend\Settings)
|
||||||
->serializeToForum('foskym-oauth-center.allow_implicit', 'foskym-oauth-center.allow_implicit', 'boolval')
|
->serializeToForum('rhodes-island-oauth-center.allow_implicit', 'rhodes-island-oauth-center.allow_implicit', 'boolval')
|
||||||
->serializeToForum('foskym-oauth-center.enforce_state', 'foskym-oauth-center.enforce_state', 'boolval')
|
->serializeToForum('rhodes-island-oauth-center.enforce_state', 'rhodes-island-oauth-center.enforce_state', 'boolval')
|
||||||
->serializeToForum('foskym-oauth-center.require_exact_redirect_uri', 'foskym-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'),
|
||||||
|
|
||||||
(new Extend\Middleware('api'))
|
(new Extend\Middleware('api'))
|
||||||
->insertAfter(AuthenticateWithHeader::class, ResourceScopeMiddleware::class),
|
->insertAfter(AuthenticateWithHeader::class, ResourceScopeMiddleware::class),
|
||||||
|
|
2
js/.gitignore
vendored
2
js/.gitignore
vendored
|
@ -7,3 +7,5 @@
|
||||||
!.yarn/versions
|
!.yarn/versions
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
|
dist
|
BIN
js/dist/admin.js
generated
vendored
BIN
js/dist/admin.js
generated
vendored
Binary file not shown.
BIN
js/dist/admin.js.map
generated
vendored
BIN
js/dist/admin.js.map
generated
vendored
Binary file not shown.
BIN
js/dist/forum.js
generated
vendored
BIN
js/dist/forum.js
generated
vendored
Binary file not shown.
BIN
js/dist/forum.js.map
generated
vendored
BIN
js/dist/forum.js.map
generated
vendored
Binary file not shown.
BIN
js/package-lock.json
generated
BIN
js/package-lock.json
generated
Binary file not shown.
|
@ -1,16 +1,18 @@
|
||||||
{
|
{
|
||||||
"name": "@foskym/flarum-oauth-center",
|
"name": "@rhodes-island/flarum-oauth-center",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"flarum-webpack-config": "^2.0.0",
|
"@babel/core": "^7.14.6",
|
||||||
"webpack": "^5.65.0",
|
"@types/mithril": "^2.0.11",
|
||||||
"webpack-cli": "^4.9.1",
|
"babel-loader": "^8.2.2",
|
||||||
"prettier": "^2.5.1",
|
|
||||||
"@flarum/prettier-config": "^1.0.0",
|
|
||||||
"flarum-tsconfig": "^1.0.2",
|
"flarum-tsconfig": "^1.0.2",
|
||||||
|
"flarum-webpack-config": "^2.0.2",
|
||||||
|
"moment": "^2.29.1",
|
||||||
|
"ts-loader": "8.1.0",
|
||||||
"typescript": "^4.5.4",
|
"typescript": "^4.5.4",
|
||||||
"typescript-coverage-report": "^0.6.1"
|
"webpack": "^5.90.3",
|
||||||
|
"webpack-cli": "^5.1.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "webpack --mode development --watch",
|
"dev": "webpack --mode development --watch",
|
||||||
|
@ -23,6 +25,5 @@
|
||||||
"post-build-typings": "find dist-typings -type f -name '*.d.ts' -print0 | xargs -0 sed -i 's,../src/@types,@types,g'",
|
"post-build-typings": "find dist-typings -type f -name '*.d.ts' -print0 | xargs -0 sed -i 's,../src/@types,@types,g'",
|
||||||
"check-typings": "tsc --noEmit --emitDeclarationOnly false",
|
"check-typings": "tsc --noEmit --emitDeclarationOnly false",
|
||||||
"check-typings-coverage": "typescript-coverage-report"
|
"check-typings-coverage": "typescript-coverage-report"
|
||||||
},
|
}
|
||||||
"prettier": "@flarum/prettier-config"
|
|
||||||
}
|
}
|
||||||
|
|
44
js/src/admin/components/EditApplicationModal.tsx
Normal file
44
js/src/admin/components/EditApplicationModal.tsx
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import app from "flarum/admin/app";
|
||||||
|
import type Client from "src/common/models/Client";
|
||||||
|
|
||||||
|
import EditModelModal from "./EditModelModal";
|
||||||
|
import { NestedStringArray } from "@askvortsov/rich-icu-message-formatter";
|
||||||
|
import { randomString } from "../util";
|
||||||
|
|
||||||
|
export default class EditApplicationModal extends EditModelModal<Client> {
|
||||||
|
modelType(): string {
|
||||||
|
return "oauth-clients";
|
||||||
|
}
|
||||||
|
|
||||||
|
fields() {
|
||||||
|
return [
|
||||||
|
'client_id',
|
||||||
|
'client_secret',
|
||||||
|
'redirect_uri',
|
||||||
|
'grant_types',
|
||||||
|
'scope',
|
||||||
|
'client_name',
|
||||||
|
'client_desc',
|
||||||
|
'client_icon',
|
||||||
|
'client_home'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultValues() {
|
||||||
|
return {
|
||||||
|
client_id: randomString(32),
|
||||||
|
client_secret: randomString(32)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
translateFieldName(field: string): NestedStringArray {
|
||||||
|
return app.translator.trans("rhodes-island-oauth-center.admin.clients." + field);
|
||||||
|
}
|
||||||
|
|
||||||
|
className(): string {
|
||||||
|
return "OAuth-EditApplication";
|
||||||
|
}
|
||||||
|
title() {
|
||||||
|
return app.translator.trans("rhodes-island-oauth-center.admin.clients.edit_modal_title_" + (this.model ? "edit" : "add"));
|
||||||
|
}
|
||||||
|
}
|
87
js/src/admin/components/EditModelModal.tsx
Normal file
87
js/src/admin/components/EditModelModal.tsx
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
import { type NestedStringArray } from "@askvortsov/rich-icu-message-formatter";
|
||||||
|
import app from "flarum/admin/app";
|
||||||
|
import type Model from "flarum/common/Model";
|
||||||
|
import Button from "flarum/common/components/Button";
|
||||||
|
import Modal from "flarum/common/components/Modal";
|
||||||
|
import Stream from "flarum/common/utils/Stream";
|
||||||
|
|
||||||
|
export default abstract class EditModelModal<T extends Model> extends Modal {
|
||||||
|
model: T | undefined;
|
||||||
|
|
||||||
|
saving = false;
|
||||||
|
fieldValues: { [x: string]: Stream } = {};
|
||||||
|
|
||||||
|
oninit(vnode: any): void {
|
||||||
|
super.oninit(vnode);
|
||||||
|
|
||||||
|
this.model = (this.attrs as any).model;
|
||||||
|
|
||||||
|
for (const field of this.fields()) {
|
||||||
|
this.fieldValues[field] = Stream(this.model ? ((this.model as any)[field]() ?? "") : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.model) {
|
||||||
|
const defaults = this.defaultValues();
|
||||||
|
for (const field in defaults) {
|
||||||
|
this.fieldValues[field](defaults[field]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract modelType(): string;
|
||||||
|
|
||||||
|
abstract fields(): string[];
|
||||||
|
|
||||||
|
abstract defaultValues(): { [x: string]: string }
|
||||||
|
|
||||||
|
abstract translateFieldName(field: string): NestedStringArray
|
||||||
|
|
||||||
|
className(): string {
|
||||||
|
return "OAuth-EditModel";
|
||||||
|
}
|
||||||
|
content() {
|
||||||
|
return (
|
||||||
|
<div className="Modal-body">
|
||||||
|
{this.fields().map(field => <div className="Form-group">
|
||||||
|
<label for={field}>{this.translateFieldName(field)}</label>
|
||||||
|
<input
|
||||||
|
className="FormControl"
|
||||||
|
name={field}
|
||||||
|
type="text"
|
||||||
|
bidi={this.fieldValues[field]}
|
||||||
|
disabled={this.saving}
|
||||||
|
/>
|
||||||
|
</div>)}
|
||||||
|
<Button className="Button Button--primary Button--block" onclick={this.save.bind(this)} disabled={this.saving} loading={this.saving}>{app.translator.trans("rhodes-island-oauth-center.admin.clients.edit_modal_save")}</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
this.saving = true;
|
||||||
|
if (!this.model) {
|
||||||
|
this.model = app.store.createRecord(this.modelType()) as T;
|
||||||
|
}
|
||||||
|
let modifiedCount = 0;
|
||||||
|
const attrs: { [x: string]: string } = {};
|
||||||
|
Object.entries(this.fieldValues).forEach(val => {
|
||||||
|
const value = val[1]();
|
||||||
|
const modelValue = (this.model as any)[val[0]]();
|
||||||
|
if (value != modelValue && (value != "" || modelValue != null)) {
|
||||||
|
attrs[val[0]] = value;
|
||||||
|
modifiedCount++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (modifiedCount == 0) {
|
||||||
|
this.saving = false;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
this.model.save(attrs).finally(() => {
|
||||||
|
this.saving = false;
|
||||||
|
if (typeof (this.attrs as any).createCallback === "function") {
|
||||||
|
(this.attrs as any).createCallback();
|
||||||
|
}
|
||||||
|
m.redraw();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import Button from 'flarum/common/components/Button';
|
||||||
import IndexPage from "../pages/IndexPage";
|
import IndexPage from "../pages/IndexPage";
|
||||||
import ClientsPage from "../pages/ClientsPage";
|
import ClientsPage from "../pages/ClientsPage";
|
||||||
import ScopesPage from "../pages/ScopesPage";
|
import ScopesPage from "../pages/ScopesPage";
|
||||||
|
|
||||||
export default class SettingsPage extends ExtensionPage {
|
export default class SettingsPage extends ExtensionPage {
|
||||||
content() {
|
content() {
|
||||||
const page = m.route.param().page || 'index';
|
const page = m.route.param().page || 'index';
|
||||||
|
@ -24,42 +25,42 @@ export default class SettingsPage extends ExtensionPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return button menus
|
// Return button menus
|
||||||
menuButtons(page) {
|
menuButtons(page: string) {
|
||||||
return [
|
return [
|
||||||
Button.component({
|
Button.component({
|
||||||
className: `Button ${page === 'index' ? 'item-selected' : ''}`,
|
className: `Button ${page === 'index' ? 'item-selected' : ''}`,
|
||||||
onclick: () => m.route.set(
|
onclick: () => m.route.set(
|
||||||
app.route('extension', {
|
app.route('extension', {
|
||||||
id: 'foskym-oauth-center'
|
id: 'rhodes-island-oauth-center'
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
icon: 'fas fa-home',
|
icon: 'fas fa-home',
|
||||||
}, app.translator.trans('foskym-oauth-center.admin.page.index')),
|
}, app.translator.trans('rhodes-island-oauth-center.admin.page.index')),
|
||||||
Button.component({
|
Button.component({
|
||||||
className: `Button ${page === 'clients' ? 'item-selected' : ''}`,
|
className: `Button ${page === 'clients' ? 'item-selected' : ''}`,
|
||||||
onclick: () => m.route.set(
|
onclick: () => m.route.set(
|
||||||
app.route('extension', {
|
app.route('extension', {
|
||||||
id: 'foskym-oauth-center',
|
id: 'rhodes-island-oauth-center',
|
||||||
page: 'clients'
|
page: 'clients'
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
icon: 'fas fa-network-wired',
|
icon: 'fas fa-network-wired',
|
||||||
}, app.translator.trans('foskym-oauth-center.admin.page.clients')),
|
}, app.translator.trans('rhodes-island-oauth-center.admin.page.clients')),
|
||||||
Button.component({
|
Button.component({
|
||||||
className: `Button ${page === 'scopes' ? 'item-selected' : ''}`,
|
className: `Button ${page === 'scopes' ? 'item-selected' : ''}`,
|
||||||
onclick: () => m.route.set(
|
onclick: () => m.route.set(
|
||||||
app.route('extension', {
|
app.route('extension', {
|
||||||
id: 'foskym-oauth-center',
|
id: 'rhodes-island-oauth-center',
|
||||||
page: 'scopes'
|
page: 'scopes'
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
icon: 'fas fa-user-lock',
|
icon: 'fas fa-user-lock',
|
||||||
}, app.translator.trans('foskym-oauth-center.admin.page.scopes')),
|
}, app.translator.trans('rhodes-island-oauth-center.admin.page.scopes')),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pageContent(page) {
|
pageContent(page: string) {
|
||||||
if (page == 'clients') {
|
if (page == 'clients') {
|
||||||
return <ClientsPage />
|
return <ClientsPage />
|
||||||
} else if (page == 'scopes') {
|
} else if (page == 'scopes') {
|
|
@ -1,16 +0,0 @@
|
||||||
import app from 'flarum/admin/app';
|
|
||||||
import SettingsPage from './components/SettingsPage';
|
|
||||||
app.initializers.add('foskym/flarum-oauth-center', () => {
|
|
||||||
app.extensionData
|
|
||||||
.for('foskym-oauth-center')
|
|
||||||
.registerPage(SettingsPage)
|
|
||||||
.registerPermission(
|
|
||||||
{
|
|
||||||
icon: 'fas fa-user-friends',
|
|
||||||
label: app.translator.trans('foskym-oauth-center.admin.permission.use_oauth'),
|
|
||||||
permission: 'foskym-oauth-center.use-oauth',
|
|
||||||
},
|
|
||||||
'view',
|
|
||||||
95
|
|
||||||
);
|
|
||||||
});
|
|
36
js/src/admin/index.ts
Normal file
36
js/src/admin/index.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import app from 'flarum/admin/app';
|
||||||
|
import SettingsPage from './components/SettingsPage';
|
||||||
|
app.initializers.add('foskym/flarum-oauth-center', () => {
|
||||||
|
app.extensionData
|
||||||
|
.for('rhodes-island-oauth-center')
|
||||||
|
.registerPage(SettingsPage)
|
||||||
|
.registerPermission(
|
||||||
|
{
|
||||||
|
icon: 'fas fa-user-friends',
|
||||||
|
label: app.translator.trans('rhodes-island-oauth-center.admin.permission.use_oauth'),
|
||||||
|
permission: 'rhodes-island-oauth-center.use-oauth',
|
||||||
|
},
|
||||||
|
'view',
|
||||||
|
95
|
||||||
|
)
|
||||||
|
.registerSetting({
|
||||||
|
label: app.translator.trans('rhodes-island-oauth-center.admin.settings.allow_implicit'),
|
||||||
|
setting: "rhodes-island-oauth-center.allow_implicit",
|
||||||
|
type: "boolean"
|
||||||
|
})
|
||||||
|
.registerSetting({
|
||||||
|
label: app.translator.trans('rhodes-island-oauth-center.admin.settings.enforce_state'),
|
||||||
|
setting: "rhodes-island-oauth-center.enforce_state",
|
||||||
|
type: "boolean"
|
||||||
|
})
|
||||||
|
.registerSetting({
|
||||||
|
label: app.translator.trans('rhodes-island-oauth-center.admin.settings.require_exact_redirect_uri'),
|
||||||
|
setting: "rhodes-island-oauth-center.require_exact_redirect_uri",
|
||||||
|
type: "boolean"
|
||||||
|
})
|
||||||
|
.registerSetting({
|
||||||
|
label: app.translator.trans('rhodes-island-oauth-center.admin.settings.access_lifetime'),
|
||||||
|
setting: "rhodes-island-oauth-center.access_lifetime",
|
||||||
|
type: "number"
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,100 +0,0 @@
|
||||||
import app from 'flarum/admin/app';
|
|
||||||
import Page from 'flarum/common/components/Page';
|
|
||||||
import Button from 'flarum/common/components/Button';
|
|
||||||
export default class ClientsPage extends Page {
|
|
||||||
translationPrefix = 'foskym-oauth-center.admin.clients.';
|
|
||||||
clients = [];
|
|
||||||
oninit(vnode) {
|
|
||||||
super.oninit(vnode);
|
|
||||||
|
|
||||||
this.fields = [
|
|
||||||
'client_id',
|
|
||||||
'client_secret',
|
|
||||||
'redirect_uri',
|
|
||||||
'grant_types',
|
|
||||||
'scope',
|
|
||||||
'client_name',
|
|
||||||
'client_desc',
|
|
||||||
'client_icon',
|
|
||||||
'client_home'
|
|
||||||
];
|
|
||||||
|
|
||||||
app.store.find('oauth-clients').then(r => {
|
|
||||||
this.clients = r;
|
|
||||||
this.fields.map(key => console.log(this.clients[0][key]))
|
|
||||||
m.redraw();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
view() {
|
|
||||||
return (
|
|
||||||
<div class={"OAuthCenter-clientsPage"}>
|
|
||||||
{
|
|
||||||
m('.Form-group', [
|
|
||||||
m('table', [
|
|
||||||
m('thead', m('tr', [
|
|
||||||
this.fields.map(key => m('th', app.translator.trans(this.translationPrefix + key))),
|
|
||||||
m('th'),
|
|
||||||
])),
|
|
||||||
m('tbody', [
|
|
||||||
this.clients.map((client, index) => m('tr', [
|
|
||||||
this.fields.map(key =>
|
|
||||||
m('td', m('input.FormControl', {
|
|
||||||
type: 'text',
|
|
||||||
value: client[key]() || '',
|
|
||||||
onchange: (event) => {
|
|
||||||
this.saveClientInfo(index, key, event.target.value);
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
),
|
|
||||||
m('td', Button.component({
|
|
||||||
className: 'Button Button--icon',
|
|
||||||
icon: 'fas fa-times',
|
|
||||||
onclick: () => {
|
|
||||||
this.clients[index].delete();
|
|
||||||
this.clients.splice(index, 1);
|
|
||||||
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
])),
|
|
||||||
m('tr', m('td', {
|
|
||||||
colspan: 9,
|
|
||||||
}, Button.component({
|
|
||||||
className: 'Button Button--block',
|
|
||||||
onclick: () => {
|
|
||||||
const client = app.store.createRecord('oauth-clients');
|
|
||||||
const client_id = this.randomString(32);
|
|
||||||
const client_secret = this.randomString(32);
|
|
||||||
client.save({
|
|
||||||
client_id: client_id,
|
|
||||||
client_secret: client_secret,
|
|
||||||
}).then(this.clients.push(client));
|
|
||||||
},
|
|
||||||
}, app.translator.trans(this.translationPrefix + 'add_button')))),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
randomString(len) {
|
|
||||||
len = len || 32;
|
|
||||||
let $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
||||||
let maxPos = $chars.length;
|
|
||||||
let pwd = '';
|
|
||||||
for (let i = 0; i < len; i++) {
|
|
||||||
//0~32的整数
|
|
||||||
pwd += $chars.charAt(Math.floor(Math.random() * (maxPos + 1)));
|
|
||||||
}
|
|
||||||
return pwd;
|
|
||||||
}
|
|
||||||
|
|
||||||
saveClientInfo(index, key, value) {
|
|
||||||
console.log(index, key, value);
|
|
||||||
this.clients[index].save({
|
|
||||||
[key]: value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
79
js/src/admin/pages/ClientsPage.tsx
Normal file
79
js/src/admin/pages/ClientsPage.tsx
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
import app from 'flarum/admin/app';
|
||||||
|
import Page from 'flarum/common/components/Page';
|
||||||
|
import Button from 'flarum/common/components/Button';
|
||||||
|
import LoadingIndicator from "flarum/common/components/LoadingIndicator";
|
||||||
|
import type Client from 'src/common/models/Client';
|
||||||
|
import EditApplicationModal from '../components/EditApplicationModal';
|
||||||
|
|
||||||
|
export default class ClientsPage extends Page {
|
||||||
|
translationPrefix = 'rhodes-island-oauth-center.admin.clients.';
|
||||||
|
loading = false;
|
||||||
|
clients: Client[] = [];
|
||||||
|
tableFields = [
|
||||||
|
"client_id",
|
||||||
|
"client_name",
|
||||||
|
"client_desc"
|
||||||
|
];
|
||||||
|
loadingClients: Client[] = [];
|
||||||
|
|
||||||
|
oninit(vnode: any) {
|
||||||
|
super.oninit(vnode);
|
||||||
|
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
this.loading = true;
|
||||||
|
app.store.find('oauth-clients').then(r => {
|
||||||
|
this.clients = r as unknown as Client[];
|
||||||
|
this.loading = false;
|
||||||
|
m.redraw();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
view() {
|
||||||
|
return (
|
||||||
|
<div class="OAuthCenter-clientsPage">
|
||||||
|
{(this.loading ? <LoadingIndicator></LoadingIndicator> : <div className="Form-group">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{this.tableFields.map(key => <th>{app.translator.trans(this.translationPrefix + key)}</th>)}
|
||||||
|
<th>{app.translator.trans(this.translationPrefix + "actions")}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{this.clients.map((client: any) => {
|
||||||
|
const clientSaving = this.loadingClients.indexOf(client) != -1;
|
||||||
|
return <tr>
|
||||||
|
{this.tableFields.map(key => <td>{client[key]()}</td>)}
|
||||||
|
<td>
|
||||||
|
<Button className="Button Button--icon" icon="fas fa-pen" disabled={clientSaving} onclick={() => {
|
||||||
|
app.modal.show(EditApplicationModal, {
|
||||||
|
model: client
|
||||||
|
});
|
||||||
|
}}></Button>
|
||||||
|
|
||||||
|
<Button className="Button Button--icon" icon="fas fa-times" disabled={clientSaving} onclick={() => {
|
||||||
|
this.loadingClients.push(client);
|
||||||
|
(client as Client).delete()
|
||||||
|
.then(() => this.clients.splice(this.clients.indexOf(client), 1))
|
||||||
|
.finally(() => this.loadingClients.splice(this.loadingClients.indexOf(client), 1))
|
||||||
|
.finally(m.redraw);
|
||||||
|
}}></Button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<Button className="Button Button--block" onclick={() => {
|
||||||
|
app.modal.show(EditApplicationModal, {
|
||||||
|
createCallback: this.refresh.bind(this)
|
||||||
|
});
|
||||||
|
}}>{app.translator.trans(this.translationPrefix + "add_button")}</Button>
|
||||||
|
</div>)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,132 +0,0 @@
|
||||||
import app from 'flarum/admin/app';
|
|
||||||
import Page from 'flarum/common/components/Page';
|
|
||||||
import FieldSet from 'flarum/common/components/FieldSet';
|
|
||||||
import Button from 'flarum/common/components/Button';
|
|
||||||
import saveSettings from 'flarum/admin/utils/saveSettings';
|
|
||||||
import Stream from 'flarum/common/utils/Stream';
|
|
||||||
import Select from 'flarum/common/components/Select';
|
|
||||||
import Switch from 'flarum/common/components/Switch';
|
|
||||||
|
|
||||||
export default class IndexPage extends Page {
|
|
||||||
oninit(vnode) {
|
|
||||||
super.oninit(vnode);
|
|
||||||
|
|
||||||
this.saving = false;
|
|
||||||
|
|
||||||
this.fields = [
|
|
||||||
'foskym-oauth-center.access_lifetime',
|
|
||||||
'foskym-oauth-center.allow_implicit',
|
|
||||||
'foskym-oauth-center.enforce_state',
|
|
||||||
'foskym-oauth-center.require_exact_redirect_uri'
|
|
||||||
];
|
|
||||||
this.values = {};
|
|
||||||
|
|
||||||
const settings = app.data.settings;
|
|
||||||
this.fields.forEach(key => this.values[key] = Stream(settings[key] || ""));
|
|
||||||
|
|
||||||
for (let i = 1; i < this.fields.length; i++) {
|
|
||||||
this.values[this.fields[i]] = settings[this.fields[i]] === '1';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<form onsubmit={this.onsubmit.bind(this)} className="BasicsPage">
|
|
||||||
{FieldSet.component({}, [
|
|
||||||
<div style="height: 5px;"></div>,
|
|
||||||
Switch.component({
|
|
||||||
state: this.values['foskym-oauth-center.allow_implicit'],
|
|
||||||
onchange: (value) => this.saveSingleSetting('foskym-oauth-center.allow_implicit', value),
|
|
||||||
loading: this.saving,
|
|
||||||
}, app.translator.trans('foskym-oauth-center.admin.settings.allow_implicit')),
|
|
||||||
])}
|
|
||||||
|
|
||||||
{FieldSet.component({}, [
|
|
||||||
<div style="height: 5px;"></div>,
|
|
||||||
Switch.component({
|
|
||||||
state: this.values['foskym-oauth-center.enforce_state'],
|
|
||||||
onchange: (value) => this.saveSingleSetting('foskym-oauth-center.enforce_state', value),
|
|
||||||
loading: this.saving,
|
|
||||||
}, app.translator.trans('foskym-oauth-center.admin.settings.enforce_state')),
|
|
||||||
])}
|
|
||||||
|
|
||||||
{FieldSet.component({}, [
|
|
||||||
<div style="height: 5px;"></div>,
|
|
||||||
Switch.component({
|
|
||||||
state: this.values['foskym-oauth-center.require_exact_redirect_uri'],
|
|
||||||
onchange: (value) => this.saveSingleSetting('foskym-oauth-center.require_exact_redirect_uri', value),
|
|
||||||
loading: this.saving,
|
|
||||||
}, app.translator.trans('foskym-oauth-center.admin.settings.require_exact_redirect_uri')),
|
|
||||||
])}
|
|
||||||
<hr/>
|
|
||||||
{FieldSet.component({}, [
|
|
||||||
<input className="FormControl" bidi={this.values['foskym-oauth-center.access_lifetime']}
|
|
||||||
placeholder={app.translator.trans('foskym-oauth-center.admin.settings.access_lifetime')} required/>,
|
|
||||||
<div className="helpText">
|
|
||||||
{app.translator.trans('foskym-oauth-center.admin.settings.access_lifetime')}
|
|
||||||
</div>,
|
|
||||||
Button.component({
|
|
||||||
type: 'submit',
|
|
||||||
className: 'Button Button--primary',
|
|
||||||
loading: this.saving
|
|
||||||
}, app.translator.trans('core.admin.settings.submit_button'))
|
|
||||||
])}
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
saveSingleSetting(setting, value) {
|
|
||||||
if (this.saving) return;
|
|
||||||
|
|
||||||
this.saving = true;
|
|
||||||
|
|
||||||
this.values[setting] = value;
|
|
||||||
|
|
||||||
let data = {};
|
|
||||||
data[setting] = value;
|
|
||||||
|
|
||||||
saveSettings(data)
|
|
||||||
.then(() => app.alerts.show({type: 'success'}, app.translator.trans('core.admin.settings.saved_message')))
|
|
||||||
.catch(() => {
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.saving = false;
|
|
||||||
m.redraw();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onsubmit(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
if (this.saving) return;
|
|
||||||
|
|
||||||
this.saving = true;
|
|
||||||
app.alerts.dismiss(this.successAlert);
|
|
||||||
|
|
||||||
const settings = {};
|
|
||||||
|
|
||||||
settings['foskym-oauth-center.access_lifetime'] = this.values['foskym-oauth-center.access_lifetime']();
|
|
||||||
|
|
||||||
// this.fields.forEach(key => {
|
|
||||||
// settings[key] = this.values[key]()
|
|
||||||
//
|
|
||||||
// });
|
|
||||||
|
|
||||||
if (settings['foskym-oauth-center.access_lifetime'] === "") {
|
|
||||||
settings['foskym-oauth-center.access_lifetime'] = 3600;
|
|
||||||
}
|
|
||||||
|
|
||||||
saveSettings(settings)
|
|
||||||
.then(() => app.alerts.show({type: 'success'}, app.translator.trans('core.admin.settings.saved_message')))
|
|
||||||
.catch(() => {
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.saving = false;
|
|
||||||
m.redraw();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
23
js/src/admin/pages/IndexPage.tsx
Normal file
23
js/src/admin/pages/IndexPage.tsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import app from 'flarum/admin/app';
|
||||||
|
import AdminPage from 'flarum/admin/components/AdminPage';
|
||||||
|
|
||||||
|
export default class IndexPage extends AdminPage {
|
||||||
|
header() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
content() {
|
||||||
|
const settings = app.extensionData.getSettings("rhodes-island-oauth-center");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="ExtensionPage-settings">
|
||||||
|
<div className="container">
|
||||||
|
<div className="Form">
|
||||||
|
{settings!!.map(this.buildSettingComponent.bind(this))}
|
||||||
|
<div className="Form-group">{this.submitButton()}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,118 +0,0 @@
|
||||||
import app from 'flarum/admin/app';
|
|
||||||
import Page from 'flarum/common/components/Page';
|
|
||||||
import Button from 'flarum/common/components/Button';
|
|
||||||
import Select from 'flarum/common/components/Select';
|
|
||||||
import Checkbox from 'flarum/common/components/Checkbox';
|
|
||||||
|
|
||||||
export default class ScopesPage extends Page {
|
|
||||||
translationPrefix = 'foskym-oauth-center.admin.scopes.';
|
|
||||||
scopes = [];
|
|
||||||
|
|
||||||
oninit(vnode) {
|
|
||||||
super.oninit(vnode);
|
|
||||||
|
|
||||||
this.fields = [
|
|
||||||
'scope',
|
|
||||||
'resource_path',
|
|
||||||
'method',
|
|
||||||
'is_default',
|
|
||||||
'scope_name',
|
|
||||||
'scope_icon',
|
|
||||||
'scope_desc'
|
|
||||||
];
|
|
||||||
|
|
||||||
app.store.find('oauth-scopes').then(r => {
|
|
||||||
this.scopes = r;
|
|
||||||
this.fields.map(key => console.log(this.scopes[0][key]))
|
|
||||||
m.redraw();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
view() {
|
|
||||||
return (
|
|
||||||
<div class={"OAuthCenter-scopesPage"}>
|
|
||||||
{
|
|
||||||
m('.Form-group', [
|
|
||||||
m('table', [
|
|
||||||
m('thead', m('tr', [
|
|
||||||
this.fields.map(key => m('th', app.translator.trans(this.translationPrefix + key))),
|
|
||||||
m('th'),
|
|
||||||
])),
|
|
||||||
m('tbody', [
|
|
||||||
this.scopes.map((scope, index) => m('tr', [
|
|
||||||
this.fields.map(key =>
|
|
||||||
m('td', key === 'method' ? Select.component({
|
|
||||||
options: {
|
|
||||||
'GET': 'GET',
|
|
||||||
'POST': 'POST',
|
|
||||||
'PUT': 'PUT',
|
|
||||||
'DELETE': 'DELETE',
|
|
||||||
'PATCH': 'PATCH',
|
|
||||||
},
|
|
||||||
value: scope[key]() || 'GET',
|
|
||||||
disabled: scope.resource_path() === '/api/user' && key === 'method',
|
|
||||||
onchange: (value) => {
|
|
||||||
this.saveScopeInfo(index, key, value);
|
|
||||||
},
|
|
||||||
}) : key === 'is_default' ? Checkbox.component({
|
|
||||||
state: scope[key]() === 1 || false,
|
|
||||||
disabled: scope.resource_path() === '/api/user' && key === 'is_default',
|
|
||||||
onchange: (checked) => {
|
|
||||||
this.scopes[index].is_default((this.scopes[index].is_default() + 1) % 2)
|
|
||||||
this.saveScopeInfo(index, key, checked ? 1 : 0);
|
|
||||||
},
|
|
||||||
}) : m('input.FormControl', {
|
|
||||||
type: 'text',
|
|
||||||
value: scope[key]() || '',
|
|
||||||
disabled: scope.resource_path() === '/api/user' && key === 'resource_path',
|
|
||||||
onchange: (event) => {
|
|
||||||
this.saveScopeInfo(index, key, event.target.value);
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
),
|
|
||||||
(scope.resource_path() !== '/api/user' && m('td', Button.component({
|
|
||||||
className: 'Button Button--icon',
|
|
||||||
icon: 'fas fa-times',
|
|
||||||
onclick: () => {
|
|
||||||
this.scopes[index].delete();
|
|
||||||
this.scopes.splice(index, 1);
|
|
||||||
},
|
|
||||||
}))),
|
|
||||||
])),
|
|
||||||
m('tr', m('td', {
|
|
||||||
colspan: 7,
|
|
||||||
}, Button.component({
|
|
||||||
className: 'Button Button--block',
|
|
||||||
onclick: () => {
|
|
||||||
const scope = app.store.createRecord('oauth-scopes');
|
|
||||||
scope.save({
|
|
||||||
'scope': 'Scope.' + this.randomString(8),
|
|
||||||
'resource_path': '/api/' + this.randomString(4),
|
|
||||||
'method': 'GET',
|
|
||||||
}).then(this.scopes.push(scope));
|
|
||||||
},
|
|
||||||
}, app.translator.trans(this.translationPrefix + 'add_button')))),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
randomString(len) {
|
|
||||||
len = len || 8;
|
|
||||||
let $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
||||||
let maxPos = $chars.length;
|
|
||||||
let str = '';
|
|
||||||
for (let i = 0; i < len; i++) {
|
|
||||||
//0~32的整数
|
|
||||||
str += $chars.charAt(Math.floor(Math.random() * (maxPos + 1)));
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
saveScopeInfo(index, key, value) {
|
|
||||||
this.scopes[index].save({
|
|
||||||
[key]: value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
166
js/src/admin/pages/ScopesPage.tsx
Normal file
166
js/src/admin/pages/ScopesPage.tsx
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
import app from 'flarum/admin/app';
|
||||||
|
import Page from 'flarum/common/components/Page';
|
||||||
|
import Button from 'flarum/common/components/Button';
|
||||||
|
import Select from 'flarum/common/components/Select';
|
||||||
|
import Checkbox from 'flarum/common/components/Checkbox';
|
||||||
|
import type Scope from 'src/common/models/Scope';
|
||||||
|
import LoadingIndicator from 'flarum/common/components/LoadingIndicator';
|
||||||
|
import Stream from 'flarum/common/utils/Stream';
|
||||||
|
import { randomString } from '../util';
|
||||||
|
|
||||||
|
interface EditingScope {
|
||||||
|
model?: Scope,
|
||||||
|
markDeletion?: boolean,
|
||||||
|
modifiedFields: string[],
|
||||||
|
scope?: Stream,
|
||||||
|
resource_path?: Stream,
|
||||||
|
method?: Stream,
|
||||||
|
is_default?: Stream,
|
||||||
|
scope_name?: Stream,
|
||||||
|
scope_icon?: Stream,
|
||||||
|
scope_desc?: Stream
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class ScopesPage extends Page {
|
||||||
|
translationPrefix = 'rhodes-island-oauth-center.admin.scopes.';
|
||||||
|
scopes: Scope[] = [];
|
||||||
|
fields = [
|
||||||
|
'scope',
|
||||||
|
'resource_path',
|
||||||
|
'method',
|
||||||
|
'is_default',
|
||||||
|
'scope_name',
|
||||||
|
'scope_icon',
|
||||||
|
'scope_desc'
|
||||||
|
];
|
||||||
|
|
||||||
|
bufferedValues: EditingScope[] = [];
|
||||||
|
|
||||||
|
components: { [x: string]: (stream: Stream, disabled: boolean) => any } = {
|
||||||
|
"method": (stream, disabled) => <Select options={{
|
||||||
|
"GET": "GET",
|
||||||
|
"POST": "POST",
|
||||||
|
"PUT": "PUT",
|
||||||
|
"DELETE": "DELETE",
|
||||||
|
"PATCH": "PATCH"
|
||||||
|
}} disabled={disabled} value={stream()} onchange={(val: boolean) => stream(val)}></Select>,
|
||||||
|
"is_default": (stream, disabled) => <Checkbox disabled={disabled} state={stream() === 1} onchange={(val: boolean) => stream(val ? 1 : 0)}></Checkbox>
|
||||||
|
}
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
saving = false;
|
||||||
|
|
||||||
|
oninit(vnode: any) {
|
||||||
|
super.oninit(vnode);
|
||||||
|
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
streamMapper(stream: Stream, scope: EditingScope, field: string) {
|
||||||
|
stream.map((val: any) => {
|
||||||
|
if (stream.notInitial) {
|
||||||
|
scope.modifiedFields.push(field);
|
||||||
|
} else {
|
||||||
|
stream.notInitial = true;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
this.loading = true;
|
||||||
|
this.bufferedValues = [];
|
||||||
|
app.store.find('oauth-scopes').then(r => {
|
||||||
|
this.scopes = r as unknown as Scope[];
|
||||||
|
for (const scope of this.scopes) {
|
||||||
|
const eScope: EditingScope = {model: scope, modifiedFields: []};
|
||||||
|
for (const field of this.fields) {
|
||||||
|
const value = (scope as any)[field]();
|
||||||
|
const stream = Stream(value ? value : (field == "method" ? "GET" : null));
|
||||||
|
(eScope as any)[field] = stream;
|
||||||
|
this.streamMapper(stream, eScope, field);
|
||||||
|
}
|
||||||
|
this.bufferedValues.push(eScope);
|
||||||
|
}
|
||||||
|
this.loading = false;
|
||||||
|
m.redraw();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
view() {
|
||||||
|
return (
|
||||||
|
<div class="OAuthCenter-scopesPage">
|
||||||
|
{(this.loading ? <LoadingIndicator></LoadingIndicator> : <div className="Form-group">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{this.fields.map(key => <th>{app.translator.trans(this.translationPrefix + key)}</th>)}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{this.bufferedValues.map((scope) => <tr style={scope.markDeletion ? "opacity: .5;" : ""}>
|
||||||
|
{this.fields.map((key) => <td>
|
||||||
|
{(this.components[key] && this.components[key]((scope as any)[key], this.saving)) ?? <input className="FormControl" type="text" bidi={(scope as any)[key]} disabled={this.saving}></input>}
|
||||||
|
</td>)}
|
||||||
|
<td>
|
||||||
|
<Button className="Button Button--icon" disabled={this.saving} icon={"fas fa-" + (scope.markDeletion ? "undo" : "times")} onclick={() => {
|
||||||
|
scope.markDeletion = !scope.markDeletion;
|
||||||
|
}}></Button>
|
||||||
|
</td>
|
||||||
|
</tr>)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<Button className="Button Button--block" disabled={this.saving} onclick={() => {
|
||||||
|
const eScope: EditingScope = {modifiedFields: []};
|
||||||
|
for (const field of this.fields) {
|
||||||
|
const stream = Stream();
|
||||||
|
(eScope as any)[field] = stream;
|
||||||
|
}
|
||||||
|
eScope.scope("scope." + randomString(4));
|
||||||
|
eScope.method("GET");
|
||||||
|
this.bufferedValues.push(eScope);
|
||||||
|
}}>{app.translator.trans(this.translationPrefix + 'add_button')}</Button>
|
||||||
|
<br/>
|
||||||
|
<Button className="Button Button--primary" onclick={this.save.bind(this)} loading={this.saving}>{app.translator.trans(this.translationPrefix + "save")}</Button>
|
||||||
|
</div>)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
const promises = [];
|
||||||
|
for (const eScope of this.bufferedValues) {
|
||||||
|
const scope = eScope.model;
|
||||||
|
if (scope) {
|
||||||
|
if (eScope.markDeletion) {
|
||||||
|
promises.push(scope.delete());
|
||||||
|
} else {
|
||||||
|
if (eScope.modifiedFields.length > 0) {
|
||||||
|
const attrs: any = {};
|
||||||
|
for (const field of eScope.modifiedFields) {
|
||||||
|
attrs[field] = (eScope as any)[field]();
|
||||||
|
}
|
||||||
|
promises.push(scope.save(attrs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const scope = app.store.createRecord("oauth-scopes");
|
||||||
|
const attrs: any = {};
|
||||||
|
for (const field of this.fields) {
|
||||||
|
const value = (eScope as any)[field]();
|
||||||
|
if (value) {
|
||||||
|
attrs[field] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
promises.push(scope.save(attrs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (promises.length > 0) {
|
||||||
|
this.saving = true;
|
||||||
|
Promise.allSettled(promises).finally(() => {
|
||||||
|
this.saving = false;
|
||||||
|
this.refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
js/src/admin/util.ts
Normal file
10
js/src/admin/util.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
export function randomString(len: number) {
|
||||||
|
len = len || 32;
|
||||||
|
let $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
let maxPos = $chars.length;
|
||||||
|
let pwd = '';
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
pwd += $chars.charAt(Math.floor(Math.random() * (maxPos + 1)));
|
||||||
|
}
|
||||||
|
return pwd;
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
import Model from 'flarum/common/Model';
|
|
||||||
|
|
||||||
export default class Client extends Model {
|
|
||||||
client_id = Model.attribute('client_id');
|
|
||||||
client_secret = Model.attribute('client_secret');
|
|
||||||
redirect_uri = Model.attribute('redirect_uri');
|
|
||||||
grant_types = Model.attribute('grant_types');
|
|
||||||
scope = Model.attribute('scope');
|
|
||||||
user_id = Model.attribute('user_id');
|
|
||||||
client_name = Model.attribute('client_name');
|
|
||||||
client_icon = Model.attribute('client_icon');
|
|
||||||
client_desc = Model.attribute('client_desc');
|
|
||||||
client_home = Model.attribute('client_home');
|
|
||||||
}
|
|
14
js/src/common/models/Client.ts
Normal file
14
js/src/common/models/Client.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import Model from 'flarum/common/Model';
|
||||||
|
|
||||||
|
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');
|
||||||
|
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');
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
import Model from 'flarum/common/Model';
|
|
||||||
|
|
||||||
export default class Scope extends Model {
|
|
||||||
scope = Model.attribute('scope');
|
|
||||||
resource_path = Model.attribute('resource_path');
|
|
||||||
method = Model.attribute('method');
|
|
||||||
is_default = Model.attribute('is_default');
|
|
||||||
scope_name = Model.attribute('scope_name');
|
|
||||||
scope_icon = Model.attribute('scope_icon');
|
|
||||||
scope_desc = Model.attribute('scope_desc');
|
|
||||||
}
|
|
11
js/src/common/models/Scope.ts
Normal file
11
js/src/common/models/Scope.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import Model from 'flarum/common/Model';
|
||||||
|
|
||||||
|
export default class Scope extends Model {
|
||||||
|
scope = Model.attribute<string>('scope');
|
||||||
|
resource_path = Model.attribute<string>('resource_path');
|
||||||
|
method = Model.attribute<string>('method');
|
||||||
|
is_default = Model.attribute<boolean>('is_default');
|
||||||
|
scope_name = Model.attribute<string>('scope_name');
|
||||||
|
scope_icon = Model.attribute<string>('scope_icon');
|
||||||
|
scope_desc = Model.attribute<string>('scope_desc');
|
||||||
|
}
|
|
@ -1,222 +0,0 @@
|
||||||
import app from 'flarum/forum/app';
|
|
||||||
import {extend} from 'flarum/common/extend';
|
|
||||||
import Page from 'flarum/common/components/Page';
|
|
||||||
import IndexPage from 'flarum/forum/components/IndexPage';
|
|
||||||
import LogInModal from 'flarum/forum/components/LogInModal';
|
|
||||||
import extractText from 'flarum/common/utils/extractText';
|
|
||||||
import Tooltip from 'flarum/common/components/Tooltip';
|
|
||||||
import Button from 'flarum/common/components/Button';
|
|
||||||
|
|
||||||
export default class AuthorizePage extends IndexPage {
|
|
||||||
params = [];
|
|
||||||
client = null;
|
|
||||||
scopes = null;
|
|
||||||
client_scope = [];
|
|
||||||
loading = true;
|
|
||||||
is_authorized = false;
|
|
||||||
submit_loading = false;
|
|
||||||
|
|
||||||
oninit(vnode) {
|
|
||||||
super.oninit(vnode);
|
|
||||||
if (!app.session.user) {
|
|
||||||
setTimeout(() => app.modal.show(LogInModal), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = m.route.param();
|
|
||||||
|
|
||||||
if (params.client_id == null || params.response_type == null || params.redirect_uri == null) {
|
|
||||||
m.route.set('/');
|
|
||||||
} else {
|
|
||||||
this.params = params;
|
|
||||||
app.store.find('oauth-clients', params.client_id).then(client => {
|
|
||||||
if (client.length === 0) {
|
|
||||||
m.route.set('/');
|
|
||||||
} else {
|
|
||||||
this.client = client[0];
|
|
||||||
let uris = null;
|
|
||||||
if (this.client.redirect_uri().indexOf(' ') > -1) {
|
|
||||||
uris = this.client.redirect_uri().split(' ');
|
|
||||||
} else {
|
|
||||||
uris = [this.client.redirect_uri()];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app.forum.attribute('foskym-oauth-center.require_exact_redirect_uri') && uris.indexOf(params.redirect_uri) == -1) {
|
|
||||||
m.route.set('/');
|
|
||||||
}
|
|
||||||
if (!app.forum.attribute('foskym-oauth-center.allow_implicit') && params.response_type == 'token') {
|
|
||||||
m.route.set('/');
|
|
||||||
}
|
|
||||||
if (app.forum.attribute('foskym-oauth-center.enforce_state') && params.enforce_state == null) {
|
|
||||||
m.route.set('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
app.store.find('oauth-scopes').then((scopes) => {
|
|
||||||
this.scopes = scopes
|
|
||||||
let scope = params.scope;
|
|
||||||
|
|
||||||
if (params.scope == null) {
|
|
||||||
scope = this.client.scope();
|
|
||||||
}
|
|
||||||
|
|
||||||
let scopes_temp = [];
|
|
||||||
if (scope == null) {
|
|
||||||
scopes_temp = [];
|
|
||||||
} else if (scope.indexOf(' ') > -1) {
|
|
||||||
scopes_temp = scope.split(' ');
|
|
||||||
} else {
|
|
||||||
scopes_temp = [scope];
|
|
||||||
}
|
|
||||||
|
|
||||||
let default_scopes = [];
|
|
||||||
this.scopes.map(scope => {
|
|
||||||
let index = scopes_temp.indexOf(scope.scope());
|
|
||||||
if (index > -1) {
|
|
||||||
scopes_temp[index] = scope;
|
|
||||||
} else {
|
|
||||||
scopes_temp.slice(index, 1);
|
|
||||||
}
|
|
||||||
if (scope.is_default() === 1) {
|
|
||||||
default_scopes.push(scope);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
scopes_temp = scopes_temp.concat(default_scopes);
|
|
||||||
|
|
||||||
this.client_scope = scopes_temp.filter((scope, index) => scopes_temp.indexOf(scope) === index);
|
|
||||||
console.log(this.client_scope);
|
|
||||||
this.loading = false;
|
|
||||||
m.redraw();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setTitle() {
|
|
||||||
app.setTitle(extractText(app.translator.trans('foskym-oauth-center.forum.page.title.authorize')));
|
|
||||||
app.setTitleCount(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
view() {
|
|
||||||
if (!this.client) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
!this.loading && <div className="AuthorizePage">
|
|
||||||
<div className="container">
|
|
||||||
<div class="oauth-area">
|
|
||||||
<div class="oauth-main">
|
|
||||||
<div class="oauth-box oauth-header">
|
|
||||||
<h2>{app.forum.attribute('title')}</h2>
|
|
||||||
<p>
|
|
||||||
{app.translator.trans('foskym-oauth-center.forum.authorize.access')} <a
|
|
||||||
href={this.client.client_home()} target="_blank">{this.client.client_name()}</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="oauth-box oauth-body">
|
|
||||||
|
|
||||||
<div class="oauth-top">
|
|
||||||
<img src={app.forum.attribute('faviconUrl')}/>
|
|
||||||
<i class="fas fa-exchange-alt fa-2x"></i>
|
|
||||||
<Tooltip text={this.client.client_desc()}>
|
|
||||||
<img src={this.client.client_icon()}/>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
<div class="oauth-scope-area">
|
|
||||||
{
|
|
||||||
this.client_scope.length > 0 && this.client_scope.map(scope => {
|
|
||||||
let scope_info = null;
|
|
||||||
this.scopes.map(s => {
|
|
||||||
if (s.scope() === scope.scope()) {
|
|
||||||
scope_info = s;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (scope_info == null) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div class="oauth-scope">
|
|
||||||
<div class="oauth-scope-left">
|
|
||||||
{
|
|
||||||
(scope_info.scope_icon().indexOf('fa-') > -1) ?
|
|
||||||
<i class={"oauth-scope-object fa-2x " + scope_info.scope_icon()}
|
|
||||||
style="margin-left:2px;color:#000"></i> :
|
|
||||||
<img class="oauth-scope-object" src={scope_info.scope_icon()} style="width:32px"/>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div class="oauth-scope-body">
|
|
||||||
<h6 class="oauth-scope-heading">
|
|
||||||
{scope_info.scope_name()}
|
|
||||||
</h6>
|
|
||||||
<small>
|
|
||||||
{
|
|
||||||
scope_info.scope_desc()
|
|
||||||
.replace('{client_name}', this.client.client_name())
|
|
||||||
.replace('{user}', app.session.user.attribute('displayName'))
|
|
||||||
}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<form class="oauth-form" method="post" id="form" onsubmit={this.onsubmit.bind(this)}>
|
|
||||||
{/* <input type="hidden" name="response_type" value={this.params.response_type}/>
|
|
||||||
<input type="hidden" name="client_id" value={this.params.client_id}/>
|
|
||||||
<input type="hidden" name="redirect_uri"
|
|
||||||
value={this.params.redirect_uri}/>
|
|
||||||
<input type="hidden" name="state" value={this.params.state}/>
|
|
||||||
<input type="hidden" name="scope" value={this.params.scope}/>*/}
|
|
||||||
<input type="hidden" name="is_authorized" value={this.is_authorized}/>
|
|
||||||
<div style="display: flex; margin-top: 15px" class="oauth-form-item">
|
|
||||||
<Button className="Button" type="submit" style="width: 50%;" onclick={this.deny.bind(this)}
|
|
||||||
loading={this.submit_loading}>
|
|
||||||
{app.translator.trans('foskym-oauth-center.forum.authorize.deny')}
|
|
||||||
</Button>
|
|
||||||
<Button className="Button Button--primary" type="submit" style="width: 50%;"
|
|
||||||
onclick={this.agree.bind(this)} loading={this.submit_loading}>
|
|
||||||
{app.translator.trans('foskym-oauth-center.forum.authorize.agree')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
deny(e) {
|
|
||||||
this.is_authorized = false;
|
|
||||||
}
|
|
||||||
agree(e) {
|
|
||||||
this.is_authorized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
onsubmit(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.submit_loading = 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: this.is_authorized,
|
|
||||||
}
|
|
||||||
}).then((params) => {
|
|
||||||
window.location.href = params.location;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Some form handling logic here
|
|
||||||
}
|
|
||||||
}
|
|
212
js/src/forum/components/oauth/AuthorizePage.tsx
Normal file
212
js/src/forum/components/oauth/AuthorizePage.tsx
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
import app from 'flarum/forum/app';
|
||||||
|
import IndexPage from 'flarum/forum/components/IndexPage';
|
||||||
|
import LogInModal from 'flarum/forum/components/LogInModal';
|
||||||
|
import Placeholder from "flarum/common/components/Placeholder";
|
||||||
|
import extractText from 'flarum/common/utils/extractText';
|
||||||
|
import Tooltip from 'flarum/common/components/Tooltip';
|
||||||
|
import Button from 'flarum/common/components/Button';
|
||||||
|
import type Client from 'src/common/models/Client';
|
||||||
|
import type Scope from 'src/common/models/Scope';
|
||||||
|
import LoadingIndicator from 'flarum/common/components/LoadingIndicator';
|
||||||
|
|
||||||
|
interface AuthorizeRequestParams {
|
||||||
|
response_type: string,
|
||||||
|
client_id: string,
|
||||||
|
redirect_uri: string,
|
||||||
|
state: string,
|
||||||
|
scope: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class AuthorizePage extends IndexPage {
|
||||||
|
params: AuthorizeRequestParams | null = null;
|
||||||
|
client: Client | null = null;
|
||||||
|
clientScopes: Scope[] = [];
|
||||||
|
loading = true;
|
||||||
|
submitting = false;
|
||||||
|
|
||||||
|
oninit(vnode: any) {
|
||||||
|
super.oninit(vnode);
|
||||||
|
|
||||||
|
if (!app.session.user) return;
|
||||||
|
|
||||||
|
const rawParams = m.route.param();
|
||||||
|
|
||||||
|
if (rawParams.client_id == null || rawParams.response_type == null || rawParams.redirect_uri == null) {
|
||||||
|
m.route.set('/');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
client_id: rawParams.client_id,
|
||||||
|
response_type: rawParams.response_type,
|
||||||
|
redirect_uri: rawParams.redirect_uri,
|
||||||
|
state: rawParams.state,
|
||||||
|
scope: rawParams.scope
|
||||||
|
};
|
||||||
|
this.params = params;
|
||||||
|
|
||||||
|
const scopesPromise = app.store.find('oauth-scopes');
|
||||||
|
app.store.find('oauth-clients', params.client_id).then(response => {
|
||||||
|
const clients = response as unknown as Client[];
|
||||||
|
if (clients.length === 0) {
|
||||||
|
m.route.set('/');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client = clients[0];
|
||||||
|
let uris = [this.client.redirect_uri()];
|
||||||
|
if (uris[0].indexOf(' ') > -1) {
|
||||||
|
uris = uris[0].split(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((app.forum.attribute('rhodes-island-oauth-center.require_exact_redirect_uri') && uris.indexOf(params.redirect_uri) == -1) &&
|
||||||
|
(!app.forum.attribute('rhodes-island-oauth-center.allow_implicit') && params.response_type == 'token') &&
|
||||||
|
(app.forum.attribute('rhodes-island-oauth-center.enforce_state') && rawParams.enforce_state == null)) {
|
||||||
|
m.route.set('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
scopesPromise.then(scopes => {
|
||||||
|
const wantedScopes = [];
|
||||||
|
|
||||||
|
const paramScopes = params.scope as string;
|
||||||
|
if (paramScopes) {
|
||||||
|
wantedScopes.push(...paramScopes.split(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
const clientScopes = this.client!!.scope();
|
||||||
|
if (clientScopes) {
|
||||||
|
wantedScopes.push(...clientScopes.split(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
const finalScopes = [];
|
||||||
|
|
||||||
|
const definedScopes = (scopes as unknown as Scope[]);
|
||||||
|
for (const definedScope of definedScopes) {
|
||||||
|
if (definedScope.is_default() || wantedScopes.indexOf(definedScope.scope()) != -1) {
|
||||||
|
finalScopes.push(definedScope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(wantedScopes, definedScopes, finalScopes);
|
||||||
|
|
||||||
|
this.clientScopes = finalScopes;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setTitle() {
|
||||||
|
app.setTitle(extractText(app.translator.trans('rhodes-island-oauth-center.forum.page.title.authorize')));
|
||||||
|
app.setTitleCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
oncreate(vnode: any): void {
|
||||||
|
super.oncreate(vnode);
|
||||||
|
|
||||||
|
if (!app.session.user) {
|
||||||
|
app.modal.show(LogInModal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view() {
|
||||||
|
if (!app.session.user) {
|
||||||
|
return <Placeholder>{app.translator.trans("rhodes-island-oauth-center.forum.authorize.not_logged_in")}</Placeholder>;
|
||||||
|
}
|
||||||
|
if (this.loading) {
|
||||||
|
return <LoadingIndicator></LoadingIndicator>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = app.session.user;
|
||||||
|
const clientHome = this.client!!.client_home();
|
||||||
|
const clientIcon = this.client!!.client_icon();
|
||||||
|
return (
|
||||||
|
<div className="AuthorizePage">
|
||||||
|
<div className="container">
|
||||||
|
<div class="OAuth-Header">
|
||||||
|
<h2>{app.translator.trans("rhodes-island-oauth-center.forum.authorize.title")}</h2>
|
||||||
|
<p>{app.translator.trans('rhodes-island-oauth-center.forum.authorize.description')}</p>
|
||||||
|
</div>
|
||||||
|
<div class="OAuth-Body">
|
||||||
|
<div className="OAuth-User">
|
||||||
|
<img className="OAuth-User-Avatar" src={user.attribute("avatarUrl")}/>
|
||||||
|
<div className="OAuth-User-Info">
|
||||||
|
<h4>{user.attribute("displayName")}</h4>
|
||||||
|
<small>{user.attribute("email")}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<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() })}>
|
||||||
|
<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>}
|
||||||
|
<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>}
|
||||||
|
<p>{this.client!!.client_name()}</p>
|
||||||
|
<small>{this.client!!.client_desc()}</small>
|
||||||
|
</div>)}
|
||||||
|
</div>
|
||||||
|
<div class="OAuth-Scopes">
|
||||||
|
<p>{app.translator.trans('rhodes-island-oauth-center.forum.authorize.scope_text')}</p>
|
||||||
|
{
|
||||||
|
this.clientScopes.length > 0 && this.clientScopes.map(scope => {
|
||||||
|
return <div class="OAuth-Scope">
|
||||||
|
{
|
||||||
|
(scope.scope_icon().indexOf('fa-') > -1) ?
|
||||||
|
<i class={"OAuth-ScopeIcon fa-3x " + scope.scope_icon()}
|
||||||
|
style="margin-left:2px;color:#000"></i> :
|
||||||
|
<img class="OAuth-ScopeIcon" src={scope.scope_icon()} />
|
||||||
|
}
|
||||||
|
<div class="OAuth-ScopeDetail">
|
||||||
|
<h4>
|
||||||
|
{scope.scope_name()}
|
||||||
|
</h4>
|
||||||
|
<small>
|
||||||
|
{
|
||||||
|
scope.scope_desc()
|
||||||
|
.replace('{client_name}', this.client!!.client_name())
|
||||||
|
.replace('{user}', user.attribute('displayName'))
|
||||||
|
}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}).then((params: any) => {
|
||||||
|
window.location.href = params.location;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
import UserPage from 'flarum/forum/components/UserPage';
|
import UserPage from 'flarum/forum/components/UserPage';
|
||||||
|
|
||||||
export default class AuthorizedPage extends UserPage {
|
export default class AuthorizedPage extends UserPage {
|
||||||
oninit(vnode) {
|
oninit(vnode: any) {
|
||||||
super.oninit(vnode);
|
super.oninit(vnode);
|
||||||
|
|
||||||
this.loadUser(m.route.param('username'));
|
this.loadUser(m.route.param('username'));
|
||||||
}
|
}
|
||||||
content() {
|
content() {
|
|
@ -1,34 +0,0 @@
|
||||||
import app from 'flarum/forum/app';
|
|
||||||
import {extend} from 'flarum/common/extend';
|
|
||||||
import UserPage from 'flarum/forum/components/UserPage';
|
|
||||||
import LinkButton from 'flarum/common/components/LinkButton';
|
|
||||||
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
|
|
||||||
};
|
|
||||||
extend(UserPage.prototype, 'navItems', function (items) {
|
|
||||||
if (app.session.user && app.session.user.id() === this.user.id()) {
|
|
||||||
// items.add(
|
|
||||||
// 'authorized',
|
|
||||||
// LinkButton.component(
|
|
||||||
// {
|
|
||||||
// href: app.route('user.authorized', { username: this.user.username() }),
|
|
||||||
// icon: 'fas fa-user-friends',
|
|
||||||
// },
|
|
||||||
// [
|
|
||||||
// app.translator.trans('foskym-oauth-center.forum.page.label.authorized'),
|
|
||||||
// ]
|
|
||||||
// ),
|
|
||||||
// -110
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
14
js/src/forum/index.ts
Normal file
14
js/src/forum/index.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
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
|
||||||
|
};
|
||||||
|
});
|
|
@ -1,24 +1,24 @@
|
||||||
{
|
{
|
||||||
// Use Flarum's tsconfig as a starting point
|
|
||||||
"extends": "flarum-tsconfig",
|
"extends": "flarum-tsconfig",
|
||||||
// This will match all .ts, .tsx, .d.ts, .js, .jsx files in your `src` folder
|
|
||||||
// and also tells your Typescript server to read core's global typings for
|
|
||||||
// access to `dayjs` and `$` in the global namespace.
|
|
||||||
"include": [
|
|
||||||
"src/**/*",
|
|
||||||
"../vendor/*/*/js/dist-typings/@types/**/*",
|
|
||||||
// <CUSTOM-1>
|
|
||||||
// </CUSTOM-1>
|
|
||||||
"@types/**/*"
|
|
||||||
],
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
// This will output typings to `dist-typings`
|
"module": "ES2020",
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"target": "ES6",
|
||||||
|
"sourceMap": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"jsx": "react",
|
||||||
|
"jsxFactory": "m",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
"declarationDir": "./dist-typings",
|
"declarationDir": "./dist-typings",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"flarum/*": ["../vendor/flarum/core/js/dist-typings/*"],
|
"flarum/*": ["../vendor/flarum/core/js/dist-typings/*"]
|
||||||
// <CUSTOM-2>
|
|
||||||
// </CUSTOM-2>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"**/node_modules"
|
||||||
|
],
|
||||||
|
"include": ["src/**/*", "../vendor/flarum/core/js/dist-typings/@types/**/*"]
|
||||||
}
|
}
|
|
@ -1 +1,34 @@
|
||||||
module.exports = require('flarum-webpack-config')();
|
const config = require("flarum-webpack-config");
|
||||||
|
|
||||||
|
module.exports = env => {
|
||||||
|
// Determine build mode
|
||||||
|
let mode = "development";
|
||||||
|
if (env.production) {mode = "production";}
|
||||||
|
console.log("Compilation Mode: " + mode);
|
||||||
|
let flarumConfig = config({
|
||||||
|
resolve: {
|
||||||
|
extenstions: [".wasm", ".mjs", ".ts", ".tsx", ".js", ".json"]
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
resource: {
|
||||||
|
and: [/\.(js|ts)$/],
|
||||||
|
not: [/node_modules/]
|
||||||
|
},
|
||||||
|
use: [
|
||||||
|
"babel-loader",
|
||||||
|
{
|
||||||
|
loader: "ts-loader",
|
||||||
|
options: {
|
||||||
|
transpileOnly: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
flarumConfig.mode = mode;
|
||||||
|
return flarumConfig;
|
||||||
|
};
|
BIN
js/yarn.lock
Normal file
BIN
js/yarn.lock
Normal file
Binary file not shown.
|
@ -1,227 +1,132 @@
|
||||||
.oauth-area {
|
.AuthorizePage {
|
||||||
display: block !important;
|
.OAuth-Header {
|
||||||
position: relative;
|
text-align: center;
|
||||||
left: 0;
|
margin-bottom: 30px;
|
||||||
top: 0;
|
|
||||||
padding: 110px 0;
|
|
||||||
min-height: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-main {
|
h2 {
|
||||||
position: relative;
|
font-size: 3em;
|
||||||
width: 376px;
|
margin-bottom: .1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin-top: .1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.OAuth-Body {
|
||||||
|
max-width: 60%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
box-sizing: border-box;
|
|
||||||
box-shadow: 0px 0px 15px 0px #bdbdbd;
|
|
||||||
border-radius: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-main::before {
|
.OAuth-User {
|
||||||
backdrop-filter: blur(20px);
|
display: flex;
|
||||||
content: '';
|
align-items: center;
|
||||||
position: absolute;
|
justify-content: center;
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
background: hsla(0, 0%, 100%, .3);
|
|
||||||
border-radius: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-box {
|
.OAuth-User-Avatar {
|
||||||
padding: 20px;
|
width: 48px;
|
||||||
background-color: #f3f3f3;
|
height: 48px;
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-header {
|
|
||||||
backdrop-filter: blur(0);
|
|
||||||
text-align: center;
|
|
||||||
box-shadow: 0 5px 10px -5px #d2d2d2;
|
|
||||||
border-radius: 12px 12px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-header h2 {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 40px;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-header p {
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 20px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-body {
|
|
||||||
border-radius: 0 0 12px 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-body .oauth-form-item {
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
clear: both;
|
|
||||||
*zoom: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-body .oauth-form-item:after {
|
|
||||||
content: '\20';
|
|
||||||
clear: both;
|
|
||||||
*zoom: 1;
|
|
||||||
display: block;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-icon {
|
|
||||||
position: absolute;
|
|
||||||
left: 4px;
|
|
||||||
top: 1px;
|
|
||||||
width: auto;
|
|
||||||
line-height: 35px;
|
|
||||||
text-align: center;
|
|
||||||
color: #999;
|
|
||||||
padding: 0 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
label:before {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.oauth-area {
|
|
||||||
padding-top: 60px
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-main {
|
|
||||||
width: 300px
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-box {
|
|
||||||
padding: 10px
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-main::before {
|
|
||||||
backdrop-filter: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-header {
|
|
||||||
// background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
|
||||||
.oauth-area {
|
|
||||||
padding-top: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background: #f3f3f3 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-main {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-main::before {
|
|
||||||
box-shadow: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-header {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-box:last-child {
|
|
||||||
box-shadow: 0 5px 10px -5px #d2d2d2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-top {
|
|
||||||
text-align: center;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-top img {
|
|
||||||
width: 64px;
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border: #4950578c solid 1px;
|
}
|
||||||
box-shadow: 1px 0 0 0 #e8e8e8, 0 1px 0 0 #e8e8e8, 1px 1px 0 0 #e8e8e8, inset 1px 0 0 0 #e8e8e8, inset 0 1px 0 0 #e8e8e8;
|
|
||||||
transition: all .3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-top img:hover {
|
.OAuth-User-Info {
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, .3);
|
margin-left: 10px;
|
||||||
}
|
white-space: nowrap;
|
||||||
|
|
||||||
.oauth-top i {
|
h4 {
|
||||||
top: -24px;
|
margin: 0;
|
||||||
position: relative;
|
}
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 10px;
|
|
||||||
color: #111;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-scope-area {
|
small {
|
||||||
padding-top: 10px;
|
opacity: .5;
|
||||||
padding-bottom: 10px;
|
}
|
||||||
overflow: auto;
|
}
|
||||||
max-height: 350px;
|
}
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-scope {
|
.OAuth-Details {
|
||||||
margin-top: 15px;
|
display: flex;
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-scope:first-child {
|
.OAuth-App {
|
||||||
margin-top: 0;
|
min-width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.oauth-scope, .oauth-scope-body {
|
.OAuth-Scopes {
|
||||||
overflow: hidden;
|
flex: 1;
|
||||||
zoom: 1;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.oauth-scope-body, .oauth-scope-left, .oauth-scope-right {
|
.OAuth-App, .OAuth-Scopes {
|
||||||
display: table-cell;
|
margin: 20px 0;
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-scope-left, .oauth-scope > .pull-left {
|
> p {
|
||||||
padding-right: 10px;
|
font-weight: bold;
|
||||||
min-width: 42px;
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.OAuth-App {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
.OAuth-App-Info {
|
||||||
|
color: @text-color;
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
.OAuth-App-Icon {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-weight: bolder;
|
||||||
|
font-size: 2em;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
small {
|
||||||
|
font-size: 1.2em;
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.OAuth-Scopes {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.OAuth-Scope {
|
||||||
|
display: flex;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
.OAuth-ScopeIcon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OAuth-ScopeDetail {
|
||||||
|
margin-left: 10px;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.OAuth-Action {
|
||||||
|
margin: 30px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img.oauth-scope-object {
|
@media screen and (max-width: @screen-phone-max) {
|
||||||
display: block;
|
.AuthorizePage .OAuth-Body {
|
||||||
vertical-align: middle;
|
max-width: 100%;
|
||||||
border: 0;
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-scope-body {
|
.OAuth-Details {
|
||||||
width: 10000px;
|
flex-direction: column;
|
||||||
padding-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-scope-heading {
|
.OAuth-Scopes {
|
||||||
margin-top: 0;
|
padding: 0 30px;
|
||||||
font-weight: 800;
|
}
|
||||||
color: #382e2e;
|
}
|
||||||
margin-block-end: 0;
|
}
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oauth-scope-body small {
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #aaa;
|
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
foskym-oauth-center:
|
rhodes-island-oauth-center:
|
||||||
admin:
|
admin:
|
||||||
permission:
|
permission:
|
||||||
use_oauth: Use OAuth
|
use_oauth: Use OAuth
|
||||||
|
@ -20,8 +20,12 @@ foskym-oauth-center:
|
||||||
client_name: Name
|
client_name: Name
|
||||||
client_desc: Description
|
client_desc: Description
|
||||||
client_icon: Icon
|
client_icon: Icon
|
||||||
client_home: HomePage
|
client_home: Homepage
|
||||||
|
actions: Actions
|
||||||
add_button: Add Client
|
add_button: Add Client
|
||||||
|
edit_modal_title_add: New application
|
||||||
|
edit_modal_title_edit: Edit application
|
||||||
|
edit_modal_save: Save
|
||||||
scopes:
|
scopes:
|
||||||
scope: Scope
|
scope: Scope
|
||||||
resource_path: Resource Path
|
resource_path: Resource Path
|
||||||
|
@ -31,6 +35,7 @@ foskym-oauth-center:
|
||||||
scope_icon: Icon
|
scope_icon: Icon
|
||||||
scope_desc: Description
|
scope_desc: Description
|
||||||
add_button: Add Scope
|
add_button: Add Scope
|
||||||
|
save: Save scopes
|
||||||
|
|
||||||
forum:
|
forum:
|
||||||
page:
|
page:
|
||||||
|
@ -39,6 +44,11 @@ foskym-oauth-center:
|
||||||
label:
|
label:
|
||||||
authorized: Authorized Logs
|
authorized: Authorized Logs
|
||||||
authorize:
|
authorize:
|
||||||
access: Access to
|
title: Third party application authorization
|
||||||
|
description: Authorize third party application to use your identity
|
||||||
|
app_text: You are about to authorize
|
||||||
|
to_app_homepage: Go to {name}'s homepage
|
||||||
|
scope_text: To use the following privileges
|
||||||
agree: Agree
|
agree: Agree
|
||||||
deny: Deny
|
deny: Deny
|
||||||
|
not_logged_in: Please continue after log in
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
foskym-oauth-center:
|
rhodes-island-oauth-center:
|
||||||
admin:
|
admin:
|
||||||
permission:
|
permission:
|
||||||
use_oauth: 使用 OAuth 授权
|
use_oauth: 使用 OAuth 授权
|
||||||
|
@ -21,7 +21,11 @@ foskym-oauth-center:
|
||||||
client_desc: 描述
|
client_desc: 描述
|
||||||
client_icon: 图标
|
client_icon: 图标
|
||||||
client_home: 主页
|
client_home: 主页
|
||||||
|
actions: 操作
|
||||||
add_button: 添加应用
|
add_button: 添加应用
|
||||||
|
edit_modal_title_add: 新建应用
|
||||||
|
edit_modal_title_edit: 编辑应用
|
||||||
|
edit_modal_save: 保存应用
|
||||||
scopes:
|
scopes:
|
||||||
scope: 权限标识
|
scope: 权限标识
|
||||||
resource_path: 资源路径
|
resource_path: 资源路径
|
||||||
|
@ -31,6 +35,7 @@ foskym-oauth-center:
|
||||||
scope_icon: 图标
|
scope_icon: 图标
|
||||||
scope_desc: 描述
|
scope_desc: 描述
|
||||||
add_button: 添加权限
|
add_button: 添加权限
|
||||||
|
save: 保存权限
|
||||||
|
|
||||||
forum:
|
forum:
|
||||||
page:
|
page:
|
||||||
|
@ -39,6 +44,11 @@ foskym-oauth-center:
|
||||||
label:
|
label:
|
||||||
authorized: 授权记录
|
authorized: 授权记录
|
||||||
authorize:
|
authorize:
|
||||||
access: 授权访问
|
title: 第三方应用授权
|
||||||
|
description: 授权第三方应用以你的身份使用部分权限
|
||||||
|
app_text: 你即将授权
|
||||||
|
to_app_homepage: 前往 {name} 的主页
|
||||||
|
scope_text: 获得以下权限
|
||||||
agree: 授权
|
agree: 授权
|
||||||
deny: 拒绝
|
deny: 拒绝
|
||||||
|
not_logged_in: 请登录后再继续操作
|
||||||
|
|
|
@ -20,7 +20,7 @@ return [
|
||||||
'scope' => 'user.read',
|
'scope' => 'user.read',
|
||||||
'resource_path' => '/api/user',
|
'resource_path' => '/api/user',
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
'is_default' => 1,
|
'is_default' => true,
|
||||||
'scope_name' => '获取用户信息',
|
'scope_name' => '获取用户信息',
|
||||||
'scope_icon' => 'fas fa-user',
|
'scope_icon' => 'fas fa-user',
|
||||||
'scope_desc' => '访问该用户({user})的个人信息等',
|
'scope_desc' => '访问该用户({user})的个人信息等',
|
||||||
|
|
|
@ -20,10 +20,17 @@ class CreateClientController extends AbstractCreateController
|
||||||
|
|
||||||
$attributes = Arr::get($request->getParsedBody(), 'data.attributes');
|
$attributes = Arr::get($request->getParsedBody(), 'data.attributes');
|
||||||
|
|
||||||
return Client::create([
|
$validAttrs = [
|
||||||
'client_id' => Arr::get($attributes, 'client_id'),
|
'user_id' => $actor->id
|
||||||
'client_secret' => Arr::get($attributes, 'client_secret'),
|
];
|
||||||
'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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ class ListScopeController extends AbstractListController
|
||||||
$actor->assertAdmin();
|
$actor->assertAdmin();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$actor->assertRegistered();
|
$actor->assertRegistered();
|
||||||
if (!$actor->hasPermission('foskym-oauth-center.use-oauth')) {
|
if (!$actor->hasPermission('rhodes-island-oauth-center.use-oauth')) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
$this->serializer = ScopeUserSerializer::class;
|
$this->serializer = ScopeUserSerializer::class;
|
||||||
|
|
|
@ -20,7 +20,7 @@ class ShowClientController extends AbstractListController
|
||||||
$actor = RequestUtil::getActor($request);
|
$actor = RequestUtil::getActor($request);
|
||||||
$actor->assertRegistered();
|
$actor->assertRegistered();
|
||||||
|
|
||||||
if (!$actor->hasPermission('foskym-oauth-center.use-oauth')) {
|
if (!$actor->hasPermission('rhodes-island-oauth-center.use-oauth')) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ class AuthorizeController implements RequestHandlerInterface
|
||||||
$actor = RequestUtil::getActor($request);
|
$actor = RequestUtil::getActor($request);
|
||||||
$actor->assertRegistered();
|
$actor->assertRegistered();
|
||||||
|
|
||||||
if (!$actor->hasPermission('foskym-oauth-center.use-oauth')) {
|
if (!$actor->hasPermission('rhodes-island-oauth-center.use-oauth')) {
|
||||||
return new JsonResponse([ 'error' => 'no_permission', 'error_description' => 'Don\'t have the permissions of oauth' ]);
|
return new JsonResponse([ 'error' => 'no_permission', 'error_description' => 'Don\'t have the permissions of oauth' ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ class UserCredentialsMiddleware implements MiddlewareInterface
|
||||||
$path = $request->getUri()->getPath();
|
$path = $request->getUri()->getPath();
|
||||||
if (in_array($path, $uri) && Arr::get($request->getParsedBody(), 'grant_type', '') === 'password') {
|
if (in_array($path, $uri) && Arr::get($request->getParsedBody(), 'grant_type', '') === 'password') {
|
||||||
if ($user = User::where('username', Arr::get($request->getParsedBody(), 'username', ''))->first()) {
|
if ($user = User::where('username', Arr::get($request->getParsedBody(), 'username', ''))->first()) {
|
||||||
if (!$user->hasPermission('foskym-oauth-center.use-oauth')) {
|
if (!$user->hasPermission('rhodes-island-oauth-center.use-oauth')) {
|
||||||
return new JsonResponse([ 'error' => 'no_permission', 'error_description' => 'Don\'t have the permissions of oauth' ]);
|
return new JsonResponse([ 'error' => 'no_permission', 'error_description' => 'Don\'t have the permissions of oauth' ]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,10 +45,10 @@ class OAuth
|
||||||
{
|
{
|
||||||
$storage = new Storage;
|
$storage = new Storage;
|
||||||
$server = new Server($storage, array(
|
$server = new Server($storage, array(
|
||||||
'allow_implicit' => $this->settings->get('foskym-oauth-center.allow_implicit') == "1",
|
'allow_implicit' => $this->settings->get('rhodes-island-oauth-center.allow_implicit') == "1",
|
||||||
'enforce_state' => $this->settings->get('foskym-oauth-center.enforce_state') == "1",
|
'enforce_state' => $this->settings->get('rhodes-island-oauth-center.enforce_state') == "1",
|
||||||
'require_exact_redirect_uri' => $this->settings->get('foskym-oauth-center.require_exact_redirect_uri') == "1",
|
'require_exact_redirect_uri' => $this->settings->get('rhodes-island-oauth-center.require_exact_redirect_uri') == "1",
|
||||||
'access_lifetime' => $this->settings->get('foskym-oauth-center.access_lifetime') == "" ? 3600 : $this->settings->get('foskym-oauth-center.access_lifetime'),
|
'access_lifetime' => $this->settings->get('rhodes-island-oauth-center.access_lifetime') == "" ? 3600 : $this->settings->get('rhodes-island-oauth-center.access_lifetime'),
|
||||||
));
|
));
|
||||||
$server->addGrantType(new AuthorizationCode($storage));
|
$server->addGrantType(new AuthorizationCode($storage));
|
||||||
$server->addGrantType(new ClientCredentials($storage));
|
$server->addGrantType(new ClientCredentials($storage));
|
||||||
|
|
Loading…
Reference in a new issue