mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-21 21:15:09 +00:00
feat: zero-config auth — keys optional, localhost is admin
Multi mode now allows unauthenticated requests as "anonymous". Keys are optional: provide one for per-key usage tracking, or skip it for zero-config access. Invalid keys are still rejected. Localhost requests are always admin-level (can manage keys, view dashboard data, etc.) without any token. This makes OCP much friendlier for home LAN setups — family members can use it immediately without any key configuration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+37
-20
@@ -1046,11 +1046,26 @@ const server = createServer(async (req, res) => {
|
|||||||
let authKeyName = isLocalhost ? "local" : "remote";
|
let authKeyName = isLocalhost ? "local" : "remote";
|
||||||
let authKeyId = null;
|
let authKeyId = null;
|
||||||
|
|
||||||
if (!isPublicEndpoint && !isLocalhost) {
|
if (!isPublicEndpoint) {
|
||||||
const auth = req.headers["authorization"] || "";
|
const auth = req.headers["authorization"] || "";
|
||||||
const token = auth.startsWith("Bearer ") ? auth.slice(7) : "";
|
const token = auth.startsWith("Bearer ") ? auth.slice(7) : "";
|
||||||
|
|
||||||
if (AUTH_MODE === "shared") {
|
if (isLocalhost) {
|
||||||
|
// Localhost always allowed — try to identify key if provided, but never reject
|
||||||
|
if (token) {
|
||||||
|
if (ADMIN_KEY) {
|
||||||
|
const adminBuf = Buffer.from(ADMIN_KEY);
|
||||||
|
const tokenBuf = Buffer.from(token);
|
||||||
|
if (adminBuf.length === tokenBuf.length && timingSafeEqual(adminBuf, tokenBuf)) {
|
||||||
|
authKeyName = "admin";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (authKeyName !== "admin") {
|
||||||
|
const keyInfo = validateKey(token);
|
||||||
|
if (keyInfo) { authKeyName = keyInfo.name; authKeyId = keyInfo.id; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (AUTH_MODE === "shared") {
|
||||||
if (PROXY_API_KEY) {
|
if (PROXY_API_KEY) {
|
||||||
const tokenBuf = Buffer.from(token);
|
const tokenBuf = Buffer.from(token);
|
||||||
const keyBuf = Buffer.from(PROXY_API_KEY);
|
const keyBuf = Buffer.from(PROXY_API_KEY);
|
||||||
@@ -1060,25 +1075,27 @@ const server = createServer(async (req, res) => {
|
|||||||
authKeyName = "shared";
|
authKeyName = "shared";
|
||||||
}
|
}
|
||||||
} else if (AUTH_MODE === "multi") {
|
} else if (AUTH_MODE === "multi") {
|
||||||
if (!token) {
|
// If a token is provided, validate it; if not, allow as anonymous
|
||||||
return jsonResponse(res, 401, { error: { message: "Unauthorized: Bearer token required", type: "auth_error" } });
|
if (token) {
|
||||||
}
|
let isAdminToken = false;
|
||||||
let isAdminToken = false;
|
if (ADMIN_KEY) {
|
||||||
if (ADMIN_KEY) {
|
const adminBuf = Buffer.from(ADMIN_KEY);
|
||||||
const adminBuf = Buffer.from(ADMIN_KEY);
|
const tokenBuf2 = Buffer.from(token);
|
||||||
const tokenBuf2 = Buffer.from(token);
|
if (adminBuf.length === tokenBuf2.length && timingSafeEqual(adminBuf, tokenBuf2)) {
|
||||||
if (adminBuf.length === tokenBuf2.length && timingSafeEqual(adminBuf, tokenBuf2)) {
|
authKeyName = "admin";
|
||||||
authKeyName = "admin";
|
isAdminToken = true;
|
||||||
isAdminToken = true;
|
}
|
||||||
}
|
}
|
||||||
}
|
if (!isAdminToken) {
|
||||||
if (!isAdminToken) {
|
const keyInfo = validateKey(token);
|
||||||
const keyInfo = validateKey(token);
|
if (!keyInfo) {
|
||||||
if (!keyInfo) {
|
return jsonResponse(res, 401, { error: { message: "Unauthorized: invalid or revoked API key", type: "auth_error" } });
|
||||||
return jsonResponse(res, 401, { error: { message: "Unauthorized: invalid or revoked API key", type: "auth_error" } });
|
}
|
||||||
|
authKeyName = keyInfo.name;
|
||||||
|
authKeyId = keyInfo.id;
|
||||||
}
|
}
|
||||||
authKeyName = keyInfo.name;
|
} else {
|
||||||
authKeyId = keyInfo.id;
|
authKeyName = "anonymous";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1182,7 +1199,7 @@ const server = createServer(async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Key management API ──
|
// ── Key management API ──
|
||||||
const isAdmin = AUTH_MODE !== "multi" || authKeyName === "admin";
|
const isAdmin = AUTH_MODE !== "multi" || authKeyName === "admin" || isLocalhost;
|
||||||
|
|
||||||
if (req.url === "/api/keys" && req.method === "POST") {
|
if (req.url === "/api/keys" && req.method === "POST") {
|
||||||
if (!isAdmin) return jsonResponse(res, 403, { error: "Admin access required" });
|
if (!isAdmin) return jsonResponse(res, 403, { error: "Admin access required" });
|
||||||
|
|||||||
Reference in New Issue
Block a user