mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-15 00:30:02 +00:00
Fix excessive DB access in SecurityConfig
Fix array parsing bug in ConfigService Potential fix for push subscription being cancelled in frontend Simplify ConfigState since we are already returning the correct types from the backend
This commit is contained in:
@@ -9,13 +9,10 @@ import {SmallInfoField} from "Frontend/components/general/SmallInfoField";
|
||||
import {Info, UserPlus} from "@phosphor-icons/react";
|
||||
import {Button, Divider, Tooltip, useDisclosure} from "@heroui/react";
|
||||
import InviteUserModal from "Frontend/components/general/modals/InviteUserModal";
|
||||
import {useSnapshot} from "valtio/react";
|
||||
import {configState} from "Frontend/state/ConfigState";
|
||||
|
||||
function UserManagementLayout({getConfig, formik}: any) {
|
||||
const inviteUserModal = useDisclosure();
|
||||
const [users, setUsers] = useState<UserInfoDto[]>([]);
|
||||
const config = useSnapshot(configState);
|
||||
|
||||
useEffect(() => {
|
||||
UserEndpoint.getAllUsers().then(
|
||||
@@ -35,7 +32,7 @@ function UserManagementLayout({getConfig, formik}: any) {
|
||||
|
||||
<div className="flex flex-row items-baseline justify-between">
|
||||
<h2 className="text-xl font-bold mt-8 mb-1">Users</h2>
|
||||
{!config.configEntries["sso.oidc.auto-register-new-users"].value &&
|
||||
{!getConfig("sso.oidc.auto-register-new-users").value &&
|
||||
<SmallInfoField className="mb-4 text-warning" icon={Info}
|
||||
message="Automatic user registration for SSO users is disabled"/>
|
||||
}
|
||||
|
||||
@@ -2,15 +2,19 @@ import {proxy} from 'valtio';
|
||||
import ConfigEntryDto from "Frontend/generated/de/grimsi/gameyfin/config/dto/ConfigEntryDto";
|
||||
import {ConfigEndpoint} from "Frontend/generated/endpoints";
|
||||
import ConfigUpdateDto from "Frontend/generated/de/grimsi/gameyfin/config/dto/ConfigUpdateDto";
|
||||
import {Subscription} from "@vaadin/hilla-frontend";
|
||||
|
||||
type ConfigState = {
|
||||
subscription?: Subscription<ConfigUpdateDto>;
|
||||
isLoaded: boolean;
|
||||
configEntries: Record<string, ConfigEntryDto>;
|
||||
configNested: NestedConfig;
|
||||
};
|
||||
|
||||
export const configState = proxy<ConfigState>({
|
||||
isLoaded: false,
|
||||
get isLoaded() {
|
||||
return this.subscription != null;
|
||||
},
|
||||
configEntries: {},
|
||||
get configNested() {
|
||||
return toNestedConfig(Object.values(this.configEntries));
|
||||
@@ -26,10 +30,9 @@ export async function initializeConfig() {
|
||||
initialEntries.forEach((entry) => {
|
||||
configState.configEntries[entry.key] = entry;
|
||||
});
|
||||
configState.isLoaded = true;
|
||||
|
||||
// Subscribe to real-time updates
|
||||
ConfigEndpoint.subscribe().onNext((updateDto: ConfigUpdateDto) => {
|
||||
configState.subscription = ConfigEndpoint.subscribe().onNext((updateDto: ConfigUpdateDto) => {
|
||||
Object.entries(updateDto.updates).forEach(([key, value]) => {
|
||||
if (configState.configEntries[key]) {
|
||||
configState.configEntries[key].value = value;
|
||||
@@ -44,63 +47,24 @@ export type NestedConfig = {
|
||||
[field: string]: any;
|
||||
}
|
||||
|
||||
function toNestedConfig(configArray: ConfigEntryDto[]): NestedConfig {
|
||||
const nestedConfig: NestedConfig = {};
|
||||
function toNestedConfig(entries: ConfigEntryDto[]): Record<string, any> {
|
||||
const result: Record<string, any> = {};
|
||||
|
||||
configArray.forEach(item => {
|
||||
const keys = item.key!.split('.');
|
||||
let currentLevel = nestedConfig;
|
||||
for (const entry of entries) {
|
||||
const keys = entry.key.split('.');
|
||||
let current = result;
|
||||
|
||||
// Traverse the nested structure and create objects as needed
|
||||
keys.forEach((key, index) => {
|
||||
if (index === keys.length - 1) {
|
||||
// Convert value to the appropriate type
|
||||
let value: any;
|
||||
switch (item.type) {
|
||||
case 'Boolean':
|
||||
value = typeof item.value == 'boolean' ? item.value : item.value === 'true';
|
||||
break;
|
||||
case 'Int':
|
||||
value = typeof item.value == 'number' ? item.value : 0;
|
||||
break;
|
||||
case 'Float':
|
||||
value = typeof item.value == 'number' ? item.value : 0.0;
|
||||
break;
|
||||
case 'Array':
|
||||
if (Array.isArray(item.value)) {
|
||||
switch (item.elementType) {
|
||||
case 'Boolean':
|
||||
value = item.value.map(v => typeof v === 'boolean' ? v : v === 'true');
|
||||
break;
|
||||
case 'Int':
|
||||
case 'Integer':
|
||||
value = item.value.map(v => typeof v == 'number' ? v : 0);
|
||||
break;
|
||||
case 'Float':
|
||||
value = item.value.map(v => typeof v == 'number' ? v : 0.0);
|
||||
break;
|
||||
case 'String':
|
||||
default:
|
||||
value = item.value.map(v => v.toString());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
value = [];
|
||||
}
|
||||
break;
|
||||
case 'String':
|
||||
default:
|
||||
value = item.value;
|
||||
break;
|
||||
}
|
||||
currentLevel[key] = value;
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
|
||||
if (i === keys.length - 1) {
|
||||
current[key] = entry.value;
|
||||
} else {
|
||||
if (!currentLevel[key]) {
|
||||
currentLevel[key] = {};
|
||||
}
|
||||
currentLevel = currentLevel[key];
|
||||
current[key] = current[key] || {};
|
||||
current = current[key];
|
||||
}
|
||||
});
|
||||
});
|
||||
return nestedConfig;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -97,9 +97,9 @@ class ConfigService(
|
||||
var configEntry = appConfigRepository.findByIdOrNull(key)
|
||||
|
||||
val parsedValue =
|
||||
if (value.javaClass.isArray)
|
||||
if (value.javaClass.isArray) {
|
||||
(value as Array<Serializable>).joinToString(",")
|
||||
else
|
||||
} else
|
||||
value.toString()
|
||||
|
||||
if (configEntry == null) {
|
||||
@@ -173,8 +173,11 @@ class ConfigService(
|
||||
configProperty.type.java.isArray -> {
|
||||
val componentType = configProperty.type.java.componentType
|
||||
// Remove the brackets and split the string by commas
|
||||
val elements = value.removeSurrounding("[", "]").split(",")
|
||||
if (elements.isEmpty()) return emptyArray<Serializable>() as T
|
||||
val elements = value
|
||||
.removeSurrounding("[", "]")
|
||||
.split(",")
|
||||
.filter { it.isNotBlank() }
|
||||
|
||||
when (componentType) {
|
||||
String::class.java -> elements.toTypedArray() as T
|
||||
Boolean::class.java -> elements.map { it.toBoolean() }.toTypedArray() as T
|
||||
|
||||
@@ -32,6 +32,7 @@ class SecurityConfig(
|
||||
) : VaadinWebSecurity() {
|
||||
|
||||
private val ssoProviderKey: String = "oidc"
|
||||
private val allowedOrigins: List<String>? = config.get(ConfigProperties.System.Cors.AllowedOrigins)?.toList()
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun configure(http: HttpSecurity) {
|
||||
@@ -55,7 +56,7 @@ class SecurityConfig(
|
||||
http.cors { cors ->
|
||||
cors.configurationSource { request ->
|
||||
val configuration = CorsConfiguration()
|
||||
configuration.allowedOrigins = config.get(ConfigProperties.System.Cors.AllowedOrigins)?.toList()
|
||||
configuration.allowedOrigins = allowedOrigins
|
||||
configuration
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user