Skip to content

Commit

Permalink
[CFDS] Hasan/CFDS-3424/mt5 deeplink redirect issue (binary-com#14547)
Browse files Browse the repository at this point in the history
* chore: console mobile os detect func

* chore: console mobile os detect func

* chore: console mobile os detect func

* chore: updated mobile os detect function

* chore: updated mobile os detect function

* chore: created async based os detect function

* chore: console

* chore: console

* chore: test react-device-detect package

* chore: test react-device-detect package

* chore: test react-device-detect package

* Revert "chore: test react-device-detect package"

This reverts commit 1ec874f.

* Revert "chore: test react-device-detect package"

This reverts commit a71712a.

* Revert "chore: test react-device-detect package"

This reverts commit 397a006.

* chore: test new regex

* chore: test new regex

* Revert "chore: test new regex"

This reverts commit 7483513.

* Revert "chore: test new regex"

This reverts commit fba5af8.

* chore: removed test useEffect

* chore: updated test cases

* fix: sonarcloud issues

* fix: updated huawei regex

* fix: console

* fix: removed updated regex

* fix: updated regex

* fix: updated regex to Set

* chore: console ua parser

* chore: console ua parser

* Revert "chore: console ua parser"

This reverts commit 4f6e581.

* Revert "chore: console ua parser"

This reverts commit 6d3e714.

* chore: merge master
  • Loading branch information
hasan-deriv authored and vinu-deriv committed May 28, 2024
1 parent 6b12797 commit 56f7999
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { render } from '@testing-library/react';
import { isSafariBrowser, mobileOSDetect } from '@deriv/shared';
import { isSafariBrowser, mobileOSDetect, mobileOSDetectAsync } from '@deriv/shared';
import MT5MobileRedirectOption from '../mt5-mobile-redirect-option';
import { DEEP_LINK, getMobileAppInstallerURL, getPlatformMt5DownloadLink } from '../../../src/Helpers/constants';

Expand Down Expand Up @@ -63,10 +63,11 @@ describe('<MT5MobileRedirectOption/>', () => {
configurable: true,
});

expect(mobileOSDetect()).toBe('iOS');
const os = await mobileOSDetectAsync();
expect(os).toBe('iOS');
expect(isSafariBrowser()).toBe(true);

const expectedUrl = getMobileAppInstallerURL({ mt5_trade_account: mock_props.mt5_trade_account });
const expectedUrl = await getMobileAppInstallerURL({ mt5_trade_account: mock_props.mt5_trade_account });
expect(expectedUrl).toBe(mock_props.mt5_trade_account.white_label_links.ios);
});

Expand All @@ -75,10 +76,11 @@ describe('<MT5MobileRedirectOption/>', () => {
value: 'Mozilla/5.0 (Linux; Android 10; SM-A205U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36',
configurable: true,
});
expect(mobileOSDetect()).toBe('Android');
const os = await mobileOSDetectAsync();
expect(os).toBe('Android');
expect(isSafariBrowser()).toBe(false);

const expectedUrl = getMobileAppInstallerURL({ mt5_trade_account: mock_props.mt5_trade_account });
const expectedUrl = await getMobileAppInstallerURL({ mt5_trade_account: mock_props.mt5_trade_account });
expect(expectedUrl).toBe(mock_props.mt5_trade_account.white_label_links.android);
});

Expand All @@ -87,10 +89,11 @@ describe('<MT5MobileRedirectOption/>', () => {
value: 'Mozilla/5.0 (Linux; Android 10; ELE-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36',
configurable: true,
});
expect(mobileOSDetect()).toBe('huawei');
const os = await mobileOSDetectAsync();
expect(os).toBe('huawei');
expect(isSafariBrowser()).toBe(false);

const expectedUrl = getMobileAppInstallerURL({ mt5_trade_account: mock_props.mt5_trade_account });
const expectedUrl = await getMobileAppInstallerURL({ mt5_trade_account: mock_props.mt5_trade_account });
expect(expectedUrl).toBe(getPlatformMt5DownloadLink('huawei'));
});

Expand Down
5 changes: 3 additions & 2 deletions packages/cfd/src/Containers/mt5-mobile-redirect-option.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ type TMT5MobileRedirectOptionProps = {
const MT5MobileRedirectOption = ({ mt5_trade_account }: TMT5MobileRedirectOptionProps) => {
let mobile_url;

const mobileURLSet = () => {
const mobileURLSet = async () => {
mobile_url = window.location.replace(DEEP_LINK({ mt5_trade_account }));
const mobileAppURL = await getMobileAppInstallerURL({ mt5_trade_account });

const timeout = setTimeout(() => {
mobile_url = window.location.replace(getMobileAppInstallerURL({ mt5_trade_account }) as string);
mobile_url = mobileAppURL && window.location.replace(mobileAppURL);
}, 1500);

if (!isSafariBrowser()) {
Expand Down
10 changes: 6 additions & 4 deletions packages/cfd/src/Helpers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
validLength,
validPassword,
validMT5Password,
mobileOSDetect,
mobileOSDetectAsync,
} from '@deriv/shared';
import { localize } from '@deriv/translations';
import { TCFDsPlatformType, TDetailsOfEachMT5Loginid, TMobilePlatforms } from 'Components/props.types';
Expand Down Expand Up @@ -151,10 +151,12 @@ const validatePassword = (password: string): string | undefined => {
}
};

const getMobileAppInstallerURL = ({ mt5_trade_account }: { mt5_trade_account: TDetailsOfEachMT5Loginid }) => {
if (mobileOSDetect() === 'iOS') {
const getMobileAppInstallerURL = async ({ mt5_trade_account }: { mt5_trade_account: TDetailsOfEachMT5Loginid }) => {
const os = await mobileOSDetectAsync();

if (os === 'iOS') {
return mt5_trade_account?.white_label_links?.ios;
} else if (mobileOSDetect() === 'huawei') {
} else if (os === 'huawei') {
return getPlatformMt5DownloadLink('huawei');
}
return mt5_trade_account?.white_label_links?.android;
Expand Down
168 changes: 168 additions & 0 deletions packages/shared/src/utils/os/os_detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,24 @@ declare global {
msDetachStream: () => void;
};
}
interface Navigator {
userAgentData?: NavigatorUAData;
}
}

type NavigatorUAData = {
brands: Array<{ brand: string; version: string }>;
mobile: boolean;
getHighEntropyValues(hints: string[]): Promise<HighEntropyValues>;
};

type HighEntropyValues = {
platform?: string;
platformVersion?: string;
model?: string;
uaFullVersion?: string;
};

export const systems = {
mac: ['Mac68K', 'MacIntel', 'MacPPC'],
linux: [
Expand Down Expand Up @@ -92,4 +108,156 @@ export const mobileOSDetect = () => {
return 'unknown';
};

// Simple regular expression to match potential Huawei device codes
const huaweiDevicesRegex = /\b([A-Z]{3}-)\b/gi;

// Set of valid Huawei device codes
const validCodes = new Set([
'ALP-',
'AMN-',
'ANA-',
'ANE-',
'ANG-',
'AQM-',
'ARS-',
'ART-',
'ATU-',
'BAC-',
'BLA-',
'BRQ-',
'CAG-',
'CAM-',
'CAN-',
'CAZ-',
'CDL-',
'CDY-',
'CLT-',
'CRO-',
'CUN-',
'DIG-',
'DRA-',
'DUA-',
'DUB-',
'DVC-',
'ELE-',
'ELS-',
'EML-',
'EVA-',
'EVR-',
'FIG-',
'FLA-',
'FRL-',
'GLK-',
'HMA-',
'HW-',
'HWI-',
'INE-',
'JAT-',
'JEF-',
'JER-',
'JKM-',
'JNY-',
'JSC-',
'LDN-',
'LIO-',
'LON-',
'LUA-',
'LYA-',
'LYO-',
'MAR-',
'MED-',
'MHA-',
'MLA-',
'MRD-',
'MYA-',
'NCE-',
'NEO-',
'NOH-',
'NOP-',
'OCE-',
'PAR-',
'PIC-',
'POT-',
'PPA-',
'PRA-',
'RNE-',
'SEA-',
'SLA-',
'SNE-',
'SPN-',
'STK-',
'TAH-',
'TAS-',
'TET-',
'TRT-',
'VCE-',
'VIE-',
'VKY-',
'VNS-',
'VOG-',
'VTR-',
'WAS-',
'WKG-',
'WLZ-',
'JAD-',
'MLD-',
'RTE-',
'NAM-',
'NEN-',
'BAL-',
'JLN-',
'YAL-',
'MGA-',
'FGD-',
'XYAO-',
'BON-',
'ALN-',
'ALT-',
'BRA-',
'DBY2-',
'STG-',
'MAO-',
'LEM-',
'GOA-',
'FOA-',
'MNA-',
'LNA-',
]);

// Function to validate Huawei device codes from a string
function validateHuaweiCodes(inputString: string) {
const matches = inputString.match(huaweiDevicesRegex);
if (matches) {
return matches.filter(code => validCodes.has(code.toUpperCase())).length > 0;
}
return false;
}

export const mobileOSDetectAsync = async () => {
const userAgent = navigator.userAgent ?? window.opera ?? '';
// Windows Phone must come first because its UA also contains "Android"
if (/windows phone/i.test(userAgent)) {
return 'Windows Phone';
}

if (/android/i.test(userAgent)) {
// Check if navigator.userAgentData is available for modern browsers
if (navigator?.userAgentData) {
const ua = await navigator.userAgentData.getHighEntropyValues(['model']);
if (validateHuaweiCodes(ua?.model || '')) {
return 'huawei';
}
} else if (validateHuaweiCodes(userAgent) || /huawei/i.test(userAgent)) {
return 'huawei';
}
return 'Android';
}

if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
return 'iOS';
}

return 'unknown';
};

export const getOSNameWithUAParser = () => UAParser().os.name;

0 comments on commit 56f7999

Please sign in to comment.