1import nodes from '../models/Node.js';
2import { writePasswordHeaders } from '../util/passwordHeader.js';
3
4const STATUS_TIMEOUT = 8000;
5
6export const listAll = async () => await nodes.findAll()
7 .then((result) => result.map((node) => ({...node, password: node.password !== null})));
8
9export const create = async (name, url, password) => await nodes.create({name: name, url: url, password: password});
10
11export const deleteNode = async (nodeId) => await nodes.destroy({where: {id: nodeId}});
12
13export const getOne = async (nodeId) => await nodes.findOne({where: {id: nodeId}});
14
15export const updateName = async (nodeId, name) => await nodes.update({name: name}, {where: {id: nodeId}});
16
17export const updatePassword = async (nodeId, password) => await nodes.update({password: password}, {where: {id: nodeId}});
18
19export const checkStatus = async (url, password) => {
20 try {
21 const res = await fetch(url + "/api/config", {
22 headers: writePasswordHeaders(password),
23 signal: AbortSignal.timeout(STATUS_TIMEOUT)
24 });
25
26 if (res.status === 401) return "PASSWORD_REQUIRED";
27 if (!res.ok) return "INVALID_URL";
28
29 const data = await res.json();
30 if (!data.ping) return "INVALID_URL";
31 if (data.viewMode) return "PASSWORD_REQUIRED";
32 return "NODE_VALID";
33 } catch {
34 return "INVALID_URL";
35 }
36}
37
38const SKIP_HEADERS = new Set(["host", "content-length", "connection"]);
39const serverError = (res) => res.status(500).json({message: "Internal server error"});
40
41export const proxyRequest = async (url, req, res) => {
42 const headers = Object.fromEntries(
43 Object.entries(req.headers).filter(([k]) => !SKIP_HEADERS.has(k.toLowerCase()))
44 );
45
46 try {
47 const response = await fetch(url, {
48 method: req.method,
49 headers,
50 body: req.method === "GET" ? undefined : JSON.stringify(req.body),
51 signal: req.signal
52 });
53
54 if (response.status >= 500) return serverError(res);
55
56 const disposition = response.headers.get("content-disposition");
57 if (disposition) res.setHeader("content-disposition", disposition);
58
59 res.status(response.status).json(await response.json().catch(() => null));
60 } catch {
61 serverError(res);
62 }
63}
64