mirror of
https://github.com/gethomepage/homepage.git
synced 2026-09-27 06:21:18 -07:00
Fix: enforce MCP token length too
This commit is contained in:
@@ -12,6 +12,8 @@ const SERVER_INFO = {
|
||||
version: "1.0.0",
|
||||
};
|
||||
|
||||
const MIN_TOKEN_LENGTH = 32;
|
||||
|
||||
const CONFIG_FILES = [
|
||||
"settings.yaml",
|
||||
"services.yaml",
|
||||
@@ -442,9 +444,18 @@ export function mcpEnabled() {
|
||||
return enabled();
|
||||
}
|
||||
|
||||
export function mcpTokenConfigError() {
|
||||
if (!enabled()) return null;
|
||||
const token = requiredToken();
|
||||
if (token && token.length < MIN_TOKEN_LENGTH) {
|
||||
return `HOMEPAGE_MCP_TOKEN must be at least ${MIN_TOKEN_LENGTH} characters. Generate one with: openssl rand -base64 32`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function mcpTokenAuthorized(req) {
|
||||
const token = requiredToken();
|
||||
if (!token) return false;
|
||||
if (!token || token.length < MIN_TOKEN_LENGTH) return false;
|
||||
|
||||
const authHeader = req.headers.authorization;
|
||||
const bearerToken = typeof authHeader === "string" && authHeader.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
||||
|
||||
@@ -622,13 +622,44 @@ describe("utils/mcp/homepage-mcp", () => {
|
||||
|
||||
expect(mod.mcpTokenAuthorized({ headers: {} })).toBe(false);
|
||||
|
||||
process.env.HOMEPAGE_MCP_TOKEN = "secret";
|
||||
expect(mod.mcpTokenAuthorized({ headers: { authorization: "Bearer secret" } })).toBe(true);
|
||||
expect(mod.mcpTokenAuthorized({ headers: { "x-homepage-mcp-token": "secret" } })).toBe(true);
|
||||
const token = "mcp-tok-0123456789abcdefghijklmnopqrstuv"; // 40 chars
|
||||
process.env.HOMEPAGE_MCP_TOKEN = token;
|
||||
expect(mod.mcpTokenAuthorized({ headers: { authorization: `Bearer ${token}` } })).toBe(true);
|
||||
expect(mod.mcpTokenAuthorized({ headers: { "x-homepage-mcp-token": token } })).toBe(true);
|
||||
expect(mod.mcpTokenAuthorized({ headers: { authorization: "Bearer wrong" } })).toBe(false);
|
||||
|
||||
process.env.HOMEPAGE_MCP_TOKEN = "é";
|
||||
// multibyte token at the minimum length still authorizes and doesn't throw on byte-length mismatch
|
||||
const multibyteToken = "é".repeat(32);
|
||||
process.env.HOMEPAGE_MCP_TOKEN = multibyteToken;
|
||||
expect(mod.mcpTokenAuthorized({ headers: { authorization: "Bearer a" } })).toBe(false);
|
||||
expect(mod.mcpTokenAuthorized({ headers: { authorization: "Bearer é" } })).toBe(true);
|
||||
expect(mod.mcpTokenAuthorized({ headers: { authorization: `Bearer ${multibyteToken}` } })).toBe(true);
|
||||
});
|
||||
|
||||
it("never authorizes a token below the minimum length, even when presented verbatim", async () => {
|
||||
const mod = await loadMcpWithConfigDir(mkdtempSync(path.join(tmpdir(), "homepage-mcp-test-")));
|
||||
|
||||
process.env.HOMEPAGE_MCP_TOKEN = "change-me";
|
||||
expect(mod.mcpTokenAuthorized({ headers: { authorization: "Bearer change-me" } })).toBe(false);
|
||||
expect(mod.mcpTokenAuthorized({ headers: { "x-homepage-mcp-token": "change-me" } })).toBe(false);
|
||||
});
|
||||
|
||||
it("reports a config error only when MCP is enabled with a too-short token", async () => {
|
||||
const mod = await loadMcpWithConfigDir(mkdtempSync(path.join(tmpdir(), "homepage-mcp-test-")));
|
||||
|
||||
process.env.HOMEPAGE_MCP_ENABLED = "true";
|
||||
process.env.HOMEPAGE_MCP_TOKEN = "change-me";
|
||||
expect(mod.mcpTokenConfigError()).toMatch(/at least 32 characters/i);
|
||||
|
||||
process.env.HOMEPAGE_MCP_TOKEN = "mcp-tok-0123456789abcdefghijklmnopqrstuv";
|
||||
expect(mod.mcpTokenConfigError()).toBeNull();
|
||||
|
||||
// no token configured is valid (session-only mode), so it is not an error
|
||||
delete process.env.HOMEPAGE_MCP_TOKEN;
|
||||
expect(mod.mcpTokenConfigError()).toBeNull();
|
||||
|
||||
// a weak token is ignored entirely when MCP is disabled
|
||||
process.env.HOMEPAGE_MCP_ENABLED = "false";
|
||||
process.env.HOMEPAGE_MCP_TOKEN = "change-me";
|
||||
expect(mod.mcpTokenConfigError()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user