Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion lib/create-server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import SolidWs from 'solid-ws'
import globalTunnel from 'global-tunnel-ng'
import debug from './debug.mjs'
import createApp from './create-app.mjs'
import ACLChecker from './acl-checker.mjs'
import url from 'url'

function createServer (argv, app) {
argv = argv || {}
Expand Down Expand Up @@ -96,7 +98,46 @@ function createServer (argv, app) {

// Setup Express app
if (ldp.live) {
const solidWs = SolidWs(server, ldpApp)
// Authorization callback for WebSocket subscriptions
// Checks ACL read permission before allowing subscription
const authorizeSubscription = function (iri, req, callback) {
// TODO: Extract userId from session cookie or Authorization header
// For now, treat all WebSocket connections as anonymous
// This still prevents anonymous access to private resources
const userId = null

try {
const parsedUrl = url.parse(iri)
const resourcePath = decodeURIComponent(parsedUrl.pathname)
const hostname = parsedUrl.hostname || req.headers.host?.split(':')[0]
const rootUrl = ldp.resourceMapper.resolveUrl(hostname)
const resourceUrl = rootUrl + resourcePath

// Create a minimal request-like object for ACLChecker
const pseudoReq = {
hostname,
path: resourcePath,
get: (header) => req.headers[header.toLowerCase()]
}

const aclChecker = ACLChecker.createFromLDPAndRequest(resourceUrl, ldp, pseudoReq)

aclChecker.can(userId, 'Read')
.then(allowed => {
debug.ACL(`WebSocket subscription ${allowed ? 'allowed' : 'denied'} for ${iri} (user: ${userId || 'anonymous'})`)
callback(null, allowed)
})
.catch(err => {
debug.ACL(`WebSocket ACL check error for ${iri}: ${err.message}`)
callback(null, false)
})
} catch (err) {
debug.ACL(`WebSocket authorization error: ${err.message}`)
callback(null, false)
}
}

const solidWs = SolidWs(server, ldpApp, { authorize: authorizeSubscription })
ldpApp.locals.ldp.live = solidWs.publish.bind(solidWs)
}

Expand Down
Loading