Skip to content

Commit 9755b19

Browse files
committed
Update configuration files and add new config endpoints; remove CEF logging (to be replaced)
1 parent 9277637 commit 9755b19

File tree

16 files changed

+1021
-1349
lines changed

16 files changed

+1021
-1349
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ restful_api_collection
2626
.vscode/
2727
yarn-debug.log*
2828
yarn-error.log*
29+
docker-compose*.yml

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ npm install
9797
```bash
9898
BROWSER= # none or chrome or firefox or edge or safari
9999
GENERATE_SOURCEMAP= # true or false
100-
VITE_BASE_URL= # url of api (e.g. https://localhost)
100+
BASE_URL= # url of api (e.g. https://localhost)
101101
VITE_MAX_VM_COUNT= # max no. of virtual machines available at any given time
102102
```
103103

@@ -248,8 +248,8 @@ MAIL_PASSWORD= # your password
248248
MAIL_DEFAULT_SENDER= # your email
249249
MAIL_MAX_EMAILS= # max_emails (int)
250250
MAIL_ASCII_ATTACHMENTS= # True or False
251-
FRONT_END_ADDRESS= # localhost, 127.0.0.1, etc.
252-
BACK_END_ADDRESS= # localhost, 127.0.0.1, etc.
251+
CLIENT_URL= # localhost, 127.0.0.1, etc.
252+
API_URL= # localhost, 127.0.0.1, etc.
253253
SSL_CERTIFICATE_PATH= # path_to_ssl_certificate
254254
SSL_KEY_PATH= # path_to_ssl_key
255255
GUNICORN_BIND_ADDRESS= # bind address, i.e. 0.0.0.0:8000
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
/*
2+
* VirtualMachineView.tsx - Virtual machine view for the application using noVNC.
3+
* Copyright (C) 2024, Kieran Gordon
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as
7+
* published by the Free Software Foundation, either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
import { FC, ReactElement, useCallback, useEffect, useState } from "react";
20+
import { Button, ButtonGroup, Modal } from "react-bootstrap";
21+
import Draggable from "react-draggable";
22+
import { useNavigate } from "react-router-dom";
23+
import Cookies from "universal-cookie";
24+
import RFB from "@novnc/novnc/lib/rfb";
25+
26+
import {
27+
deleteVirtualMachine,
28+
getVirtualMachineByUser,
29+
} from "../api/VirtualMachineAPI";
30+
31+
interface VmDetails {
32+
wsport: number;
33+
id: number;
34+
name: string;
35+
version: string;
36+
desktop: string;
37+
password: string;
38+
homepage: string;
39+
desktop_homepage: string;
40+
}
41+
42+
const VirtualMachineViewScreen: FC = (): ReactElement => {
43+
const cookies = new Cookies(null, { path: "/" });
44+
const [vmDetails, setVmDetails] = useState<VmDetails>({
45+
wsport: 0,
46+
id: 0,
47+
name: "",
48+
version: "",
49+
desktop: "",
50+
password: "",
51+
homepage: "",
52+
desktop_homepage: "",
53+
});
54+
const [isModalOpen, setIsModalOpen] = useState(false);
55+
const API_URL = import.meta.env.VITE_API_URL.replace(
56+
/(^\w+:|^)\/\//,
57+
""
58+
);
59+
const navigate = useNavigate();
60+
61+
// Fetches the virtual machine details from the database
62+
useEffect(() => {
63+
const fetchVMDetails = async () => {
64+
const response = await getVirtualMachineByUser();
65+
const data = response.data;
66+
if (data) {
67+
setVmDetails({
68+
wsport: data.wsport,
69+
id: data.id,
70+
name: data.name,
71+
version: data.version,
72+
desktop: data.desktop,
73+
password: data.vnc_password,
74+
homepage: data.homepage,
75+
desktop_homepage: data.desktop_homepage,
76+
});
77+
}
78+
};
79+
fetchVMDetails();
80+
}, []);
81+
82+
// Sets the document title to the virtual machine name, version, and desktop, and handles keydown events
83+
useEffect(() => {
84+
document.title = `${vmDetails.name} ${vmDetails.version} ${vmDetails.desktop} - Buffet`;
85+
86+
window.addEventListener("keydown", handleKeyDown);
87+
});
88+
89+
// Check for the cookie and conditionally open the modal
90+
useEffect(() => {
91+
const modalCookie = cookies.get("modalShown");
92+
if (!modalCookie && vmDetails.wsport !== 0) {
93+
setIsModalOpen(true);
94+
cookies.set("modalShown", "true", { path: "/" });
95+
}
96+
}, [vmDetails.wsport]);
97+
98+
// Function to manually open the modal
99+
const handleOpenModal = () => {
100+
setIsModalOpen(true);
101+
};
102+
103+
// Deletes the virtual machine from the database and navigates to the home page
104+
const deleteVM = useCallback(() => {
105+
deleteVirtualMachine(String(vmDetails.id)).then(() => {
106+
navigate("/os");
107+
});
108+
}, [vmDetails.id, navigate]);
109+
110+
// Handles the keydown event. If the key is F11, it toggles fullscreen mode.
111+
const handleKeyDown = useCallback((event: KeyboardEvent) => {
112+
if (event.key === "F11") {
113+
event.preventDefault();
114+
handleFullscreen();
115+
}
116+
}, []);
117+
118+
// Toggles fullscreen mode. If the document is currently in fullscreen mode, it exits fullscreen mode. Otherwise, it enters fullscreen mode.
119+
const handleFullscreen = () => {
120+
const elem = document.getElementById("app");
121+
if (document.fullscreenElement) {
122+
document.exitFullscreen();
123+
} else {
124+
elem?.requestFullscreen();
125+
}
126+
};
127+
128+
// Connect to the virtual machine using noVNC when the wsport is set
129+
const connectToVM = useCallback(() => {
130+
const appElement = document.getElementById("app");
131+
if (appElement) {
132+
const protocol = import.meta.env.DEV || !import.meta.env.VITE_SSL_ENABLED ? "ws" : "wss";
133+
const rfb = new RFB(
134+
appElement,
135+
`${protocol}://${import.meta.env.DEV ? 'localhost:5700' : `${API_URL}/websockify/${vmDetails.wsport}/`}`,
136+
{
137+
credentials: {
138+
username: "",
139+
password: vmDetails.password,
140+
target: "",
141+
},
142+
}
143+
);
144+
145+
rfb.scaleViewport = true;
146+
rfb.resizeSession = true;
147+
rfb.focusOnClick = true;
148+
rfb.clipViewport = true;
149+
150+
// When the connection is established, focus on the virtual machine
151+
rfb.addEventListener("connect", () => {
152+
rfb.focus();
153+
});
154+
155+
rfb.addEventListener("disconnect", () => {
156+
navigate("/os");
157+
});
158+
}
159+
}, [API_URL, vmDetails.password, vmDetails.wsport]);
160+
161+
// Connect to the virtual machine when the wsport is set
162+
useEffect(() => {
163+
if (vmDetails.wsport !== 0) {
164+
const timeout = setTimeout(connectToVM, 250);
165+
return () => clearTimeout(timeout);
166+
}
167+
}, [connectToVM, vmDetails.wsport]);
168+
169+
return (
170+
<div id="virtual-machine-view">
171+
<div
172+
id="app"
173+
style={{
174+
height: "100vh",
175+
width: "100vw",
176+
overflow: "hidden",
177+
position: "absolute",
178+
top: 0,
179+
left: 0,
180+
}}
181+
/>
182+
183+
<Draggable bounds="#app">
184+
<ButtonGroup
185+
style={{
186+
position: "absolute",
187+
top: 0,
188+
left: 0,
189+
zIndex: 100,
190+
margin: "10px",
191+
}}
192+
>
193+
<Button
194+
variant="light"
195+
href={vmDetails.homepage}
196+
target="_blank"
197+
rel="noreferrer"
198+
>
199+
{vmDetails.name} {vmDetails.version}
200+
</Button>
201+
<Button
202+
variant="secondary"
203+
href={vmDetails.desktop_homepage}
204+
target="_blank"
205+
rel="noreferrer"
206+
>
207+
{vmDetails.desktop}
208+
</Button>
209+
<Button disabled variant="dark">
210+
:: Buffet ::
211+
</Button>
212+
</ButtonGroup>
213+
</Draggable>
214+
215+
<Draggable bounds="#app">
216+
<ButtonGroup
217+
style={{
218+
position: "absolute",
219+
top: 0,
220+
right: 0,
221+
zIndex: 100,
222+
margin: "10px",
223+
}}
224+
>
225+
<Button disabled variant="dark">
226+
:: Buffet ::
227+
</Button>
228+
<Button variant="primary" href="/os">
229+
Home
230+
</Button>
231+
<Button variant="info" onClick={() => handleOpenModal()}>
232+
Information
233+
</Button>
234+
<Button variant="warning" onClick={handleFullscreen}>
235+
Fullscreen
236+
</Button>
237+
<Button variant="danger" onClick={deleteVM}>
238+
Shutdown
239+
</Button>
240+
</ButtonGroup>
241+
</Draggable>
242+
243+
{/* Information modal */}
244+
<Modal show={isModalOpen} onHide={() => setIsModalOpen(false)} centered>
245+
<Modal.Header closeButton>
246+
<Modal.Title>For Your Information</Modal.Title>
247+
</Modal.Header>
248+
<Modal.Body>
249+
<p>
250+
Buffet is currently in development. Some features may not work as
251+
expected. If you find a bug, please report it on GitHub.
252+
</p>
253+
<p>
254+
Due to technical limitations, you need to click the viewer to
255+
interact with the virtual machine.
256+
</p>
257+
<p>
258+
<strong>Please note:</strong> All internet traffic is logged, and
259+
can be viewed by the system administrator. Any misuse of the system
260+
will result in your account being terminated.
261+
</p>
262+
</Modal.Body>
263+
<Modal.Footer>
264+
<ButtonGroup>
265+
<Button
266+
variant="secondary"
267+
href="https://github.com/kgdn/buffet/issues/new"
268+
target="_blank"
269+
rel="noreferrer"
270+
>
271+
Report Bug
272+
</Button>
273+
<Button variant="primary" onClick={() => setIsModalOpen(false)}>
274+
Close
275+
</Button>
276+
</ButtonGroup>
277+
</Modal.Footer>
278+
</Modal>
279+
</div>
280+
);
281+
};
282+
283+
export default VirtualMachineViewScreen;

server/.dockerignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
__pycache__
22
iso
3-
.venv
3+
.venv
4+
.env

0 commit comments

Comments
 (0)