OPCUA Status und Name Lesen

This commit is contained in:
ISA
2025-02-10 11:27:41 +01:00
parent 4dd8e7d3b0
commit cb6e6d3926
7 changed files with 88 additions and 51 deletions

View File

@@ -1,3 +1,4 @@
NEXT_PUBLIC_NODE_ENV=development NEXT_PUBLIC_NODE_ENV=development
NEXT_PUBLIC_ENCRYPTION_KEY=your-secure-encryption-key NEXT_PUBLIC_ENCRYPTION_KEY=1
NEXT_PUBLIC_ENCRYPTION_IV=1

View File

@@ -1,2 +1,3 @@
NEXT_PUBLIC_NODE_ENV=production NEXT_PUBLIC_NODE_ENV=production
NEXT_PUBLIC_ENCRYPTION_KEY=your-secure-encryption-key NEXT_PUBLIC_ENCRYPTION_KEY=1
NEXT_PUBLIC_ENCRYPTION_IV=1

View File

@@ -1,18 +1,17 @@
"use client"; //components/modales/settingsModal/SettingsModal.jsx "use client"; // components/modales/settingsModal/SettingsModal.jsx
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import ReactModal from "react-modal"; import ReactModal from "react-modal";
import { ClipLoader } from "react-spinners";
import "bootstrap-icons/font/bootstrap-icons.css"; import "bootstrap-icons/font/bootstrap-icons.css";
import { useSelector, useDispatch } from "react-redux"; import { useSelector } from "react-redux";
import handleClearDatabase from "./handlers/handleClearDatabase"; import handleClearDatabase from "./handlers/handleClearDatabase";
import handleReboot from "./handlers/handleReboot"; import handleReboot from "./handlers/handleReboot";
import handleSetDateTime from "./handlers/handleSetDateTime"; import handleSetDateTime from "./handlers/handleSetDateTime";
import handleSubmit from "./handlers/handleSubmit"; import handleSubmit from "./handlers/handleSubmit";
import { useRouter } from "next/router";
import bcrypt from "bcryptjs"; import bcrypt from "bcryptjs";
import CryptoJS from "crypto-js";
ReactModal.setAppElement("#__next"); ReactModal.setAppElement("#__next");
const USERS = { const USERS = {
Admin: { Admin: {
username: "admin", username: "admin",
@@ -21,7 +20,22 @@ const USERS = {
role: "Admin", role: "Admin",
}, },
}; };
// Function to generate JWT token
// Funktion zur Generierung eines AES-Schlüssels und IVs
function generateKeyAndIV() {
const encryptionKey = process.env.NEXT_PUBLIC_ENCRYPTION_KEY;
const encryptionIV = process.env.NEXT_PUBLIC_ENCRYPTION_IV;
if (!encryptionKey || !encryptionIV) {
throw new Error("Encryption key or IV is not defined.");
}
const key = CryptoJS.enc.Utf8.parse(encryptionKey);
const iv = CryptoJS.enc.Utf8.parse(encryptionIV);
return { key, iv };
}
// Funktion zur Generierung eines Tokens
function generateToken(user) { function generateToken(user) {
const payload = { const payload = {
username: user.username, username: user.username,
@@ -29,40 +43,34 @@ function generateToken(user) {
exp: Date.now() + 5 * 60 * 1000, // Ablaufzeit: 5 Minuten exp: Date.now() + 5 * 60 * 1000, // Ablaufzeit: 5 Minuten
}; };
const token = JSON.stringify(payload); const token = JSON.stringify(payload);
const encryptedToken = CryptoJS.AES.encrypt( const { key, iv } = generateKeyAndIV();
token, const encryptedToken = CryptoJS.AES.encrypt(token, key, { iv }).toString();
process.env.NEXT_PUBLIC_ENCRYPTION_KEY
).toString();
return encryptedToken; return encryptedToken;
} }
// Funktion zur Entschlüsselung des Tokens
function decryptToken(encryptedToken) { function decryptToken(encryptedToken) {
const bytes = CryptoJS.AES.decrypt( const { key, iv } = generateKeyAndIV();
encryptedToken, const bytes = CryptoJS.AES.decrypt(encryptedToken, key, { iv });
process.env.NEXT_PUBLIC_ENCRYPTION_KEY
);
const decryptedToken = bytes.toString(CryptoJS.enc.Utf8); const decryptedToken = bytes.toString(CryptoJS.enc.Utf8);
return JSON.parse(decryptedToken); return JSON.parse(decryptedToken);
} }
function SettingModal({ showModal, onClose }) { function SettingModal({ showModal, onClose }) {
const [isAdminLoggedIn, setAdminLoggedIn] = useState(false); const [isAdminLoggedIn, setAdminLoggedIn] = useState(false);
//const isAdminLoggedIn = sessionStorage.getItem("token");
const [username, setUsername] = useState(""); const [username, setUsername] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [error, setError] = useState(""); const [error, setError] = useState("");
const [showLoginForm, setShowLoginForm] = useState(false); // Zustand für Login-Formular const [showLoginForm, setShowLoginForm] = useState(false);
const router = useRouter();
function handleAdminLogin(e) { function handleAdminLogin(e) {
e.preventDefault(); e.preventDefault();
const user = USERS.Admin; // Finde den Admin-Benutzer const user = USERS.Admin;
bcrypt.compare(password, user.password, (err, isMatch) => { bcrypt.compare(password, user.password, (err, isMatch) => {
if (isMatch) { if (isMatch) {
const token = generateToken(user); const token = generateToken(user);
sessionStorage.setItem("token", token); // Speichere Token in SessionStorage sessionStorage.setItem("token", token);
localStorage.setItem("isAdminLoggedIn", "true"); localStorage.setItem("isAdminLoggedIn", "true");
setShowLoginForm(false); setShowLoginForm(false);
onClose(); onClose();
} else { } else {
@@ -72,6 +80,25 @@ function SettingModal({ showModal, onClose }) {
} }
}); });
} }
useEffect(() => {
if (showModal) {
const token = sessionStorage.getItem("token");
if (token) {
try {
const { exp } = decryptToken(token);
if (Date.now() < exp) {
setAdminLoggedIn(true);
} else {
sessionStorage.removeItem("token");
localStorage.setItem("isAdminLoggedIn", "false");
}
} catch (error) {
console.error("Token-Entschlüsselung fehlgeschlagen:", error);
}
}
}
}, [showModal]);
const deviceName_Redux = useSelector((state) => state.variables.deviceName); const deviceName_Redux = useSelector((state) => state.variables.deviceName);
const mac1_Redux = useSelector((state) => state.variables.mac1); const mac1_Redux = useSelector((state) => state.variables.mac1);
const ip_Redux = useSelector((state) => state.variables.ip); const ip_Redux = useSelector((state) => state.variables.ip);
@@ -154,16 +181,30 @@ function SettingModal({ showModal, onClose }) {
ntpTimezone_Redux, ntpTimezone_Redux,
active_Redux, active_Redux,
]); ]);
useEffect(() => { useEffect(() => {
// Check if a valid token exists in localStorage // Überprüfen, ob ein Token im SessionStorage vorhanden ist
const token = sessionStorage.getItem("token"); const token = sessionStorage.getItem("token");
if (token) { if (token) {
setAdminLoggedIn(true); try {
const { exp } = JSON.parse(atob(token)); // Token mit CryptoJS entschlüsseln
if (Date.now() < exp) { const bytes = CryptoJS.AES.decrypt(
setAdminLoggedIn(true); token,
} else { process.env.NEXT_PUBLIC_ENCRYPTION_KEY
// localStorage.removeItem("token"); // Remove expired token );
const decryptedToken = JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
// Ablaufzeit überprüfen
if (Date.now() < decryptedToken.exp) {
setAdminLoggedIn(true);
} else {
// Token ist abgelaufen
sessionStorage.removeItem("token");
setAdminLoggedIn(false);
}
} catch (error) {
console.error("Fehler beim Entschlüsseln des Tokens:", error);
setAdminLoggedIn(false);
} }
} }
}, []); }, []);

7
package-lock.json generated
View File

@@ -36,6 +36,7 @@
"@testing-library/jest-dom": "^6.6.3", "@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0", "@testing-library/react": "^16.2.0",
"@types/bcryptjs": "^2.4.6", "@types/bcryptjs": "^2.4.6",
"@types/crypto-js": "^4.2.2",
"@types/cypress": "^1.1.6", "@types/cypress": "^1.1.6",
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^22.10.10", "@types/node": "^22.10.10",
@@ -1602,6 +1603,12 @@
"integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==", "integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==",
"dev": true "dev": true
}, },
"node_modules/@types/crypto-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz",
"integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==",
"dev": true
},
"node_modules/@types/cypress": { "node_modules/@types/cypress": {
"version": "1.1.6", "version": "1.1.6",
"resolved": "https://registry.npmjs.org/@types/cypress/-/cypress-1.1.6.tgz", "resolved": "https://registry.npmjs.org/@types/cypress/-/cypress-1.1.6.tgz",

View File

@@ -40,6 +40,7 @@
"@testing-library/jest-dom": "^6.6.3", "@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0", "@testing-library/react": "^16.2.0",
"@types/bcryptjs": "^2.4.6", "@types/bcryptjs": "^2.4.6",
"@types/crypto-js": "^4.2.2",
"@types/cypress": "^1.1.6", "@types/cypress": "^1.1.6",
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^22.10.10", "@types/node": "^22.10.10",

View File

@@ -272,34 +272,17 @@ function Dashboard() {
<p className="text-sm font-medium text-gray-700">{gateway}</p> <p className="text-sm font-medium text-gray-700">{gateway}</p>
</div> </div>
</div> </div>
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<img src="/images/IP-icon.svg" alt="OPC UA Status" className="w-6 " /> <div className="text-xs font-bold text-blue-600">OPC-UA</div>
<div> <div>
<p className="text-xs text-gray-500">OPCUA Status</p> <p className="text-xs text-gray-500">Status</p>
<p className="text-sm font-medium text-gray-700">{opcUaZustand}</p> <p className="text-sm font-medium text-gray-700">{opcUaZustand}</p>
</div> </div>
</div> </div>
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<img
src="/images/client-icon.svg"
alt="OPC UA Clients"
className="w-6 "
/>
<div>
<p className="text-xs text-gray-500">Verbundene Clients</p>
<p className="text-sm font-medium text-gray-700">
{opcUaActiveClientCount}
</p>
</div>
</div>
<div className="flex items-center space-x-4">
<img
src="/images/nodeset-icon.svg"
alt="Nodeset Name"
className="w-6 "
/>
<div> <div>
<p className="text-xs text-gray-500">Nodeset Name</p> <p className="text-xs text-gray-500">Nodeset Name</p>
<p className="text-sm font-medium text-gray-700"> <p className="text-sm font-medium text-gray-700">

View File

@@ -54,6 +54,9 @@ export async function loadWindowVariables(): Promise<WindowVariables> {
"win_analogeEingaenge6", "win_analogeEingaenge6",
"win_analogeEingaenge7", "win_analogeEingaenge7",
"win_analogeEingaenge8", "win_analogeEingaenge8",
"win_opcUaZustand",
"win_opcUaActiveClientCount",
"win_opcUaNodesetName",
]; ];
const loadScript = (src: string): Promise<void> => { const loadScript = (src: string): Promise<void> => {