From fa5fb54876f47b748839d5aecce585e5d493c999 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Wed, 7 May 2025 08:27:03 +0200 Subject: [PATCH 1/4] update: ReadMe --- README.md | 17 +++-------------- demo-totp-qrcode.png | Bin 1946 -> 0 bytes 2 files changed, 3 insertions(+), 14 deletions(-) delete mode 100644 demo-totp-qrcode.png diff --git a/README.md b/README.md index 1ac5ff6..6f1136c 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,9 @@ Dieses Repository dient hauptsächlich zur Verwaltung der Mitgliederdaten, aber Eine Demo dieser Seite finden Sie unter [https://admin-demo.ff-admin.de](https://admin-demo.ff-admin.de). -Für die Verwendung muss ein TOTP-Code eingegeben werden. +Die Zugangsdaten (Lesebeschränkt) sind unterhalb dem Login angegeben. -Die Zugangsdaten (Lesebeschränkt) sind:\ -EMAIL: demo-besucher\ -TOTP: ![alt text](demo-totp-qrcode.png)\ -TOTP-Code: FBMDAJKFOYQXM2DNH47GWWBGJ5KWOUCW +Das Handbuch zur Anwendung finden sie unter [https://ff-admin.de/ff-admin-handbook](https://ff-admin.de/ff-admin-handbook). ## Installation @@ -29,17 +26,9 @@ services: image: docker.registry.jk-effects.cloud/ehrenamt/ff-admin/app:latest container_name: ff_admin restart: unless-stopped - + #environment: # - SERVERADDRESS= # wichtig: ohne Pfad - # - APPNAMEOVERWRITE= # ersetzt den Namen FF-Admin auf der Login-Seite und sonstigen Positionen in der Oberfläche - # - IMPRINTLINK= - # - PRIVACYLINK= - # - CUSTOMLOGINMESSAGE=betrieben von xy - #volumes: - # - /favicon.ico:/usr/share/nginx/html/favicon.ico # 48x48 px Auflösung - # - /favicon.png:/usr/share/nginx/html/favicon.png # 512x512 px Auflösung - wird als pwa Icon genutzt - # - /Logo.png:/usr/share/nginx/html/Logo.png ``` Wenn keine Server-Adresse angegeben wird, wird versucht das Backend unter der URL des Frontends zu erreichen. Dazu muss das Backend auf der gleichen URL wie das Frontend laufen. Zur Unterscheidung von Frontend und Backend bei gleicher URL müssen alle Anfragen mit dem PathPrefix `/api` an das Backend weitergeleitet werden. diff --git a/demo-totp-qrcode.png b/demo-totp-qrcode.png deleted file mode 100644 index ae03670cbfe00b52ba89f1524e6fa8d9e55781af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1946 zcmb7FZ)g)|7|$l?6uL4?5Y(~hT!Z()(tNp1yJp&0dm}X_y^0%*&O$!z!%fkdLP^;s zb%`jG60BqxnjT%w{Xt~|m69qN7!^S#7RJEn;eld>CZ7^^Hv2u#UCiA+Z69*)UG90_ z_j!JQo=fiAyQgK%`ZXSpr$y=uMzQ`%zt>jc`oW!*ek`v_!JTsamBsamKRljQ1N8L# z#?I4Q_N=}Bq5p2Z?mu=q@zL9n`|oUBxU<;0aP8K?pHFUFxc2-1TFj+Q={ZeL&QGL# z!a#9@5Ek0gVL60*)j!x3sbz%jLkFI1KJnYO!&m~N9~VV!Hc}p+m&-xpR7x_WVq02@ zU6_>5=R@AGP>_tw>z{x6_~OEDT22hjRC=-PKv6-+Oo}7h)0!?7eM0vX-YMIEI(p{j zC+ptF^47K=DyrU+)`p|!g!6J&1lPP7*x`(rrn1hVO4>uk25ktx5YPFwkhdPQ>%>yI z+3{nw!;0kX^3;@7NmZoN8iy7_Mpo`bI`z&++nf6bZ5%>^k~cGNz6AH%7dOTx83A!{ zcFHOl7|P|LFP&KR5iA8%Hz_~J$8(6ws+A;wF3Dv#Nc-t{g#jcO>23m)NU`Whv{M^p zGVEGL?==ZFm!=5O>hXC3fnyuVV2=`rRs}%Tj-$Gy-7%I+f$HY8&l?6MO0*WV$R3%d zCU9O(7g104JqJkLYQ^H5Kv#!32fau}3$}S#uOYfX>Hv-Hcwgdb2;LF{O}){7W`C2f z;jyKY^72edL`ft?bfjnG?ntNBr9oUQ2DcRZSbMa4B^V? zZ3)zd65~Ba8)*Vrkm5K%6otZ5Te(;g)$afYa0G%HK<0bi0(mSJo%4k`N77mm;N*m3A&1wBqDlE?efe&;R*$^X9ryXjK&O-1cOExEz-l@$_k)S5{795yoo5L0U zUxocdh>c}|-1?SuMmA@f4y!%t@n-2Y5C+!t1Bu{>=9`{9;u;hNrXvC*qXcWAv~io4 zFyvBo40dxV#&SpJs^2mO4-KR?FlqDF-)*`IQ*Zzh$#AuV01p|Gd(g;0moAHZah0Hr z_h2ik7&+FL!4hl9iSU*08C-HE6@XCs5)f*UGMO<-S9j&Ng#^9=kTp$XD}DpuB~s`9 zbk4MxFvi1=Et2HX2FJ1p*&HFEt~PPL6gco~ZL?weO8vK|N+5Tz@YR#>;lJ>)^+>z- L27lT0+1LL718%Zi -- 2.45.3 From c17355fcd16dfa8e811b68f7b01a2cc71d429857 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Wed, 7 May 2025 08:27:31 +0200 Subject: [PATCH 2/4] change: request method for account credential change --- src/components/account/ChangeToPassword.vue | 2 +- src/components/account/ChangeToTOTP.vue | 2 +- src/components/account/PasswordChange.vue | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/account/ChangeToPassword.vue b/src/components/account/ChangeToPassword.vue index 86b7c8e..cbd14c7 100644 --- a/src/components/account/ChangeToPassword.vue +++ b/src/components/account/ChangeToPassword.vue @@ -84,7 +84,7 @@ export default defineComponent({ this.changeStatus = "loading"; this.changeError = ""; this.$http - .post(`/user/changeToPW`, { + .patch(`/user/changeToPW`, { newpassword: await hashString(formData.new.value), }) .then((result) => { diff --git a/src/components/account/ChangeToTOTP.vue b/src/components/account/ChangeToTOTP.vue index c04197c..3d5dab3 100644 --- a/src/components/account/ChangeToTOTP.vue +++ b/src/components/account/ChangeToTOTP.vue @@ -69,7 +69,7 @@ export default defineComponent({ this.verifyStatus = "loading"; this.verifyError = ""; this.$http - .post(`/user/changeToTOTP`, { + .patch(`/user/changeToTOTP`, { otp: this.otp, totp: formData.totp.value, }) diff --git a/src/components/account/PasswordChange.vue b/src/components/account/PasswordChange.vue index 268e5bc..eebd339 100644 --- a/src/components/account/PasswordChange.vue +++ b/src/components/account/PasswordChange.vue @@ -87,7 +87,7 @@ export default defineComponent({ this.changeStatus = "loading"; this.changeError = ""; this.$http - .post(`/user/changepw`, { + .patch(`/user/changepw`, { current: await hashString(formData.current.value), newpassword: await hashString(formData.new.value), }) -- 2.45.3 From b4fdd5fc6091f3292c9ed634068e1c5c169a1d87 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Wed, 7 May 2025 09:05:25 +0200 Subject: [PATCH 3/4] enhance: permission handling --- src/components/admin/Permission.vue | 10 +++---- src/stores/ability.ts | 46 +++++++++++++++++------------ src/types/permissionTypes.ts | 14 +++++++++ 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/components/admin/Permission.vue b/src/components/admin/Permission.vue index 9be7f19..7da9b9d 100644 --- a/src/components/admin/Permission.vue +++ b/src/components/admin/Permission.vue @@ -18,22 +18,22 @@
@@ -132,7 +132,7 @@ export default defineComponent({ }; }, computed: { - ...mapState(useAbilityStore, ["_can"]), + ...mapState(useAbilityStore, ["_can", "_canSection"]), canSaveOrReset(): boolean { return isEqual(this.permissions, this.permissionUpdate); }, diff --git a/src/stores/ability.ts b/src/stores/ability.ts index d5190af..f65f6fe 100644 --- a/src/stores/ability.ts +++ b/src/stores/ability.ts @@ -11,21 +11,18 @@ export const useAbilityStore = defineStore("ability", { getters: { can: (state) => - (type: PermissionType | "admin", section: PermissionSection, module?: PermissionModule): boolean => { + (type: PermissionType | "admin", section: PermissionSection, module: PermissionModule): boolean => { const permissions = state.permissions; if (state.isOwner) return true; - if (type == "admin") return permissions?.admin ?? false; - if (permissions?.admin) return true; + if (type == "admin") return permissions?.admin ?? permissions?.adminByOwner ?? false; + if (permissions?.admin || permissions?.adminByOwner) return true; if ( - (!module && - permissions[section] != undefined && - (permissions[section]?.all == "*" || permissions[section]?.all?.includes(type))) || permissions[section]?.all == "*" || - permissions[section]?.all?.includes(type) + permissions[section]?.all?.includes(type) || + permissions[section]?.[module] == "*" || + permissions[section]?.[module]?.includes(type) ) return true; - if (module && (permissions[section]?.[module] == "*" || permissions[section]?.[module]?.includes(type))) - return true; return false; }, canSection: @@ -33,8 +30,8 @@ export const useAbilityStore = defineStore("ability", { (type: PermissionType | "admin", section: PermissionSection): boolean => { const permissions = state.permissions; if (state.isOwner) return true; - if (type == "admin") return permissions?.admin ?? false; - if (permissions?.admin) return true; + if (type == "admin") return permissions?.admin ?? permissions?.adminByOwner ?? false; + if (permissions?.admin || permissions?.adminByOwner) return true; if ( permissions[section]?.all == "*" || permissions[section]?.all?.includes(type) || @@ -54,20 +51,31 @@ export const useAbilityStore = defineStore("ability", { permissions: PermissionObject, type: PermissionType | "admin", section: PermissionSection, - module?: PermissionModule + module: PermissionModule ): boolean => { // ignores ownership - if (type == "admin") return permissions?.admin ?? false; - if (permissions?.admin) return true; + if (type == "admin") return permissions?.admin ?? permissions?.adminByOwner ?? false; + if (permissions?.admin || permissions?.adminByOwner) return true; if ( - (!module && - permissions[section] != undefined && - (permissions[section]?.all == "*" || permissions[section]?.all?.includes(type))) || permissions[section]?.all == "*" || - permissions[section]?.all?.includes(type) + permissions[section]?.all?.includes(type) || + permissions[section]?.[module] == "*" || + permissions[section]?.[module]?.includes(type) ) return true; - if (module && (permissions[section]?.[module] == "*" || permissions[section]?.[module]?.includes(type))) + return false; + }, + _canSection: + () => + (permissions: PermissionObject, type: PermissionType | "admin", section: PermissionSection): boolean => { + // ignores ownership + if (type == "admin") return permissions?.admin ?? permissions?.adminByOwner ?? false; + if (permissions?.admin || permissions?.adminByOwner) return true; + if ( + permissions[section]?.all == "*" || + permissions[section]?.all?.includes(type) || + permissions[section] != undefined + ) return true; return false; }, diff --git a/src/types/permissionTypes.ts b/src/types/permissionTypes.ts index 72f15c7..eff7fd1 100644 --- a/src/types/permissionTypes.ts +++ b/src/types/permissionTypes.ts @@ -31,6 +31,7 @@ export type PermissionString = | `${PermissionSection}.${PermissionModule}.*` // für alle Berechtigungen in einem Modul | `${PermissionSection}.${PermissionType}` // für spezifische Berechtigungen in einem Abschnitt | `${PermissionSection}.*` // für alle Berechtigungen in einem Abschnitt + | `additional.${string}.${string}` // additional | "*"; // für Admin export type PermissionObject = { @@ -39,10 +40,20 @@ export type PermissionObject = { } & { all?: Array | "*" }; } & { admin?: boolean; + adminByOwner?: boolean; +} & { + additional?: { [key: string]: string }; }; export type SectionsAndModulesObject = { [section in PermissionSection]: Array; +} & { + additional?: Array<{ + key: string; + name: string; + type: "number" | "string"; + emptyIfAdmin: boolean; + }>; }; export const permissionSections: Array = ["club", "configuration", "management"]; @@ -87,4 +98,7 @@ export const sectionsAndModules: SectionsAndModulesObject = { "newsletter_config", ], management: ["user", "role", "webapi", "backup", "setting"], + additional: [ + //{ key: "val", name: "name", type: "number", emptyIfAdmin: true }, + ], }; -- 2.45.3 From 18d52e4babda133fc7142796bf6a9f7ef140a67a Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Wed, 7 May 2025 09:20:32 +0200 Subject: [PATCH 4/4] change: refactor imports --- src/components/Header.vue | 2 +- src/components/account/ChangeToPassword.vue | 2 +- src/components/account/PasswordChange.vue | 2 +- src/components/admin/MemberSearchSelect.vue | 2 +- src/components/admin/club/member/CreateMemberModal.vue | 4 ++-- .../admin/club/newsletter/CreateNewsletterModal.vue | 4 ++-- src/components/admin/management/backup/BackupListItem.vue | 2 +- .../admin/management/backup/RestoreBackupModal.vue | 4 ++-- .../admin/management/webapi/CreateWebapiModal.vue | 2 +- .../admin/management/webapi/WebapiTokenModal.vue | 2 +- src/components/setup/Account.vue | 2 +- src/components/setup/App.vue | 2 +- src/components/setup/Club.vue | 2 +- src/components/setup/Images.vue | 2 +- src/components/setup/Mail.vue | 2 +- src/helpers/queryFormatter.ts | 2 +- src/router/backupGuard.ts | 2 +- src/router/newsletterGuard.ts | 2 +- src/router/protocolGuard.ts | 2 +- src/stores/admin/club/newsletter/newsletterPrintout.ts | 5 ++--- src/stores/admin/configuration/queryStore.ts | 6 +++--- src/stores/admin/management/backup.ts | 2 +- src/stores/admin/navigation.ts | 2 +- src/stores/configuration.ts | 2 +- src/stores/setup.ts | 2 +- src/viewmodels/admin/club/calendar.models.ts | 2 +- src/viewmodels/admin/club/member/communication.models.ts | 2 +- src/viewmodels/admin/club/member/member.models.ts | 2 +- .../admin/club/newsletter/newsletterDates.models.ts | 2 +- .../admin/club/newsletter/newsletterRecipients.models.ts | 2 +- src/viewmodels/admin/management/backup.models.ts | 2 +- src/views/Login.vue | 2 +- src/views/account/LoginData.vue | 8 ++++---- src/views/admin/club/members/MemberEdit.vue | 2 +- src/views/admin/club/newsletter/Newsletter.vue | 2 +- src/views/admin/club/newsletter/NewsletterPrintout.vue | 2 +- src/views/admin/club/newsletter/NewsletterRouting.vue | 4 ++-- src/views/setup/Setup.vue | 2 +- 38 files changed, 48 insertions(+), 49 deletions(-) diff --git a/src/components/Header.vue b/src/components/Header.vue index 9872753..109c38a 100644 --- a/src/components/Header.vue +++ b/src/components/Header.vue @@ -42,7 +42,7 @@ import UserMenu from "./UserMenu.vue"; diff --git a/src/components/admin/club/newsletter/CreateNewsletterModal.vue b/src/components/admin/club/newsletter/CreateNewsletterModal.vue index f589b89..40da0c4 100644 --- a/src/components/admin/club/newsletter/CreateNewsletterModal.vue +++ b/src/components/admin/club/newsletter/CreateNewsletterModal.vue @@ -36,8 +36,8 @@ import SuccessCheckmark from "@/components/SuccessCheckmark.vue"; import FailureXMark from "@/components/FailureXMark.vue"; import { useProtocolStore } from "@/stores/admin/club/protocol/protocol"; import type { CreateProtocolViewModel } from "@/viewmodels/admin/club/protocol/protocol.models"; -import { useNewsletterStore } from "../../../../stores/admin/club/newsletter/newsletter"; -import type { CreateNewsletterViewModel } from "../../../../viewmodels/admin/club/newsletter/newsletter.models"; +import { useNewsletterStore } from "@/stores/admin/club/newsletter/newsletter"; +import type { CreateNewsletterViewModel } from "@/viewmodels/admin/club/newsletter/newsletter.models";