fix: Remove URL encoding from base64 strings before decoding

This commit is contained in:
Joachim Van Herwegen 2023-10-03 11:19:47 +02:00
parent 4f095243df
commit d31393f475
2 changed files with 25 additions and 1 deletions

View File

@ -62,7 +62,15 @@ export class EncodingPathStorage<T> implements KeyValueStorage<string, T> {
* Converts an internal storage path string into the original path key. * Converts an internal storage path string into the original path key.
*/ */
protected pathToKey(path: string): string { protected pathToKey(path: string): string {
const buffer = Buffer.from(path.slice(this.basePath.length), 'base64'); // While the main part of a base64 encoded string is same from any changes from encoding or decoding URL parts,
// the `=` symbol that is used for padding is not.
// This can cause incorrect results when calling these function,
// where the original path contains `YXBwbGU%3D` instead of `YXBwbGU=`.
// This does not create any issues when the source store does not encode the string, so is safe to always call.
// For consistency, we might want to also always encode when creating the path in `keyToPath()`,
// but that would potentially break existing implementations that do not do encoding,
// and is not really necessary to solve any issues.
const buffer = Buffer.from(decodeURIComponent(path.slice(this.basePath.length)), 'base64');
return buffer.toString('utf-8'); return buffer.toString('utf-8');
} }
} }

View File

@ -48,4 +48,20 @@ describe('An EncodingPathStorage', (): void => {
expect(results).toHaveLength(1); expect(results).toHaveLength(1);
expect(results[0]).toEqual([ 'key', data ]); expect(results[0]).toEqual([ 'key', data ]);
}); });
it('correctly handles keys that have been encoded by the source storage.', async(): Promise<void> => {
// Base 64 encoding of 'apple'
const encodedKey = 'YXBwbGU=';
const generatedPath = `${relativePath}${encodeURIComponent(encodedKey)}`;
const data = 'data';
map.set(generatedPath, data);
const results = [];
for await (const entry of storage.entries()) {
results.push(entry);
}
expect(results).toHaveLength(1);
expect(results[0]).toEqual([ 'apple', data ]);
});
}); });