fix: allow users with create permissions to scan for devices (#1611)

* fix: allow users with create permissions to scan for devices

* fix: show scan tab in frontend
This commit is contained in:
Joshua Higgins
2026-02-12 18:00:54 -05:00
committed by GitHub
parent 8ae36d61cc
commit 5440ab3b25
4 changed files with 60 additions and 28 deletions

View File

@@ -7,6 +7,32 @@ import (
"github.com/pocketbase/pocketbase/tools/hook" "github.com/pocketbase/pocketbase/tools/hook"
) )
func RequireScanDevicesPermission() *hook.Handler[*core.RequestEvent] {
return &hook.Handler[*core.RequestEvent]{
Func: func(e *core.RequestEvent) error {
if e.HasSuperuserAuth() {
return e.Next()
}
user := e.Auth
if user == nil {
return apis.NewUnauthorizedError("The request requires superuser or record authorization token to be set.", nil)
}
res, err := e.App.FindFirstRecordByFilter(
"permissions",
"user.id = {:userId} && create = true",
dbx.Params{"userId": user.Id},
)
if res == nil || err != nil {
return apis.NewForbiddenError("You are not allowed to perform this request.", nil)
}
return e.Next()
},
}
}
func RequireUpSnapPermission() *hook.Handler[*core.RequestEvent] { func RequireUpSnapPermission() *hook.Handler[*core.RequestEvent] {
return &hook.Handler[*core.RequestEvent]{ return &hook.Handler[*core.RequestEvent]{
Func: func(e *core.RequestEvent) error { Func: func(e *core.RequestEvent) error {

View File

@@ -75,7 +75,7 @@ func StartPocketBase(distDirFS fs.FS) {
se.Router.GET("/api/upsnap/sleep/{id}", HandlerSleep).Bind(RequireUpSnapPermission()) se.Router.GET("/api/upsnap/sleep/{id}", HandlerSleep).Bind(RequireUpSnapPermission())
se.Router.GET("/api/upsnap/reboot/{id}", HandlerReboot).Bind(RequireUpSnapPermission()) se.Router.GET("/api/upsnap/reboot/{id}", HandlerReboot).Bind(RequireUpSnapPermission())
se.Router.GET("/api/upsnap/shutdown/{id}", HandlerShutdown).Bind(RequireUpSnapPermission()) se.Router.GET("/api/upsnap/shutdown/{id}", HandlerShutdown).Bind(RequireUpSnapPermission())
se.Router.GET("/api/upsnap/scan", HandlerScan).Bind(apis.RequireSuperuserAuth()) se.Router.GET("/api/upsnap/scan", HandlerScan).Bind(RequireScanDevicesPermission())
se.Router.POST("/api/upsnap/init-superuser", HandlerInitSuperuser) // https://github.com/pocketbase/pocketbase/discussions/6198 se.Router.POST("/api/upsnap/init-superuser", HandlerInitSuperuser) // https://github.com/pocketbase/pocketbase/discussions/6198
se.Router.POST("/api/upsnap/validate-cron", HandlerValidateCron) se.Router.POST("/api/upsnap/validate-cron", HandlerValidateCron)
se.Router.GET("/api/upsnap/manifest.webmanifest", HandlerWebsiteManifest) se.Router.GET("/api/upsnap/manifest.webmanifest", HandlerWebsiteManifest)

View File

@@ -24,6 +24,8 @@
let replaceNetmaskCheckbox = false; let replaceNetmaskCheckbox = false;
let replaceNetmask = ''; let replaceNetmask = '';
let loading = true;
onMount(() => { onMount(() => {
if (!$settingsPriv) { if (!$settingsPriv) {
$pocketbase $pocketbase
@@ -35,11 +37,12 @@
scanRange = settings.scan_range; scanRange = settings.scan_range;
}) })
.catch((err) => { .catch((err) => {
toast.error(err.message); //toast.error(err.message);
}); });
} else { } else {
scanRange = $settingsPriv.scan_range; scanRange = $settingsPriv.scan_range;
} }
loading = false;
}); });
function saveSettings() { function saveSettings() {
@@ -118,7 +121,7 @@
} }
</script> </script>
{#if $settingsPriv} {#if !loading}
<div class="card bg-base-200 mt-6 w-full shadow-sm"> <div class="card bg-base-200 mt-6 w-full shadow-sm">
<div class="card-body"> <div class="card-body">
<h2 class="card-title">{m['device_tabs.1']()}</h2> <h2 class="card-title">{m['device_tabs.1']()}</h2>
@@ -126,36 +129,39 @@
{m.device_network_scan_desc()} {m.device_network_scan_desc()}
</p> </p>
<div class="flex flex-row flex-wrap items-end gap-4"> <div class="flex flex-row flex-wrap items-end gap-4">
<form {#if $settingsPriv}
onsubmit={(e) => { <form
e.preventDefault(); onsubmit={(e) => {
saveSettings(); e.preventDefault();
}} saveSettings();
> }}
<fieldset class="fieldset p-0"> >
<label class="floating-label mt-2"> <fieldset class="fieldset p-0">
<span>{m.device_network_scan_ip_range()}</span> <label class="floating-label mt-2">
<div class="join max-w-xs"> <span>{m.device_network_scan_ip_range()}</span>
<input <div class="join max-w-xs">
id="scan-range" <input
class="input join-item w-full" id="scan-range"
type="text" class="input join-item w-full"
placeholder="192.168.1.0/24" type="text"
bind:value={scanRange} placeholder="192.168.1.0/24"
/> bind:value={scanRange}
<button class="btn btn-neutral join-item" type="submit">{m.buttons_save()}</button> />
</div> <button class="btn btn-neutral join-item" type="submit">{m.buttons_save()}</button
</label> >
</fieldset> </div>
</form> </label>
</fieldset>
</form>
{/if}
<div> <div>
<div> <div>
{#if !$settingsPriv.scan_range} {#if $settingsPriv && !$settingsPriv.scan_range}
<button class="btn btn-error" disabled> <button class="btn btn-error" disabled>
<Fa icon={faX} /> <Fa icon={faX} />
{m.device_network_scan_no_range()} {m.device_network_scan_no_range()}
</button> </button>
{:else if scanRange !== $settingsPriv.scan_range} {:else if $settingsPriv && scanRange !== $settingsPriv.scan_range}
<button class="btn btn-error" disabled> <button class="btn btn-error" disabled>
<Fa icon={faX} /> <Fa icon={faX} />
{m.device_network_scan_unsaved_changes()} {m.device_network_scan_unsaved_changes()}

View File

@@ -68,7 +68,7 @@
name: 'scan', name: 'scan',
ll_name: m['device_tabs.1'](), ll_name: m['device_tabs.1'](),
icon: faBinoculars, icon: faBinoculars,
show: $pocketbase.authStore.isSuperuser show: true
} }
]; ];
</script> </script>