Description
New Issue Checklist
- I am not disclosing a vulnerability.
- I am not just asking a question.
- I have searched through existing issues.
- I can reproduce the issue with the latest versions of Parse Server and the Parse JS SDK.
Issue Description
new Parse.File()fails with large base64 string caused by complex regex test.
Steps to reproduce
Review the source code of ParseFile.js 3.3.4, line 210.
In 3.3.4, this code is executed in Parse.File() to verify the base64 encoded file data:
// Check if data URI or base64 string is valid
const validationRegex = new RegExp(base64Regex.source + '|' + dataUriRegex.source, 'i');
And here the regex:
const base64Regex = new RegExp('([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))', 'i');
const dataUriRegex = new RegExp(`^data:([a-zA-Z]+\\/[-a-zA-Z0-9+.]+(;[a-z-]+=[a-zA-Z0-9+.-]+)?)?(;base64)?,(${base64Regex.source})*$`, 'i');
The passed base64 is created from Uint8Array.toString("base64");
The problem has meanwhile been worked around by passing a byte array. This introduces memory overhead as a new byte array has to be created with Array.from(Uint8Array) as an UInt8Array is not accepted by Parse.File. Parse.File than uses its own base64 encoding algorithm to create a base64 string instead of the Internal javascript runtime version => Uint8Array.toString("base64");
In short:
- Parse.File does a highly inefficient, unnecessary and failing base64 check, breaking core functionality
- Parse.File does not accept a JS buffer making it necessary to convert it to a plain byte array causing memory overhead
- base64 encoding in Parse.File does not use the JS runtime function but it's own (much less efficient) implementation
The base64 check should simply be removed. Worse case the base64 data is invalid and either:
- save/upload fails (?)
- the storage adapter fails (?)
- a client reading it fails (most definately)
The 1st two can be caught by the client-app while uploading.
The last one can also happen with pure binary data and is the client-app responsibility to catch, not the Parse SDK.
If I find some time I'm happy to create a PR with native Buffer support, something along the line of:
if(Buffer.isBuffer(data) {
this._data = Uint8Array.from(data).toString("base64");
this._source = {
format: 'base64',
base64: this._data,
type: specifiedType
};
}
Actual Outcome
With a ~2MB base64 string (jpeg image) it took around 6 minutes (!!!) with 100% cpu (=full single core) until the regex failed. The base64 was however correct as any image saved with Parse JS-SDK 3.3.0 and earlier could be downloaded/viewed without error.
Expected Outcome
Seamless passing of base64 string, leaving it to the client to make sure the base64 is valid.
Alternative, a much more efficient base64 check than the current complex, failing regex and/or Buffer support.
Environment
MaxOS, node 14
Linux Node 12
Server
n/a, client issue (Parse-SDK-JS)
Database
n/a, client issue (Parse-SDK-JS)
Client
- Parse JS SDK version: 3.3.4
Logs
n/a (Exception with "Cannot create a Parse.File without valid data URIs or base64 encoded data.")