Skip to content

Commit 81bc7cd

Browse files
authored
Merge pull request #436 from Goodnessukaigwe/fix/393-backend-configure-zod-class-validator-strict-validation-pipes
feat: configure strict stellar validation pipes and decorators
2 parents 90df0e1 + e99ff59 commit 81bc7cd

File tree

3 files changed

+62
-4
lines changed

3 files changed

+62
-4
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { validate } from 'class-validator';
2+
import { IsStellarPublicKey } from './is-stellar-key.validator';
3+
4+
class TestDto {
5+
@IsStellarPublicKey()
6+
publicKey: string;
7+
}
8+
9+
describe('IsStellarPublicKey', () => {
10+
it('accepts valid 56-char Stellar public keys starting with G', async () => {
11+
const dto = new TestDto();
12+
dto.publicKey = `G${'A'.repeat(55)}`;
13+
14+
const errors = await validate(dto);
15+
expect(errors).toHaveLength(0);
16+
});
17+
18+
it('rejects keys with invalid prefix', async () => {
19+
const dto = new TestDto();
20+
dto.publicKey = `S${'A'.repeat(55)}`;
21+
22+
const errors = await validate(dto);
23+
expect(errors.length).toBeGreaterThan(0);
24+
});
25+
26+
it('rejects keys shorter than 56 chars', async () => {
27+
const dto = new TestDto();
28+
dto.publicKey = `G${'A'.repeat(54)}`;
29+
30+
const errors = await validate(dto);
31+
expect(errors.length).toBeGreaterThan(0);
32+
});
33+
34+
it('rejects keys longer than 56 chars', async () => {
35+
const dto = new TestDto();
36+
dto.publicKey = `G${'A'.repeat(56)}`;
37+
38+
const errors = await validate(dto);
39+
expect(errors.length).toBeGreaterThan(0);
40+
});
41+
42+
it('rejects non-base32 characters', async () => {
43+
const dto = new TestDto();
44+
dto.publicKey = `G${'A'.repeat(54)}!`;
45+
46+
const errors = await validate(dto);
47+
expect(errors.length).toBeGreaterThan(0);
48+
});
49+
});

backend/src/common/validators/is-stellar-key.validator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export function IsStellarPublicKey(validationOptions?: ValidationOptions) {
2828
}
2929

3030
// Stellar public keys: start with G, exactly 56 chars, Base32 (A-Z, 2-7)
31-
const stellarKeyPattern = /^G[A-Z2-7]{54}$/;
31+
const stellarKeyPattern = /^G[A-Z2-7]{55}$/;
3232
return stellarKeyPattern.test(value);
3333
},
3434
defaultMessage(args: ValidationArguments) {
@@ -63,7 +63,7 @@ export function IsSorobanContractId(validationOptions?: ValidationOptions) {
6363
}
6464

6565
// Soroban contract IDs: start with C, exactly 56 chars, Base32 (A-Z, 2-7)
66-
const sorobanContractPattern = /^C[A-Z2-7]{54}$/;
66+
const sorobanContractPattern = /^C[A-Z2-7]{55}$/;
6767
return sorobanContractPattern.test(value);
6868
},
6969
defaultMessage(args: ValidationArguments) {

backend/src/modules/savings/dto/subscribe.dto.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { IsUUID, IsNumber, Min } from 'class-validator';
2-
import { ApiProperty } from '@nestjs/swagger';
1+
import { IsUUID, IsNumber, Min, IsOptional } from 'class-validator';
2+
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
3+
import { IsStellarPublicKey } from '../../../common/validators/is-stellar-key.validator';
34

45
export class SubscribeDto {
56
@ApiProperty({ description: 'Savings product ID to subscribe to' })
@@ -10,4 +11,12 @@ export class SubscribeDto {
1011
@IsNumber()
1112
@Min(0.01)
1213
amount: number;
14+
15+
@ApiPropertyOptional({
16+
example: 'GABCDEF234567ABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFGHJKLMN',
17+
description: 'Optional Stellar wallet address associated with this subscription',
18+
})
19+
@IsOptional()
20+
@IsStellarPublicKey()
21+
walletAddress?: string;
1322
}

0 commit comments

Comments
 (0)