users need always login
This commit is contained in:
+18
-15
@@ -37,7 +37,7 @@ there is no browser-side persistence or independent playback state.
|
||||
flowchart TB
|
||||
Main[main.rkt<br/>configuration and lifecycle]
|
||||
Server[private/server.rkt<br/>HTTP adapter]
|
||||
Users[private/users.rkt<br/>users, networks and sessions]
|
||||
Users[private/users.rkt<br/>users, trusted proxies and sessions]
|
||||
Player[private/player.rkt<br/>application state and commands]
|
||||
Playlists[private/playlists.rkt<br/>durable playlist tabs]
|
||||
DLNAAdapter[private/dlna-playback.rkt<br/>playlist transition orchestration]
|
||||
@@ -241,16 +241,19 @@ on every render.
|
||||
### 3.7 User authentication
|
||||
|
||||
Authentication is enabled by adding Argon2id password hashes under `[users]`.
|
||||
Requests whose effective client address belongs to a configured local network
|
||||
bypass login. A forwarded address is accepted only when the direct peer belongs
|
||||
to `[authentication] trusted-proxies`; the rightmost `X-Forwarded-For` value is
|
||||
used so an untrusted client cannot prepend a local address.
|
||||
All browser clients then authenticate, including clients on the local network.
|
||||
A forwarded address is accepted only when the direct peer belongs to
|
||||
`[authentication] trusted-proxies`; the rightmost `X-Forwarded-For` value is
|
||||
used so an untrusted client cannot prepend a forged address.
|
||||
|
||||
Successful logins create opaque 256-bit session tokens. Only the token is sent
|
||||
to the browser in a `Secure`, `HttpOnly`, `SameSite=Strict` cookie; server-side
|
||||
session state has an idle timeout and is intentionally volatile. Login failures
|
||||
are rate-limited per effective client address. Agent endpoints are outside user
|
||||
sessions and retain their separate application-ID authorization.
|
||||
are rate-limited per effective client address. Authenticated requests move the
|
||||
server-side idle deadline. Once half the configured lifetime has elapsed, the
|
||||
cookie is reissued with a fresh lifetime; this avoids a `Set-Cookie` header on
|
||||
every one-second state poll. Agent endpoints are outside user sessions and
|
||||
retain their separate application-ID authorization.
|
||||
|
||||
## 4. Key runtime flows
|
||||
|
||||
@@ -334,7 +337,7 @@ file:
|
||||
setting remains supported);
|
||||
- allowed 256-bit playback-agent IDs under `[playback-agents]`;
|
||||
- the optional playlist-keystore override under `[player]`;
|
||||
- Argon2id user hashes, local networks, trusted proxies, and session timeout.
|
||||
- Argon2id user hashes, trusted proxies, and session timeout.
|
||||
|
||||
Command-line network settings override INI values. Library paths from both
|
||||
sources are combined and de-duplicated.
|
||||
@@ -345,13 +348,13 @@ and sessions still reset when the process restarts.
|
||||
|
||||
## 7. Security and operational boundaries
|
||||
|
||||
The browser API has optional user authentication but no TLS termination or
|
||||
per-user player state. Authentication must be enabled before exposing it to an
|
||||
untrusted network, and a reverse proxy must provide HTTPS because session
|
||||
cookies are always marked `Secure`. Local-network bypass and forwarded client
|
||||
addresses are security-sensitive configuration: only known reverse-proxy peers
|
||||
may be trusted, and the application port should remain firewalled from the
|
||||
internet.
|
||||
The browser API has optional user authentication but no TLS termination.
|
||||
Authentication must be enabled before exposing it to an untrusted network, and
|
||||
a reverse proxy must provide HTTPS because session cookies are always marked
|
||||
`Secure`. Forwarded client addresses are security-sensitive configuration:
|
||||
only known reverse-proxy peers may be trusted, and the application port should
|
||||
remain firewalled from the internet. Playlists are isolated by username, while
|
||||
renderer selection and transport state remain shared.
|
||||
|
||||
Playback-agent registration and polling are authorized against a default-deny
|
||||
INI allowlist. Media URLs additionally contain an opaque per-track token. The
|
||||
|
||||
@@ -41,9 +41,8 @@ podcasts=D:\Podcasts
|
||||
7b4776ef27104e8eb9f7ea2c622ce76ca23de4260b0f94e6880d321017b32a0e4=true
|
||||
|
||||
[authentication]
|
||||
local-networks=127.0.0.0/8;::1/128;10.0.0.0/8;172.16.0.0/12;192.168.0.0/16
|
||||
trusted-proxies=127.0.0.0/8;::1/128
|
||||
session-seconds=43200
|
||||
session-seconds=604800
|
||||
|
||||
[users]
|
||||
hans=$argon2id$v=19$m=19456,t=2,p=1$...
|
||||
@@ -57,8 +56,8 @@ ondersteund. Playlisttabs worden standaard opgeslagen in de keystore
|
||||
`playlist-keystore=...` onder `[player]` kan desgewenst een ander pad worden
|
||||
gebruikt.
|
||||
|
||||
Zodra `[users]` minstens één gebruiker bevat, toont de webinterface voor
|
||||
niet-lokale clients een eigen loginvenster. Wachtwoorden staan uitsluitend als
|
||||
Zodra `[users]` minstens één gebruiker bevat, moeten alle browserclients
|
||||
inloggen, zowel lokaal als via internet. Wachtwoorden staan uitsluitend als
|
||||
Argon2id-hash in de INI. Maak zo'n hash vanuit Racket:
|
||||
|
||||
```racket
|
||||
@@ -69,7 +68,6 @@ Argon2id-hash in de INI. Maak zo'n hash vanuit Racket:
|
||||
(displayln (make-password-hash "een lang en uniek wachtwoord"))
|
||||
```
|
||||
|
||||
`local-networks` bepaalt welke clients zonder login mogen werken.
|
||||
`trusted-proxies` bepaalt uitsluitend van welke directe peers de laatste
|
||||
`X-Forwarded-For`-waarde wordt geaccepteerd. Laat die lijst zo klein mogelijk;
|
||||
bij Apache op dezelfde machine zijn loopbackadressen voldoende. Zonder
|
||||
@@ -108,21 +106,25 @@ tab verdwijnt daarbij ook uit de keystore. Voor iedere gebruiker bevat de key
|
||||
GUID-key staan de naam en tracks van die playlist. Tracks uit verschillende
|
||||
geconfigureerde libraries mogen in dezelfde playlist staan; ontbrekende of
|
||||
buiten de libraries gelegen bestanden worden bij het laden overgeslagen.
|
||||
`local`, `anonymous` en iedere aangemelde gebruiker hebben daarbij een eigen
|
||||
playlistverzameling. Het fysieke afspeelpunt en de transportbediening blijven
|
||||
gedeeld; een playlistcommando van een andere gebruiker neemt die speler over.
|
||||
Iedere aangemelde gebruiker heeft daarbij een eigen playlistverzameling. Als
|
||||
authenticatie is uitgeschakeld, wordt de verzameling van `anonymous` gebruikt.
|
||||
Het fysieke afspeelpunt en de transportbediening blijven gedeeld; een
|
||||
playlistcommando van een andere gebruiker neemt die speler over. Een oudere
|
||||
`playlists-for-local`-verzameling blijft in de keystore staan, maar wordt niet
|
||||
automatisch aan een gebruiker toegewezen.
|
||||
|
||||
De server luistert standaard alleen op localhost. Geef alleen bewust een
|
||||
LAN-adres aan `--listen-ip`. Configureer gebruikersauthenticatie voordat de
|
||||
webinterface via een publiek bereikbare reverse proxy wordt aangeboden.
|
||||
|
||||
Externe gebruikers krijgen na succesvolle aanmelding een willekeurige 256-bit
|
||||
sessiecookie met `Secure`, `HttpOnly` en `SameSite=Strict`. Sessies verlopen na
|
||||
de ingestelde inactiviteitsduur en worden niet over een serverherstart heen
|
||||
bewaard. Na vijf mislukte pogingen vanaf hetzelfde clientadres wordt aanmelden
|
||||
vijf minuten geblokkeerd. De `/api/agent/*`-routes gebruiken geen
|
||||
gebruikerssessie: daarvoor blijft de afzonderlijke playback-agent-allowlist
|
||||
gelden.
|
||||
Gebruikers krijgen na succesvolle aanmelding een willekeurige 256-bit
|
||||
sessiecookie met `Secure`, `HttpOnly` en `SameSite=Strict`. De standaard
|
||||
inactiviteitsduur is zeven dagen. Geldig gebruik verschuift de servertermijn;
|
||||
halverwege de termijn wordt ook de browsercookie opnieuw voor zeven dagen
|
||||
uitgegeven. Sessies worden niet over een serverherstart heen bewaard. Na vijf
|
||||
mislukte pogingen vanaf hetzelfde clientadres wordt aanmelden vijf minuten
|
||||
geblokkeerd. De `/api/agent/*`-routes gebruiken geen gebruikerssessie: daarvoor
|
||||
blijft de afzonderlijke playback-agent-allowlist gelden.
|
||||
|
||||
## Windows playback agent
|
||||
|
||||
|
||||
@@ -55,14 +55,9 @@
|
||||
(define/contract (run-web-player music-paths
|
||||
#:allowed-agent-ids [allowed-agent-ids '()]
|
||||
#:users [users '()]
|
||||
#:local-networks
|
||||
[local-networks
|
||||
'("127.0.0.0/8" "::1/128"
|
||||
"10.0.0.0/8" "172.16.0.0/12"
|
||||
"192.168.0.0/16")]
|
||||
#:trusted-proxies
|
||||
[trusted-proxies '("127.0.0.0/8" "::1/128")]
|
||||
#:session-seconds [session-seconds 43200]
|
||||
#:session-seconds [session-seconds 604800]
|
||||
#:listen-ip [listen-ip "127.0.0.1"]
|
||||
#:port [port 8080]
|
||||
#:dlna-port [dlna-port 8734]
|
||||
@@ -72,7 +67,6 @@
|
||||
(->* ((listof library-spec/c))
|
||||
(#:allowed-agent-ids (listof string?)
|
||||
#:users (listof (cons/c string? string?))
|
||||
#:local-networks (listof string?)
|
||||
#:trusted-proxies (listof string?)
|
||||
#:session-seconds exact-positive-integer?
|
||||
#:listen-ip string?
|
||||
@@ -88,7 +82,6 @@
|
||||
#:dlna-port dlna-port))
|
||||
(auth-manager
|
||||
(make-auth-manager users
|
||||
#:local-networks local-networks
|
||||
#:trusted-proxies trusted-proxies
|
||||
#:session-seconds session-seconds)))
|
||||
(info-rkt-web-player
|
||||
@@ -179,19 +172,13 @@
|
||||
#:when (string? (cdr entry)))
|
||||
entry))
|
||||
|
||||
(define local-networks
|
||||
(configuration-list
|
||||
(ini-get config 'authentication 'local-networks "")
|
||||
'("127.0.0.0/8" "::1/128"
|
||||
"10.0.0.0/8" "172.16.0.0/12" "192.168.0.0/16")))
|
||||
|
||||
(define trusted-proxies
|
||||
(configuration-list
|
||||
(ini-get config 'authentication 'trusted-proxies "")
|
||||
'("127.0.0.0/8" "::1/128")))
|
||||
|
||||
(define session-seconds
|
||||
(ini-get config 'authentication 'session-seconds 43200))
|
||||
(ini-get config 'authentication 'session-seconds 604800))
|
||||
|
||||
(define all-libraries
|
||||
(append configured-libraries
|
||||
@@ -203,7 +190,6 @@
|
||||
all-libraries
|
||||
#:allowed-agent-ids allowed-agent-ids
|
||||
#:users configured-users
|
||||
#:local-networks local-networks
|
||||
#:trusted-proxies trusted-proxies
|
||||
#:session-seconds session-seconds
|
||||
#:listen-ip (or listen-ip
|
||||
|
||||
+10
-10
@@ -1126,7 +1126,7 @@
|
||||
(string-downcase app-id)))
|
||||
(define store (open-playlist-store playlist-keystore))
|
||||
(define stored-tabs
|
||||
(load-user-playlists store "local" libraries))
|
||||
(load-user-playlists store "anonymous" libraries))
|
||||
(let* ((library (and (pair? libraries) (car libraries)))
|
||||
(browser-entries
|
||||
(if library
|
||||
@@ -1142,7 +1142,7 @@
|
||||
(selected-index 0)
|
||||
(contexts (make-hash))
|
||||
(initial-context (playlist-context tabs selected-index)))
|
||||
(hash-set! contexts "local" initial-context)
|
||||
(hash-set! contexts "anonymous" initial-context)
|
||||
(define value
|
||||
(player libraries
|
||||
(remove-duplicates normalized-agent-ids string=?)
|
||||
@@ -1175,7 +1175,7 @@
|
||||
(make-hash)
|
||||
store
|
||||
contexts
|
||||
"local"
|
||||
"anonymous"
|
||||
dlna-port))
|
||||
value))
|
||||
|
||||
@@ -1185,7 +1185,7 @@
|
||||
; post : Cached DLNA playback information has been incorporated.
|
||||
; result : A JSON-compatible hash.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define (player-state->jsexpr value #:username [username "local"])
|
||||
(define (player-state->jsexpr value #:username [username "anonymous"])
|
||||
(define normalized (normal-playlist-username username))
|
||||
(call-with-semaphore
|
||||
(player-command-lock value)
|
||||
@@ -1264,7 +1264,7 @@
|
||||
"playlist-clear" "tab-add" "tab-select" "tab-rename"
|
||||
"tab-delete" "play"))
|
||||
|
||||
(define (player-command! value command data #:username [username "local"])
|
||||
(define (player-command! value command data #:username [username "anonymous"])
|
||||
(define normalized (normal-playlist-username username))
|
||||
(call-with-semaphore
|
||||
(player-command-lock value)
|
||||
@@ -1488,7 +1488,7 @@
|
||||
; post : Player state remains unchanged.
|
||||
; result : Artwork bytes and MIME type, or #f when unavailable.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define (player-track-artwork value artwork-id #:username [username "local"])
|
||||
(define (player-track-artwork value artwork-id #:username [username "anonymous"])
|
||||
(define item
|
||||
(call-with-semaphore
|
||||
(player-command-lock value)
|
||||
@@ -1757,10 +1757,10 @@
|
||||
"tab-rename"
|
||||
(hasheq 'index 1 'name "Hans favorieten")
|
||||
#:username "hans")
|
||||
(define local-after-hans
|
||||
(player-state->jsexpr example-player #:username "local"))
|
||||
(check-equal? (length (hash-ref local-after-hans 'tabs)) 1)
|
||||
(check-equal? (length (hash-ref local-after-hans 'tracks)) 2)
|
||||
(define anonymous-after-hans
|
||||
(player-state->jsexpr example-player #:username "anonymous"))
|
||||
(check-equal? (length (hash-ref anonymous-after-hans 'tabs)) 1)
|
||||
(check-equal? (length (hash-ref anonymous-after-hans 'tracks)) 2)
|
||||
(player-close! example-player)
|
||||
|
||||
(define restored-player
|
||||
|
||||
+19
-2
@@ -54,7 +54,6 @@
|
||||
(let ((user (auth-request-user current-auth request)))
|
||||
(json-response
|
||||
(hasheq 'enabled (auth-enabled? current-auth)
|
||||
'local (auth-request-local? current-auth request)
|
||||
'authenticated (and user #t)
|
||||
'username (or user 'null)))))
|
||||
|
||||
@@ -215,6 +214,24 @@
|
||||
(regexp-match? #px"^/api/(?:auth|agent)(?:/|$)"
|
||||
(request-path request)))
|
||||
|
||||
(define (response-add-header value extra-header)
|
||||
(response (response-code value)
|
||||
(response-message value)
|
||||
(response-seconds value)
|
||||
(response-mime value)
|
||||
(cons extra-header (response-headers value))
|
||||
(response-output value)))
|
||||
|
||||
(define (dispatch-api request)
|
||||
(define value (api-dispatch request))
|
||||
(define renewed-cookie
|
||||
(and (not (regexp-match? #px"^/api/agent(?:/|$)"
|
||||
(request-path request)))
|
||||
(auth-renewal-cookie current-auth request)))
|
||||
(if renewed-cookie
|
||||
(response-add-header value (header #"Set-Cookie" renewed-cookie))
|
||||
value))
|
||||
|
||||
(define (dispatch request)
|
||||
(cond
|
||||
((and (bytes=? (request-method request) #"POST")
|
||||
@@ -225,7 +242,7 @@
|
||||
#:code 415))
|
||||
((or (public-api-request? request)
|
||||
(auth-request-user current-auth request))
|
||||
(api-dispatch request))
|
||||
(dispatch-api request))
|
||||
(else
|
||||
(json-response
|
||||
(hasheq 'error "Aanmelden is vereist"
|
||||
|
||||
+54
-31
@@ -14,18 +14,20 @@
|
||||
make-auth-manager
|
||||
auth-manager?
|
||||
auth-enabled?
|
||||
auth-request-local?
|
||||
auth-request-user
|
||||
auth-login!
|
||||
auth-logout!
|
||||
auth-session-cookie
|
||||
auth-renewal-cookie
|
||||
auth-expired-cookie)
|
||||
|
||||
(struct ip-network (address prefix) #:transparent)
|
||||
(struct session (username [last-seen #:mutable]) #:transparent)
|
||||
(struct session
|
||||
(username [last-seen #:mutable] [last-cookie-renewal #:mutable])
|
||||
#:transparent)
|
||||
(struct failures ([attempts #:mutable] [started #:mutable]) #:transparent)
|
||||
(struct auth-manager
|
||||
(users local-networks trusted-proxies session-seconds sessions failed lock)
|
||||
(users trusted-proxies session-seconds sessions failed lock)
|
||||
#:transparent)
|
||||
|
||||
(define password-kdf
|
||||
@@ -136,11 +138,6 @@
|
||||
(define (auth-enabled? manager)
|
||||
(positive? (hash-count (auth-manager-users manager))))
|
||||
|
||||
(define (auth-request-local? manager request)
|
||||
(ormap (lambda (network)
|
||||
(network-contains? network (request-address manager request)))
|
||||
(auth-manager-local-networks manager)))
|
||||
|
||||
(define (request-session-token request)
|
||||
(for/or ((cookie (in-list (request-cookies request))))
|
||||
(and (string=? (client-cookie-name cookie) session-cookie-name)
|
||||
@@ -156,7 +153,6 @@
|
||||
(define (auth-request-user manager request)
|
||||
(cond
|
||||
((not (auth-enabled? manager)) "anonymous")
|
||||
((auth-request-local? manager request) "local")
|
||||
(else
|
||||
(let ((token (request-session-token request))
|
||||
(now (current-seconds)))
|
||||
@@ -215,7 +211,7 @@
|
||||
(prune-sessions! manager now)
|
||||
(hash-set! (auth-manager-sessions manager)
|
||||
token
|
||||
(session normalized now))
|
||||
(session normalized now now))
|
||||
token)
|
||||
(begin
|
||||
(record-failure! manager address now)
|
||||
@@ -237,6 +233,30 @@
|
||||
token
|
||||
(auth-manager-session-seconds manager))))
|
||||
|
||||
;; Return a refreshed cookie at most once per half session lifetime. The
|
||||
;; server-side inactivity timer is updated on every authenticated request, but
|
||||
;; limiting Set-Cookie avoids rewriting it for every one-second player poll.
|
||||
(define (auth-renewal-cookie manager request)
|
||||
(and (auth-enabled? manager)
|
||||
(let ((token (request-session-token request))
|
||||
(now (current-seconds)))
|
||||
(and token
|
||||
(call-with-semaphore
|
||||
(auth-manager-lock manager)
|
||||
(lambda ()
|
||||
(prune-sessions! manager now)
|
||||
(define value
|
||||
(hash-ref (auth-manager-sessions manager) token #f))
|
||||
(and value
|
||||
(>= (- now (session-last-cookie-renewal value))
|
||||
(max 1
|
||||
(quotient
|
||||
(auth-manager-session-seconds manager)
|
||||
2)))
|
||||
(begin
|
||||
(set-session-last-cookie-renewal! value now)
|
||||
(auth-session-cookie manager token)))))))))
|
||||
|
||||
(define (auth-expired-cookie)
|
||||
(string->bytes/utf-8
|
||||
(format
|
||||
@@ -244,14 +264,9 @@
|
||||
session-cookie-name)))
|
||||
|
||||
(define (make-auth-manager user-pairs
|
||||
#:local-networks
|
||||
[local-network-values
|
||||
'("127.0.0.0/8" "::1/128"
|
||||
"10.0.0.0/8" "172.16.0.0/12"
|
||||
"192.168.0.0/16")]
|
||||
#:trusted-proxies
|
||||
[trusted-proxy-values '("127.0.0.0/8" "::1/128")]
|
||||
#:session-seconds [session-seconds 43200])
|
||||
#:session-seconds [session-seconds 604800])
|
||||
(unless (exact-positive-integer? session-seconds)
|
||||
(raise-argument-error 'make-auth-manager "exact-positive-integer?"
|
||||
session-seconds))
|
||||
@@ -277,7 +292,6 @@
|
||||
(hash-set! users (string-downcase (string-trim (car entry)))
|
||||
(cdr entry)))
|
||||
(auth-manager users
|
||||
(map parse-network local-network-values)
|
||||
(map parse-network trusted-proxy-values)
|
||||
session-seconds
|
||||
(make-hash)
|
||||
@@ -297,30 +311,35 @@
|
||||
(define manager
|
||||
(make-auth-manager
|
||||
(list (cons "Hans" test-hash))
|
||||
#:local-networks '("192.168.1.0/24")
|
||||
#:trusted-proxies '("127.0.0.1/32")))
|
||||
|
||||
(define (test-request peer [headers '()])
|
||||
(request #"GET" (string->url "http://example.test/api/state")
|
||||
headers (delay '()) #f "127.0.0.1" 80 peer))
|
||||
|
||||
(check-true (auth-request-local? manager (test-request "192.168.1.42")))
|
||||
(check-false (auth-request-local? manager (test-request "192.168.2.42")))
|
||||
(check-true
|
||||
(auth-request-local?
|
||||
manager
|
||||
(test-request "127.0.0.1"
|
||||
(list (header #"X-Forwarded-For" #"198.51.100.2, 192.168.1.8")))))
|
||||
(check-false
|
||||
(auth-request-local?
|
||||
manager
|
||||
(test-request "198.51.100.2"
|
||||
(list (header #"X-Forwarded-For" #"192.168.1.8")))))
|
||||
|
||||
(define remote (test-request "198.51.100.2"))
|
||||
;; Local and remote browser requests follow the same login path.
|
||||
(check-false (auth-request-user manager (test-request "127.0.0.1")))
|
||||
(check-equal?
|
||||
(request-address
|
||||
manager
|
||||
(test-request
|
||||
"127.0.0.1"
|
||||
(list (header #"X-Forwarded-For"
|
||||
#"198.51.100.8, 203.0.113.9"))))
|
||||
"203.0.113.9")
|
||||
(check-equal?
|
||||
(request-address
|
||||
manager
|
||||
(test-request
|
||||
"198.51.100.2"
|
||||
(list (header #"X-Forwarded-For" #"203.0.113.9"))))
|
||||
"198.51.100.2")
|
||||
(define token
|
||||
(auth-login! manager remote "hans" "correct horse battery staple"))
|
||||
(check-true (string? token))
|
||||
(check-true
|
||||
(regexp-match? #rx#"Max-Age=604800" (auth-session-cookie manager token)))
|
||||
(define authenticated
|
||||
(test-request
|
||||
"198.51.100.2"
|
||||
@@ -329,6 +348,10 @@
|
||||
(string->bytes/utf-8
|
||||
(format "~a=~a" session-cookie-name token))))))
|
||||
(check-equal? (auth-request-user manager authenticated) "hans")
|
||||
(define stored-session (hash-ref (auth-manager-sessions manager) token))
|
||||
(set-session-last-cookie-renewal! stored-session 0)
|
||||
(check-true (bytes? (auth-renewal-cookie manager authenticated)))
|
||||
(check-false (auth-renewal-cookie manager authenticated))
|
||||
(auth-logout! manager authenticated)
|
||||
(check-false (auth-request-user manager authenticated))
|
||||
(check-false (auth-login! manager remote "hans" "wrong password")))
|
||||
|
||||
+2
-2
@@ -101,8 +101,8 @@ function hideLogin() {
|
||||
async function refreshAuth() {
|
||||
try {
|
||||
const auth = await api("/api/auth/status");
|
||||
elements.logout.hidden = !auth.enabled || auth.local || !auth.authenticated;
|
||||
if (auth.enabled && !auth.local && !auth.authenticated) showLogin();
|
||||
elements.logout.hidden = !auth.enabled || !auth.authenticated;
|
||||
if (auth.enabled && !auth.authenticated) showLogin();
|
||||
} catch (error) {
|
||||
setStatus(`Authenticatiestatus onbekend: ${error.message}`);
|
||||
}
|
||||
|
||||
@@ -14,11 +14,10 @@ dlna-port=8734
|
||||
; 7b4776ef27104e8eb9f7ea2c622ce76ca23de4260b0f94e6880d321017b32a0e4=true
|
||||
|
||||
[authentication]
|
||||
; Local clients do not need to log in. Separate networks with semicolons.
|
||||
local-networks=127.0.0.0/8;::1/128;10.0.0.0/8;172.16.0.0/12;192.168.0.0/16
|
||||
; Only these direct peers may supply X-Forwarded-For.
|
||||
trusted-proxies=127.0.0.0/8;::1/128
|
||||
session-seconds=43200
|
||||
; Seven-day sliding idle timeout. Active cookies are renewed halfway through.
|
||||
session-seconds=604800
|
||||
|
||||
[users]
|
||||
; Generate a hash with (make-password-hash "a long password") from
|
||||
|
||||
@@ -21,9 +21,8 @@ browser by Racket's web server.
|
||||
(list/c string? path-string?)))]
|
||||
[#:allowed-agent-ids allowed-agent-ids (listof string?) null]
|
||||
[#:users users (listof (cons/c string? string?)) null]
|
||||
[#:local-networks local-networks (listof string?)]
|
||||
[#:trusted-proxies trusted-proxies (listof string?)]
|
||||
[#:session-seconds session-seconds exact-positive-integer? 43200]
|
||||
[#:session-seconds session-seconds exact-positive-integer? 604800]
|
||||
[#:listen-ip listen-ip string? "127.0.0.1"]
|
||||
[#:port port exact-positive-integer? 8080]
|
||||
[#:dlna-port dlna-port exact-positive-integer? 8734]
|
||||
@@ -45,6 +44,10 @@ network renderer. Playlist tabs are atomically persisted in
|
||||
resources are closed when the web server exits. The default is
|
||||
@tt{data/playlists.keystore} below the installed rkt-web-player collection.
|
||||
Each username owns an ordered GUID index and separate playlist values.
|
||||
When @racket[users] is non-empty, every browser client must authenticate.
|
||||
Sessions have a sliding idle timeout; an active browser cookie is renewed once
|
||||
half of @racket[session-seconds] has elapsed. Playback-agent endpoints continue
|
||||
to use their separate application-ID allowlist.
|
||||
|
||||
The default listen address only exposes the interface to the local computer.
|
||||
Use a LAN address deliberately if other devices should control the player.
|
||||
|
||||
Reference in New Issue
Block a user