Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ coverage
dist
build_extension
.note
.DS_Store
.idea
1 change: 1 addition & 0 deletions client/.babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@cd/selectors": "./src/selectors",
"@cd/services": "./src/services",
"@cd/shared": "./src/shared",
"@cd/libs": "./src/libs",
"@cd/store": "./src/store",
"@cd/config": "./src/config",
"@cd/constants": "./src/constants",
Expand Down
1 change: 1 addition & 0 deletions client/.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
SKIP_PREFLIGHT_CHECK=true
NODE_ENV=development
REACT_APP_SENTRY_DSN=
3 changes: 2 additions & 1 deletion client/.env.development.local
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
REACT_APP_API_ROOT=http://localhost:3001
REACT_APP_AUCTION_HASH=93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2
REACT_APP_DEBUG_ENV=true
AUTO_LOCK_TIMEOUT_ALARM=10
AUTO_LOCK_TIMEOUT_ALARM=10
REACT_APP_SENTRY_DSN=
1 change: 1 addition & 0 deletions client/.env.production.local
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ REACT_APP_AUCTION_HASH=ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04
REACT_APP_AVAILABLE_FEATURES=["home","dashboard","history","nfts","tokens","staking"]
APP_ENVIRONMENT=prod
REACT_APP_VERSION=1.6.2
REACT_APP_SENTRY_DSN=
1 change: 1 addition & 0 deletions client/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const config = {
"^@cd/actions(.*)$": "<rootDir>/src/actions$1",
"^@cd/helpers(.*)$": "<rootDir>/src/helpers$1",
"^@cd/selectors(.*)$": "<rootDir>/src/selectors$1",
"^@cd/libs(.*)$": "<rootDir>/src/libs$1",
"^@cd/services(.*)$": "<rootDir>/src/services$1",
"^@cd/shared(.*)$": "<rootDir>/src/shared$1",
"^@cd/store(.*)$": "<rootDir>/src/store$1",
Expand Down
2 changes: 2 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"@popperjs/core": "2.11.6",
"@redux-requests/axios": "^1.1.1",
"@redux-requests/core": "^1.6.2",
"@sentry/browser": "^7.59.3",
"@sentry/integrations": "^7.60.0",
"@tanstack/react-query": "^4.29.5",
"@zondax/ledger-casper": "^0.0.1",
"apexcharts": "^3.30.0",
Expand Down
2 changes: 2 additions & 0 deletions client/src/app/web-extension/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import 'react-toastify/dist/ReactToastify.css';
import '../../../node_modules/bootstrap/dist/css/bootstrap.min.css';
import './App.scss';

import '@cd/libs/installSentry';

const getRoutes = (routes) => {
return (
routes &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
selectCreateWalletDerivationPath,
} from '@cd/selectors/createWallet';
import { createUserServiceSW } from '@cd/components/hooks/useServiceWorker';
import { ERRORS } from '@cd/constants/errors';

const useCreateUser = () => {
const navigate = useNavigate();
Expand All @@ -34,7 +35,7 @@ const useCreateUser = () => {
async (password) => {
try {
if (!keyPhrase) {
throw new Error('Missing keyphrase');
throw new Error(ERRORS.MISSING_KEYPHRASE);
}

const result = await createUserServiceSW(password, keyPhrase, encryptionType, derivationPath);
Expand Down
4 changes: 4 additions & 0 deletions client/src/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ const CONFIG_OPTIONS = {
env: 'REACT_APP_EXPLORER_ROOT_LINK',
default: 'https://testnet.cspr.live',
},
SENTRY_DSN: {
env: 'REACT_APP_SENTRY_DSN',
default: '',
}
};

const getConfigOption = (option) => {
Expand Down
11 changes: 11 additions & 0 deletions client/src/constants/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const ERRORS = {
MISSING_KEYPHRASE: 'Missing keyphrase',
YOUR_ACCOUNT_HAS_NOT_BEEN_CREATED: 'Your account has not been created',
PROVIDED_TARGET_PUBLIC_KEY_DOESNT_MATCH: 'Provided target public key doesn\'t match the one in deploy',
PROVIDED_TARGET_PUBLIC_KEY_DOESNT_MATCH_DEPLOY: 'The provided target public key does not match the one specified in the deploy',
TARGET_SPECIFIED_IN_DEPLOY_NOT_CORRECT_FORMAT: 'The target specified in the deploy is not in the correct format, it must be either an AccountHash or a PublicKey',
FAILED_TO_PARSE_KEY_ARGUMENT: 'Failed to parse key argument',
MISSING_USER_SERVICE_INSTANCE: 'Missing UserService instance',
THIS_SITE_IS_NOT_CONNECTED: 'This site is not connected',
CAN_NOT_SIGN_MESSAGE: 'Can not sign message',
}
9 changes: 5 additions & 4 deletions client/src/helpers/extension/signing.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
CLPublicKey
} from 'casper-js-sdk';
import browser from 'webextension-polyfill';
import { ERRORS } from '@cd/constants/errors';

export async function updateStatusEvent(tabId, msg, {
isUnlocked,
Expand Down Expand Up @@ -46,7 +47,7 @@ export function verifyTargetAccountMatch(

if (providedTargetKeyHash !== targetAccountHash) {
throw new Error(
"Provided target public key doesn't match the one in deploy"
ERRORS.PROVIDED_TARGET_PUBLIC_KEY_DOESNT_MATCH
);
}
}
Expand Down Expand Up @@ -120,12 +121,12 @@ export const parseTransferData = (transferDeploy, providedTarget) => {
case CLTypeTag.PublicKey:
targetFromDeployHex = targetFromDeploy.toHex();
if (providedTarget && targetFromDeployHex.toLowerCase() !== providedTarget.toLowerCase()) {
throw new Error("The provided target public key does not match the one specified in the deploy.");
throw new Error(ERRORS.PROVIDED_TARGET_PUBLIC_KEY_DOESNT_MATCH_DEPLOY);
}
transferArgs['Recipient (Key)'] = targetFromDeployHex;
break;
default:
throw new Error('The target specified in the deploy is not in the correct format, it must be either an AccountHash or a PublicKey.');
throw new Error(ERRORS.TARGET_SPECIFIED_IN_DEPLOY_NOT_CORRECT_FORMAT);
}

transferArgs['Amount'] = transferDeploy.getArgByName('amount').value().toString();
Expand Down Expand Up @@ -160,7 +161,7 @@ export function parseDeployArg(arg) {
if (key.isAccount() || key.isURef() || key.isHash()) {
return parseDeployArg(value);
}
throw new Error('Failed to parse key argument');
throw new Error(ERRORS.FAILED_TO_PARSE_KEY_ARGUMENT);
}

case CLTypeTag.URef:
Expand Down
3 changes: 3 additions & 0 deletions client/src/libs/installSentry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { setupSentry } from './setupSentry';

setupSentry();
33 changes: 33 additions & 0 deletions client/src/libs/setupSentry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import config from '@cd/config';
import { getVersion } from '@cd/helpers/key';
import * as Sentry from '@sentry/browser';
import { Dedupe as DedupeIntegration } from "@sentry/integrations";
import { ERRORS } from '@cd/constants/errors';

const IGNORE_ERRORS = [
...Object.values(ERRORS),
];

export const setupSentry = () => {
Sentry.init({
dsn: config.SENTRY_DSN,
environment: config.APP_ENVIRONMENT,
release: 'casperdash-extension@' + getVersion(),
beforeSend(event, hint) {
const error = hint.originalException;
if (
error &&
error.message &&
error.message.match(new RegExp(IGNORE_ERRORS.join('|'), 'i'))
) {

return null;
}

return event;
},
integrations: [
new DedupeIntegration(),
],
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { DeployUtil, signFormattedMessage } from 'casper-js-sdk';
import _get from 'lodash-es/get';
import UserService from '@cd/services/ServiceWorker/UserService';
import { getConnectedAccountChromeLocalStorage, cacheLoginInfoToLocalStorage } from '@cd/actions/userActions.utils';
import { ERRORS } from '@cd/constants/errors';
class AccountController {
/**
* Only available after creating new User or successfully
Expand Down Expand Up @@ -81,7 +82,7 @@ class AccountController {

getPublicKey = async () => {
if (!this.userService) {
throw new Error('Missing UserService instance');
throw new Error(ERRORS.MISSING_USER_SERVICE_INSTANCE);
}

return this.userService.getPublicKey();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import _isEmpty from 'lodash-es/isEmpty';
import _get from 'lodash-es/get';
import { getLastError, updateStatusEvent } from '@cd/helpers/extension/signing';
import { getConnectedAccountChromeLocalStorage } from '@cd/actions/userActions.utils';
import { ERRORS } from '@cd/constants/errors';

const CONNECTED_SITES = 'connectedSites';
const BLACKLIST_PROTOCOLS = ['chrome-extension:', 'chrome:'];
Expand Down Expand Up @@ -92,7 +93,7 @@ class PopupController {
const account = await getConnectedAccountChromeLocalStorage();
const loginOptions = _get(account, 'loginOptions', null);
if (!loginOptions) {
throw new Error('Your account has not been created.');
throw new Error(ERRORS.YOUR_ACCOUNT_HAS_NOT_BEEN_CREATED);
}

const isConnected = await this.isConnected({ origin });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import EventEmitter from 'events';
import { DeployUtil, encodeBase16, formatMessageWithHeaders } from 'casper-js-sdk';
import _pick from 'lodash-es/pick';
import { getDeployArgs, getDeployPayment, getDeployType } from '@cd/helpers/extension/signing';
import { ERRORS } from '@cd/constants/errors';

const SIGNING_STATUS = {
unsigned: 'Unsigned',
Expand All @@ -24,7 +25,7 @@ class SigningController extends EventEmitter {
getActivePublicKey = async ({ origin }) => {
const isConnected = await this.popupController.isConnected({ origin });
if (!isConnected) {
throw new Error('This site is not connected');
throw new Error(ERRORS.THIS_SITE_IS_NOT_CONNECTED);
}

return this.accountController.getCurrentPublicKey();
Expand All @@ -33,7 +34,7 @@ class SigningController extends EventEmitter {
signDeploy = async ({ deploy, signingPublicKeyHex, targetPublicKeyHex, origin }) => {
const isConnected = await this.popupController.isConnected({ origin });
if (!isConnected) {
throw new Error('This site is not connected');
throw new Error(ERRORS.THIS_SITE_IS_NOT_CONNECTED);
}

let innerDeploy = DeployUtil.deployFromJson(deploy);
Expand Down Expand Up @@ -128,7 +129,7 @@ class SigningController extends EventEmitter {
signMessage = async ({ message, signingPublicKey, origin }) => {
const isConnected = await this.popupController.isConnected({ origin });
if (!isConnected) {
throw new Error('This site is not connected');
throw new Error(ERRORS.THIS_SITE_IS_NOT_CONNECTED);
}

let messageBytes;
Expand Down Expand Up @@ -163,7 +164,7 @@ class SigningController extends EventEmitter {
return reject(new Error(message));
}
default:
reject(new Error('Can not sign message'));
reject(new Error(ERRORS.CAN_NOT_SIGN_MESSAGE));
}
});
});
Expand Down
1 change: 0 additions & 1 deletion client/src/services/stakeServices.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ export const getStakeDeploy = ({
network,
);
} catch (error) {
console.error(error);
throw new Error(`Failed to get stake deploy.`);
}
};
7 changes: 7 additions & 0 deletions client/src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import axios from 'axios';
import { handleRequests } from '@redux-requests/core';
import { createDriver } from '@redux-requests/axios';
import * as Sentry from '@sentry/browser';
import { combineReducers, createStore, applyMiddleware, compose } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import webLocalStorage from 'redux-persist/lib/storage';
Expand Down Expand Up @@ -94,6 +95,12 @@ const { requestsReducer, requestsMiddleware } = handleRequests({
},
onError: (error, action, store) => {
store.dispatch(removeLoadingStatus(action.type));

Sentry.withScope(function (scope) {
scope.setTag('api', 'true');
Sentry.captureException(error);
});

throw error;
},
onAbort: (action, store) => {
Expand Down
2 changes: 1 addition & 1 deletion client/template/extension/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"default_popup": "popup.html"
},
"content_security_policy": {
"extension_pages": "default-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'; script-src 'self'; img-src http: https: data:; connect-src https://testnet-api.casperdash.io https://api.casperdash.io https://cdn.jsdelivr.net https://api.cspr.live; style-src 'unsafe-inline'"
"extension_pages": "default-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'; script-src 'self'; img-src http: https: data:; connect-src https://testnet-api.casperdash.io https://api.casperdash.io https://cdn.jsdelivr.net https://api.cspr.live https://o4505474114715648.ingest.sentry.io; style-src 'unsafe-inline'"
},
"content_scripts": [
{
Expand Down
Loading