@@ -7,7 +7,6 @@ import axiosInstance from "@/libs/Middleware/axiosInstace";
77import { toast } from "@/components/ui/use-toast" ;
88import { useTranslator } from "@/hooks/use-translations" ;
99import { encryptDataField , decryptDataField } from "@/libs/encryption" ;
10- import { secureGetItem } from "@/libs/local-storage-utils" ;
1110
1211// Raw data structure from API
1312export interface PasswordHistoryItem {
@@ -25,80 +24,56 @@ export interface ProcessedPasswordHistoryItem extends Omit<PasswordHistoryItem,
2524 decryptSuccess : boolean ; // Whether decryption was successful
2625}
2726
27+ /**
28+ * Convert a base64 string to hex string
29+ * @param base64 Base64 encoded string
30+ * @returns Hex string
31+ */
32+ function base64ToHex ( base64 : string ) : string {
33+ // Decode base64 to binary string
34+ const binaryString = window . atob ( base64 ) ;
35+
36+ // Convert binary string to hex
37+ let hex = '' ;
38+ for ( let i = 0 ; i < binaryString . length ; i ++ ) {
39+ const charCode = binaryString . charCodeAt ( i ) ;
40+ // Convert each character to hex and ensure it's two digits
41+ const hexByte = charCode . toString ( 16 ) . padStart ( 2 , '0' ) ;
42+ hex += hexByte ;
43+ }
44+
45+ return hex ;
46+ }
47+
2848export function usePasswordHistory ( ) {
2949 const { translate } = useTranslator ( ) ;
3050 const [ isLoading , setIsLoading ] = useState ( false ) ;
3151 const [ passwordHistory , setPasswordHistory ] = useState < ProcessedPasswordHistoryItem [ ] > ( [ ] ) ;
3252 const userData = useSelector ( ( state : RootState ) => state . user . userData ) ;
3353
34- // Get workspaces from Redux store for project name lookup (like other hooks)
35- const workspaces = useSelector ( ( state : RootState ) => state . workspace . workspaces ) ;
36- const selectedProjectId = useSelector ( ( state : RootState ) => state . workspace . selectedProjectId ) ;
37- const selectedWorkspaceId = useSelector ( ( state : RootState ) => state . workspace . selectedWorkspaceId ) ;
54+ // Get static encryption key from env and convert it to hex
55+ const base64Key = process . env . NEXT_PUBLIC_INDEXED_DB_AES_KEY || "" ;
56+ // Remove any padding characters if present
57+ const cleanBase64Key = base64Key . replace ( / = + $ / , '' ) ;
58+ const encryptionKey = cleanBase64Key ? base64ToHex ( cleanBase64Key ) : "" ;
3859
39- const [ projectKey , setProjectKey ] = useState < string | null > ( null ) ;
40- const [ isProjectKeyLoading , setIsProjectKeyLoading ] = useState ( true ) ;
41-
42- // Load the project key when component mounts or project changes
43- useEffect ( ( ) => {
44- const loadProjectKey = async ( ) => {
45- setIsProjectKeyLoading ( true ) ;
46- if ( ! workspaces || ! selectedWorkspaceId || ! selectedProjectId ) {
47- console . log ( "Missing workspace or project information for key loading" ) ;
48- setProjectKey ( null ) ;
49- setIsProjectKeyLoading ( false ) ;
50- return ;
51- }
52-
53- try {
54- // Find the current project using workspaces from the component scope (like account management hook)
55- const currentProject = workspaces
56- . find ( ws => ws . workspaceId === selectedWorkspaceId )
57- ?. projects . find ( p => p . project_id === selectedProjectId ) ;
58-
59- if ( ! currentProject ) {
60- console . log ( "Project not found in workspaces for key loading" ) ;
61- setProjectKey ( null ) ;
62- setIsProjectKeyLoading ( false ) ;
63- return ;
64- }
65-
66- // Get the project's AES key from session storage (standard pattern)
67- const projectKeyName = `projectKey_${ currentProject . name } ` ;
68- console . log ( `Looking for project key with name: ${ projectKeyName } ` ) ;
69- const key = await secureGetItem ( projectKeyName ) ;
70-
71- console . log ( "Project key lookup result:" , {
72- projectName : currentProject . name ,
73- projectId : selectedProjectId ,
74- keyFound : ! ! key
75- } ) ;
76-
77- setProjectKey ( key ) ;
78- } catch ( error ) {
79- console . error ( "Error loading project key:" , error ) ;
80- setProjectKey ( null ) ;
81- } finally {
82- setIsProjectKeyLoading ( false ) ;
83- }
84- } ;
60+ // Helper function to attempt decryption with environment variable key
61+ const tryDecrypt = async ( encryptedData : string ) : Promise < { success : boolean ; data : string } > => {
62+ if ( ! encryptionKey ) {
63+ console . log ( "No encryption key available in environment variables" ) ;
64+ return { success : false , data : "**No Encryption Key**" } ;
65+ }
8566
86- loadProjectKey ( ) ;
87- } , [ workspaces , selectedWorkspaceId , selectedProjectId ] ) ;
88-
89- // Helper function to attempt decryption with various strategies
90- const tryDecrypt = async ( encryptedData : string , projectKey : string ) : Promise < { success : boolean ; data : string } > => {
9167 try {
9268 // If it looks like our encrypted format (contains a period separator for IV)
9369 if ( encryptedData . includes ( '.' ) ) {
94- const decryptedValue = await decryptDataField ( encryptedData , projectKey ) ;
70+ const decryptedValue = await decryptDataField ( encryptedData , encryptionKey ) ;
9571 return { success : true , data : decryptedValue } ;
9672 }
9773 // If it's not in encrypted format, return as is (plaintext)
9874 return { success : true , data : encryptedData } ;
9975 } catch ( error ) {
100- // Don't log the error as this is an expected scenario when switching between projects
101- // We're handling it by filtering out passwords that don't belong to the current project
76+ console . error ( "Decryption error:" , error ) ;
10277 return { success : false , data : "**Decryption Error**" } ;
10378 }
10479 } ;
@@ -120,42 +95,19 @@ export function usePasswordHistory() {
12095 new Date ( b . created_at ) . getTime ( ) - new Date ( a . created_at ) . getTime ( )
12196 ) ;
12297
123- // Process items - decrypt the data field if we have project key
124- let processedItems : ProcessedPasswordHistoryItem [ ] = [ ] ;
125-
126- if ( projectKey ) {
127- console . log ( "Project key available, attempting to decrypt items" ) ;
128- const decryptResults = await Promise . all (
129- historyItems . map ( async ( item ) => {
130- const decryptResult = await tryDecrypt ( item . data , projectKey ) ;
131-
132- return {
133- ...item ,
134- data : decryptResult . data ,
135- encryptedData : item . data ,
136- decryptSuccess : decryptResult . success
137- } ;
138- } )
139- ) ;
140-
141- // Filter to only include successfully decrypted items for this project
142- processedItems = decryptResults . filter ( item => item . decryptSuccess ) ;
143-
144- // Only log how many items were filtered (not as an error)
145- const excluded = historyItems . length - processedItems . length ;
146- if ( excluded > 0 ) {
147- console . log ( `Filtered out ${ excluded } password(s) that don't belong to the current project context.` ) ;
148- }
149- } else {
150- console . log ( "No project key available, marking items as encrypted" ) ;
151- // If no project key, just mark data as encrypted
152- processedItems = historyItems . map ( item => ( {
153- ...item ,
154- data : "**Encrypted**" ,
155- encryptedData : item . data ,
156- decryptSuccess : false
157- } ) ) ;
158- }
98+ // Process items - decrypt the data field with env key
99+ const processedItems = await Promise . all (
100+ historyItems . map ( async ( item ) => {
101+ const decryptResult = await tryDecrypt ( item . data ) ;
102+
103+ return {
104+ ...item ,
105+ data : decryptResult . data ,
106+ encryptedData : item . data ,
107+ decryptSuccess : decryptResult . success
108+ } ;
109+ } )
110+ ) ;
159111
160112 // Limit to the last 10 items (they're already sorted by creation date)
161113 setPasswordHistory ( processedItems . slice ( 0 , 10 ) ) ;
@@ -177,7 +129,7 @@ export function usePasswordHistory() {
177129 } finally {
178130 setIsLoading ( false ) ;
179131 }
180- } , [ translate , projectKey ] ) ;
132+ } , [ translate , encryptionKey ] ) ;
181133
182134 // Save password to history
183135 const savePasswordToHistory = useCallback ( async ( password : string ) : Promise < void > => {
@@ -189,11 +141,11 @@ export function usePasswordHistory() {
189141 try {
190142 let dataToSave : string ;
191143
192- if ( projectKey ) {
193- console . log ( "Encrypting password before saving (project key available )" ) ;
194- dataToSave = await encryptDataField ( password , projectKey ) ;
144+ if ( encryptionKey ) {
145+ console . log ( "Encrypting password before saving (using environment variable key )" ) ;
146+ dataToSave = await encryptDataField ( password , encryptionKey ) ;
195147 } else {
196- console . log ( "No project key available at save time , saving password without encryption" ) ;
148+ console . log ( "No encryption key available in environment variables , saving password without encryption" ) ;
197149 dataToSave = password ;
198150 }
199151
@@ -212,13 +164,11 @@ export function usePasswordHistory() {
212164 } ) ;
213165 throw error ;
214166 }
215- } , [ projectKey , translate ] ) ;
167+ } , [ translate , encryptionKey ] ) ;
216168
217169 return {
218170 passwordHistory,
219171 isLoading,
220- isProjectKeyLoading,
221- projectKey,
222172 fetchPasswordHistory,
223173 savePasswordToHistory
224174 } ;
0 commit comments