Skip to content

Commit b5dbd70

Browse files
committed
feat: add isMessageWhitelisted() in MessageBuilder
TICKET: SC-2419
1 parent e74eaaf commit b5dbd70

File tree

7 files changed

+42
-50
lines changed

7 files changed

+42
-50
lines changed

modules/account-lib/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ export { Vet };
206206
import * as CosmosSharedCoin from '@bitgo/sdk-coin-cosmos';
207207
export { CosmosSharedCoin };
208208

209-
import { validateAgainstMessageTemplates, MIDNIGHT_TNC_HASH } from './utils';
210-
export { MIDNIGHT_TNC_HASH };
209+
import { isMessageWhitelisted, MIDNIGHT_TNC_HASH, MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE } from './utils';
210+
export { isMessageWhitelisted, MIDNIGHT_TNC_HASH, MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE };
211211

212212
const coinBuilderMap = {
213213
trx: Trx.WrappedBuilder,
@@ -435,7 +435,7 @@ export async function verifyMessage(
435435
if (!isValidMessageEncoded) {
436436
return false;
437437
}
438-
return validateAgainstMessageTemplates(messageRaw);
438+
return messageBuilder.isMessageWhitelisted(messageRaw);
439439
} catch (e) {
440440
console.error(`Error verifying message for coin ${coinName}:`, e);
441441
return false;

modules/account-lib/src/utils/messages/index.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,20 @@ export const MIDNIGHT_TNC_HASH = '31a6bab50a84b8439adcfb786bb2020f6807e6e8fda629
55
* then " to addr" or " to addr_test1", followed by a 50+ character alphanumeric address,
66
* and ends with the midnight TnC hash
77
*/
8-
const MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE = `STAR \\d+ to addr(?:1|_test1)[a-z0-9]{50,} ${MIDNIGHT_TNC_HASH}`;
9-
10-
/**
11-
* @file Utility functions for validating messages against whitelisted templates.
12-
* This is used to ensure that only specific message formats are accepted.
13-
*/
14-
const whitelistedMessageTemplates = [MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE];
8+
export const MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE = `STAR \\d+ to addr(?:1|_test1)[a-z0-9]{50,} ${MIDNIGHT_TNC_HASH}`;
159

1610
/**
1711
* Validates a message against a set of whitelisted templates.
1812
* The templates can contain placeholders like {{variable}} which will be replaced with a wildcard in the regex.
1913
*
14+
* @param whitelistedMessageTemplates - An array of whitelisted message templates.
2015
* @param {string} messageRaw - The raw message to validate.
2116
* @returns {boolean} - Returns true if the message matches any of the whitelisted templates, false otherwise.
2217
*/
23-
export function validateAgainstMessageTemplates(messageRaw: string): boolean {
18+
export function isMessageWhitelisted(whitelistedMessageTemplates: string[], messageRaw: string): boolean {
19+
if (!whitelistedMessageTemplates || whitelistedMessageTemplates.length === 0) {
20+
return true;
21+
}
2422
return whitelistedMessageTemplates.some((template) => {
2523
const regex = new RegExp(`^${template}$`, 's'); // 's' flag to match newlines
2624
return regex.test(messageRaw);

modules/account-lib/test/unit/utils/messages/index.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,38 @@
11
import should from 'should';
2-
import { MIDNIGHT_TNC_HASH, validateAgainstMessageTemplates } from '../../../../src/utils';
2+
import {
3+
MIDNIGHT_TNC_HASH,
4+
isMessageWhitelisted,
5+
MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE,
6+
} from '../../../../src/utils';
37

48
describe('Message validation', () => {
5-
describe('validateAgainstMessageTemplates', () => {
9+
describe('isMessageWhitelisted', () => {
10+
const whitelistedMessageTemplates = [MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE];
11+
612
const adaTestnetDestinationAddress = 'addr_test1vz7xs7ceu4xx9n5xn57lfe86vrwddqpp77vjwq5ptlkh49cqy3wur';
713
const adaMainnetDestinationAddress =
814
'addr1q9k6u7lhf467y2f8skr2dafldx2npsd8fymq0mslnj0t44nd4ealwnt4ug5j0pvx5m6n76v4xrq6wjfkqlhpl8y7httq2m9cmu';
915

1016
it('should validate testnet message matching the Midnight glacier drop claim template', () => {
1117
const messageRaw = `STAR 100 to ${adaTestnetDestinationAddress} ${MIDNIGHT_TNC_HASH}`;
1218

13-
const result = validateAgainstMessageTemplates(messageRaw);
19+
const result = isMessageWhitelisted(whitelistedMessageTemplates, messageRaw);
1420

1521
should.equal(result, true);
1622
});
1723

1824
it('should validate mainnet message matching the Midnight glacier drop claim template', () => {
1925
const messageRaw = `STAR 100 to ${adaMainnetDestinationAddress} ${MIDNIGHT_TNC_HASH}`;
2026

21-
const result = validateAgainstMessageTemplates(messageRaw);
27+
const result = isMessageWhitelisted(whitelistedMessageTemplates, messageRaw);
2228

2329
should.equal(result, true);
2430
});
2531

2632
it('should not validate message with incorrect format', () => {
2733
const messageRaw = `INCORRECT 100 to ${adaTestnetDestinationAddress} ${MIDNIGHT_TNC_HASH}`;
2834

29-
const result = validateAgainstMessageTemplates(messageRaw);
35+
const result = isMessageWhitelisted(whitelistedMessageTemplates, messageRaw);
3036

3137
should.equal(result, false);
3238
});
@@ -35,7 +41,7 @@ describe('Message validation', () => {
3541
// Missing "to addr" part
3642
const messageRaw = `STAR 100 ${MIDNIGHT_TNC_HASH}`;
3743

38-
const result = validateAgainstMessageTemplates(messageRaw);
44+
const result = isMessageWhitelisted(whitelistedMessageTemplates, messageRaw);
3945

4046
should.equal(result, false);
4147
});
@@ -46,21 +52,21 @@ describe('Message validation', () => {
4652
'5af1adf825baa496729e2eac1e895ebc77973744bce67f44276bf6006f5c21de863ed121e11828d8fc0241773191e26dc1134803a681a9a98ba0ae812553db24';
4753
const messageRaw = `STAR 100 to ${adaTestnetDestinationAddress} ${incorrectHash}`;
4854

49-
const result = validateAgainstMessageTemplates(messageRaw);
55+
const result = isMessageWhitelisted(whitelistedMessageTemplates, messageRaw);
5056

5157
should.equal(result, false);
5258
});
5359

5460
it('should handle empty message', () => {
55-
const result = validateAgainstMessageTemplates('');
61+
const result = isMessageWhitelisted(whitelistedMessageTemplates, '');
5662

5763
should.equal(result, false);
5864
});
5965

6066
it('should not validate message with special regex characters', () => {
6167
const messageRaw = `STAR shade.with+special*chars to addr.with[special]chars ${MIDNIGHT_TNC_HASH}`;
6268

63-
const result = validateAgainstMessageTemplates(messageRaw);
69+
const result = isMessageWhitelisted(whitelistedMessageTemplates, messageRaw);
6470

6571
should.equal(result, false);
6672
});
Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
11
import { Cip8Message } from './cip8Message';
22
import { BaseCoin as CoinConfig } from '@bitgo/statics';
33
import { BaseMessageBuilder, IMessage, MessageOptions, MessageStandardType } from '@bitgo/sdk-core';
4+
import { MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE } from '@bitgo/account-lib';
45

56
/**
67
* Builder for CIP-8 messages
78
*/
89
export class Cip8MessageBuilder extends BaseMessageBuilder {
9-
private static readonly MIDNIGHT_TNC_HASH = '31a6bab50a84b8439adcfb786bb2020f6807e6e8fda629b424110fc7bb1c6b8b';
10-
11-
/*
12-
* matches a message that starts with "STAR ", followed by a number,
13-
* then " to addr" or " to addr_test1", followed by a 50+ character alphanumeric address,
14-
* and ends with the midnight TnC hash
15-
*/
16-
private static readonly MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE = `STAR \\d+ to addr(?:1|_test1)[a-z0-9]{50,} ${Cip8MessageBuilder.MIDNIGHT_TNC_HASH}`;
1710
/**
1811
* Base constructor.
1912
* @param _coinConfig BaseCoin from statics library
2013
*/
2114
public constructor(_coinConfig: Readonly<CoinConfig>) {
2215
super(_coinConfig, MessageStandardType.CIP8);
16+
this.whitelistedMessageTemplates = [
17+
MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE,
18+
// Add more templates as needed
19+
];
2320
}
2421

2522
/**
@@ -30,15 +27,4 @@ export class Cip8MessageBuilder extends BaseMessageBuilder {
3027
async buildMessage(options: MessageOptions): Promise<IMessage> {
3128
return new Cip8Message(options);
3229
}
33-
34-
/**
35-
* Validates the signable payload
36-
* @param message The message to validate
37-
* @returns A boolean indicating whether the signable payload is valid
38-
*/
39-
public validateSignablePayload(message: string | Buffer): boolean {
40-
const messageStr = Buffer.isBuffer(message) ? message.toString('utf8') : message;
41-
const regex = new RegExp(`^${Cip8MessageBuilder.MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE}$`, 's');
42-
return regex.test(messageStr);
43-
}
4430
}

modules/sdk-core/src/account-lib/baseCoin/messages/baseMessageBuilder.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { BroadcastableMessage, MessageOptions, MessagePayload, MessageStandardTy
22
import { BaseCoin as CoinConfig } from '@bitgo/statics';
33
import { IMessage, IMessageBuilder } from './iface';
44
import { deserializeSignatures, Signature } from '../iface';
5+
import { isMessageWhitelisted } from '@bitgo/account-lib';
56

67
/**
78
* Base Message Builder
@@ -12,6 +13,7 @@ export abstract class BaseMessageBuilder implements IMessageBuilder {
1213
protected type: MessageStandardType;
1314
protected signatures: Signature[] = [];
1415
protected signers: string[] = [];
16+
protected whitelistedMessageTemplates: string[] = [];
1517
protected metadata?: Record<string, unknown> = {};
1618
protected digest?: string;
1719

@@ -118,13 +120,8 @@ export abstract class BaseMessageBuilder implements IMessageBuilder {
118120
return this;
119121
}
120122

121-
/**
122-
* Validates the signable payload
123-
* @param message The message to validate
124-
* @returns A boolean indicating whether the signable payload is valid
125-
*/
126-
public validateSignablePayload(message: string | Buffer): boolean {
127-
return true;
123+
public isMessageWhitelisted(messageRaw: string): boolean {
124+
return isMessageWhitelisted(this.whitelistedMessageTemplates, messageRaw);
128125
}
129126

130127
/**

modules/sdk-core/src/account-lib/baseCoin/messages/iface.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,11 @@ export interface IMessageBuilder {
137137
getPayload(): MessagePayload | undefined;
138138

139139
/**
140-
* Validates the signable payload
141-
* @param message The message to validate
142-
* @returns A boolean indicating whether the signable payload is valid
140+
* Checks if the message string is whitelisted
141+
* @param messageRaw The raw message string to check
142+
* @return True if the message is whitelisted, false otherwise
143143
*/
144-
validateSignablePayload(message: string | Buffer): boolean;
144+
isMessageWhitelisted(messageRaw: string): boolean;
145145

146146
/**
147147
* Gets the current metadata

modules/sdk-core/src/account-lib/baseCoin/messages/simple/simpleMessageBuilder.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { BaseCoin as CoinConfig } from '@bitgo/statics';
33
import { BaseMessageBuilder } from '../baseMessageBuilder';
44
import { MessageOptions, MessageStandardType } from '../../../../bitgo';
55
import { IMessage } from '../iface';
6+
import { MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE } from '@bitgo/account-lib';
67

78
/**
89
* Builder for string messages
@@ -14,6 +15,10 @@ export class SimpleMessageBuilder extends BaseMessageBuilder {
1415
*/
1516
public constructor(_coinConfig: Readonly<CoinConfig>) {
1617
super(_coinConfig, MessageStandardType.SIMPLE);
18+
this.whitelistedMessageTemplates = [
19+
MIDNIGHT_GLACIER_DROP_CLAIM_MESSAGE_TEMPLATE,
20+
// Add more templates as needed
21+
];
1722
}
1823

1924
/**

0 commit comments

Comments
 (0)