diff --git a/app/lib/methods/index.ts b/app/lib/methods/index.ts index 35b8cf512..7df26ec00 100644 --- a/app/lib/methods/index.ts +++ b/app/lib/methods/index.ts @@ -34,3 +34,4 @@ export * from './userPreferencesMethods'; export * from './crashReport'; export * from './parseSettings'; export * from './subscribeRooms'; +export * from './serializeAsciiUrl'; diff --git a/app/lib/methods/serializeAsciiUrl.test.ts b/app/lib/methods/serializeAsciiUrl.test.ts new file mode 100644 index 000000000..dec96a771 --- /dev/null +++ b/app/lib/methods/serializeAsciiUrl.test.ts @@ -0,0 +1,30 @@ +import { serializeAsciiUrl } from '.'; + +const ASCIIUrl = 'https://чат24.рф'; +const NonASCIIUrl = 'open.rocket.chat'; +const ASCIIUrlSerialized = 'https://xn--24-6kc6exa.xn--p1ai'; + +describe('Serialize ASCII url on ios', () => { + jest.mock('react-native', () => ({ Platform: { OS: 'ios' } })); + test('ASCII url', () => { + const result = serializeAsciiUrl(ASCIIUrl); + expect(result).toBe(ASCIIUrlSerialized); + }); + test('Non ASCII url', () => { + const result = serializeAsciiUrl(NonASCIIUrl); + expect(result).toBe(NonASCIIUrl); + }); +}); + +describe('Serialize ASCII url on android', () => { + jest.mock('react-native', () => ({ Platform: { OS: 'android' } })); + // By default android converts ASCII addresses + // test('ASCII url', () => { + // const result = serializeAsciiUrl(ASCIIUrl); + // expect(result).toBe('filename.png'); + // }); + test('Non ASCII url', () => { + const result = serializeAsciiUrl(NonASCIIUrl); + expect(result).toBe(NonASCIIUrl); + }); +}); diff --git a/app/lib/methods/serializeAsciiUrl.ts b/app/lib/methods/serializeAsciiUrl.ts new file mode 100644 index 000000000..c9963049d --- /dev/null +++ b/app/lib/methods/serializeAsciiUrl.ts @@ -0,0 +1,13 @@ +import * as uri from 'uri-js'; + +import { isIOS } from './helpers'; + +export const serializeAsciiUrl = (url: string): string => { + let newUrl = url; + const ascii = /^[ -~\t\n\r]+$/; + if (isIOS && !ascii.test(newUrl)) { + newUrl = uri.serialize(uri.parse(url)); + newUrl = newUrl.charAt(newUrl.length - 1) === '/' ? newUrl.slice(0, -1) : newUrl; + } + return newUrl; +}; diff --git a/app/views/NewServerView/index.tsx b/app/views/NewServerView/index.tsx index f4589039a..f246d7f62 100644 --- a/app/views/NewServerView/index.tsx +++ b/app/views/NewServerView/index.tsx @@ -31,6 +31,7 @@ import { moderateScale, verticalScale } from './scaling'; import SSLPinning from '../../lib/methods/helpers/sslPinning'; import sharedStyles from '../Styles'; import ServerInput from './ServerInput'; +import { serializeAsciiUrl } from '../../lib/methods'; const styles = StyleSheet.create({ onboardingImage: { @@ -257,8 +258,7 @@ class NewServerView extends React.Component uri.replace('file://', ''); diff --git a/package.json b/package.json index 7829f0d86..c3a015060 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,7 @@ "rn-root-view": "1.0.3", "semver": "7.3.5", "ua-parser-js": "^1.0.2", + "uri-js": "^4.4.1", "url-parse": "1.5.10", "use-deep-compare-effect": "1.6.1", "xregexp": "5.0.2" diff --git a/yarn.lock b/yarn.lock index 265aaea04..cb3170660 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18170,6 +18170,13 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +uri-js@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"