From aeda1dfdcce579635095fb6ca9f99e23e0516eb9 Mon Sep 17 00:00:00 2001 From: vas Date: Tue, 17 May 2022 16:41:56 +0300 Subject: [PATCH] automatically add protocol to Server URL (#2083) (#2106) * automatically add protocol to Server URL (#2083) * refactor NewTeamModal to only detect protocol on save * use window.postMessage for intercom + only ping on form save --- src/common/communication.ts | 2 ++ src/common/utils/requests.ts | 17 ++++++++++++++ src/main/app/initialize.ts | 3 +++ src/main/app/intercom.ts | 14 ++++++++++++ src/main/preload/modalPreload.js | 11 +++++++++ src/renderer/components/NewTeamModal.tsx | 29 +++++++++++++++++++++--- 6 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/common/utils/requests.ts diff --git a/src/common/communication.ts b/src/common/communication.ts index b167f1f1..d021c13d 100644 --- a/src/common/communication.ts +++ b/src/common/communication.ts @@ -120,3 +120,5 @@ export const DESKTOP_SOURCES_RESULT = 'desktop-sources-result'; export const RELOAD_CURRENT_VIEW = 'reload-current-view'; +export const PING_DOMAIN = 'ping-domain'; +export const PING_DOMAIN_RESPONSE = 'ping-domain-response'; diff --git a/src/common/utils/requests.ts b/src/common/utils/requests.ts new file mode 100644 index 00000000..e6b68d2a --- /dev/null +++ b/src/common/utils/requests.ts @@ -0,0 +1,17 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import * as http from 'http'; +import * as https from 'https'; + +type Method = 'GET' | 'POST' | 'DELETE' | 'PUT' | 'OPTIONS' | 'HEAD'; + +export async function ping(url: URL, method: Method = 'GET'): Promise { + const f = url.protocol === 'http:' ? http.request : https.request; + return new Promise((yes, no) => { + const req = f(url, {method}); + req.on('error', no); + req.on('response', yes); + req.end(); + }); +} diff --git a/src/main/app/initialize.ts b/src/main/app/initialize.ts index 80f21d10..d35dee19 100644 --- a/src/main/app/initialize.ts +++ b/src/main/app/initialize.ts @@ -33,6 +33,7 @@ import { USER_ACTIVITY_UPDATE, START_UPGRADE, START_DOWNLOAD, + PING_DOMAIN, } from 'common/communication'; import Config from 'common/config'; import urlUtils from 'common/utils/url'; @@ -81,6 +82,7 @@ import { handleSwitchServer, handleSwitchTab, handleUpdateLastActive, + handlePingDomain, } from './intercom'; import { clearAppCache, @@ -253,6 +255,7 @@ function initializeInterCommunicationEventListeners() { ipcMain.handle(GET_DOWNLOAD_LOCATION, handleSelectDownload); ipcMain.on(START_DOWNLOAD, handleStartDownload); ipcMain.on(START_UPGRADE, handleStartUpgrade); + ipcMain.handle(PING_DOMAIN, handlePingDomain); } function initializeAfterAppReady() { diff --git a/src/main/app/intercom.ts b/src/main/app/intercom.ts index f6d23e8d..597aaabb 100644 --- a/src/main/app/intercom.ts +++ b/src/main/app/intercom.ts @@ -9,6 +9,7 @@ import {MentionData} from 'types/notification'; import Config from 'common/config'; import {getDefaultTeamWithTabsFromTeam} from 'common/tabs/TabView'; +import {ping} from 'common/utils/requests'; import {displayMention} from 'main/notifications'; import {getLocalPreload, getLocalURLString} from 'main/utils'; @@ -256,3 +257,16 @@ export function handleUpdateLastActive(event: IpcMainEvent, serverName: string, Config.set('lastActiveTeam', teams.find((team) => team.name === serverName)?.order || 0); } +export function handlePingDomain(event: IpcMainInvokeEvent, url: string): Promise { + return Promise.allSettled([ + ping(new URL(`https://${url}`)), + ping(new URL(`http://${url}`)), + ]).then(([https, http]): string => { + if (https.status === 'fulfilled') { + return 'https'; + } else if (http.status === 'fulfilled') { + return 'http'; + } + throw new Error('Could not find server ' + url); + }); +} diff --git a/src/main/preload/modalPreload.js b/src/main/preload/modalPreload.js index 3303e6fd..63e1d67f 100644 --- a/src/main/preload/modalPreload.js +++ b/src/main/preload/modalPreload.js @@ -16,6 +16,8 @@ import { DARK_MODE_CHANGE, GET_MODAL_UNCLOSEABLE, MODAL_UNCLOSEABLE, + PING_DOMAIN, + PING_DOMAIN_RESPONSE, } from 'common/communication'; console.log('preloaded for the modal!'); @@ -59,6 +61,15 @@ window.addEventListener('message', async (event) => { console.log('getting dark mode value'); window.postMessage({type: DARK_MODE_CHANGE, data: await ipcRenderer.invoke(GET_DARK_MODE)}, window.location.href); break; + case PING_DOMAIN: + console.log('pinging domain: ' + event.data.data); + try { + const protocol = await ipcRenderer.invoke(PING_DOMAIN, event.data.data); + window.postMessage({type: PING_DOMAIN_RESPONSE, data: protocol}, window.location.href); + } catch (error) { + window.postMessage({type: PING_DOMAIN_RESPONSE, data: error}, window.location.href); + } + break; default: console.log(`got a message: ${event}`); console.log(event); diff --git a/src/renderer/components/NewTeamModal.tsx b/src/renderer/components/NewTeamModal.tsx index f71ee82f..49aa4a96 100644 --- a/src/renderer/components/NewTeamModal.tsx +++ b/src/renderer/components/NewTeamModal.tsx @@ -8,6 +8,7 @@ import {Modal, Button, FormGroup, FormControl, FormLabel, FormText} from 'react- import {TeamWithIndex} from 'types/config'; import urlUtils from 'common/utils/url'; +import {PING_DOMAIN, PING_DOMAIN_RESPONSE} from 'common/communication'; type Props = { onClose?: () => void; @@ -115,8 +116,29 @@ export default class NewTeamModal extends React.PureComponent { } handleTeamUrlChange = (e: React.ChangeEvent) => { - this.setState({ - teamUrl: e.target.value, + const teamUrl = e.target.value; + this.setState({teamUrl}); + } + + addProtocolToUrl = (teamUrl: string): Promise => { + if (teamUrl.startsWith('http://') || teamUrl.startsWith('https://')) { + return Promise.resolve(undefined); + } + + return new Promise((resolve) => { + const handler = (event: {data: {type: string; data: string | Error}}) => { + if (event.data.type === PING_DOMAIN_RESPONSE) { + if (event.data.data instanceof Error) { + console.error(`Could not ping url: ${teamUrl}`); + } else { + this.setState({teamUrl: `${event.data.data}://${this.state.teamUrl}`}); + } + window.removeEventListener('message', handler); + resolve(undefined); + } + }; + window.addEventListener('message', handler); + window.postMessage({type: PING_DOMAIN, data: teamUrl}, window.location.href); }); } @@ -145,7 +167,8 @@ export default class NewTeamModal extends React.PureComponent { this.getTeamUrlValidationState() === null; } - save = () => { + save = async () => { + await this.addProtocolToUrl(this.state.teamUrl); this.setState({ saveStarted: true, }, () => {