diff --git a/app/analytics/index.js b/app/analytics/index.js index 9a7cb05ed..48063c6c9 100644 --- a/app/analytics/index.js +++ b/app/analytics/index.js @@ -7,22 +7,38 @@ export async function init (accountId) { return; } - await segment.init(); - await google.init(accountId); + try { + await segment.init(); + await google.init(accountId); - initialized = true; + initialized = true; + } catch (e) { + // Just to be extra safe + } } export function trackEvent (...args) { - google.sendEvent(...args); - console.log(`[analytics] track ${args.join(', ')}`); + try { + google.sendEvent(...args); + console.log(`[analytics] track ${args.join(', ')}`); + } catch (e) { + // Just to be extra safe + } } export function setAccountId (accountId) { - google.setUserId(accountId); - console.log(`[analytics] account Id ${accountId}`); + try { + google.setUserId(accountId); + console.log(`[analytics] account Id ${accountId}`); + } catch (e) { + // Just to be extra safe + } } export function trackLegacyEvent (event, properties) { - segment.trackLegacyEvent(event, properties) + try { + segment.trackLegacyEvent(event, properties) + } catch (e) { + // Just to be extra safe + } } diff --git a/app/common/__tests__/misc.test.js b/app/common/__tests__/misc.test.js index 2e0f830d3..e2ee8774e 100644 --- a/app/common/__tests__/misc.test.js +++ b/app/common/__tests__/misc.test.js @@ -125,8 +125,8 @@ describe('prepareUrlForSending()', () => { }); it('encodes querystring with repeated keys', () => { - const url = misc.prepareUrlForSending('https://google.com?s=foo&s=foo %20100%'); - expect(url).toBe('https://google.com/?s=foo&s=foo%20%20100%25'); + const url = misc.prepareUrlForSending('https://google.com/;@,!?s=foo,;@-!&s=foo %20100%'); + expect(url).toBe('https://google.com/;@,!?s=foo%2C%3B%40-!&s=foo%20%20100%25'); }); }); diff --git a/app/common/__tests__/network.test.js b/app/common/__tests__/network.test.js index b289216d6..83205a876 100644 --- a/app/common/__tests__/network.test.js +++ b/app/common/__tests__/network.test.js @@ -68,8 +68,7 @@ describe('buildRequestConfig()', () => { rejectUnauthorized: true, time: true, timeout: 0, - url: 'http://foo.com:3332/%E2%98%85/hi%40gmail.com/' + - 'foo%20bar?bar=baz&foo%20bar=hello%26world' + url: 'http://foo.com:3332/%E2%98%85/hi@gmail.com/foo%20bar?bar=baz&foo%20bar=hello%26world' }) }) }); diff --git a/app/common/misc.js b/app/common/misc.js index bf2bf63b3..baf5224c9 100644 --- a/app/common/misc.js +++ b/app/common/misc.js @@ -1,6 +1,7 @@ import uuid from 'node-uuid'; import {parse as urlParse, format as urlFormat} from 'url'; import {DEBOUNCE_MILLIS} from "./constants"; +import * as querystring from './querystring'; export function getBasicAuthHeader (username, password) { const name = 'Authorization'; @@ -88,7 +89,10 @@ export function prepareUrlForSending (url) { if (parsedUrl.pathname) { const segments = parsedUrl.pathname.split('/'); - parsedUrl.pathname = segments.map(flexibleEncodeComponent).join('/'); + parsedUrl.pathname = segments.map(flexibleEncodeComponent).join('/') + .replace(/%3B/gi, ';') // Don't encode ; in pathname + .replace(/%40/gi, '@') // Don't encode @ in pathname + .replace(/%2C/gi, ','); // Don't encode , in pathname } // ~~~~~~~~~~~~~~ // @@ -98,6 +102,16 @@ export function prepareUrlForSending (url) { // Deleting search key will force url.format to encode parsedURL.query delete parsedUrl.search; + for (const name of Object.keys(parsedUrl.query)) { + const value = parsedUrl.query[name]; + delete parsedUrl[name]; + if (Array.isArray(value)) { + parsedUrl[flexibleEncodeComponent(name)] = value.map(flexibleEncodeComponent); + } else { + parsedUrl[flexibleEncodeComponent(name)] = flexibleEncodeComponent(value); + } + } + return urlFormat(parsedUrl); } diff --git a/app/package.json b/app/package.json index a3f70989a..b6b1b4368 100644 --- a/app/package.json +++ b/app/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "insomnia", - "version": "3.7.1", + "version": "3.7.2", "productName": "Insomnia", "longName": "Insomnia REST Client", "description": "A simple and beautiful REST API client", diff --git a/app/ui/components/Toast.js b/app/ui/components/Toast.js index 36af98db8..a023cde23 100644 --- a/app/ui/components/Toast.js +++ b/app/ui/components/Toast.js @@ -40,13 +40,18 @@ class Toast extends Component { } _handleClick (notification) { + if (!notification) { + // Not sure how this happened, but Sentry says it has + return; + } + if (notification.key === KEY_PLUS_IS_HERE) { showModal(SettingsModal, TAB_PLUS); } - analytics.trackEvent('Notification', 'Click', notification.key); - this._markAsRead(notification); + + analytics.trackEvent('Notification', 'Click', notification.key); } _handleShowNotifications () { diff --git a/app/ui/components/modals/PaymentModal.js b/app/ui/components/modals/PaymentModal.js index c3cb4bb68..2b7b8010e 100644 --- a/app/ui/components/modals/PaymentModal.js +++ b/app/ui/components/modals/PaymentModal.js @@ -69,28 +69,55 @@ class PaymentModal extends Component { return; } + const cardType = Stripe.card.cardType(value); const lastChar = value[e.target.value.length - 1]; const num = value.replace(/[^0-9]*/g, ''); - const g1 = num.slice(0, 4); - const g2 = num.slice(4, 8); - const g3 = num.slice(8, 12); - const g4 = num.slice(12, 16); + let newNum = ''; - let newNum = g1; - newNum += g2 ? `-${g2}` : ''; - newNum += g3 ? `-${g3}` : ''; - newNum += g4 ? `-${g4}` : ''; + if (cardType === 'American Express') { + // 1111 222222 33333 + const g1 = num.slice(0, 4); + const g2 = num.slice(4, 10); + const g3 = num.slice(10, 15); - // Handle trailing dash so we can add and delete dashes properly - const numNumbers = (g1 + g2 + g3 + g4).length; - if (lastChar === '-' && g4.length !== 4 && numNumbers % 4 === 0) { - newNum += '-'; + newNum = g1; + newNum += g2 ? ` ${g2}` : ''; + newNum += g3 ? ` ${g3}` : ''; + } else if (cardType === 'Diners Club') { + // 1111 2222 3333 44 + const g1 = num.slice(0, 4); + const g2 = num.slice(4, 8); + const g3 = num.slice(8, 12); + const g4 = num.slice(12, 14); + + newNum = g1; + newNum += g2 ? ` ${g2}` : ''; + newNum += g3 ? ` ${g3}` : ''; + newNum += g4 ? ` ${g4}` : ''; + } else { + // 1111 2222 3333 4444 + const g1 = num.slice(0, 4); + const g2 = num.slice(4, 8); + const g3 = num.slice(8, 12); + const g4 = num.slice(12, 16); + + newNum = g1; + newNum += g2 ? ` ${g2}` : ''; + newNum += g3 ? ` ${g3}` : ''; + newNum += g4 ? ` ${g4}` : ''; + } + + // Handle trailing dash so we can add and delete dashes properly + if (lastChar === ' ') { + newNum += ' '; } - const cardType = Stripe.card.cardType(newNum); this.setState({cardType: cardType === 'Unknown' ? '' : cardType}); - e.target.value = newNum; + // Only update number if it changed from the user's original to prevent cursor jump + if (newNum !== value) { + e.target.value = newNum; + } } _handleSubmit (e) { @@ -100,7 +127,7 @@ class PaymentModal extends Component { const params = { name: this._nameInput.value, - number: this._cardNumberInput.value.replace(/-/g, ''), + number: this._cardNumberInput.value.replace(/ /g, ''), cvc: this._cvcInput.value, exp_month: parseInt(this._expiryMonthInput.value, 10), exp_year: parseInt(this._expiryYearInput.value, 10), @@ -185,9 +212,8 @@ class PaymentModal extends Component {