Browse Source

sink import to write permissios

fix signer
imwald-v0.58.5
silberengel 4 months ago
parent
commit
90765506ee
  1. 30
      app/server.go
  2. 28
      app/web/src/App.svelte
  3. 5
      app/web/src/ImportView.svelte
  4. 2
      build-image-v0.58.5.sh

30
app/server.go

@ -14,12 +14,19 @@ import (
"sync" "sync"
"time" "time"
"git.mleku.dev/mleku/nostr/encoders/event"
"git.mleku.dev/mleku/nostr/encoders/filter"
"git.mleku.dev/mleku/nostr/encoders/hex"
"git.mleku.dev/mleku/nostr/encoders/tag"
"git.mleku.dev/mleku/nostr/httpauth"
"git.mleku.dev/mleku/nostr/protocol/auth"
"lol.mleku.dev/chk" "lol.mleku.dev/chk"
"next.orly.dev/app/branding" "next.orly.dev/app/branding"
"next.orly.dev/app/config" "next.orly.dev/app/config"
"next.orly.dev/pkg/acl" "next.orly.dev/pkg/acl"
acliface "next.orly.dev/pkg/interfaces/acl" "next.orly.dev/pkg/archive"
"next.orly.dev/pkg/blossom" "next.orly.dev/pkg/blossom"
"next.orly.dev/pkg/bunker"
"next.orly.dev/pkg/database" "next.orly.dev/pkg/database"
domainevents "next.orly.dev/pkg/domain/events" domainevents "next.orly.dev/pkg/domain/events"
"next.orly.dev/pkg/domain/events/subscribers" "next.orly.dev/pkg/domain/events/subscribers"
@ -29,25 +36,18 @@ import (
"next.orly.dev/pkg/event/routing" "next.orly.dev/pkg/event/routing"
"next.orly.dev/pkg/event/specialkinds" "next.orly.dev/pkg/event/specialkinds"
"next.orly.dev/pkg/event/validation" "next.orly.dev/pkg/event/validation"
"git.mleku.dev/mleku/nostr/encoders/event" acliface "next.orly.dev/pkg/interfaces/acl"
"git.mleku.dev/mleku/nostr/encoders/filter"
"git.mleku.dev/mleku/nostr/encoders/hex"
"git.mleku.dev/mleku/nostr/encoders/tag"
"next.orly.dev/pkg/policy" "next.orly.dev/pkg/policy"
"git.mleku.dev/mleku/nostr/protocol/auth"
"git.mleku.dev/mleku/nostr/httpauth"
"next.orly.dev/pkg/protocol/graph" "next.orly.dev/pkg/protocol/graph"
"next.orly.dev/pkg/protocol/nip43" "next.orly.dev/pkg/protocol/nip43"
"next.orly.dev/pkg/protocol/publish"
"next.orly.dev/pkg/bunker"
"next.orly.dev/pkg/protocol/nrc" "next.orly.dev/pkg/protocol/nrc"
"next.orly.dev/pkg/protocol/publish"
"next.orly.dev/pkg/ratelimit" "next.orly.dev/pkg/ratelimit"
"next.orly.dev/pkg/spider" "next.orly.dev/pkg/spider"
"next.orly.dev/pkg/storage" "next.orly.dev/pkg/storage"
dsync "next.orly.dev/pkg/sync" dsync "next.orly.dev/pkg/sync"
"next.orly.dev/pkg/wireguard"
"next.orly.dev/pkg/archive"
"next.orly.dev/pkg/tor" "next.orly.dev/pkg/tor"
"next.orly.dev/pkg/wireguard"
) )
type Server struct { type Server struct {
@ -1118,7 +1118,7 @@ func (s *Server) handleEventsMine(w http.ResponseWriter, r *http.Request) {
w.Write(jsonData) w.Write(jsonData)
} }
// handleImport receives a JSONL/NDJSON file or body and enqueues an async import using NIP-98 authentication. Admins only. // handleImport receives a JSONL/NDJSON file or body and enqueues an async import using NIP-98 authentication. Write, admin, or owner roles required.
func (s *Server) handleImport(w http.ResponseWriter, r *http.Request) { func (s *Server) handleImport(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost { if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
@ -1138,11 +1138,11 @@ func (s *Server) handleImport(w http.ResponseWriter, r *http.Request) {
return return
} }
// Check permissions - require admin or owner level // Check permissions - require write, admin, or owner level
accessLevel := acl.Registry.GetAccessLevel(pubkey, r.RemoteAddr) accessLevel := acl.Registry.GetAccessLevel(pubkey, r.RemoteAddr)
if accessLevel != "admin" && accessLevel != "owner" { if accessLevel != "write" && accessLevel != "admin" && accessLevel != "owner" {
http.Error( http.Error(
w, "Admin or owner permission required", http.StatusForbidden, w, "Write, admin, or owner permission required", http.StatusForbidden,
) )
return return
} }

28
app/web/src/App.svelte

@ -921,9 +921,9 @@
async function loadRelayData() { async function loadRelayData() {
// Fetch user role for already logged in users // Fetch user role for already logged in users
if (isLoggedIn) { if (isLoggedIn) {
fetchUserRole(); await fetchUserRole();
} }
fetchACLMode(); await fetchACLMode();
// Load sprocket configuration // Load sprocket configuration
loadSprocketConfig(); loadSprocketConfig();
@ -2410,11 +2410,26 @@
async function importEvents() { async function importEvents() {
// Skip login/permission check when ACL is "none" (open relay mode) // Skip login/permission check when ACL is "none" (open relay mode)
if (aclMode !== "none" && (!isLoggedIn || (userRole !== "admin" && userRole !== "owner"))) { if (aclMode !== "none") {
importMessage = "Admin or owner permission required"; // Ensure user is logged in
if (!isLoggedIn) {
importMessage = "Please log in first";
setTimeout(() => { importMessage = ""; }, 5000);
return;
}
// If role is not yet loaded, fetch it first
if (!userRole && isLoggedIn && userPubkey) {
await fetchUserRole();
}
// Check permissions
if (userRole !== "write" && userRole !== "admin" && userRole !== "owner") {
importMessage = "Write, admin, or owner permission required";
setTimeout(() => { importMessage = ""; }, 5000); setTimeout(() => { importMessage = ""; }, 5000);
return; return;
} }
}
if (!selectedFile) { if (!selectedFile) {
importMessage = "Please select a file"; importMessage = "Please select a file";
@ -2429,6 +2444,11 @@
// Build headers - only include auth when ACL is not "none" // Build headers - only include auth when ACL is not "none"
const headers = {}; const headers = {};
if (aclMode !== "none" && isLoggedIn) { if (aclMode !== "none" && isLoggedIn) {
// Ensure signer is available for extension users
if (!userSigner && authMethod === "extension" && window.nostr) {
userSigner = window.nostr;
console.log("Restored extension signer for import");
}
headers.Authorization = await createNIP98AuthHeader( headers.Authorization = await createNIP98AuthHeader(
`${getApiBase()}/api/import`, `${getApiBase()}/api/import`,
"POST", "POST",

5
app/web/src/ImportView.svelte

@ -9,7 +9,8 @@
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
// When ACL is "none", allow access without login // When ACL is "none", allow access without login
$: canImport = aclMode === "none" || (isLoggedIn && (currentEffectiveRole === "admin" || currentEffectiveRole === "owner")); // Write, admin, and owner roles can import events
$: canImport = aclMode === "none" || (isLoggedIn && (currentEffectiveRole === "write" || currentEffectiveRole === "admin" || currentEffectiveRole === "owner"));
function handleFileSelect(event) { function handleFileSelect(event) {
dispatch("fileSelect", event); dispatch("fileSelect", event);
@ -52,7 +53,7 @@
<div class="permission-denied"> <div class="permission-denied">
<h3 class="recovery-header">Import Events</h3> <h3 class="recovery-header">Import Events</h3>
<p class="recovery-description"> <p class="recovery-description">
Admin or owner permission required for import functionality. Write, admin, or owner permission required for import functionality.
</p> </p>
</div> </div>
{:else} {:else}

2
build-image-v0.58.5.sh

@ -46,7 +46,7 @@ mkdir -p app/web/dist
echo "<!-- Placeholder - will be replaced by Docker build -->" > app/web/dist/index.html echo "<!-- Placeholder - will be replaced by Docker build -->" > app/web/dist/index.html
echo "Using Dockerfile.with-web (will build web UI in Docker with latest changes)..." echo "Using Dockerfile.with-web (will build web UI in Docker with latest changes)..."
DOCKERFILE="Dockerfile.with-web" DOCKERFILE="Dockerfile.with-web"
# Check if local nostr clone exists and prepare it for Docker build # Check if local nostr clone exists and prepare it for Docker build
NOSTR_PATH="${NOSTR_PATH:-/home/firefly/Dokumente/repos/nostr}" NOSTR_PATH="${NOSTR_PATH:-/home/firefly/Dokumente/repos/nostr}"

Loading…
Cancel
Save