diff --git a/package.json b/package.json index 3d627d04a1..f1dddae754 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,8 @@ }, "config": { "bundledKubectlVersion": "1.18.15", - "bundledHelmVersion": "3.5.4" + "bundledHelmVersion": "3.5.4", + "sentryDsn": "" }, "engines": { "node": ">=12 <13" diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index beeb2078e1..e5c65cddbc 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -59,7 +59,7 @@ export class UserStore extends BaseStore /* implements UserStore @observable seenContexts = observable.set(); @observable newContexts = observable.set(); @observable allowTelemetry: boolean; - @observable allowErrorReporting: boolean; + @observable allowErrorReporting: dsnIsValid; @observable allowUntrustedCAs: boolean; @observable colorTheme: string; @observable localeTimezone: string; diff --git a/src/common/utils/isValidURL.ts b/src/common/utils/isValidURL.ts new file mode 100644 index 0000000000..df47f98f6b --- /dev/null +++ b/src/common/utils/isValidURL.ts @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * check if string is valid URL + * + * @param {(string | undefined | null)} url + * @return {boolean} + */ +export const isValidURL = (url: string | undefined | null) => { + if (Boolean(url)) { + try { + new URL(url); + + return true; + } catch { + // ignore TypeError and return false + } + } + + return false; +}; diff --git a/src/common/vars.ts b/src/common/vars.ts index b2ccc23ca7..1ca3d19d6a 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -24,6 +24,7 @@ import path from "path"; import { SemVer } from "semver"; import packageInfo from "../../package.json"; import { defineGlobal } from "./utils/defineGlobal"; +import { isValidURL } from "./utils/isValidURL"; export const isMac = process.platform === "darwin"; export const isWindows = process.platform === "win32"; @@ -71,7 +72,6 @@ export const supportUrl = "https://docs.k8slens.dev/latest/support/" as string; export const appSemVer = new SemVer(packageInfo.version); export const docsUrl = `https://docs.k8slens.dev/main/` as string; -// Sentry DSNs are safe to keep public because they only allow submission of new events -// and related event data; they do not allow read access to any information. -// ref: https://docs.sentry.io/product/sentry-basics/dsn-explainer/#dsn-utilization -export const dsn = "https://673ac8dc2d4649b5bc498639765f995b@o625296.ingest.sentry.io/5753768"; +export const dsn = packageInfo.config.sentryDsn; +export const dsnIsValid = isValidURL(packageInfo.config?.sentryDsn); + diff --git a/src/main/index.ts b/src/main/index.ts index 188f3ceca0..5260b25809 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -26,7 +26,7 @@ import * as Mobx from "mobx"; import * as LensExtensionsCommonApi from "../extensions/common-api"; import * as LensExtensionsMainApi from "../extensions/main-api"; import { app, autoUpdater, dialog, powerMonitor } from "electron"; -import { appName, isMac, productName, dsn, isProduction } from "../common/vars"; +import { appName, isMac, productName, dsn, dsnIsValid, isProduction } from "../common/vars"; import path from "path"; import { LensProxy } from "./proxy/lens-proxy"; import { WindowManager } from "./window-manager"; @@ -62,27 +62,30 @@ import { FilesystemProvisionerStore } from "./extension-filesystem"; import { CaptureConsole, Dedupe, Offline } from "@sentry/integrations"; import * as Sentry from "@sentry/electron/dist/main"; -Sentry.init({ - beforeSend(event) { - const allow = UserStore.getInstance().allowErrorReporting; +if (dsnIsValid) { + Sentry.init({ + beforeSend(event) { + const allow = UserStore.getInstance().allowErrorReporting; - if (allow) return event; + if (allow) return event; + + return null; + }, + dsn, + integrations: [ + new CaptureConsole({ levels: ["error"] }), + new Dedupe(), + new Offline() + ], + initialScope: { + tags: { + "process": "main" + } + }, + environment: isProduction ? "production" : "development" + }); +} - return null; - }, - dsn, - integrations: [ - new CaptureConsole({ levels: ["error"] }), - new Dedupe(), - new Offline() - ], - initialScope: { - tags: { - "process": "main" - } - }, - environment: isProduction ? "production" : "development" -}); const workingDir = path.join(app.getPath("appData"), appName); const cleanup = disposer(); diff --git a/src/renderer/components/+preferences/preferences.tsx b/src/renderer/components/+preferences/preferences.tsx index 61f6554d4b..ddc270ca64 100644 --- a/src/renderer/components/+preferences/preferences.tsx +++ b/src/renderer/components/+preferences/preferences.tsx @@ -41,6 +41,7 @@ import { FormSwitch, Switcher } from "../switch"; import { KubeconfigSyncs } from "./kubeconfig-syncs"; import { SettingLayout } from "../layout/setting-layout"; import { Checkbox } from "../checkbox"; +import { dsnIsValid } from "../../../common/vars"; enum Pages { Application = "application", @@ -258,25 +259,29 @@ export class Preferences extends React.Component {

Telemetry

{telemetryExtensions.map(this.renderExtension)} - -
- - { - UserStore.getInstance().allowErrorReporting = value; - }} - /> -
- + {dsnIsValid ? ( + +
+ + { + UserStore.getInstance().allowErrorReporting = value; + }} + /> +
+ Automatic error reports provide vital information about issues and application crashes. It is highly recommended to keep this feature enabled to ensure fast turnaround for issues you might encounter. - -
-
-
-
+
+
+
+
+
) : + // we don't need to shows the checkbox at all if dsn is not a valid url + null + }
)} {this.activeTab == Pages.Extensions && ( diff --git a/src/renderer/lens-app.tsx b/src/renderer/lens-app.tsx index a82b0d0f57..21109c9355 100644 --- a/src/renderer/lens-app.tsx +++ b/src/renderer/lens-app.tsx @@ -36,32 +36,35 @@ import { registerIpcHandlers } from "./ipc"; import { ipcRenderer } from "electron"; import { IpcRendererNavigationEvents } from "./navigation/events"; import { catalogEntityRegistry } from "./api/catalog-entity-registry"; -import { dsn, isProduction } from "../common/vars"; +import { dsn, dsnIsValid, isProduction } from "../common/vars"; import { CaptureConsole, Dedupe, Offline } from "@sentry/integrations"; import * as Sentry from "@sentry/electron/dist/renderer"; import { UserStore } from "../common/user-store"; -Sentry.init({ - beforeSend(event) { - const allow = UserStore.getInstance().allowErrorReporting; +if (dsnIsValid) { + Sentry.init({ + beforeSend(event) { + const allow = UserStore.getInstance().allowErrorReporting; - if (allow) return event; + if (allow) return event; + + return null; + }, + dsn, + integrations: [ + new CaptureConsole({ levels: ["error"] }), + new Dedupe(), + new Offline() + ], + initialScope: { + tags: { + "process": "renderer" + } + }, + environment: isProduction ? "production" : "development" + }); +} - return null; - }, - dsn, - integrations: [ - new CaptureConsole({ levels: ["error"] }), - new Dedupe(), - new Offline() - ], - initialScope: { - tags: { - "process": "renderer" - } - }, - environment: isProduction ? "production" : "development" -}); @observer export class LensApp extends React.Component {