Browse Source

sink import to write permissios

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

76
app/server.go

@ -14,12 +14,19 @@ import ( @@ -14,12 +14,19 @@ import (
"sync"
"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"
"next.orly.dev/app/branding"
"next.orly.dev/app/config"
"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/bunker"
"next.orly.dev/pkg/database"
domainevents "next.orly.dev/pkg/domain/events"
"next.orly.dev/pkg/domain/events/subscribers"
@ -29,25 +36,18 @@ import ( @@ -29,25 +36,18 @@ import (
"next.orly.dev/pkg/event/routing"
"next.orly.dev/pkg/event/specialkinds"
"next.orly.dev/pkg/event/validation"
"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"
acliface "next.orly.dev/pkg/interfaces/acl"
"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/nip43"
"next.orly.dev/pkg/protocol/publish"
"next.orly.dev/pkg/bunker"
"next.orly.dev/pkg/protocol/nrc"
"next.orly.dev/pkg/protocol/publish"
"next.orly.dev/pkg/ratelimit"
"next.orly.dev/pkg/spider"
"next.orly.dev/pkg/storage"
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/wireguard"
)
type Server struct {
@ -57,7 +57,7 @@ type Server struct { @@ -57,7 +57,7 @@ type Server struct {
Config *config.C
// Ctx holds the server context.
// Deprecated: Use Context() method instead of accessing directly.
Ctx context.Context
Ctx context.Context
publishers *publish.S
// Admins holds the admin pubkeys.
// Deprecated: Use IsAdmin() method instead of accessing directly.
@ -84,30 +84,30 @@ type Server struct { @@ -84,30 +84,30 @@ type Server struct {
// Use RLock() for normal message processing, Lock() for updates
messagePauseMutex sync.RWMutex
paymentProcessor *PaymentProcessor
sprocketManager *SprocketManager
policyManager *policy.P
spiderManager *spider.Spider
directorySpider *spider.DirectorySpider
syncManager *dsync.Manager
relayGroupMgr *dsync.RelayGroupManager
clusterManager *dsync.ClusterManager
blossomServer *blossom.Server
InviteManager *nip43.InviteManager
graphExecutor *graph.Executor
rateLimiter *ratelimit.Limiter
cfg *config.C
db database.Database // Changed from *database.D to interface
paymentProcessor *PaymentProcessor
sprocketManager *SprocketManager
policyManager *policy.P
spiderManager *spider.Spider
directorySpider *spider.DirectorySpider
syncManager *dsync.Manager
relayGroupMgr *dsync.RelayGroupManager
clusterManager *dsync.ClusterManager
blossomServer *blossom.Server
InviteManager *nip43.InviteManager
graphExecutor *graph.Executor
rateLimiter *ratelimit.Limiter
cfg *config.C
db database.Database // Changed from *database.D to interface
// Domain services for event handling
eventValidator *validation.Service
eventAuthorizer *authorization.Service
eventRouter *routing.DefaultRouter
eventProcessor *processing.Service
eventDispatcher *domainevents.Dispatcher
ingestionService *ingestion.Service
specialKinds *specialkinds.Registry
aclRegistry acliface.Registry
eventValidator *validation.Service
eventAuthorizer *authorization.Service
eventRouter *routing.DefaultRouter
eventProcessor *processing.Service
eventDispatcher *domainevents.Dispatcher
ingestionService *ingestion.Service
specialKinds *specialkinds.Registry
aclRegistry acliface.Registry
// WireGuard VPN and NIP-46 Bunker
wireguardServer *wireguard.Server
@ -1118,7 +1118,7 @@ func (s *Server) handleEventsMine(w http.ResponseWriter, r *http.Request) { @@ -1118,7 +1118,7 @@ func (s *Server) handleEventsMine(w http.ResponseWriter, r *http.Request) {
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) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
@ -1138,11 +1138,11 @@ func (s *Server) handleImport(w http.ResponseWriter, r *http.Request) { @@ -1138,11 +1138,11 @@ func (s *Server) handleImport(w http.ResponseWriter, r *http.Request) {
return
}
// Check permissions - require admin or owner level
// Check permissions - require write, admin, or owner level
accessLevel := acl.Registry.GetAccessLevel(pubkey, r.RemoteAddr)
if accessLevel != "admin" && accessLevel != "owner" {
if accessLevel != "write" && accessLevel != "admin" && accessLevel != "owner" {
http.Error(
w, "Admin or owner permission required", http.StatusForbidden,
w, "Write, admin, or owner permission required", http.StatusForbidden,
)
return
}

34
app/web/src/App.svelte

@ -895,7 +895,7 @@ @@ -895,7 +895,7 @@
// Restore signer for extension method
if (storedAuthMethod === "extension") {
if (window.nostr) {
userSigner = window.nostr;
userSigner = window.nostr;
} else {
// Extension might not be loaded yet, try again after a short delay
setTimeout(() => {
@ -921,9 +921,9 @@ @@ -921,9 +921,9 @@
async function loadRelayData() {
// Fetch user role for already logged in users
if (isLoggedIn) {
fetchUserRole();
await fetchUserRole();
}
fetchACLMode();
await fetchACLMode();
// Load sprocket configuration
loadSprocketConfig();
@ -2410,10 +2410,25 @@ @@ -2410,10 +2410,25 @@
async function importEvents() {
// Skip login/permission check when ACL is "none" (open relay mode)
if (aclMode !== "none" && (!isLoggedIn || (userRole !== "admin" && userRole !== "owner"))) {
importMessage = "Admin or owner permission required";
setTimeout(() => { importMessage = ""; }, 5000);
return;
if (aclMode !== "none") {
// 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);
return;
}
}
if (!selectedFile) {
@ -2429,6 +2444,11 @@ @@ -2429,6 +2444,11 @@
// Build headers - only include auth when ACL is not "none"
const headers = {};
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(
`${getApiBase()}/api/import`,
"POST",

6
app/web/src/EventsView.svelte

@ -67,8 +67,8 @@ @@ -67,8 +67,8 @@
// Check cache first
if (profileCache.has(pubkey)) {
return profileCache.get(pubkey);
}
}
// Fetch profile
try {
const profile = await fetchUserProfile(pubkey);
@ -136,7 +136,7 @@ @@ -136,7 +136,7 @@
class="avatar-image"
/>
{:else}
<div class="avatar-placeholder">👤</div>
<div class="avatar-placeholder">👤</div>
{/if}
</div>
<div class="events-view-info">

5
app/web/src/ImportView.svelte

@ -9,7 +9,8 @@ @@ -9,7 +9,8 @@
const dispatch = createEventDispatcher();
// 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) {
dispatch("fileSelect", event);
@ -52,7 +53,7 @@ @@ -52,7 +53,7 @@
<div class="permission-denied">
<h3 class="recovery-header">Import Events</h3>
<p class="recovery-description">
Admin or owner permission required for import functionality.
Write, admin, or owner permission required for import functionality.
</p>
</div>
{:else}

2
build-image-v0.58.5.sh

@ -46,7 +46,7 @@ mkdir -p app/web/dist @@ -46,7 +46,7 @@ mkdir -p app/web/dist
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)..."
DOCKERFILE="Dockerfile.with-web"
DOCKERFILE="Dockerfile.with-web"
# Check if local nostr clone exists and prepare it for Docker build
NOSTR_PATH="${NOSTR_PATH:-/home/firefly/Dokumente/repos/nostr}"

Loading…
Cancel
Save