mirror of
https://github.com/zulip/zulip-desktop.git
synced 2025-11-13 10:26:15 +00:00
Remove the insecure ignoreCerts option.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
@@ -225,7 +225,6 @@ app.on('ready', () => {
|
||||
) /* eslint-disable-line max-params */ => {
|
||||
// TODO: The entire concept of selectively ignoring certificate errors
|
||||
// is ill-conceived, and this handler needs to be deleted.
|
||||
event.preventDefault();
|
||||
|
||||
const {origin} = new URL(url);
|
||||
const filename = CertificateUtil.getCertificate(encodeURIComponent(origin));
|
||||
@@ -237,6 +236,7 @@ app.on('ready', () => {
|
||||
);
|
||||
if (certificate.data.replace(/[\r\n]/g, '') ===
|
||||
savedCertificate.replace(/[\r\n]/g, '')) {
|
||||
event.preventDefault();
|
||||
callback(true);
|
||||
return;
|
||||
}
|
||||
@@ -245,21 +245,12 @@ app.on('ready', () => {
|
||||
}
|
||||
}
|
||||
|
||||
page.send(
|
||||
'certificate-error',
|
||||
webContents.id === mainWindow.webContents.id ? null : webContents.id,
|
||||
makeRendererCallback(ignore => {
|
||||
callback(ignore);
|
||||
if (!ignore) {
|
||||
dialog.showErrorBox(
|
||||
'Certificate error',
|
||||
`The server presented an invalid certificate for ${origin}:
|
||||
|
||||
${error}`
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
page.session.setPermissionRequestHandler((webContents, permission, callback, details) => {
|
||||
|
||||
@@ -24,7 +24,6 @@ interface WebViewProps {
|
||||
nodeIntegration: boolean;
|
||||
preload: boolean;
|
||||
onTitleChange: () => void;
|
||||
ignoreCerts?: boolean;
|
||||
hasPermission?: (origin: string, permission: string) => boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -360,7 +360,6 @@ class ServerManagerView {
|
||||
url: server.url,
|
||||
role: 'server',
|
||||
name: CommonUtil.decodeString(server.alias),
|
||||
ignoreCerts: server.ignoreCerts,
|
||||
hasPermission: (origin: string, permission: string) =>
|
||||
origin === server.url && permission === 'notifications',
|
||||
isActive: () => {
|
||||
@@ -816,21 +815,6 @@ class ServerManagerView {
|
||||
});
|
||||
}
|
||||
|
||||
ipcRenderer.on('certificate-error', (
|
||||
event: Event,
|
||||
webContentsId: number | null,
|
||||
rendererCallbackId: number
|
||||
) => {
|
||||
const ignore = webContentsId !== null &&
|
||||
this.tabs.some(
|
||||
({webview}) =>
|
||||
!webview.loading &&
|
||||
webview.$el.getWebContentsId() === webContentsId &&
|
||||
webview.props.ignoreCerts
|
||||
);
|
||||
ipcRenderer.send('renderer-callback', rendererCallbackId, ignore);
|
||||
});
|
||||
|
||||
ipcRenderer.on('permission-request', (
|
||||
event: Event,
|
||||
{webContentsId, origin, permission}: {
|
||||
|
||||
@@ -17,7 +17,6 @@ export interface ServerConf {
|
||||
url: string;
|
||||
alias?: string;
|
||||
icon?: string;
|
||||
ignoreCerts?: boolean;
|
||||
}
|
||||
|
||||
const logger = new Logger({
|
||||
@@ -55,26 +54,14 @@ export function getDomain(index: number): ServerConf {
|
||||
return db.getData(`/domains[${index}]`);
|
||||
}
|
||||
|
||||
export function shouldIgnoreCerts(url: string): boolean {
|
||||
const domains = getDomains();
|
||||
for (const domain of domains) {
|
||||
if (domain.url === url) {
|
||||
return domain.ignoreCerts;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function updateDomain(index: number, server: ServerConf): void {
|
||||
reloadDB();
|
||||
db.push(`/domains[${index}]`, server, true);
|
||||
}
|
||||
|
||||
export async function addDomain(server: ServerConf): Promise<void> {
|
||||
const {ignoreCerts} = server;
|
||||
if (server.icon) {
|
||||
const localIconUrl = await saveServerIcon(server, ignoreCerts);
|
||||
const localIconUrl = await saveServerIcon(server);
|
||||
server.icon = localIconUrl;
|
||||
db.push('/domains[]', server, true);
|
||||
reloadDB();
|
||||
@@ -118,33 +105,16 @@ async function checkCertError(domain: string, serverConf: ServerConf, error: any
|
||||
const certErrorMessage = Messages.certErrorMessage(domain, error);
|
||||
const certErrorDetail = Messages.certErrorDetail();
|
||||
|
||||
const {response} = await dialog.showMessageBox({
|
||||
type: 'warning',
|
||||
buttons: ['Yes', 'No'],
|
||||
defaultId: 1,
|
||||
await dialog.showMessageBox({
|
||||
type: 'error',
|
||||
buttons: ['OK'],
|
||||
message: certErrorMessage,
|
||||
detail: certErrorDetail
|
||||
});
|
||||
if (response === 0) {
|
||||
// Set ignoreCerts parameter to true in case user responds with yes
|
||||
serverConf.ignoreCerts = true;
|
||||
try {
|
||||
return await getServerSettings(domain, serverConf.ignoreCerts);
|
||||
} catch (_) {
|
||||
if (error === Messages.noOrgsError(domain)) {
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
return serverConf;
|
||||
}
|
||||
} else {
|
||||
throw new Error('Untrusted certificate.');
|
||||
}
|
||||
}
|
||||
|
||||
// ignoreCerts parameter helps in fetching server icon and
|
||||
// other server details when user chooses to ignore certificate warnings
|
||||
export async function checkDomain(domain: string, ignoreCerts = false, silent = false): Promise<ServerConf> {
|
||||
export async function checkDomain(domain: string, silent = false): Promise<ServerConf> {
|
||||
if (!silent && duplicateDomain(domain)) {
|
||||
// Do not check duplicate in silent mode
|
||||
throw new Error('This server has been added.');
|
||||
@@ -155,12 +125,11 @@ export async function checkDomain(domain: string, ignoreCerts = false, silent =
|
||||
const serverConf = {
|
||||
icon: defaultIconUrl,
|
||||
url: domain,
|
||||
alias: domain,
|
||||
ignoreCerts
|
||||
alias: domain
|
||||
};
|
||||
|
||||
try {
|
||||
return await getServerSettings(domain, serverConf.ignoreCerts);
|
||||
return await getServerSettings(domain);
|
||||
} catch (error_) {
|
||||
// Make sure that error is an error or string not undefined
|
||||
// so validation does not throw error.
|
||||
@@ -176,10 +145,10 @@ export async function checkDomain(domain: string, ignoreCerts = false, silent =
|
||||
}
|
||||
}
|
||||
|
||||
async function getServerSettings(domain: string, ignoreCerts = false): Promise<ServerConf> {
|
||||
async function getServerSettings(domain: string): Promise<ServerConf> {
|
||||
const serverSettingsOptions = {
|
||||
url: domain + '/api/v1/server_settings',
|
||||
...RequestUtil.requestOptions(domain, ignoreCerts)
|
||||
...RequestUtil.requestOptions(domain)
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -196,8 +165,7 @@ async function getServerSettings(domain: string, ignoreCerts = false): Promise<S
|
||||
// Following check handles both the cases
|
||||
icon: realm_icon.startsWith('/') ? realm_uri + realm_icon : realm_icon,
|
||||
url: realm_uri,
|
||||
alias: escape(realm_name),
|
||||
ignoreCerts
|
||||
alias: escape(realm_name)
|
||||
});
|
||||
} else {
|
||||
reject(Messages.noOrgsError(domain));
|
||||
@@ -209,13 +177,13 @@ async function getServerSettings(domain: string, ignoreCerts = false): Promise<S
|
||||
});
|
||||
}
|
||||
|
||||
export async function saveServerIcon(server: ServerConf, ignoreCerts = false): Promise<string> {
|
||||
export async function saveServerIcon(server: ServerConf): Promise<string> {
|
||||
const url = server.icon;
|
||||
const domain = server.url;
|
||||
|
||||
const serverIconOptions = {
|
||||
url,
|
||||
...RequestUtil.requestOptions(domain, ignoreCerts)
|
||||
...RequestUtil.requestOptions(domain)
|
||||
};
|
||||
|
||||
// The save will always succeed. If url is invalid, downgrade to default icon.
|
||||
@@ -251,10 +219,9 @@ export async function saveServerIcon(server: ServerConf, ignoreCerts = false): P
|
||||
export async function updateSavedServer(url: string, index: number): Promise<void> {
|
||||
// Does not promise successful update
|
||||
const oldIcon = getDomain(index).icon;
|
||||
const {ignoreCerts} = getDomain(index);
|
||||
try {
|
||||
const newServerConf = await checkDomain(url, ignoreCerts, true);
|
||||
const localIconUrl = await saveServerIcon(newServerConf, ignoreCerts);
|
||||
const newServerConf = await checkDomain(url, true);
|
||||
const localIconUrl = await saveServerIcon(newServerConf);
|
||||
if (!oldIcon || localIconUrl !== '../renderer/img/icon.png') {
|
||||
newServerConf.icon = localIconUrl;
|
||||
updateDomain(index, newServerConf);
|
||||
|
||||
@@ -5,7 +5,6 @@ import backoff from 'backoff';
|
||||
import request from 'request';
|
||||
import Logger from './logger-util';
|
||||
import * as RequestUtil from './request-util';
|
||||
import * as DomainUtil from './domain-util';
|
||||
|
||||
const logger = new Logger({
|
||||
file: 'domain-util.log',
|
||||
@@ -35,15 +34,10 @@ export default class ReconnectUtil {
|
||||
async isOnline(): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
try {
|
||||
const ignoreCerts = DomainUtil.shouldIgnoreCerts(this.url);
|
||||
if (ignoreCerts === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
request(
|
||||
{
|
||||
url: `${this.url}/static/favicon.ico`,
|
||||
...RequestUtil.requestOptions(this.url, ignoreCerts)
|
||||
...RequestUtil.requestOptions(this.url)
|
||||
},
|
||||
(error: Error, response: request.Response) => {
|
||||
const isValidResponse =
|
||||
|
||||
@@ -20,12 +20,9 @@ interface RequestUtilResponse {
|
||||
proxy: string | void | ProxyUtil.ProxyRule;
|
||||
ecdhCurve: 'auto';
|
||||
headers: { 'User-Agent': string };
|
||||
rejectUnauthorized: boolean;
|
||||
}
|
||||
|
||||
// ignoreCerts parameter helps in fetching server icon and
|
||||
// other server details when user chooses to ignore certificate warnings
|
||||
export function requestOptions(domain: string, ignoreCerts: boolean): RequestUtilResponse {
|
||||
export function requestOptions(domain: string): RequestUtilResponse {
|
||||
domain = formatUrl(domain);
|
||||
const certificate = CertificateUtil.getCertificate(
|
||||
encodeURIComponent(domain)
|
||||
@@ -56,8 +53,7 @@ export function requestOptions(domain: string, ignoreCerts: boolean): RequestUti
|
||||
ca: certificateLocation ? certificateLocation : '',
|
||||
proxy: proxyEnabled ? ProxyUtil.getProxy(domain) : '',
|
||||
ecdhCurve: 'auto',
|
||||
headers: {'User-Agent': SystemUtil.getUserAgent()},
|
||||
rejectUnauthorized: !ignoreCerts
|
||||
headers: {'User-Agent': SystemUtil.getUserAgent()}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,14 +19,12 @@ export function noOrgsError(domain: string): string {
|
||||
}
|
||||
|
||||
export function certErrorMessage(domain: string, error: string): string {
|
||||
return `Do you trust certificate from ${domain}? \n ${error}`;
|
||||
return `Certificate error for ${domain}\n${error}`;
|
||||
}
|
||||
|
||||
export function certErrorDetail(): string {
|
||||
return `The organization you're connecting to is either someone impersonating the Zulip server you entered, or the server you're trying to connect to is configured in an insecure way.
|
||||
\nIf you have a valid certificate please add it from Settings>Organizations and try to add the organization again.
|
||||
\nUnless you have a good reason to believe otherwise, you should not proceed.
|
||||
\nYou can click here if you'd like to proceed with the connection.`;
|
||||
\nIf you have a valid certificate please add it from Settings>Organizations and try to add the organization again.`;
|
||||
}
|
||||
|
||||
export function enterpriseOrgError(length: number, domains: string[]): DialogBoxError {
|
||||
|
||||
Reference in New Issue
Block a user