UNPKG

@ankimcp/anki-mcp-server

Version:

Model Context Protocol server for Anki - enables AI assistants to interact with your Anki flashcards

78 lines • 3.72 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var HostValidationGuard_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.HostValidationGuard = void 0; exports.shouldWarnLoopbackOnly = shouldWarnLoopbackOnly; const common_1 = require("@nestjs/common"); const config_1 = require("../../config/index.js"); const LOOPBACK_BIND_HOSTS = new Set(["localhost", "127.0.0.1", "::1"]); function shouldWarnLoopbackOnly(host, allowedHosts) { const normalized = host.trim().toLowerCase(); const isLoopbackBind = LOOPBACK_BIND_HOSTS.has(normalized); return !isLoopbackBind && allowedHosts.length === 0; } let HostValidationGuard = class HostValidationGuard { static { HostValidationGuard_1 = this; } logger = new common_1.Logger(HostValidationGuard_1.name); allowedHosts; static LOOPBACK_HOSTS = ["localhost", "127.0.0.1", "::1"]; constructor(config) { this.allowedHosts = new Set([ ...HostValidationGuard_1.LOOPBACK_HOSTS, ...config.allowedHosts.map((host) => HostValidationGuard_1.extractHostname(host)), ].filter((host) => host.length > 0)); } canActivate(context) { const request = context.switchToHttp().getRequest(); const hostHeader = request.headers.host; if (!hostHeader || hostHeader.trim().length === 0) { this.logger.warn("Rejected request with missing Host header (DNS-rebinding protection)"); return false; } const hostname = HostValidationGuard_1.extractHostname(hostHeader); if (this.allowedHosts.has(hostname)) { return true; } this.logger.warn(`Rejected request with disallowed Host header: "${hostHeader}". ` + `Allowed hosts are loopback by default; set ALLOWED_HOSTS ` + `(comma-separated hostnames) to permit additional hosts.`); return false; } static extractHostname(value) { const trimmed = value.trim().toLowerCase(); if (trimmed.length === 0) { return ""; } if (trimmed.startsWith("[")) { const closing = trimmed.indexOf("]"); if (closing !== -1) { return trimmed.slice(1, closing); } } const firstColon = trimmed.indexOf(":"); const lastColon = trimmed.lastIndexOf(":"); if (firstColon !== -1 && firstColon === lastColon) { return trimmed.slice(0, firstColon); } return trimmed; } }; exports.HostValidationGuard = HostValidationGuard; exports.HostValidationGuard = HostValidationGuard = HostValidationGuard_1 = __decorate([ (0, common_1.Injectable)(), __param(0, (0, common_1.Inject)(config_1.APP_CONFIG)), __metadata("design:paramtypes", [Object]) ], HostValidationGuard); //# sourceMappingURL=host-validation.guard.js.map