frontend: require login to access Publish page and hide Publish link when logged out; use stored token for uploads\n\nbackend: add ALLOW_ANON_READ env toggle (default false) to require auth for reads\n\nCo-authored-by: openhands <openhands@all-hands.dev>

This commit is contained in:
openhands
2026-01-09 01:35:56 +00:00
parent 64c79bb28e
commit ae0ccca59c
3 changed files with 29 additions and 8 deletions

View File

@@ -44,6 +44,8 @@ BLOB_DIR = DATA_DIR / "blobs"
META_DIR = DATA_DIR / "meta"
ROCKSDB_DIR = DATA_DIR / "rocksdb"
JWT_SECRET = os.environ.get("JWT_SECRET", "dev-secret-key")
# Control whether anonymous reads are allowed. Default: False (auth required for reads)
ALLOW_ANON_READ = os.environ.get("ALLOW_ANON_READ", "false").lower() == "true"
# Initialize storage
BLOB_DIR.mkdir(parents=True, exist_ok=True)
@@ -97,8 +99,8 @@ def require_scopes(required_scopes: list) -> Optional[Dict[str, Any]]:
"""Check if request has required scopes."""
auth_header = request.headers.get("Authorization", "")
if not auth_header.startswith("Bearer "):
# For MVP, allow unauthenticated read access
if "read" in required_scopes:
# Allow unauthenticated read access only if explicitly enabled
if "read" in required_scopes and ALLOW_ANON_READ:
return {"sub": "anonymous", "scopes": ["read"]}
raise RepositoryError("Missing authorization", 401, "UNAUTHORIZED")

View File

@@ -34,7 +34,7 @@ export default function PublishPage() {
const response = await fetch(url, {
method: 'PUT',
headers: {
'Authorization': 'Bearer demo-token',
'Authorization': `Bearer ${localStorage.getItem('token')}` ,
},
body: formData.file
});
@@ -67,6 +67,23 @@ export default function PublishPage() {
}
};
// Require login
const token = typeof window !== 'undefined' ? localStorage.getItem('token') : null;
if (!token) {
return (
<div className={styles.container}>
<div className={styles.header}>
<h1>Publish Package</h1>
<p>You must be logged in to publish packages.</p>
</div>
<div className={styles.form__actions}>
<a href="/login" className={`${styles.button} ${styles['button--primary']}`}>Go to Login</a>
</div>
</div>
);
}
return (
<div className={styles.container}>
<div className={styles.header}>

View File

@@ -41,11 +41,13 @@ export default function Navbar() {
Browse
</Link>
</li>
<li>
<Link href="/publish" className={styles.navbar__link}>
Publish
</Link>
</li>
{user && (
<li>
<Link href="/publish" className={styles.navbar__link}>
Publish
</Link>
</li>
)}
<li>
<Link href="/docs" className={styles.navbar__link}>
Docs