Skip to content

Commit 576952f

Browse files
committed
changed password history to use env aes key instead of project key
1 parent ad4f9fc commit 576952f

File tree

2 files changed

+54
-105
lines changed

2 files changed

+54
-105
lines changed

packages/frontend-web/components/generate-password-dialog.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,7 @@ export function GeneratePasswordDialog({ onClose }: GeneratePasswordDialogProps)
127127
passwordHistory,
128128
isLoading: isHistoryLoading,
129129
fetchPasswordHistory,
130-
savePasswordToHistory,
131-
isProjectKeyLoading
130+
savePasswordToHistory
132131
} = usePasswordHistory()
133132
const [selectedMode, setSelectedMode] = useState("strong")
134133
const [showHistory, setShowHistory] = useState(false)

packages/frontend-web/hooks/use-password-history.ts

Lines changed: 53 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import axiosInstance from "@/libs/Middleware/axiosInstace";
77
import { toast } from "@/components/ui/use-toast";
88
import { useTranslator } from "@/hooks/use-translations";
99
import { encryptDataField, decryptDataField } from "@/libs/encryption";
10-
import { secureGetItem } from "@/libs/local-storage-utils";
1110

1211
// Raw data structure from API
1312
export 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+
2848
export 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

Comments
 (0)