diff --git a/.nvmrc b/.nvmrc index a00f43e30..45a4fb75d 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v8 +8 diff --git a/app/common/__tests__/misc.test.js b/app/common/__tests__/misc.test.js index 209c3fd33..8eb84ac7d 100644 --- a/app/common/__tests__/misc.test.js +++ b/app/common/__tests__/misc.test.js @@ -150,6 +150,11 @@ describe('prepareUrlForSending()', () => { expect(url2).toBe('https://google.com/%40%3B%2C%26%5E'); }); + it('leaves already encoded characters alone', () => { + const url = misc.prepareUrlForSending('https://google.com/%2B%2A%2F>'); + expect(url).toBe('https://google.com/%2B%2A%2F%3E'); + }); + it('doesn\'t encode if last param set', () => { const url = misc.prepareUrlForSending('https://google.com/%%?foo=%%', false); expect(url).toBe('https://google.com/%%?foo=%%'); diff --git a/app/common/misc.js b/app/common/misc.js index ff1c00b09..2f04d1fc3 100644 --- a/app/common/misc.js +++ b/app/common/misc.js @@ -110,45 +110,33 @@ export function flexibleEncodeComponent (str: string, ignore: string = ''): stri // Sometimes spaces screw things up because of url.parse str = str.replace(/%20/g, ' '); - const ignoredChars = ignore.split(''); + // Handle all already-encoded characters so we don't touch them + str = str.replace(/%([0-9a-fA-F]{2})/g, '__ENC__$1'); // Do a special encode of ignored chars, so they aren't touched. // This first pass, surrounds them with a special tag (anything unique // will work), so it can change them back later // Example: will replace %40 with __LEAVE_40_LEAVE__, and we'll change // it back to %40 at the end. - for (const c of ignoredChars) { + for (const c of ignore) { const code = encodeURIComponent(c).replace('%', ''); - - // Replace encoded versions - const re = new RegExp(encodeURIComponent(c), 'g'); - str = str.replace(re, `__ENCODED_${code}_ENCODED__`); - - // Replace raw versions - const re2 = new RegExp(`[${c}]`, 'g'); - str = str.replace(re2, `__RAW_${code}_RAW__`); - } - - try { - str = decodeURIComponent(str); - } catch (e) { - // Malformed (probably not encoded) so assume it's decoded already + const re2 = new RegExp(escapeRegex(c), 'g'); + str = str.replace(re2, `__RAW__${code}`); } // Encode it str = encodeURIComponent(str); + // Put back the raw version of the ignored chars + for (const match of str.match(/__RAW__([0-9a-fA-F]{2})/g) || []) { + const code = match.replace('__RAW__', ''); + str = str.replace(match, decodeURIComponent(`%${code}`)); + } + // Put back the encoded version of the ignored chars - for (const c of ignoredChars) { - const code = encodeURIComponent(c).replace('%', ''); - - // Put back encoded versions - const re = new RegExp(`__ENCODED_${code}_ENCODED__`, 'g'); - str = str.replace(re, encodeURIComponent(c)); - - // Put back raw versions - const re2 = new RegExp(`__RAW_${code}_RAW__`, 'g'); - str = str.replace(re2, c); + for (const match of str.match(/__ENC__([0-9a-fA-F]{2})/g) || []) { + const code = match.replace('__ENC__', ''); + str = str.replace(match, `%${code}`); } return str;