added sudo link

master
bjarne 4 weeks ago
parent 863560921e
commit c395a61625

@ -0,0 +1,119 @@
'use client';
import { useState } from 'react';
import Link from "next/link";
const GrantSudoLink = ({ text, isCard }) => {
const [isHovered, setIsHovered] = useState(false);
const [showDialog, setShowDialog] = useState(false);
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
// hover over eeffect
const handleMouseEnter = () => {
setIsHovered(true);
};
const handleMouseLeave = () => {
setIsHovered(false);
};
const cardStyle = {
boxShadow: isHovered ? '0 4px 20px rgba(0, 0, 0, 0.2)' : '0 1px 3px rgba(0, 0, 0, 0.1)',
transition: 'box-shadow 0.3s ease-in-out',
};
// username dialog box
const openDialog = () => {
setShowDialog(true);
};
const closeDialog = () => {
setShowDialog(false);
};
const handleGrantSudoRights = async () => {
try {
const response = await fetch('/api/grant-sudo', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
const data = await response.json();
if (response.ok) {
alert('Sudo rights granted successfully.');
} else {
alert(data.error);
}
closeDialog();
} catch (error) {
alert('Error granting sudo rights');
}
};
return (
<div>
{isCard ? (
<Link href="#" onClick={openDialog} className="text-decoration-none">
<div
className="card h-100"
style={cardStyle}
onClick={openDialog}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div className="card-body text-center">
<h5 className="card-title">{text}</h5>
<p className="card-text">You need to do this once</p>
</div>
</div>
</Link>
) : (
<a href="#" onClick={openDialog} className="text-decoration-none">
{text}
</a>
)}
{showDialog && (
<div className="modal show" style={{ display: 'block' }}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Grant Sudo Rights</h5>
<button type="button" className="btn-close" aria-label="Close" onClick={closeDialog}></button>
</div>
<div className="modal-body">
<div className="form-group">
<label htmlFor="username">Username</label>
<input
type="text"
className="form-control"
id="username"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
type="password"
className="form-control"
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={closeDialog}>
Cancel
</button>
<button type="button" className="btn btn-primary" onClick={handleGrantSudoRights}>
Grant Sudo Rights
</button>
</div>
</div>
</div>
</div>
)}
</div>
);
};
export default GrantSudoLink;

@ -2,6 +2,7 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useNotification } from '@/app/context/NotificationContext'; import { useNotification } from '@/app/context/NotificationContext';
import GrantSudoLink from '@/app/components/GrantSudoLink';
export default function ConfigurePage() { export default function ConfigurePage() {
const [config, setConfig] = useState(''); const [config, setConfig] = useState('');
@ -53,35 +54,6 @@ export default function ConfigurePage() {
} }
}; };
// automatically add webserver to sudo
const openDialog = () => {
setShowDialog(true);
};
const closeDialog = () => {
setShowDialog(false);
};
const handleGrantSudoRights = async () => {
try {
const response = await fetch('/api/grant-sudo', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
const data = await response.json();
if (response.ok) {
showNotification('Sudo rights granted successfully.', 'success');
} else {
showNotification(data.error, 'error');
}
closeDialog();
} catch (error) {
showNotification('Error granting sudo rights', 'error');
}
};
return ( return (
<div className="container mt-5"> <div className="container mt-5">
<h1 className="mb-4">Configure DHCP Options</h1> <h1 className="mb-4">Configure DHCP Options</h1>
@ -101,53 +73,11 @@ export default function ConfigurePage() {
<button className="btn btn-primary mt-3" onClick={handleSave}> <button className="btn btn-primary mt-3" onClick={handleSave}>
Save and Restart DHCP Server Save and Restart DHCP Server
</button> </button>
<button className="btn btn-warning mt-3 ml-2" onClick={openDialog}>
Grant Sudo Rights
</button>
{showDialog && ( <div className="mt-4">
<div className="modal show" style={{display: 'block'}}> <GrantSudoLink text="Grant Sudo Rights"/>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Grant Sudo Rights</h5>
<button type="button" className="btn-close" aria-label="Close"
onClick={closeDialog}></button>
</div>
<div className="modal-body">
<div className="form-group">
<label htmlFor="username">Username</label>
<input
type="text"
className="form-control"
id="username"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
type="password"
className="form-control"
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div> </div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={closeDialog}>
Cancel
</button>
<button type="button" className="btn btn-primary" onClick={handleGrantSudoRights}>
Grant Sudo Rights
</button>
</div>
</div>
</div>
</div>
)}
</div> </div>
); );
} }

@ -1,10 +1,15 @@
import Card from './components/Card'; import Card from '@/app/components/Card';
import GrantSudoLink from '@/app/components/GrantSudoLink';
export default function Home() { export default function Home() {
return ( return (
<div className="container mt-5"> <div className="container mt-5">
<div className="container"> <div className="container">
<div className="row"> <div className="row">
<div className="col-md-6 mb-4">
<GrantSudoLink text="Grant Sudo Rights" isCard/>
</div>
<Card <Card
title="Leases" title="Leases"
text="View current DHCP leases." text="View current DHCP leases."

@ -2,6 +2,7 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useNotification } from '@/app/context/NotificationContext'; import { useNotification } from '@/app/context/NotificationContext';
import GrantSudoLink from "@/app/components/GrantSudoLink";
export default function TFTPPage() { export default function TFTPPage() {
const [files, setFiles] = useState([]); const [files, setFiles] = useState([]);
@ -79,7 +80,6 @@ export default function TFTPPage() {
<h1 className="mb-4">TFTP Server Files</h1> <h1 className="mb-4">TFTP Server Files</h1>
<div className="mb-3"> <div className="mb-3">
<label htmlFor="fileUpload" className="form-label">Upload New File</label>
<input <input
type="file" type="file"
className="form-control" className="form-control"
@ -93,7 +93,11 @@ export default function TFTPPage() {
Refresh Refresh
</button> </button>
</div> </div>
<div className="mb-3">
<div>
If upload fails: <GrantSudoLink text="Grant Sudo Rights"/>
</div>
</div>
<table className="table table-striped"> <table className="table table-striped">
<thead> <thead>
<tr> <tr>

40
package-lock.json generated

@ -9,7 +9,6 @@
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"bootstrap": "^5.3.3", "bootstrap": "^5.3.3",
"formidable": "^3.5.1",
"fs": "^0.0.1-security", "fs": "^0.0.1-security",
"next": "14.2.7", "next": "14.2.7",
"react": "^18", "react": "^18",
@ -762,11 +761,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
},
"node_modules/ast-types-flow": { "node_modules/ast-types-flow": {
"version": "0.0.8", "version": "0.0.8",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
@ -1115,15 +1109,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/dezalgo": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
"integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
"dependencies": {
"asap": "^2.0.0",
"wrappy": "1"
}
},
"node_modules/dir-glob": { "node_modules/dir-glob": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@ -1925,19 +1910,6 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/formidable": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.1.tgz",
"integrity": "sha512-WJWKelbRHN41m5dumb0/k8TeAx7Id/y3a+Z7QfhxP/htI9Js5zYaEDtG8uMgG0vM0lOlqnmjE99/kfpOYi/0Og==",
"dependencies": {
"dezalgo": "^1.0.4",
"hexoid": "^1.0.0",
"once": "^1.4.0"
},
"funding": {
"url": "https://ko-fi.com/tunnckoCore/commissions"
}
},
"node_modules/fs": { "node_modules/fs": {
"version": "0.0.1-security", "version": "0.0.1-security",
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
@ -2246,14 +2218,6 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/hexoid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==",
"engines": {
"node": ">=8"
}
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@ -3146,6 +3110,7 @@
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"dependencies": { "dependencies": {
"wrappy": "1" "wrappy": "1"
} }
@ -4360,7 +4325,8 @@
"node_modules/wrappy": { "node_modules/wrappy": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
}, },
"node_modules/yocto-queue": { "node_modules/yocto-queue": {
"version": "0.1.0", "version": "0.1.0",

@ -10,7 +10,6 @@
}, },
"dependencies": { "dependencies": {
"bootstrap": "^5.3.3", "bootstrap": "^5.3.3",
"formidable": "^3.5.1",
"fs": "^0.0.1-security", "fs": "^0.0.1-security",
"next": "14.2.7", "next": "14.2.7",
"react": "^18", "react": "^18",

Loading…
Cancel
Save

Powered by TurnKey Linux.