feat: add random identifier to bugsnag reports

This commit is contained in:
Baptiste Grob
2021-01-22 15:31:56 +01:00
parent 2c4742a91d
commit 0bd3143481
6 changed files with 49 additions and 8 deletions

View File

@@ -1,3 +1,3 @@
import { SNWebCrypto } from "@standardnotes/sncrypto-web"; import { SNWebCrypto } from "@standardnotes/sncrypto-web";
export const Crypto = new SNWebCrypto(); export const WebCrypto = new SNWebCrypto();

View File

@@ -24,6 +24,11 @@ import { BackupFile, ContentType } from '@standardnotes/snjs';
import { confirmDialog, alertDialog } from '@/services/alertService'; import { confirmDialog, alertDialog } from '@/services/alertService';
import { autorun, IReactionDisposer } from 'mobx'; import { autorun, IReactionDisposer } from 'mobx';
import { storage, StorageKey } from '@/services/localStorage'; import { storage, StorageKey } from '@/services/localStorage';
import {
disableErrorReporting,
enableErrorReporting,
errorReportingId
} from '@/services/errorReporting';
const ELEMENT_ID_IMPORT_PASSWORD_INPUT = 'import-password-request'; const ELEMENT_ID_IMPORT_PASSWORD_INPUT = 'import-password-request';
@@ -66,6 +71,7 @@ type AccountMenuState = {
syncInProgress: boolean; syncInProgress: boolean;
syncError: string; syncError: string;
showSessions: boolean; showSessions: boolean;
errorReportingId: string | null;
} }
class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> { class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
@@ -99,6 +105,7 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
showBetaWarning: false, showBetaWarning: false,
errorReportingEnabled: storage.get(StorageKey.DisableErrorReporting) === false, errorReportingEnabled: storage.get(StorageKey.DisableErrorReporting) === false,
showSessions: false, showSessions: false,
errorReportingId: errorReportingId(),
} as AccountMenuState; } as AccountMenuState;
} }
@@ -550,9 +557,9 @@ class AccountMenuCtrl extends PureViewCtrl<unknown, AccountMenuState> {
toggleErrorReportingEnabled() { toggleErrorReportingEnabled() {
if (this.state.errorReportingEnabled) { if (this.state.errorReportingEnabled) {
storage.set(StorageKey.DisableErrorReporting, true); disableErrorReporting();
} else { } else {
storage.set(StorageKey.DisableErrorReporting, false); enableErrorReporting();
} }
if (!this.state.syncInProgress) { if (!this.state.syncInProgress) {
window.location.reload(); window.location.reload();

View File

@@ -2,6 +2,7 @@ import { isNullOrUndefined, SNLog } from '@standardnotes/snjs';
import { isDesktopApplication, isDev } from '@/utils'; import { isDesktopApplication, isDev } from '@/utils';
import { storage, StorageKey } from './localStorage'; import { storage, StorageKey } from './localStorage';
import Bugsnag from '@bugsnag/js'; import Bugsnag from '@bugsnag/js';
import { WebCrypto } from '../crypto';
declare const __VERSION__: string; declare const __VERSION__: string;
declare global { declare global {
@@ -21,7 +22,7 @@ function redactFilePath(line: string): string {
} }
} }
export function startErrorReporting() { export function startErrorReporting(): void {
const disableErrorReporting = storage.get(StorageKey.DisableErrorReporting); const disableErrorReporting = storage.get(StorageKey.DisableErrorReporting);
if ( if (
/** /**
@@ -37,6 +38,15 @@ export function startErrorReporting() {
return; return;
} }
try { try {
const storedUserId = storage.get(StorageKey.AnonymousUserId);
let anonymousUserId: string;
if (storedUserId === null) {
anonymousUserId = WebCrypto.generateUUIDSync();
storage.set(StorageKey.AnonymousUserId, anonymousUserId);
} else {
anonymousUserId = storedUserId;
}
Bugsnag.start({ Bugsnag.start({
apiKey: window._bugsnag_api_key, apiKey: window._bugsnag_api_key,
appType: isDesktopApplication() ? 'desktop' : 'web', appType: isDesktopApplication() ? 'desktop' : 'web',
@@ -46,6 +56,8 @@ export function startErrorReporting() {
releaseStage: isDev ? 'development' : undefined, releaseStage: isDev ? 'development' : undefined,
enabledBreadcrumbTypes: ['error', 'log'], enabledBreadcrumbTypes: ['error', 'log'],
onError(event) { onError(event) {
event.setUser(anonymousUserId);
/** /**
* Redact any data that could be used to identify user, * Redact any data that could be used to identify user,
* such as file paths. * such as file paths.
@@ -95,3 +107,16 @@ export function startErrorReporting() {
SNLog.onError = console.error; SNLog.onError = console.error;
} }
} }
export function disableErrorReporting() {
storage.remove(StorageKey.AnonymousUserId);
storage.set(StorageKey.DisableErrorReporting, true);
}
export function enableErrorReporting() {
storage.set(StorageKey.DisableErrorReporting, false);
}
export function errorReportingId() {
return storage.get(StorageKey.AnonymousUserId);
}

View File

@@ -1,9 +1,11 @@
export enum StorageKey { export enum StorageKey {
DisableErrorReporting = 'DisableErrorReporting', DisableErrorReporting = 'DisableErrorReporting',
AnonymousUserId = 'AnonymousUserId',
} }
export type StorageValue = { export type StorageValue = {
[StorageKey.DisableErrorReporting]: boolean; [StorageKey.DisableErrorReporting]: boolean;
[StorageKey.AnonymousUserId]: string;
} }
export const storage = { export const storage = {
@@ -11,10 +13,10 @@ export const storage = {
const value = localStorage.getItem(key); const value = localStorage.getItem(key);
return value ? JSON.parse(value) : null; return value ? JSON.parse(value) : null;
}, },
set<K extends StorageKey>(key: K, value: StorageValue[K]) { set<K extends StorageKey>(key: K, value: StorageValue[K]): void {
localStorage.setItem(key, JSON.stringify(value)); localStorage.setItem(key, JSON.stringify(value));
}, },
remove(key: StorageKey) { remove(key: StorageKey): void {
localStorage.removeItem(key); localStorage.removeItem(key);
}, },
}; };

View File

@@ -26,7 +26,7 @@ import {
} from '@/services'; } from '@/services';
import { AppState } from '@/ui_models/app_state'; import { AppState } from '@/ui_models/app_state';
import { Bridge } from '@/services/bridge'; import { Bridge } from '@/services/bridge';
import { Crypto } from '@/crypto'; import { WebCrypto } from '@/crypto';
type WebServices = { type WebServices = {
appState: AppState; appState: AppState;
@@ -60,7 +60,7 @@ export class WebApplication extends SNApplication {
bridge.environment, bridge.environment,
platformFromString(getPlatformString()), platformFromString(getPlatformString()),
deviceInterface, deviceInterface,
Crypto, WebCrypto,
new AlertService(), new AlertService(),
identifier, identifier,
undefined, undefined,

View File

@@ -293,6 +293,13 @@
p.sk-p p.sk-p
| Help us improve Standard Notes by automatically submitting | Help us improve Standard Notes by automatically submitting
| anonymized error reports. | anonymized error reports.
p.sk-p.selectable(ng-if="self.state.errorReportingId")
| Your random identifier is
strong {{ self.state.errorReportingId }}
p.sk-p(ng-if="self.state.errorReportingId")
| Disabling error reporting will remove that identifier from your
| local storage, and a new identifier will be created should you
| decide to enable error reporting again in the future.
.sk-panel-row .sk-panel-row
button(ng-click="self.toggleErrorReportingEnabled()").sk-button.info button(ng-click="self.toggleErrorReportingEnabled()").sk-button.info
span.sk-label {{ self.state.errorReportingEnabled ? 'Disable' : 'Enable'}} Error Reporting span.sk-label {{ self.state.errorReportingEnabled ? 'Disable' : 'Enable'}} Error Reporting