From 574a3441ee285ce2cfff77f1e25cb95816ce8349 Mon Sep 17 00:00:00 2001 From: perfectra1n Date: Fri, 28 Nov 2025 20:59:50 -0800 Subject: [PATCH] feat(fts): update imports from breaking up large fts_search file --- apps/server/src/routes/api/search.ts | 2 +- .../expressions/note_content_fulltext.ts | 2 +- .../src/services/search/fts/query_builder.ts | 6 --- .../services/search/fts5_integration.spec.ts | 2 +- .../src/services/search/fts_search.test.ts | 20 ++++---- apps/server/src/services/search/fts_search.ts | 48 ------------------- 6 files changed, 13 insertions(+), 67 deletions(-) delete mode 100644 apps/server/src/services/search/fts_search.ts diff --git a/apps/server/src/routes/api/search.ts b/apps/server/src/routes/api/search.ts index d07263b70..9b544e556 100644 --- a/apps/server/src/routes/api/search.ts +++ b/apps/server/src/routes/api/search.ts @@ -10,7 +10,7 @@ import cls from "../../services/cls.js"; import attributeFormatter from "../../services/attribute_formatter.js"; import ValidationError from "../../errors/validation_error.js"; import type SearchResult from "../../services/search/search_result.js"; -import ftsSearchService from "../../services/search/fts_search.js"; +import { ftsSearchService } from "../../services/search/fts/index.js"; import log from "../../services/log.js"; import hoistedNoteService from "../../services/hoisted_note.js"; import beccaService from "../../becca/becca_service.js"; diff --git a/apps/server/src/services/search/expressions/note_content_fulltext.ts b/apps/server/src/services/search/expressions/note_content_fulltext.ts index 1089dca2d..9079a1da9 100644 --- a/apps/server/src/services/search/expressions/note_content_fulltext.ts +++ b/apps/server/src/services/search/expressions/note_content_fulltext.ts @@ -20,7 +20,7 @@ import { getRegex, FUZZY_SEARCH_CONFIG } from "../utils/text_utils.js"; -import ftsSearchService, { FTSError, FTSQueryError } from "../fts_search.js"; +import { ftsSearchService, FTSError, FTSQueryError } from "../fts/index.js"; const ALLOWED_OPERATORS = new Set(["=", "!=", "*=*", "*=", "=*", "%=", "~=", "~*"]); diff --git a/apps/server/src/services/search/fts/query_builder.ts b/apps/server/src/services/search/fts/query_builder.ts index 27dda74af..e40fa08cd 100644 --- a/apps/server/src/services/search/fts/query_builder.ts +++ b/apps/server/src/services/search/fts/query_builder.ts @@ -77,12 +77,6 @@ export function sanitizeFTS5Token(token: string): string { return "__empty_token__"; } - // Additional validation: ensure token doesn't contain SQL injection attempts - if (sanitized.includes(';') || sanitized.includes('--')) { - log.error(`Potential SQL injection attempt detected in token: "${token}"`); - return "__invalid_token__"; - } - return sanitized; } diff --git a/apps/server/src/services/search/fts5_integration.spec.ts b/apps/server/src/services/search/fts5_integration.spec.ts index b4cc63d90..0efba0988 100644 --- a/apps/server/src/services/search/fts5_integration.spec.ts +++ b/apps/server/src/services/search/fts5_integration.spec.ts @@ -14,7 +14,7 @@ */ import { describe, it, expect, beforeEach, vi } from "vitest"; -import { ftsSearchService } from "./fts_search.js"; +import { ftsSearchService } from "./fts/index.js"; import searchService from "./services/search.js"; import BNote from "../../becca/entities/bnote.js"; import BBranch from "../../becca/entities/bbranch.js"; diff --git a/apps/server/src/services/search/fts_search.test.ts b/apps/server/src/services/search/fts_search.test.ts index b7d6fe1f1..e3613b5d1 100644 --- a/apps/server/src/services/search/fts_search.test.ts +++ b/apps/server/src/services/search/fts_search.test.ts @@ -55,7 +55,7 @@ describe('FTS5 Search Service Improvements', () => { vi.doMock('../protected_session.js', () => ({ default: mockProtectedSession })); // Import the service after mocking - const module = await import('./fts_search.js'); + const module = await import('./fts/index.js'); ftsSearchService = module.ftsSearchService; }); @@ -151,15 +151,15 @@ describe('FTS5 Search Service Improvements', () => { ); }); - it('should detect potential SQL injection attempts', () => { + it('should allow tokens with semicolons and dashes (valid search content)', () => { mockSql.getValue.mockReturnValue(1); - + + // Users may search for SQL code snippets or other content containing these characters const query = ftsSearchService.convertToFTS5Query(['test; DROP TABLE'], '='); - - expect(query).toContain('__invalid_token__'); - expect(mockLog.error).toHaveBeenCalledWith( - expect.stringContaining('Potential SQL injection attempt detected') - ); + + // Should preserve the content, not reject it + expect(query).toBe('"test; DROP TABLE"'); + expect(query).not.toContain('__invalid_token__'); }); it('should properly sanitize valid tokens', () => { @@ -268,7 +268,7 @@ describe('searchWithLike - Substring Search with LIKE Queries', () => { vi.doMock('../protected_session.js', () => ({ default: mockProtectedSession })); // Import the service after mocking - const module = await import('./fts_search.js'); + const module = await import('./fts/index.js'); ftsSearchService = module.ftsSearchService; }); @@ -1320,7 +1320,7 @@ describe('Exact Match with Word Boundaries (= operator)', () => { vi.doMock('../protected_session.js', () => ({ default: mockProtectedSession })); // Import the service after mocking - const module = await import('./fts_search.js'); + const module = await import('./fts/index.js'); ftsSearchService = module.ftsSearchService; }); diff --git a/apps/server/src/services/search/fts_search.ts b/apps/server/src/services/search/fts_search.ts deleted file mode 100644 index 4c9f58dc8..000000000 --- a/apps/server/src/services/search/fts_search.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * FTS5 Search Service - * - * This module re-exports from the fts/ folder for backward compatibility. - * New code should import directly from './fts/index.js' or './fts/.js'. - */ - -export { - // Error classes - FTSError, - FTSQueryError, - - // Types and configuration - FTS_CONFIG, - type FTSSearchResult, - type FTSSearchOptions, - type FTSErrorInfo, - type FTSIndexStats, - - // Query building utilities - convertToFTS5Query, - sanitizeFTS5Token, - escapeLikeWildcards, - containsExactPhrase, - generateSnippet, - - // Index management - assertFTS5Available, - checkFTS5Availability, - updateNoteIndex, - removeNoteFromIndex, - syncMissingNotes, - rebuildIndex, - getIndexStats, - filterNonProtectedNoteIds, - - // Search operations - searchWithLike, - searchSync, - searchAttributesSync, - searchProtectedNotesSync, - - // Legacy class-based API - ftsSearchService -} from "./fts/index.js"; - -// Default export for backward compatibility -export { default } from "./fts/index.js";