andrew-dataverse-mcp
Version:
A Model Context Protocol server for Microsoft Dataverse with comprehensive CRUD operations
107 lines (106 loc) • 3.43 kB
JavaScript
import { createLogger } from './logger.js';
const logger = createLogger('Validation');
/**
* Validates that a value is a non-empty string
*/
export function validateRequiredString(value, fieldName) {
if (typeof value !== 'string' || value.trim() === '') {
throw new Error(`${fieldName} is required and must be a non-empty string`);
}
return value.trim();
}
/**
* Validates that a value is a valid GUID
*/
export function validateGuid(value, fieldName) {
const guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
const stringValue = validateRequiredString(value, fieldName);
if (!guidRegex.test(stringValue)) {
throw new Error(`${fieldName} must be a valid GUID format (e.g., 12345678-1234-1234-1234-123456789012)`);
}
return stringValue;
}
/**
* Validates that a value is a positive integer
*/
export function validatePositiveInteger(value, fieldName) {
const numValue = Number(value);
if (!Number.isInteger(numValue) || numValue <= 0) {
throw new Error(`${fieldName} must be a positive integer`);
}
return numValue;
}
/**
* Validates that a value is a non-negative integer
*/
export function validateNonNegativeInteger(value, fieldName) {
const numValue = Number(value);
if (!Number.isInteger(numValue) || numValue < 0) {
throw new Error(`${fieldName} must be a non-negative integer`);
}
return numValue;
}
/**
* Validates that a table name is valid (alphanumeric, underscores, no spaces)
*/
export function validateTableName(value, fieldName = 'table') {
const stringValue = validateRequiredString(value, fieldName);
const tableNameRegex = /^[a-zA-Z][a-zA-Z0-9_]*$/;
if (!tableNameRegex.test(stringValue)) {
throw new Error(`${fieldName} must be a valid table name (start with letter, contain only letters, numbers, and underscores)`);
}
return stringValue;
}
/**
* Validates OData query parameters
*/
export function validateODataQuery(query, paramName) {
const trimmedQuery = query.trim();
if (trimmedQuery === '') {
throw new Error(`${paramName} cannot be empty`);
}
// Basic validation - check for potentially dangerous patterns
const dangerousPatterns = [
/drop\s+table/i,
/delete\s+from/i,
/update\s+.*\s+set/i,
/insert\s+into/i,
/<script/i,
/javascript:/i,
];
for (const pattern of dangerousPatterns) {
if (pattern.test(trimmedQuery)) {
logger.warn(`Potentially dangerous pattern detected in ${paramName}: ${trimmedQuery}`);
throw new Error(`${paramName} contains potentially unsafe content`);
}
}
return trimmedQuery;
}
/**
* Validates that an object is not null or undefined
*/
export function validateRequired(value, fieldName) {
if (value === null || value === undefined) {
throw new Error(`${fieldName} is required`);
}
return value;
}
/**
* Validates that a URL is properly formatted
*/
export function validateUrl(value, fieldName) {
const stringValue = validateRequiredString(value, fieldName);
try {
new URL(stringValue);
return stringValue;
}
catch {
throw new Error(`${fieldName} must be a valid URL`);
}
}
/**
* Sanitizes a string for use in OData queries
*/
export function sanitizeODataString(value) {
return value.replace(/'/g, "''");
}