diff --git a/apps/browser-extension/src/utils/db/queries/FolderQueries.ts b/apps/browser-extension/src/utils/db/queries/FolderQueries.ts new file mode 100644 index 000000000..632760f07 --- /dev/null +++ b/apps/browser-extension/src/utils/db/queries/FolderQueries.ts @@ -0,0 +1,92 @@ +/** + * SQL query constants for Folder operations. + * Centralizes all folder-related queries to avoid duplication. + */ +export class FolderQueries { + /** + * Get all active folders. + */ + public static readonly GET_ALL = ` + SELECT Id, Name, ParentFolderId, Weight + FROM Folders + WHERE IsDeleted = 0 + ORDER BY Weight, Name`; + + /** + * Get folder by ID. + */ + public static readonly GET_BY_ID = ` + SELECT Id, Name, ParentFolderId + FROM Folders + WHERE Id = ? AND IsDeleted = 0`; + + /** + * Insert a new folder. + */ + public static readonly INSERT = ` + INSERT INTO Folders (Id, Name, ParentFolderId, Weight, IsDeleted, CreatedAt, UpdatedAt) + VALUES (?, ?, ?, 0, 0, ?, ?)`; + + /** + * Update folder name. + */ + public static readonly UPDATE_NAME = ` + UPDATE Folders + SET Name = ?, + UpdatedAt = ? + WHERE Id = ?`; + + /** + * Soft delete folder. + */ + public static readonly SOFT_DELETE = ` + UPDATE Folders + SET IsDeleted = 1, + UpdatedAt = ? + WHERE Id = ?`; + + /** + * Clear folder reference from items. + */ + public static readonly CLEAR_ITEMS_FOLDER = ` + UPDATE Items + SET FolderId = NULL, + UpdatedAt = ? + WHERE FolderId = ?`; + + /** + * Trash items in folder. + */ + public static readonly TRASH_ITEMS_IN_FOLDER = ` + UPDATE Items + SET DeletedAt = ?, + UpdatedAt = ?, + FolderId = NULL + WHERE FolderId = ? AND IsDeleted = 0 AND DeletedAt IS NULL`; + + /** + * Get all child folder IDs (direct children only). + */ + public static readonly GET_CHILD_FOLDER_IDS = ` + SELECT Id + FROM Folders + WHERE ParentFolderId = ? AND IsDeleted = 0`; + + /** + * Update parent folder for child folders. + */ + public static readonly UPDATE_PARENT_FOLDER = ` + UPDATE Folders + SET ParentFolderId = ?, + UpdatedAt = ? + WHERE ParentFolderId = ?`; + + /** + * Move item to folder. + */ + public static readonly MOVE_ITEM = ` + UPDATE Items + SET FolderId = ?, + UpdatedAt = ? + WHERE Id = ?`; +} diff --git a/apps/browser-extension/src/utils/db/queries/ItemQueries.ts b/apps/browser-extension/src/utils/db/queries/ItemQueries.ts index d0b4b06fb..3455daabf 100644 --- a/apps/browser-extension/src/utils/db/queries/ItemQueries.ts +++ b/apps/browser-extension/src/utils/db/queries/ItemQueries.ts @@ -265,6 +265,14 @@ export class ItemQueries { AND fv.IsDeleted = 0 AND i.IsDeleted = 0 AND i.DeletedAt IS NULL`; + + /** + * Get item-level fields for change detection during updates. + */ + public static readonly GET_ITEM_FIELDS = ` + SELECT Name, ItemType, FolderId, LogoId + FROM Items + WHERE Id = ?`; } /** @@ -408,3 +416,63 @@ export class FieldHistoryQueries { SET IsDeleted = 1, UpdatedAt = ? WHERE Id = ?`; } + +/** + * SQL query constants for TotpCode operations. + */ +export class TotpCodeQueries { + /** + * Get existing TOTP codes for an item. + */ + public static readonly GET_BY_ITEM_ID = ` + SELECT Id, Name, SecretKey + FROM TotpCodes + WHERE ItemId = ? AND IsDeleted = 0`; + + /** + * Insert a new TOTP code. + */ + public static readonly INSERT = ` + INSERT INTO TotpCodes (Id, Name, SecretKey, ItemId, CreatedAt, UpdatedAt, IsDeleted) + VALUES (?, ?, ?, ?, ?, ?, ?)`; + + /** + * Update an existing TOTP code. + */ + public static readonly UPDATE = ` + UPDATE TotpCodes + SET Name = ?, + SecretKey = ?, + UpdatedAt = ? + WHERE Id = ?`; + + /** + * Soft delete a TOTP code. + */ + public static readonly SOFT_DELETE = ` + UPDATE TotpCodes + SET IsDeleted = 1, + UpdatedAt = ? + WHERE Id = ?`; +} + +/** + * SQL query constants for Attachment operations. + */ +export class AttachmentQueries { + /** + * Insert a new attachment. + */ + public static readonly INSERT = ` + INSERT INTO Attachments (Id, Filename, Blob, ItemId, CreatedAt, UpdatedAt, IsDeleted) + VALUES (?, ?, ?, ?, ?, ?, ?)`; + + /** + * Soft delete an attachment. + */ + public static readonly SOFT_DELETE = ` + UPDATE Attachments + SET IsDeleted = 1, + UpdatedAt = ? + WHERE Id = ?`; +} diff --git a/apps/browser-extension/src/utils/db/queries/LogoQueries.ts b/apps/browser-extension/src/utils/db/queries/LogoQueries.ts new file mode 100644 index 000000000..2455cc0d9 --- /dev/null +++ b/apps/browser-extension/src/utils/db/queries/LogoQueries.ts @@ -0,0 +1,33 @@ +/** + * SQL query constants for Logo operations. + * Centralizes all logo-related queries to avoid duplication. + */ +export class LogoQueries { + /** + * Check if logo exists for source. + */ + public static readonly GET_ID_FOR_SOURCE = ` + SELECT Id FROM Logos + WHERE Source = ? AND IsDeleted = 0 + LIMIT 1`; + + /** + * Insert new logo. + */ + public static readonly INSERT = ` + INSERT INTO Logos (Id, Source, FileData, CreatedAt, UpdatedAt, IsDeleted) + VALUES (?, ?, ?, ?, ?, ?)`; + + /** + * Count items using a logo. + */ + public static readonly COUNT_USAGE = ` + SELECT COUNT(*) as count FROM Items + WHERE LogoId = ? AND IsDeleted = 0`; + + /** + * Hard delete logo. + */ + public static readonly HARD_DELETE = ` + DELETE FROM Logos WHERE Id = ?`; +} diff --git a/apps/browser-extension/src/utils/db/queries/PasskeyQueries.ts b/apps/browser-extension/src/utils/db/queries/PasskeyQueries.ts new file mode 100644 index 000000000..40c3b030c --- /dev/null +++ b/apps/browser-extension/src/utils/db/queries/PasskeyQueries.ts @@ -0,0 +1,155 @@ +import { FieldKey } from '@/utils/dist/core/models/vault'; + +/** + * SQL query constants for Passkey operations. + * Centralizes all passkey-related queries to avoid duplication. + */ +export class PasskeyQueries { + /** + * Base SELECT for passkeys with item information. + */ + public static readonly BASE_SELECT_WITH_ITEM = ` + SELECT + p.Id, + p.ItemId, + p.RpId, + p.UserHandle, + p.PublicKey, + p.PrivateKey, + p.DisplayName, + p.PrfKey, + p.AdditionalData, + p.CreatedAt, + p.UpdatedAt, + p.IsDeleted, + i.Name as ServiceName, + (SELECT fv.Value FROM FieldValues fv WHERE fv.ItemId = i.Id AND fv.FieldKey = '${FieldKey.LoginUsername}' AND fv.IsDeleted = 0 LIMIT 1) as Username + FROM Passkeys p + INNER JOIN Items i ON p.ItemId = i.Id`; + + /** + * Base SELECT for passkeys without item information. + */ + public static readonly BASE_SELECT = ` + SELECT + p.Id, + p.ItemId, + p.RpId, + p.UserHandle, + p.PublicKey, + p.PrivateKey, + p.DisplayName, + p.PrfKey, + p.AdditionalData, + p.CreatedAt, + p.UpdatedAt, + p.IsDeleted + FROM Passkeys p`; + + /** + * Get passkeys by relying party ID. + */ + public static readonly GET_BY_RP_ID = ` + SELECT + p.Id, + p.ItemId, + p.RpId, + p.UserHandle, + p.PublicKey, + p.PrivateKey, + p.DisplayName, + p.PrfKey, + p.AdditionalData, + p.CreatedAt, + p.UpdatedAt, + p.IsDeleted, + i.Name as ServiceName, + (SELECT fv.Value FROM FieldValues fv WHERE fv.ItemId = i.Id AND fv.FieldKey = '${FieldKey.LoginUsername}' AND fv.IsDeleted = 0 LIMIT 1) as Username + FROM Passkeys p + INNER JOIN Items i ON p.ItemId = i.Id + WHERE p.RpId = ? AND p.IsDeleted = 0 + AND i.IsDeleted = 0 AND i.DeletedAt IS NULL + ORDER BY p.CreatedAt DESC`; + + /** + * Get passkey by ID with item information. + */ + public static readonly GET_BY_ID_WITH_ITEM = ` + SELECT + p.Id, + p.ItemId, + p.RpId, + p.UserHandle, + p.PublicKey, + p.PrivateKey, + p.DisplayName, + p.PrfKey, + p.AdditionalData, + p.CreatedAt, + p.UpdatedAt, + p.IsDeleted, + i.Name as ServiceName, + (SELECT fv.Value FROM FieldValues fv WHERE fv.ItemId = i.Id AND fv.FieldKey = '${FieldKey.LoginUsername}' AND fv.IsDeleted = 0 LIMIT 1) as Username + FROM Passkeys p + INNER JOIN Items i ON p.ItemId = i.Id + WHERE p.Id = ? AND p.IsDeleted = 0 + AND i.IsDeleted = 0 AND i.DeletedAt IS NULL`; + + /** + * Get passkeys by item ID. + */ + public static readonly GET_BY_ITEM_ID = ` + SELECT + p.Id, + p.ItemId, + p.RpId, + p.UserHandle, + p.PublicKey, + p.PrivateKey, + p.DisplayName, + p.PrfKey, + p.AdditionalData, + p.CreatedAt, + p.UpdatedAt, + p.IsDeleted + FROM Passkeys p + WHERE p.ItemId = ? AND p.IsDeleted = 0 + ORDER BY p.CreatedAt DESC`; + + /** + * Insert a new passkey. + */ + public static readonly INSERT = ` + INSERT INTO Passkeys ( + Id, ItemId, RpId, UserHandle, PublicKey, PrivateKey, + PrfKey, DisplayName, AdditionalData, CreatedAt, UpdatedAt, IsDeleted + ) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`; + + /** + * Update passkey display name. + */ + public static readonly UPDATE_DISPLAY_NAME = ` + UPDATE Passkeys + SET DisplayName = ?, + UpdatedAt = ? + WHERE Id = ?`; + + /** + * Soft delete passkey by ID. + */ + public static readonly SOFT_DELETE = ` + UPDATE Passkeys + SET IsDeleted = 1, + UpdatedAt = ? + WHERE Id = ?`; + + /** + * Soft delete passkeys by item ID. + */ + public static readonly SOFT_DELETE_BY_ITEM = ` + UPDATE Passkeys + SET IsDeleted = 1, + UpdatedAt = ? + WHERE ItemId = ?`; +} diff --git a/apps/browser-extension/src/utils/db/queries/SettingsQueries.ts b/apps/browser-extension/src/utils/db/queries/SettingsQueries.ts new file mode 100644 index 000000000..d5ddcc59a --- /dev/null +++ b/apps/browser-extension/src/utils/db/queries/SettingsQueries.ts @@ -0,0 +1,74 @@ +/** + * SQL query constants for Settings operations. + * Centralizes all settings-related queries to avoid duplication. + */ +export class SettingsQueries { + /** + * Get setting by key. + */ + public static readonly GET_SETTING = ` + SELECT s.Value + FROM Settings s + WHERE s.Key = ?`; + + /** + * Check if a setting exists. + */ + public static readonly COUNT_BY_KEY = ` + SELECT COUNT(*) as count + FROM Settings + WHERE Key = ?`; + + /** + * Update an existing setting. + */ + public static readonly UPDATE_SETTING = ` + UPDATE Settings + SET Value = ?, + UpdatedAt = ? + WHERE Key = ?`; + + /** + * Insert a new setting. + */ + public static readonly INSERT_SETTING = ` + INSERT INTO Settings (Key, Value, CreatedAt, UpdatedAt, IsDeleted) + VALUES (?, ?, ?, ?, ?)`; + + /** + * Get all encryption keys. + */ + public static readonly GET_ENCRYPTION_KEYS = ` + SELECT + x.PublicKey, + x.PrivateKey, + x.IsPrimary + FROM EncryptionKeys x`; + + /** + * Get TOTP codes for an item. + */ + public static readonly GET_TOTP_FOR_ITEM = ` + SELECT + Id, + Name, + SecretKey, + ItemId + FROM TotpCodes + WHERE ItemId = ? AND IsDeleted = 0`; + + /** + * Get attachments for an item. + */ + public static readonly GET_ATTACHMENTS_FOR_ITEM = ` + SELECT + Id, + Filename, + Blob, + ItemId, + CreatedAt, + UpdatedAt, + IsDeleted + FROM Attachments + WHERE ItemId = ? AND IsDeleted = 0`; +} diff --git a/apps/browser-extension/src/utils/db/repositories/FolderRepository.ts b/apps/browser-extension/src/utils/db/repositories/FolderRepository.ts index b59ede8bf..8e47981dc 100644 --- a/apps/browser-extension/src/utils/db/repositories/FolderRepository.ts +++ b/apps/browser-extension/src/utils/db/repositories/FolderRepository.ts @@ -1,4 +1,5 @@ import { BaseRepository } from '../BaseRepository'; +import { FolderQueries } from '../queries/FolderQueries'; /** * Folder entity type. @@ -10,98 +11,6 @@ export type Folder = { Weight: number; } -/** - * SQL query constants for Folder operations. - */ -const FolderQueries = { - /** - * Get all active folders. - */ - GET_ALL: ` - SELECT Id, Name, ParentFolderId, Weight - FROM Folders - WHERE IsDeleted = 0 - ORDER BY Weight, Name`, - - /** - * Get folder by ID. - */ - GET_BY_ID: ` - SELECT Id, Name, ParentFolderId - FROM Folders - WHERE Id = ? AND IsDeleted = 0`, - - /** - * Insert a new folder. - */ - INSERT: ` - INSERT INTO Folders (Id, Name, ParentFolderId, Weight, IsDeleted, CreatedAt, UpdatedAt) - VALUES (?, ?, ?, 0, 0, ?, ?)`, - - /** - * Update folder name. - */ - UPDATE_NAME: ` - UPDATE Folders - SET Name = ?, - UpdatedAt = ? - WHERE Id = ?`, - - /** - * Soft delete folder. - */ - SOFT_DELETE: ` - UPDATE Folders - SET IsDeleted = 1, - UpdatedAt = ? - WHERE Id = ?`, - - /** - * Clear folder reference from items. - */ - CLEAR_ITEMS_FOLDER: ` - UPDATE Items - SET FolderId = NULL, - UpdatedAt = ? - WHERE FolderId = ?`, - - /** - * Trash items in folder. - */ - TRASH_ITEMS_IN_FOLDER: ` - UPDATE Items - SET DeletedAt = ?, - UpdatedAt = ?, - FolderId = NULL - WHERE FolderId = ? AND IsDeleted = 0 AND DeletedAt IS NULL`, - - /** - * Get all child folder IDs (direct children only). - */ - GET_CHILD_FOLDER_IDS: ` - SELECT Id - FROM Folders - WHERE ParentFolderId = ? AND IsDeleted = 0`, - - /** - * Update parent folder for child folders. - */ - UPDATE_PARENT_FOLDER: ` - UPDATE Folders - SET ParentFolderId = ?, - UpdatedAt = ? - WHERE ParentFolderId = ?`, - - /** - * Move item to folder. - */ - MOVE_ITEM: ` - UPDATE Items - SET FolderId = ?, - UpdatedAt = ? - WHERE Id = ?` -}; - /** * Repository for Folder CRUD operations. */ diff --git a/apps/browser-extension/src/utils/db/repositories/ItemRepository.ts b/apps/browser-extension/src/utils/db/repositories/ItemRepository.ts index 092f21d4e..6db7959f5 100644 --- a/apps/browser-extension/src/utils/db/repositories/ItemRepository.ts +++ b/apps/browser-extension/src/utils/db/repositories/ItemRepository.ts @@ -8,7 +8,9 @@ import { ItemQueries, FieldValueQueries, FieldDefinitionQueries, - FieldHistoryQueries + FieldHistoryQueries, + TotpCodeQueries, + AttachmentQueries } from '../queries/ItemQueries'; import type { LogoRepository } from './LogoRepository'; @@ -183,7 +185,7 @@ export class ItemRepository extends BaseRepository { ItemType: number; FolderId: string | null; LogoId: string | null; - }>(`SELECT Name, ItemType, FolderId, LogoId FROM Items WHERE Id = ?`, [item.Id])[0]; + }>(ItemQueries.GET_ITEM_FIELDS, [item.Id])[0]; if (existing) { const nameChanged = (item.Name ?? null) !== existing.Name; @@ -754,8 +756,7 @@ export class ItemRepository extends BaseRepository { private insertTotpCodes(itemId: string, totpCodes: TotpCode[], currentDateTime: string): void { for (const totpCode of totpCodes) { this.client.executeUpdate( - `INSERT INTO TotpCodes (Id, Name, SecretKey, ItemId, CreatedAt, UpdatedAt, IsDeleted) - VALUES (?, ?, ?, ?, ?, ?, ?)`, + TotpCodeQueries.INSERT, [ totpCode.Id || this.generateId(), totpCode.Name, @@ -783,7 +784,7 @@ export class ItemRepository extends BaseRepository { Id: string; Name: string; SecretKey: string; - }>(`SELECT Id, Name, SecretKey FROM TotpCodes WHERE ItemId = ? AND IsDeleted = 0`, [itemId]); + }>(TotpCodeQueries.GET_BY_ITEM_ID, [itemId]); const existingByIdMap = new Map(existingTotpCodes.map(tc => [tc.Id, tc])); @@ -793,7 +794,7 @@ export class ItemRepository extends BaseRepository { if (totpCode.IsDeleted) { if (wasOriginal) { this.client.executeUpdate( - `UPDATE TotpCodes SET IsDeleted = 1, UpdatedAt = ? WHERE Id = ?`, + TotpCodeQueries.SOFT_DELETE, [currentDateTime, totpCode.Id] ); } @@ -802,14 +803,13 @@ export class ItemRepository extends BaseRepository { const existing = existingByIdMap.get(totpCode.Id); if (existing && (existing.Name !== totpCode.Name || existing.SecretKey !== totpCode.SecretKey)) { this.client.executeUpdate( - `UPDATE TotpCodes SET Name = ?, SecretKey = ?, UpdatedAt = ? WHERE Id = ?`, + TotpCodeQueries.UPDATE, [totpCode.Name, totpCode.SecretKey, currentDateTime, totpCode.Id] ); } } else { this.client.executeUpdate( - `INSERT INTO TotpCodes (Id, Name, SecretKey, ItemId, CreatedAt, UpdatedAt, IsDeleted) - VALUES (?, ?, ?, ?, ?, ?, ?)`, + TotpCodeQueries.INSERT, [ totpCode.Id || this.generateId(), totpCode.Name, @@ -834,8 +834,7 @@ export class ItemRepository extends BaseRepository { : new Uint8Array(attachment.Blob); this.client.executeUpdate( - `INSERT INTO Attachments (Id, Filename, Blob, ItemId, CreatedAt, UpdatedAt, IsDeleted) - VALUES (?, ?, ?, ?, ?, ?, ?)`, + AttachmentQueries.INSERT, [ attachment.Id || this.generateId(), attachment.Filename, @@ -865,7 +864,7 @@ export class ItemRepository extends BaseRepository { for (const originalId of originalIds) { if (!currentAttachmentIds.has(originalId)) { this.client.executeUpdate( - `UPDATE Attachments SET IsDeleted = 1, UpdatedAt = ? WHERE Id = ?`, + AttachmentQueries.SOFT_DELETE, [currentDateTime, originalId] ); } @@ -878,7 +877,7 @@ export class ItemRepository extends BaseRepository { if (attachment.IsDeleted) { if (wasOriginal) { this.client.executeUpdate( - `UPDATE Attachments SET IsDeleted = 1, UpdatedAt = ? WHERE Id = ?`, + AttachmentQueries.SOFT_DELETE, [currentDateTime, attachment.Id] ); } @@ -888,8 +887,7 @@ export class ItemRepository extends BaseRepository { : new Uint8Array(attachment.Blob); this.client.executeUpdate( - `INSERT INTO Attachments (Id, Filename, Blob, ItemId, CreatedAt, UpdatedAt, IsDeleted) - VALUES (?, ?, ?, ?, ?, ?, ?)`, + AttachmentQueries.INSERT, [ attachment.Id || this.generateId(), attachment.Filename, diff --git a/apps/browser-extension/src/utils/db/repositories/LogoRepository.ts b/apps/browser-extension/src/utils/db/repositories/LogoRepository.ts index 3fb91f94a..c2677c11d 100644 --- a/apps/browser-extension/src/utils/db/repositories/LogoRepository.ts +++ b/apps/browser-extension/src/utils/db/repositories/LogoRepository.ts @@ -1,37 +1,5 @@ import { BaseRepository } from '../BaseRepository'; - -/** - * SQL query constants for Logo operations. - */ -const LogoQueries = { - /** - * Check if logo exists for source. - */ - GET_ID_FOR_SOURCE: ` - SELECT Id FROM Logos - WHERE Source = ? AND IsDeleted = 0 - LIMIT 1`, - - /** - * Insert new logo. - */ - INSERT: ` - INSERT INTO Logos (Id, Source, FileData, CreatedAt, UpdatedAt, IsDeleted) - VALUES (?, ?, ?, ?, ?, ?)`, - - /** - * Count items using a logo. - */ - COUNT_USAGE: ` - SELECT COUNT(*) as count FROM Items - WHERE LogoId = ? AND IsDeleted = 0`, - - /** - * Hard delete logo. - */ - HARD_DELETE: ` - DELETE FROM Logos WHERE Id = ?` -}; +import { LogoQueries } from '../queries/LogoQueries'; /** * Repository for Logo management operations. diff --git a/apps/browser-extension/src/utils/db/repositories/PasskeyRepository.ts b/apps/browser-extension/src/utils/db/repositories/PasskeyRepository.ts index d26623963..1a1b121c4 100644 --- a/apps/browser-extension/src/utils/db/repositories/PasskeyRepository.ts +++ b/apps/browser-extension/src/utils/db/repositories/PasskeyRepository.ts @@ -1,161 +1,8 @@ import type { Passkey } from '@/utils/dist/core/models/vault'; -import { FieldKey } from '@/utils/dist/core/models/vault'; import { BaseRepository } from '../BaseRepository'; import { PasskeyMapper, type PasskeyRow, type PasskeyWithItemRow, type PasskeyWithItem } from '../mappers/PasskeyMapper'; - -/** - * SQL query constants for Passkey operations. - */ -const PasskeyQueries = { - /** - * Base SELECT for passkeys with item information. - */ - BASE_SELECT_WITH_ITEM: ` - SELECT - p.Id, - p.ItemId, - p.RpId, - p.UserHandle, - p.PublicKey, - p.PrivateKey, - p.DisplayName, - p.PrfKey, - p.AdditionalData, - p.CreatedAt, - p.UpdatedAt, - p.IsDeleted, - i.Name as ServiceName, - (SELECT fv.Value FROM FieldValues fv WHERE fv.ItemId = i.Id AND fv.FieldKey = '${FieldKey.LoginUsername}' AND fv.IsDeleted = 0 LIMIT 1) as Username - FROM Passkeys p - INNER JOIN Items i ON p.ItemId = i.Id`, - - /** - * Base SELECT for passkeys without item information. - */ - BASE_SELECT: ` - SELECT - p.Id, - p.ItemId, - p.RpId, - p.UserHandle, - p.PublicKey, - p.PrivateKey, - p.DisplayName, - p.PrfKey, - p.AdditionalData, - p.CreatedAt, - p.UpdatedAt, - p.IsDeleted - FROM Passkeys p`, - - /** - * Get passkeys by relying party ID. - */ - GET_BY_RP_ID: ` - SELECT - p.Id, - p.ItemId, - p.RpId, - p.UserHandle, - p.PublicKey, - p.PrivateKey, - p.DisplayName, - p.PrfKey, - p.AdditionalData, - p.CreatedAt, - p.UpdatedAt, - p.IsDeleted, - i.Name as ServiceName, - (SELECT fv.Value FROM FieldValues fv WHERE fv.ItemId = i.Id AND fv.FieldKey = '${FieldKey.LoginUsername}' AND fv.IsDeleted = 0 LIMIT 1) as Username - FROM Passkeys p - INNER JOIN Items i ON p.ItemId = i.Id - WHERE p.RpId = ? AND p.IsDeleted = 0 - AND i.IsDeleted = 0 AND i.DeletedAt IS NULL - ORDER BY p.CreatedAt DESC`, - - /** - * Get passkey by ID with item information. - */ - GET_BY_ID_WITH_ITEM: ` - SELECT - p.Id, - p.ItemId, - p.RpId, - p.UserHandle, - p.PublicKey, - p.PrivateKey, - p.DisplayName, - p.PrfKey, - p.AdditionalData, - p.CreatedAt, - p.UpdatedAt, - p.IsDeleted, - i.Name as ServiceName, - (SELECT fv.Value FROM FieldValues fv WHERE fv.ItemId = i.Id AND fv.FieldKey = '${FieldKey.LoginUsername}' AND fv.IsDeleted = 0 LIMIT 1) as Username - FROM Passkeys p - INNER JOIN Items i ON p.ItemId = i.Id - WHERE p.Id = ? AND p.IsDeleted = 0 - AND i.IsDeleted = 0 AND i.DeletedAt IS NULL`, - - /** - * Get passkeys by item ID. - */ - GET_BY_ITEM_ID: ` - SELECT - p.Id, - p.ItemId, - p.RpId, - p.UserHandle, - p.PublicKey, - p.PrivateKey, - p.DisplayName, - p.PrfKey, - p.AdditionalData, - p.CreatedAt, - p.UpdatedAt, - p.IsDeleted - FROM Passkeys p - WHERE p.ItemId = ? AND p.IsDeleted = 0 - ORDER BY p.CreatedAt DESC`, - - /** - * Insert a new passkey. - */ - INSERT: ` - INSERT INTO Passkeys ( - Id, ItemId, RpId, UserHandle, PublicKey, PrivateKey, - PrfKey, DisplayName, AdditionalData, CreatedAt, UpdatedAt, IsDeleted - ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - - /** - * Update passkey display name. - */ - UPDATE_DISPLAY_NAME: ` - UPDATE Passkeys - SET DisplayName = ?, - UpdatedAt = ? - WHERE Id = ?`, - - /** - * Soft delete passkey by ID. - */ - SOFT_DELETE: ` - UPDATE Passkeys - SET IsDeleted = 1, - UpdatedAt = ? - WHERE Id = ?`, - - /** - * Soft delete passkeys by item ID. - */ - SOFT_DELETE_BY_ITEM: ` - UPDATE Passkeys - SET IsDeleted = 1, - UpdatedAt = ? - WHERE ItemId = ?` -}; +import { PasskeyQueries } from '../queries/PasskeyQueries'; /** * Repository for Passkey CRUD operations. diff --git a/apps/browser-extension/src/utils/db/repositories/SettingsRepository.ts b/apps/browser-extension/src/utils/db/repositories/SettingsRepository.ts index 5c3ab799a..ee9be89d8 100644 --- a/apps/browser-extension/src/utils/db/repositories/SettingsRepository.ts +++ b/apps/browser-extension/src/utils/db/repositories/SettingsRepository.ts @@ -1,6 +1,7 @@ import type { EncryptionKey, PasswordSettings, TotpCode, Attachment } from '@/utils/dist/core/models/vault'; import { BaseRepository } from '../BaseRepository'; +import { SettingsQueries } from '../queries/SettingsQueries'; /** * Sort order options for credentials list. @@ -8,56 +9,6 @@ import { BaseRepository } from '../BaseRepository'; */ export type CredentialSortOrder = 'OldestFirst' | 'NewestFirst' | 'Alphabetical'; -/** - * SQL query constants for Settings and related operations. - */ -const SettingsQueries = { - /** - * Get setting by key. - */ - GET_SETTING: ` - SELECT s.Value - FROM Settings s - WHERE s.Key = ?`, - - /** - * Get all encryption keys. - */ - GET_ENCRYPTION_KEYS: ` - SELECT - x.PublicKey, - x.PrivateKey, - x.IsPrimary - FROM EncryptionKeys x`, - - /** - * Get TOTP codes for an item. - */ - GET_TOTP_FOR_ITEM: ` - SELECT - Id, - Name, - SecretKey, - ItemId - FROM TotpCodes - WHERE ItemId = ? AND IsDeleted = 0`, - - /** - * Get attachments for an item. - */ - GET_ATTACHMENTS_FOR_ITEM: ` - SELECT - Id, - Filename, - Blob, - ItemId, - CreatedAt, - UpdatedAt, - IsDeleted - FROM Attachments - WHERE ItemId = ? AND IsDeleted = 0` -}; - /** * Repository for Settings and auxiliary data operations. */ @@ -220,19 +171,19 @@ export class SettingsRepository extends BaseRepository { // Check if setting exists const results = this.client.executeQuery<{ count: number }>( - `SELECT COUNT(*) as count FROM Settings WHERE Key = ?`, + SettingsQueries.COUNT_BY_KEY, [key] ); const exists = results[0]?.count > 0; if (exists) { this.client.executeUpdate( - `UPDATE Settings SET Value = ?, UpdatedAt = ? WHERE Key = ?`, + SettingsQueries.UPDATE_SETTING, [value, now, key] ); } else { this.client.executeUpdate( - `INSERT INTO Settings (Key, Value, CreatedAt, UpdatedAt, IsDeleted) VALUES (?, ?, ?, ?, ?)`, + SettingsQueries.INSERT_SETTING, [key, value, now, now, 0] ); }