diff --git a/Core/Configuration/Settings.class.php b/Core/Configuration/Settings.class.php index fe6a8a1..48c8e98 100644 --- a/Core/Configuration/Settings.class.php +++ b/Core/Configuration/Settings.class.php @@ -84,15 +84,8 @@ class Settings { } public static function loadDefaults(): Settings { - $hostname = $_SERVER["SERVER_NAME"] ?? null; - if (empty($hostname)) { - $hostname = $_SERVER["HTTP_HOST"] ?? null; - if (empty($hostname)) { - $hostname = "localhost"; - } - } - $protocol = getProtocol(); + $hostname = getHostName(); $settings = new Settings(); // General diff --git a/Core/Objects/Context.class.php b/Core/Objects/Context.class.php index aa32c50..c92a4da 100644 --- a/Core/Objects/Context.class.php +++ b/Core/Objects/Context.class.php @@ -92,7 +92,8 @@ class Context { public function sendCookies(): void { // TODO: what will we do, when there is a domain mismatch? forbid access or just send cookies for the current domain? or should we send a redirect? - $domain = $this->getSettings()->getDomain(); + // $domain = $this->getSettings()->getDomain(); + $domain = getCurrentHostName(); $this->language->sendCookie($domain); $this->session?->sendCookie($domain); $this->session?->update(); @@ -202,7 +203,7 @@ class Context { return $this->language; } - public function invalidateSessions(bool $keepCurrent = true): bool { + public function invalidateSessions(bool $keepCurrent = false): bool { $query = $this->sql->update("Session") ->set("active", false) ->whereEq("user_id", $this->user->getId()); diff --git a/Core/core.php b/Core/core.php index 09464d9..781e7b2 100644 --- a/Core/core.php +++ b/Core/core.php @@ -36,6 +36,18 @@ function getProtocol(): string { return $isSecure ? 'https' : 'http'; } +function getCurrentHostName(): string { + $hostname = $_SERVER["SERVER_NAME"] ?? null; + if (empty($hostname)) { + $hostname = $_SERVER["HTTP_HOST"] ?? null; + if (empty($hostname)) { + $hostname = gethostname(); + } + } + + return $hostname; +} + function uuidv4(): string { $data = random_bytes(16); $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100 diff --git a/react/admin-panel/src/AdminDashboard.jsx b/react/admin-panel/src/AdminDashboard.jsx index fb91d08..c428878 100644 --- a/react/admin-panel/src/AdminDashboard.jsx +++ b/react/admin-panel/src/AdminDashboard.jsx @@ -1,5 +1,5 @@ import React, {lazy, Suspense, useCallback, useState} from "react"; -import {BrowserRouter, Route, Routes} from "react-router-dom"; +import {BrowserRouter, Navigate, Route, Routes} from "react-router-dom"; import Dialog from "shared/elements/dialog"; import Sidebar from "./elements/sidebar"; import Footer from "./elements/footer"; @@ -73,7 +73,7 @@ export default function AdminDashboard(props) {
{L("general.loading")}... }> - }/> + }/> }/> }/> }/> diff --git a/react/admin-panel/src/views/group/group-edit.js b/react/admin-panel/src/views/group/group-edit.js index 0d685ee..58ee438 100644 --- a/react/admin-panel/src/views/group/group-edit.js +++ b/react/admin-panel/src/views/group/group-edit.js @@ -1,4 +1,4 @@ -import {useCallback, useContext, useEffect, useState} from "react"; +import {useCallback, useContext, useEffect, useRef, useState} from "react"; import {Link, useNavigate, useParams} from "react-router-dom"; import {LocaleContext} from "shared/locale"; import SearchField from "shared/elements/search-field"; @@ -34,7 +34,7 @@ export default function EditGroupView(props) { const [fetchGroup, setFetchGroup] = useState(!isNewGroup); const [group, setGroup] = useState(isNewGroup ? defaultGroupData : null); const [members, setMembers] = useState([]); - const [selectedUser, setSelectedUser] = useState(null); + const selectedUserRef = useRef(null); // ui const [dialogData, setDialogData] = useState({open: false}); @@ -86,19 +86,19 @@ export default function EditGroupView(props) { }, [api, showDialog, groupId, members]); const onAddMember = useCallback(() => { - if (selectedUser) { - api.addGroupMember(groupId, selectedUser.id).then(data => { + if (selectedUserRef.current) { + api.addGroupMember(groupId, selectedUserRef.current.id).then(data => { if (!data.success) { showDialog(data.msg, L("account.add_group_member_error")); } else { let newMembers = [...members]; - newMembers.push(selectedUser); + newMembers.push(selectedUserRef.current); setMembers(newMembers); } - setSelectedUser(null); + selectedUserRef.current = null; }); } - }, [api, showDialog, groupId, selectedUser, members]) + }, [api, showDialog, groupId, selectedUserRef, members]) const onSave = useCallback(() => { setSaving(true); @@ -152,15 +152,19 @@ export default function EditGroupView(props) { size: "small", key: "search", element: SearchField, onSearch: v => onSearchUser(v), - onSelect: u => setSelectedUser(u), + onSelect: u => { selectedUserRef.current = u }, getOptionLabel: u => u.fullName || u.name } ], - onOption: (option) => option === 0 ? - onAddMember() : - setSelectedUser(null) + onOption: (option) => { + if(option === 0) { + onAddMember() + } else { + selectedUserRef.current = null + } + } }); - }, [onAddMember, onSearchUser, setSelectedUser, setDialogData]); + }, [onAddMember, onSearchUser, selectedUserRef, setDialogData]); useEffect(() => { onFetchGroup(); diff --git a/react/admin-panel/src/views/profile/profile.js b/react/admin-panel/src/views/profile/profile.js index 1910c4d..70fc5f8 100644 --- a/react/admin-panel/src/views/profile/profile.js +++ b/react/admin-panel/src/views/profile/profile.js @@ -7,7 +7,7 @@ import { CircularProgress, FormControl, FormGroup, - FormLabel, Paper, styled, + FormLabel, styled, TextField } from "@mui/material"; import { @@ -26,6 +26,7 @@ import ButtonBar from "../../elements/button-bar"; import MfaTotp from "./mfa-totp"; import MfaFido from "./mfa-fido"; import Dialog from "shared/elements/dialog"; +import PasswordStrength from "shared/elements/password-strength"; const GpgKeyField = styled(TextField)((props) => ({ "& > div": { @@ -211,8 +212,6 @@ export default function ProfileView(props) { reader.readAsText(file); }, [showDialog]); - console.log("SELECTED USER:", profile.twoFactorToken); - return <>
@@ -285,6 +284,9 @@ export default function ProfileView(props) { onChange={e => setChangePassword({...changePassword, confirm: e.target.value })} /> + + + ({ + textAlign: "center", + borderRadius: 5, + borderStyle: "solid", + borderWidth: 1, + borderColor: props.theme.palette.action, + padding: props.theme.spacing(0.5), + position: "relative", + "& > div": { + zIndex: 0, + position: "absolute", + top: 0, + left: 0, + height: "100%", + }, + "& > span": { + zIndex: 1, + position: "relative", + } +})); + +export default function PasswordStrength(props) { + + const {password, ...other} = props; + const {translate: L} = useContext(LocaleContext); + + const ref = 14; + let strength = password.length >= ref ? 100 : Math.round(password.length / ref * 100.0); + let label = "account.password_very_weak"; + let bgColor = "red"; + + if (strength >= 85) { + label = "account.password_very_strong"; + bgColor = "darkgreen"; + } else if (strength >= 65) { + label = "account.password_strong"; + bgColor = "green"; + } else if (strength >= 50) { + label = "account.password_ok"; + bgColor = "yellow"; + } else if (strength >= 25) { + label = "account.password_weak"; + bgColor = "orange"; + } + + return + + {L(label)} + +} \ No newline at end of file diff --git a/react/shared/views/login.jsx b/react/shared/views/login.jsx index 015c39c..a3b5b10 100644 --- a/react/shared/views/login.jsx +++ b/react/shared/views/login.jsx @@ -129,6 +129,7 @@ export default function LoginForm(props) { return; } + console.log("navigator.credentials.get") set2FAToken({ ...tfaToken, step: 1, error: "" }); navigator.credentials.get({ publicKey: {