Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: basic input validation #36

Merged
merged 5 commits into from
Nov 2, 2023
Merged
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
2 changes: 1 addition & 1 deletion packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/NasCorp/ChainTrack.git"
},
"source": {
"shasum": "OvK593qWxunqLzYauRLiCYdyz+BM8fvQRyAl5h7h4To=",
"shasum": "zHEfroS3bbzLdjFj6gCNkjHdw+oH38IOyhtYmrmeoZE=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
70 changes: 53 additions & 17 deletions packages/snap/src/rpc/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ import { panel, heading, text, copyable, divider } from '@metamask/snaps-ui';
import { ChainIdToNameEnum } from '../../../shared/types';
import { create } from './create';

function sanitizeString(str: string): string {
return str
.replace(/[\r\n]/gmu, '')
.replace(/\s+/gu, ' ')
.trim();
}

function validateAddress(address: string): boolean {
return /^0x[a-fA-F0-9]{40}$/u.test(address);
}

/**
* Handle incoming JSON-RPC requests, sent through `wallet_invokeSnap`.
*
Expand Down Expand Up @@ -39,8 +50,6 @@ export async function add(): Promise<void> {
throw new Error('Network is not confirmed');
}

// Get the wallet address, from which we expect to have transactions
// TODO: add validation for wallet address
const wallets = await window.ethereum.request<string[]>({
method: 'eth_requestAccounts',
});
Expand All @@ -49,6 +58,19 @@ export async function add(): Promise<void> {
throw new Error('Wallets are not provided');
}

const sanitizedWallets = wallets.map((wallet) => {
if (typeof wallet !== 'string') {
throw new Error('Wallet is not a string');
}
return sanitizeString(wallet);
});

for (const wallet of sanitizedWallets) {
if (!validateAddress(wallet)) {
throw new Error('Wallet address is invalid');
}
}

let name = await snap.request({
method: 'snap_dialog',
params: {
Expand Down Expand Up @@ -86,6 +108,10 @@ export async function add(): Promise<void> {
throw new Error('From is not a string');
}

if (from.length !== 0 && !validateAddress(from)) {
throw new Error('From address is invalid');
}

const intervalHours = await snap.request({
method: 'snap_dialog',
params: {
Expand All @@ -112,26 +138,34 @@ export async function add(): Promise<void> {
throw new Error('Interval can not be less than 1 hour');
}

let contractAddress = await snap.request({
method: 'snap_dialog',
params: {
type: 'prompt',
content: panel([
heading('Contract Address'),
text('By default we monitor ETH transactions.'),
text(
'By default, ChainTrack monitors ETH transactions. To track transactions of another ERC-20 token, please enter its contract address.',
),
]),
let contractAddress: string | boolean | null | undefined = await snap.request(
{
method: 'snap_dialog',
params: {
type: 'prompt',
content: panel([
heading('Contract Address'),
text('By default we monitor ETH transactions.'),
text(
'By default, ChainTrack monitors ETH transactions. To track transactions of another ERC-20 token, please enter its contract address.',
),
]),
},
},
});
);

if (typeof contractAddress !== 'string') {
throw new Error('ContractAddress is not a string');
}

contractAddress = sanitizeString(contractAddress);

if (contractAddress.length !== 0 && !validateAddress(contractAddress)) {
throw new Error('ContractAddress is invalid');
}

if (contractAddress.length === 0) {
contractAddress = null;
contractAddress = undefined;
}

let amount = await snap.request({
Expand All @@ -153,6 +187,8 @@ export async function add(): Promise<void> {
throw new Error('Amount is not a string');
}

amount = sanitizeString(amount);

if (amount.length === 0) {
amount = '0';
} else {
Expand All @@ -165,14 +201,14 @@ export async function add(): Promise<void> {
}
}

for (const wallet of wallets) {
for (const wallet of sanitizedWallets) {
await create({
name,
network,
from,
to: wallet,
intervalHours,
contractAddress: contractAddress || undefined,
contractAddress,
amount: parseFloat(amount),
});
}
Expand Down
5 changes: 4 additions & 1 deletion packages/snap/src/rpc/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { v4 as uuidv4 } from 'uuid';
import storage, { Data } from '../storage';
import { Monitor } from '../../../shared/types';

export type CreateParams = Omit<Monitor, 'intervalMs' | 'lastTransaction'>;
export type CreateParams = Omit<
Monitor,
'intervalMs' | 'lastTransaction' | 'id'
> & { id?: string };

export async function create({
id,
Expand Down