Skip to content

Commit

Permalink
watcher: add checks for base64 in cosmwasm
Browse files Browse the repository at this point in the history
  • Loading branch information
panoel committed Oct 23, 2023
1 parent 76babfe commit edc3b97
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 4 deletions.
22 changes: 18 additions & 4 deletions watcher/src/watchers/CosmwasmWatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { makeBlockKey, makeVaaKey } from '../databases/utils';
import { Watcher } from './Watcher';
import { SHA256 } from 'jscrypto/SHA256';
import { Base64 } from 'jscrypto/Base64';
import { isBase64Encoded } from './utils';

export class CosmwasmWatcher extends Watcher {
latestBlockTag: string;
Expand Down Expand Up @@ -112,14 +113,27 @@ export class CosmwasmWatcher extends Watcher {
// only care about _contract_address, message.sender and message.sequence
const numAttrs = attrs.length;
for (let k = 0; k < numAttrs; k++) {
const key = Buffer.from(attrs[k].key, 'base64').toString().toLowerCase();
let base64Encoded: boolean = false;
let key: string;
if (isBase64Encoded(attrs[k].key)) {
key = Buffer.from(attrs[k].key, 'base64').toString().toLowerCase();
base64Encoded = true;
} else {
key = attrs[k].key.toLowerCase();
}
this.logger.debug('Encoded Key = ' + attrs[k].key + ', decoded = ' + key);
if (key === 'message.sender') {
emitter = Buffer.from(attrs[k].value, 'base64').toString();
emitter = base64Encoded
? Buffer.from(attrs[k].value, 'base64').toString()
: attrs[k].value;
} else if (key === 'message.sequence') {
sequence = Buffer.from(attrs[k].value, 'base64').toString();
sequence = base64Encoded
? Buffer.from(attrs[k].value, 'base64').toString()
: attrs[k].value;
} else if (key === '_contract_address' || key === 'contract_address') {
let addr = Buffer.from(attrs[k].value, 'base64').toString();
let addr = base64Encoded
? Buffer.from(attrs[k].value, 'base64').toString()
: attrs[k].value;
if (addr === address) {
coreContract = true;
}
Expand Down
22 changes: 22 additions & 0 deletions watcher/src/watchers/__tests__/CosmwasmWatcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { InjectiveExplorerWatcher } from '../InjectiveExplorerWatcher';
import { SeiExplorerWatcher } from '../SeiExplorerWatcher';
import { WormchainWatcher } from '../WormchainWatcher';
import { INITIAL_DEPLOYMENT_BLOCK_BY_CHAIN } from '@wormhole-foundation/wormhole-monitor-common';
import { isBase64Encoded } from '../utils';

jest.setTimeout(60000);

Expand Down Expand Up @@ -213,3 +214,24 @@ test('getMessagesForBlocks(wormchain)', async () => {
'4D861F1BE86325D227FA006CA2745BBC6748AF5B5E0811DE536D02792928472A:3104/aeb534c45c3049d380b9d9b966f9895f53abd4301bfaff407fa09dea8ae7a924/0',
]);
});

test('isBase64Encoded', async () => {
const msg1: string = 'message.sender';
const bmsg1: string = Buffer.from(msg1).toString('base64');
const msg2: string = 'message.sequence';
const bmsg2: string = Buffer.from(msg1).toString('base64');
const msg3: string = '_contract.address';
const bmsg3: string = Buffer.from(msg1).toString('base64');
expect(isBase64Encoded(msg1)).toBe(false);
expect(isBase64Encoded(msg2)).toBe(false);
expect(isBase64Encoded(msg3)).toBe(false);
expect(isBase64Encoded(bmsg1)).toBe(true);
expect(isBase64Encoded(bmsg2)).toBe(true);
expect(isBase64Encoded(bmsg3)).toBe(true);

// This test shows the risk involved with checking for base64 encoding.
// The following is, actually, clear text. But it passes the base64 encoding check.
// So, passing addresses into the check should be done with caution.
const addr: string = 'terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp';
expect(isBase64Encoded(addr)).toBe(true);
});
14 changes: 14 additions & 0 deletions watcher/src/watchers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,17 @@ export function makeFinalizedWatcher(chainName: ChainName): Watcher {
throw new Error(`Attempted to create finalized watcher for unsupported chain ${chainName}`);
}
}

// This function uses a regex string to check if the input could
// possibly be base64 encoded.
//
// WARNING: There are clear text strings that are NOT base64 encoded
// that will pass this check.
export function isBase64Encoded(input: string): boolean {
const b64Regex = new RegExp('^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$');
const match = b64Regex.exec(input);
if (match) {
return true;
}
return false;
}

0 comments on commit edc3b97

Please sign in to comment.