feat: make authentication optional — no tokens = no auth
Lint & Test / test (push) Successful in 10s
Lint & Test / test (push) Successful in 10s
When no api_tokens are configured (the new default), all endpoints are accessible without authentication. The frontend detects this via /api/health's auth_required field and skips the login form. - Backend: auth.py skips verification when api_tokens is empty - Frontend: shared getAuthHeaders()/hasCredentials() helpers replace scattered token logic across all JS modules - Health endpoint exposes auth_required for frontend discovery - config.example.yaml ships with tokens commented out - CLI --show-token and startup log reflect disabled state Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
import {
|
||||
t, showToast, escapeHtml, closeDialog,
|
||||
SEARCH_DEBOUNCE_MS, EMPTY_SVG_FILE, EMPTY_SVG_FOLDER, emptyStateHtml,
|
||||
getAuthHeaders, hasCredentials,
|
||||
} from './core.js';
|
||||
|
||||
// Browser state
|
||||
@@ -24,14 +25,10 @@ const THUMBNAIL_CACHE_MAX = 200;
|
||||
// Load media folders on page load
|
||||
export async function loadMediaFolders() {
|
||||
try {
|
||||
const token = localStorage.getItem('media_server_token');
|
||||
if (!token) {
|
||||
console.error('No API token found');
|
||||
return;
|
||||
}
|
||||
if (!hasCredentials()) return;
|
||||
|
||||
const response = await fetch('/api/browser/folders', {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
headers: getAuthHeaders()
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Failed to load folders');
|
||||
@@ -119,11 +116,7 @@ async function browsePath(folderId, path, offset = 0, nocache = false) {
|
||||
showBrowserSearch(false);
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('media_server_token');
|
||||
if (!token) {
|
||||
console.error('No API token found');
|
||||
return;
|
||||
}
|
||||
if (!hasCredentials()) return;
|
||||
|
||||
// Show loading spinner
|
||||
const container = document.getElementById('browserGrid');
|
||||
@@ -135,7 +128,7 @@ async function browsePath(folderId, path, offset = 0, nocache = false) {
|
||||
if (nocache) url += '&nocache=true';
|
||||
const response = await fetch(
|
||||
url,
|
||||
{ headers: { 'Authorization': `Bearer ${token}` } }
|
||||
{ headers: getAuthHeaders() }
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -487,11 +480,7 @@ function formatBitrate(bps) {
|
||||
|
||||
async function loadThumbnail(imgElement, fileName) {
|
||||
try {
|
||||
const token = localStorage.getItem('media_server_token');
|
||||
if (!token) {
|
||||
console.error('No API token found');
|
||||
return;
|
||||
}
|
||||
if (!hasCredentials()) return;
|
||||
|
||||
const absolutePath = buildAbsolutePath(currentFolderId, currentPath, fileName);
|
||||
|
||||
@@ -510,7 +499,7 @@ async function loadThumbnail(imgElement, fileName) {
|
||||
|
||||
const response = await fetch(
|
||||
`/api/browser/thumbnail?path=${encodedPath}&size=medium`,
|
||||
{ headers: { 'Authorization': `Bearer ${token}` } }
|
||||
{ headers: getAuthHeaders() }
|
||||
);
|
||||
|
||||
if (response.status === 200) {
|
||||
@@ -576,20 +565,13 @@ async function playMediaFile(fileName) {
|
||||
if (playInProgress) return;
|
||||
playInProgress = true;
|
||||
try {
|
||||
const token = localStorage.getItem('media_server_token');
|
||||
if (!token) {
|
||||
console.error('No API token found');
|
||||
return;
|
||||
}
|
||||
if (!hasCredentials()) return;
|
||||
|
||||
const absolutePath = buildAbsolutePath(currentFolderId, currentPath, fileName);
|
||||
|
||||
const response = await fetch('/api/browser/play', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
headers: { 'Content-Type': 'application/json', ...getAuthHeaders() },
|
||||
body: JSON.stringify({ path: absolutePath })
|
||||
});
|
||||
|
||||
@@ -610,15 +592,11 @@ export async function playAllFolder() {
|
||||
const btn = document.getElementById('playAllBtn');
|
||||
if (btn) btn.disabled = true;
|
||||
try {
|
||||
const token = localStorage.getItem('media_server_token');
|
||||
if (!token || !currentFolderId) return;
|
||||
if (!hasCredentials() || !currentFolderId) return;
|
||||
|
||||
const response = await fetch('/api/browser/play-folder', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
headers: { 'Content-Type': 'application/json', ...getAuthHeaders() },
|
||||
body: JSON.stringify({ folder_id: currentFolderId, path: currentPath })
|
||||
});
|
||||
|
||||
@@ -640,8 +618,7 @@ export async function playAllFolder() {
|
||||
|
||||
export async function downloadFile(fileName, event) {
|
||||
if (event) event.stopPropagation();
|
||||
const token = localStorage.getItem('media_server_token');
|
||||
if (!token) return;
|
||||
if (!hasCredentials()) return;
|
||||
|
||||
const fullPath = currentPath === '/'
|
||||
? '/' + fileName
|
||||
@@ -651,7 +628,7 @@ export async function downloadFile(fileName, event) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/browser/download?folder_id=${currentFolderId}&path=${encodedPath}`,
|
||||
{ headers: { 'Authorization': `Bearer ${token}` } }
|
||||
{ headers: getAuthHeaders() }
|
||||
);
|
||||
if (!response.ok) throw new Error('Download failed');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user