UNPKG

doclyft

Version:

CLI for DocLyft - Interactive documentation generator with hosted documentation support

127 lines (126 loc) 5.59 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateRepositoryName = validateRepositoryName; exports.validateGitHubToken = validateGitHubToken; exports.validateAPIKey = validateAPIKey; exports.validateFilePath = validateFilePath; exports.validateSections = validateSections; exports.validateOutputDirectory = validateOutputDirectory; const errors_1 = require("./errors"); const path_1 = require("path"); function validateRepositoryName(repo) { if (!repo || typeof repo !== 'string') { throw new errors_1.ValidationError('Repository name is required'); } if (!repo.includes('/')) { throw new errors_1.ValidationError('Repository must be in format owner/name (e.g., facebook/react)', 'repo'); } const parts = repo.split('/'); if (parts.length !== 2) { throw new errors_1.ValidationError('Repository must be in format owner/name (e.g., facebook/react)', 'repo'); } const [owner, name] = parts; // Validate owner and name format (GitHub rules) const validPattern = /^[a-zA-Z0-9._-]+$/; if (!validPattern.test(owner)) { throw new errors_1.ValidationError('Repository owner contains invalid characters. Only alphanumeric characters, dots, hyphens, and underscores are allowed.', 'owner'); } if (!validPattern.test(name)) { throw new errors_1.ValidationError('Repository name contains invalid characters. Only alphanumeric characters, dots, hyphens, and underscores are allowed.', 'name'); } if (owner.length === 0 || name.length === 0) { throw new errors_1.ValidationError('Both owner and repository name must be non-empty'); } if (owner.length > 39 || name.length > 100) { throw new errors_1.ValidationError('Repository owner or name is too long'); } return { owner, name }; } function validateGitHubToken(token) { if (!token || typeof token !== 'string') { throw new errors_1.ValidationError('GitHub token is required'); } // GitHub tokens should start with specific prefixes const validPrefixes = ['ghp_', 'gho_', 'ghu_', 'ghs_', 'ghr_', 'github_pat_']; const hasValidPrefix = validPrefixes.some(prefix => token.startsWith(prefix)); if (!hasValidPrefix) { throw new errors_1.ValidationError('Invalid GitHub token format. Make sure you\'re using a valid personal access token. Expected format: ghp_*, gho_*, ghu_*, ghs_*, ghr_*, or github_pat_*'); } if (token.length < 40) { throw new errors_1.ValidationError('GitHub token appears to be too short'); } } function validateAPIKey(apiKey) { if (!apiKey || typeof apiKey !== 'string') { throw new errors_1.ValidationError('API key is required'); } if (!apiKey.startsWith('dk_prod_')) { throw new errors_1.ValidationError('Invalid API key format. API keys should start with "dk_prod_"'); } if (apiKey.length < 30) { throw new errors_1.ValidationError('API key appears to be too short'); } } function validateFilePath(filePath) { if (!filePath || typeof filePath !== 'string') { throw new errors_1.ValidationError('File path is required'); } // Basic path validation const invalidChars = /[<>:"|?*]/; if (invalidChars.test(filePath)) { throw new errors_1.ValidationError('File path contains invalid characters'); } } function validateSections(sections) { if (!sections || typeof sections !== 'string') { throw new errors_1.ValidationError('Sections must be provided as a comma-separated string'); } const sectionList = sections.split(',').map(s => s.trim()).filter(s => s.length > 0); if (sectionList.length === 0) { throw new errors_1.ValidationError('At least one section must be specified'); } const validSections = [ 'overview', 'installation', 'usage', 'apiReference', 'testing', 'projectStructure', 'deployment', 'troubleshooting', 'contributing', 'changelog', 'license' ]; const invalidSections = sectionList.filter(section => !validSections.includes(section)); if (invalidSections.length > 0) { throw new errors_1.ValidationError(`Invalid sections: ${invalidSections.join(', ')}. Valid sections are: ${validSections.join(', ')}`); } return sectionList; } function validateOutputDirectory(outputDir) { if (!outputDir || typeof outputDir !== 'string') { throw new errors_1.ValidationError('Output directory is required'); } // Basic directory name validation const invalidChars = /[<>:"|?*]/; if (invalidChars.test(outputDir)) { throw new errors_1.ValidationError('Output directory contains invalid characters'); } // Enhanced path traversal protection const normalizedPath = (0, path_1.normalize)(outputDir); const resolvedPath = (0, path_1.resolve)(normalizedPath); const currentDir = process.cwd(); // Check for parent directory references in various forms if (normalizedPath.includes('..') || outputDir.includes('%2e%2e') || outputDir.includes('..\\') || outputDir.includes('../') || !resolvedPath.startsWith(currentDir)) { throw new errors_1.ValidationError('Output directory must be within current working directory'); } // Additional security checks if (outputDir.startsWith('/') || outputDir.startsWith('\\') || outputDir.match(/^[a-zA-Z]:/)) { throw new errors_1.ValidationError('Output directory must be a relative path'); } }