Skip to content

Commit a58149c

Browse files
committed
move corrupted cache cleanup from SecretStorage to WorkOsAuthProvider
1 parent a68b804 commit a58149c

File tree

2 files changed

+51
-64
lines changed

2 files changed

+51
-64
lines changed

extensions/vscode/src/stubs/SecretStorage.ts

Lines changed: 39 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -59,50 +59,39 @@ export class SecretStorage {
5959
}
6060

6161
async decrypt(filePath: string): Promise<string> {
62-
try {
63-
const key = await this.getOrCreateEncryptionKey();
64-
const data = fs.readFileSync(filePath);
65-
66-
// Validate minimum data size to detect corruption early
67-
const minSize = this.saltLength + this.ivLength + this.tagLength;
68-
if (data.length < minSize) {
69-
throw new Error(
70-
`Corrupted cache file: insufficient data (${data.length} bytes, expected at least ${minSize})`,
71-
);
72-
}
73-
74-
const salt = data.subarray(0, this.saltLength);
75-
const iv = data.subarray(
76-
this.saltLength,
77-
this.saltLength + this.ivLength,
78-
);
79-
const tag = data.subarray(
80-
this.saltLength + this.ivLength,
81-
this.saltLength + this.ivLength + this.tagLength,
82-
);
83-
const encrypted = data.subarray(
84-
this.saltLength + this.ivLength + this.tagLength,
85-
);
62+
const key = await this.getOrCreateEncryptionKey();
63+
const data = fs.readFileSync(filePath);
8664

87-
const decipher: crypto.DecipherGCM = crypto.createDecipheriv(
88-
this.algorithm,
89-
key,
90-
iv,
91-
) as crypto.DecipherGCM;
92-
decipher.setAuthTag(tag);
93-
94-
const decrypted = Buffer.concat([
95-
decipher.update(encrypted),
96-
decipher.final(),
97-
]);
98-
return decrypted.toString("utf8");
99-
} catch (error: any) {
100-
// Log the error with context for debugging
101-
console.error(`Failed to decrypt cache file ${filePath}:`, error.message);
65+
// Validate minimum data size to detect corruption early
66+
const minSize = this.saltLength + this.ivLength + this.tagLength;
67+
if (data.length < minSize) {
10268
throw new Error(
103-
`Cache decryption failed: ${error.message}. The cache file may be corrupted.`,
69+
`Corrupted cache file: insufficient data (${data.length} bytes, expected at least ${minSize})`,
10470
);
10571
}
72+
73+
const salt = data.subarray(0, this.saltLength);
74+
const iv = data.subarray(this.saltLength, this.saltLength + this.ivLength);
75+
const tag = data.subarray(
76+
this.saltLength + this.ivLength,
77+
this.saltLength + this.ivLength + this.tagLength,
78+
);
79+
const encrypted = data.subarray(
80+
this.saltLength + this.ivLength + this.tagLength,
81+
);
82+
83+
const decipher: crypto.DecipherGCM = crypto.createDecipheriv(
84+
this.algorithm,
85+
key,
86+
iv,
87+
) as crypto.DecipherGCM;
88+
decipher.setAuthTag(tag);
89+
90+
const decrypted = Buffer.concat([
91+
decipher.update(encrypted),
92+
decipher.final(),
93+
]);
94+
return decrypted.toString("utf8");
10695
}
10796

10897
private keyToFilepath(key: string): string {
@@ -119,31 +108,17 @@ export class SecretStorage {
119108
async get(key: string): Promise<string | undefined> {
120109
const filePath = this.keyToFilepath(key);
121110
if (fs.existsSync(filePath)) {
122-
try {
123-
const value = await this.decrypt(filePath);
124-
return value;
125-
} catch (error: any) {
126-
// Corrupted cache file - delete it and return undefined
127-
// This allows the auth flow to continue with a fresh start
128-
console.error(
129-
`Corrupted cache file detected for key "${key}". Deleting file and returning undefined.`,
130-
error.message,
131-
);
132-
133-
try {
134-
fs.unlinkSync(filePath);
135-
console.log(`Successfully deleted corrupted cache file: ${filePath}`);
136-
} catch (deleteError: any) {
137-
console.error(
138-
`Failed to delete corrupted cache file ${filePath}:`,
139-
deleteError.message,
140-
);
141-
}
142-
143-
// Return undefined to signal missing data (same as if file didn't exist)
144-
return undefined;
145-
}
111+
const value = await this.decrypt(filePath);
112+
return value;
146113
}
147114
return undefined;
148115
}
116+
117+
async delete(key: string): Promise<void> {
118+
const filePath = this.keyToFilepath(key);
119+
if (fs.existsSync(filePath)) {
120+
fs.unlinkSync(filePath);
121+
console.log(`Successfully deleted cache file: ${filePath}`);
122+
}
123+
}
149124
}

extensions/vscode/src/stubs/WorkOsAuthProvider.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,18 @@ export class WorkOsAuthProvider implements AuthenticationProvider, Disposable {
177177
});
178178

179179
console.warn(`Error retrieving or parsing sessions: ${e.message}`);
180+
181+
// Delete the corrupted cache file to allow fresh start on next attempt
182+
// This handles cases where decryption succeeded but JSON parsing failed
183+
try {
184+
await this.secretStorage.delete(SESSIONS_SECRET_KEY);
185+
} catch (deleteError: any) {
186+
console.error(
187+
`Failed to delete corrupted sessions cache:`,
188+
deleteError.message,
189+
);
190+
}
191+
180192
return [];
181193
}
182194
}

0 commit comments

Comments
 (0)