feat: add random identifier to bugsnag reports
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user