Compare commits

..

3 Commits

Author SHA1 Message Date
henrygd
e9fb9b856f install script: remove newlines from KEY (#1139) 2025-09-04 11:26:53 -04:00
Sven van Ginkel
66bca11d36 [Bug] Update install script to use crontab on Alpine (#1136)
* add cron

* update the install script
2025-09-03 23:10:38 -04:00
henrygd
86e87f0d47 refactor hub dev server
- moved html replacement functionality from vite to go
2025-09-01 22:16:57 -04:00
9 changed files with 26 additions and 125 deletions

View File

@@ -19,7 +19,6 @@ import (
"time"
"github.com/google/uuid"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
@@ -300,30 +299,3 @@ func (h *Hub) MakeLink(parts ...string) string {
}
return base
}
type SystemInfo struct {
Name string `json:"name"`
Id string `json:"id"`
Status string `json:"status"`
Port uint16 `json:"port"`
Host string `json:"host"`
Info string `json:"info"`
}
func (h *Hub) getUserSystemsFromRequest(req *http.Request) ([]SystemInfo, error) {
systems := []SystemInfo{}
token, err := req.Cookie("beszauth")
if err != nil {
return systems, err
}
if token.Value != "" {
user, err := h.FindAuthRecordByToken(token.Value)
if err != nil {
return systems, err
}
h.DB().NewQuery("SELECT s.id, s.info, s.status, s.name, s.port, s.host FROM systems s JOIN json_each(s.users) AS je WHERE je.value = {:user_id}").Bind(dbx.Params{
"user_id": user.Id,
}).All(&systems)
}
return systems, err
}

View File

@@ -4,7 +4,6 @@ package hub
import (
"beszel"
"encoding/json"
"fmt"
"io"
"log/slog"
@@ -16,36 +15,29 @@ import (
"github.com/pocketbase/pocketbase/core"
)
// responseModifier wraps an http.RoundTripper to modify HTML responses
// Wraps http.RoundTripper to modify dev proxy HTML responses
type responseModifier struct {
transport http.RoundTripper
hub *Hub
}
// RoundTrip implements http.RoundTripper interface with response modification
func (rm *responseModifier) RoundTrip(req *http.Request) (*http.Response, error) {
resp, err := rm.transport.RoundTrip(req)
if err != nil {
return resp, err
}
// Only modify HTML responses
contentType := resp.Header.Get("Content-Type")
if !strings.Contains(contentType, "text/html") {
return resp, nil
}
// Read the response body
body, err := io.ReadAll(resp.Body)
if err != nil {
return resp, err
}
resp.Body.Close()
// Modify the HTML content here
modifiedBody := rm.modifyHTML(string(body), req)
// Create a new response with the modified body
modifiedBody := rm.modifyHTML(string(body))
resp.Body = io.NopCloser(strings.NewReader(modifiedBody))
resp.ContentLength = int64(len(modifiedBody))
resp.Header.Set("Content-Length", fmt.Sprintf("%d", len(modifiedBody)))
@@ -53,8 +45,7 @@ func (rm *responseModifier) RoundTrip(req *http.Request) (*http.Response, error)
return resp, nil
}
// modifyHTML applies modifications to HTML content
func (rm *responseModifier) modifyHTML(html string, req *http.Request) string {
func (rm *responseModifier) modifyHTML(html string) string {
parsedURL, err := url.Parse(rm.hub.appURL)
if err != nil {
return html
@@ -63,19 +54,7 @@ func (rm *responseModifier) modifyHTML(html string, req *http.Request) string {
basePath := strings.TrimSuffix(parsedURL.Path, "/") + "/"
html = strings.ReplaceAll(html, "./", basePath)
html = strings.Replace(html, "{{V}}", beszel.Version, 1)
slog.Info("modifying HTML", "appURL", rm.hub.appURL)
html = strings.Replace(html, "{{HUB_URL}}", rm.hub.appURL, 1)
systems, err := rm.hub.getUserSystemsFromRequest(req)
if err != nil {
return html
}
systemsJson, err := json.Marshal(systems)
if err != nil {
return html
}
html = strings.Replace(html, "'{SYSTEMS}'", string(systemsJson), 1)
return html
}
@@ -87,7 +66,6 @@ func (h *Hub) startServer(se *core.ServeEvent) error {
Host: "localhost:5173",
})
// Set up custom transport with response modification
proxy.Transport = &responseModifier{
transport: http.DefaultTransport,
hub: h,

View File

@@ -5,9 +5,7 @@ package hub
import (
"beszel"
"beszel/site"
"encoding/json"
"io/fs"
"log/slog"
"net/http"
"net/url"
"strings"
@@ -47,15 +45,6 @@ func (h *Hub) startServer(se *core.ServeEvent) error {
e.Response.Header().Del("X-Frame-Options")
e.Response.Header().Set("Content-Security-Policy", csp)
}
systems, err := h.getUserSystemsFromRequest(e.Request)
if err != nil {
slog.Error("error getting user systems", "error", err)
}
systemsJson, err := json.Marshal(systems)
if err != nil {
slog.Error("error marshalling user systems", "error", err)
}
html = strings.Replace(html, "'{SYSTEMS}'", string(systemsJson), 1)
return e.HTML(http.StatusOK, html)
})
return nil

View File

@@ -10,8 +10,7 @@
globalThis.BESZEL = {
BASE_PATH: "%BASE_URL%",
HUB_VERSION: "{{V}}",
HUB_URL: "{{HUB_URL}}",
SYSTEMS: '{SYSTEMS}'
HUB_URL: "{{HUB_URL}}"
}
</script>
</head>

View File

@@ -12,13 +12,6 @@ export const pb = new PocketBase(basePath)
export const isAdmin = () => pb.authStore.record?.role === "admin"
export const isReadOnlyUser = () => pb.authStore.record?.role === "readonly"
export const updateCookieToken = () => {
console.log("setting token", pb.authStore.token)
document.cookie = `beszauth=${pb.authStore.token}; path=/; expires=${new Date(
Date.now() + 7 * 24 * 60 * 60 * 1000
).toString()}`
}
export const verifyAuth = () => {
pb.collection("users")
.authRefresh()

View File

@@ -141,13 +141,7 @@ export async function subscribe() {
}
/** Refresh all systems with latest data from the hub */
export async function refresh(records: SystemRecord[] = []) {
if (records.length) {
for (const record of records) {
add(record)
}
return
}
export async function refresh() {
try {
const records = await fetchSystems()
if (!records.length) {

View File

@@ -5,7 +5,7 @@ import ReactDOM from "react-dom/client"
import { ThemeProvider } from "./components/theme-provider.tsx"
import { DirectionProvider } from "@radix-ui/react-direction"
import { $authenticated, $publicKey, $copyContent, $direction } from "./lib/stores.ts"
import { pb, updateUserSettings, updateCookieToken } from "./lib/api.ts"
import { pb, updateUserSettings } from "./lib/api.ts"
import * as systemsManager from "./lib/systemsManager.ts"
import { useStore } from "@nanostores/react"
import { Toaster } from "./components/ui/toaster.tsx"
@@ -27,10 +27,8 @@ const App = memo(() => {
useEffect(() => {
// change auth store on auth change
updateCookieToken()
pb.authStore.onChange(() => {
$authenticated.set(pb.authStore.isValid)
updateCookieToken()
})
// get version / public key
pb.send("/api/beszel/getkey", {}).then((data) => {
@@ -38,17 +36,11 @@ const App = memo(() => {
})
// get user settings
updateUserSettings()
const startingSystems = globalThis.BESZEL.SYSTEMS
for (const system of startingSystems) {
// if (typeof system.info === "string") {
system.info = JSON.parse(system.info as unknown as string)
// }
}
// need to get system list before alerts
systemsManager.init()
systemsManager
// get current systems list
.refresh(startingSystems)
.refresh()
// subscribe to new system updates
.then(systemsManager.subscribe)
// get current alerts
@@ -59,7 +51,6 @@ const App = memo(() => {
// updateFavicon("favicon.svg")
alertManager.unsubscribe()
systemsManager.unsubscribe()
globalThis.BESZEL.SYSTEMS = []
}
}, [])

View File

@@ -7,8 +7,6 @@ declare global {
BASE_PATH: string
HUB_VERSION: string
HUB_URL: string
/** initial list of systems */
SYSTEMS: SystemRecord[]
}
}

View File

@@ -216,11 +216,11 @@ if [ "$UNINSTALL" = true ]; then
echo "Removing the OpenRC service files..."
rm -f /etc/init.d/beszel-agent
# Remove the update service if it exists
echo "Removing the daily update service..."
rc-service beszel-agent-update stop 2>/dev/null
rc-update del beszel-agent-update default 2>/dev/null
rm -f /etc/init.d/beszel-agent-update
# Remove the daily update cron job if it exists
echo "Removing the daily update cron job..."
if crontab -u root -l 2>/dev/null | grep -q "beszel-agent.*update"; then
crontab -u root -l 2>/dev/null | grep -v "beszel-agent.*update" | crontab -u root -
fi
# Remove log files
echo "Removing log files..."
@@ -321,6 +321,9 @@ if [ -z "$KEY" ]; then
read KEY
fi
# Remove newlines from KEY
KEY=$(echo "$KEY" | tr -d '\n')
# TOKEN and HUB_URL are optional for backwards compatibility - no interactive prompts
# They will be set as empty environment variables if not provided
@@ -523,35 +526,19 @@ EOF
elif [ "$AUTO_UPDATE_FLAG" = "false" ]; then
AUTO_UPDATE="n"
else
printf "\nWould you like to enable automatic daily updates for beszel-agent? (y/n): "
printf "\nEnable automatic daily updates for beszel-agent? (y/n): "
read AUTO_UPDATE
fi
case "$AUTO_UPDATE" in
[Yy]*)
echo "Setting up daily automatic updates for beszel-agent..."
cat >/etc/init.d/beszel-agent-update <<EOF
#!/sbin/openrc-run
# Create cron job to run beszel-agent update command daily at midnight
if ! crontab -u root -l 2>/dev/null | grep -q "beszel-agent.*update"; then
(crontab -u root -l 2>/dev/null; echo "12 0 * * * /opt/beszel-agent/beszel-agent update >/dev/null 2>&1") | crontab -u root -
fi
name="beszel-agent-update"
description="Update beszel-agent if needed"
depend() {
need beszel-agent
}
start() {
ebegin "Checking for beszel-agent updates"
/opt/beszel-agent/beszel-agent update
eend $?
}
EOF
chmod +x /etc/init.d/beszel-agent-update
rc-update add beszel-agent-update default
rc-service beszel-agent-update start
printf "\nAutomatic daily updates have been enabled.\n"
printf "\nDaily updates have been enabled via cron job.\n"
;;
esac
@@ -612,7 +599,7 @@ EOF
AUTO_UPDATE="n"
sleep 1 # give time for the service to start
else
printf "\nWould you like to enable automatic daily updates for beszel-agent? (y/n): "
printf "\nEnable automatic daily updates for beszel-agent? (y/n): "
read AUTO_UPDATE
fi
case "$AUTO_UPDATE" in
@@ -620,12 +607,12 @@ EOF
echo "Setting up daily automatic updates for beszel-agent..."
cat >/etc/crontabs/beszel <<EOF
0 0 * * * /etc/init.d/beszel-agent update
12 0 * * * /etc/init.d/beszel-agent update
EOF
/etc/init.d/cron restart
printf "\nAutomatic daily updates have been enabled.\n"
printf "\nDaily updates have been enabled.\n"
;;
esac
@@ -695,7 +682,7 @@ EOF
AUTO_UPDATE="n"
sleep 1 # give time for the service to start
else
printf "\nWould you like to enable automatic daily updates for beszel-agent? (y/n): "
printf "\nEnable automatic daily updates for beszel-agent? (y/n): "
read AUTO_UPDATE
fi
case "$AUTO_UPDATE" in
@@ -730,7 +717,7 @@ EOF
systemctl daemon-reload
systemctl enable --now beszel-agent-update.timer
printf "\nAutomatic daily updates have been enabled.\n"
printf "\nDaily updates have been enabled.\n"
;;
esac