fix: allow CLI file tokens for RPC access
Build and Push Docker Container / build-and-push (push) Successful in 1m2s

- Accept files-scoped bearer tokens on servicelink RPC calls.
- Keep mesh shared-secret auth for trusted internal callers.
- Validate CLI auth scopes and reject unsupported values early.
- Stop CLI browser login waiting for the full timeout after callback.
- Add tests for scope normalization, RPC access, and login callback timing.
This commit is contained in:
2026-07-27 17:08:23 +02:00
parent 6e4e5b837b
commit 9db36c2d5b
6 changed files with 110 additions and 17 deletions
+8 -6
View File
@@ -4,7 +4,7 @@ Lets other nodes (browser-cli, website) push files in and read file metadata
over the shared servicelink envelope at POST /rpc, alongside the existing web
UI and /api routes.
Every call needs a bearer token carrying the `mesh` scope; the endpoint is rate
Every call needs a bearer token carrying the `files` or `mesh` scope; the endpoint is rate
limited and body-size capped. Keep /rpc on the internal node network.
'''
from __future__ import annotations
@@ -17,16 +17,18 @@ from quart import current_app
from my_modules.app.setup import LIMITER
from my_modules.expiry import ensure_utc, parse_expires
from my_modules.file_meta import format_size, iso_stamp_filename
from servicelink import InvalidParams, NotFound, Router, Unauthorized, any_verifier, bearer_verifier, create_link_blueprint, shared_secret_verifier
from servicelink import Forbidden, InvalidParams, NotFound, Router, Unauthorized, any_verifier, bearer_verifier, create_link_blueprint, shared_secret_verifier
MAX_RPC_BODY = 16 * 1024 * 1024
MESH_SCOPE = 'mesh'
RPC_SCOPES = ('files', 'mesh')
router = Router('picoshare')
def _user_id(ctx):
if ctx.principal is None:
raise Unauthorized('authentication required')
if not any(ctx.principal.has_scope(scope) for scope in RPC_SCOPES):
raise Forbidden('missing required scope: files')
return ctx.principal.subject
@router.method('files.upload')
@@ -110,11 +112,11 @@ async def _decode_access_token(token):
return payload
def _build_verify():
# Accept a JWT access token with the mesh scope (public path) OR, on the
# Accept a JWT access token with a file/RPC scope (public path) OR, on the
# trusted Docker network, a static shared secret from SERVICELINK_MESH_SECRET.
jwt = bearer_verifier(_decode_access_token, require_scope=MESH_SCOPE)
jwt = bearer_verifier(_decode_access_token)
secret = os.getenv('SERVICELINK_MESH_SECRET')
return any_verifier(shared_secret_verifier(secret, scopes=(MESH_SCOPE,)), jwt) if secret else jwt
return any_verifier(shared_secret_verifier(secret, scopes=('mesh',)), jwt) if secret else jwt
verify = _build_verify()
link_bp = create_link_blueprint(router, verify=verify, limiter=LIMITER.limit('30 per minute'), max_body=MAX_RPC_BODY)