@@ -59,31 +59,50 @@ export class SecretStorage {
5959 }
6060
6161 async decrypt ( filePath : string ) : Promise < string > {
62- const key = await this . getOrCreateEncryptionKey ( ) ;
63- const data = fs . readFileSync ( filePath ) ;
64-
65- const salt = data . subarray ( 0 , this . saltLength ) ;
66- const iv = data . subarray ( this . saltLength , this . saltLength + this . ivLength ) ;
67- const tag = data . subarray (
68- this . saltLength + this . ivLength ,
69- this . saltLength + this . ivLength + this . tagLength ,
70- ) ;
71- const encrypted = data . subarray (
72- this . saltLength + this . ivLength + this . tagLength ,
73- ) ;
74-
75- const decipher : crypto . DecipherGCM = crypto . createDecipheriv (
76- this . algorithm ,
77- key ,
78- iv ,
79- ) as crypto . DecipherGCM ;
80- decipher . setAuthTag ( tag ) ;
81-
82- const decrypted = Buffer . concat ( [
83- decipher . update ( encrypted ) ,
84- decipher . final ( ) ,
85- ] ) ;
86- return decrypted . toString ( "utf8" ) ;
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+ ) ;
86+
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 ) ;
102+ throw new Error (
103+ `Cache decryption failed: ${ error . message } . The cache file may be corrupted.` ,
104+ ) ;
105+ }
87106 }
88107
89108 private keyToFilepath ( key : string ) : string {
@@ -100,8 +119,30 @@ export class SecretStorage {
100119 async get ( key : string ) : Promise < string | undefined > {
101120 const filePath = this . keyToFilepath ( key ) ;
102121 if ( fs . existsSync ( filePath ) ) {
103- const value = await this . decrypt ( filePath ) ;
104- return value ;
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+ }
105146 }
106147 return undefined ;
107148 }
0 commit comments