-
Notifications
You must be signed in to change notification settings - Fork 96
Feat/backend global validation pipe #461
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
Changes from all commits
10ef1a5
dda382f
1150261
d0a7d80
b2859f5
53c5a30
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,14 @@ | ||
| import { Module } from '@nestjs/common'; | ||
| import { AppController } from './app.controller'; | ||
| import { AppService } from './app.service'; | ||
| import { ResolverModule } from './resolver/resolver.module'; | ||
| import { VaultModule } from './vault/vault.module'; | ||
| import { AuctionModule } from './auction/auction.module'; | ||
|
|
||
| @Module({ | ||
| imports: [ResolverModule, VaultModule, AuctionModule], | ||
| controllers: [AppController], | ||
| providers: [AppService], | ||
| }) | ||
| export class AppModule {} | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| import { IsNotEmpty, IsNumberString, Matches } from 'class-validator'; | ||
| import { ApiProperty } from '@nestjs/swagger'; | ||
|
|
||
| export class AuctionInfoDto { | ||
|
|
@@ -45,12 +46,19 @@ export class AuctionListItemDto { | |
|
|
||
| export class PlaceBidDto { | ||
| @ApiProperty({ description: 'Bidder Stellar address', example: 'GXYZ9876STELLAR1234BIDDERADDRESS' }) | ||
| @IsNotEmpty() | ||
| @Matches(/^G[A-Z2-7]{55}$/, { | ||
| message: 'Invalid Stellar wallet address format', | ||
| }) | ||
| bidder: string; | ||
|
Comment on lines
48
to
53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep the bid example consistent with the Stellar regex.
🤖 Prompt for AI Agents |
||
|
|
||
| @ApiProperty({ description: 'Bid amount in XLM', example: '150.00' }) | ||
| @IsNotEmpty() | ||
| @IsNumberString() | ||
| amount: string; | ||
| } | ||
|
|
||
|
|
||
| export class BidResponseDto { | ||
| @ApiProperty({ description: 'Whether the bid was accepted', example: true }) | ||
| success: boolean; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { ApiProperty } from '@nestjs/swagger'; | ||
| import { IsNotEmpty, IsString, Matches } from 'class-validator'; | ||
|
|
||
| export class LoginDto { | ||
| @ApiProperty({ description: 'Stellar wallet address', example: 'GABC1234STELLAR5678WALLETADDRESS' }) | ||
| @IsString() | ||
| @IsNotEmpty() | ||
| @Matches(/^G[A-Z2-7]{55}$/, { | ||
| message: 'Invalid Stellar wallet address format', | ||
| }) | ||
| address: string; | ||
|
Comment on lines
+5
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a Swagger example that satisfies the validator.
🤖 Prompt for AI Agents |
||
|
|
||
| @ApiProperty({ description: 'Signature for authentication', example: 'sig_abc123...' }) | ||
| @IsString() | ||
| @IsNotEmpty() | ||
| signature: string; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| import { IsNotEmpty, IsString, Matches } from 'class-validator'; | ||
| import { ApiProperty } from '@nestjs/swagger'; | ||
|
|
||
| export class ResolveResponseDto { | ||
|
|
@@ -13,15 +14,31 @@ export class ResolveResponseDto { | |
|
|
||
| export class RegisterUsernameDto { | ||
| @ApiProperty({ description: 'Username to register (without @)', example: 'alice' }) | ||
| @IsString() | ||
| @IsNotEmpty() | ||
| @Matches(/^[a-zA-Z0-9_]{3,20}$/, { | ||
| message: 'Username must be 3-20 characters long and contain only letters, numbers, and underscores', | ||
| }) | ||
| username: string; | ||
|
|
||
| @ApiProperty({ description: 'Stellar wallet address to link', example: 'GABC1234STELLAR5678WALLETADDRESS' }) | ||
| @IsString() | ||
| @IsNotEmpty() | ||
| @Matches(/^G[A-Z2-7]{55}$/, { | ||
| message: 'Invalid Stellar wallet address format', | ||
| }) | ||
| walletAddress: string; | ||
|
|
||
| @ApiProperty({ description: 'Zero-knowledge commitment hash', example: '0xabc123...' }) | ||
| @IsString() | ||
| @IsNotEmpty() | ||
| @Matches(/^0x[a-fA-F0-9]{64}$/, { | ||
| message: 'Commitment must be a 32-byte hex string prefixed with 0x', | ||
| }) | ||
|
Comment on lines
16
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Align the Swagger examples with the new validation rules. The current 💡 Suggested update `@ApiProperty`({ description: 'Stellar wallet address to link', example: 'GABC1234STELLAR5678WALLETADDRESS' })
+ `@ApiProperty`({
+ description: 'Stellar wallet address to link',
+ example: `G${'A'.repeat(55)}`,
+ })
@@
- `@ApiProperty`({ description: 'Zero-knowledge commitment hash', example: '0xabc123...' })
+ `@ApiProperty`({
+ description: 'Zero-knowledge commitment hash',
+ example: `0x${'a'.repeat(64)}`,
+ })🤖 Prompt for AI Agents |
||
| commitment: string; | ||
| } | ||
|
|
||
|
|
||
| export class RegisterResponseDto { | ||
| @ApiProperty({ description: 'Whether registration succeeded', example: true }) | ||
| success: boolean; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| import { Test, TestingModule } from '@nestjs/testing'; | ||
| import { INestApplication, ValidationPipe } from '@nestjs/common'; | ||
| import * as request from 'supertest'; | ||
| import { AppModule } from './../src/app.module'; | ||
|
|
||
| describe('Global Validation (e2e)', () => { | ||
| let app: INestApplication; | ||
|
|
||
| beforeAll(async () => { | ||
| const moduleFixture: TestingModule = await Test.createTestingModule({ | ||
| imports: [AppModule], | ||
| }).compile(); | ||
|
|
||
| app = moduleFixture.createNestApplication(); | ||
| app.useGlobalPipes( | ||
| new ValidationPipe({ | ||
| whitelist: true, | ||
| forbidNonWhitelisted: true, | ||
| transform: true, | ||
| }), | ||
| ); | ||
| await app.init(); | ||
| }); | ||
|
|
||
| afterAll(async () => { | ||
| await app.close(); | ||
| }); | ||
|
|
||
| describe('Resolver Registration Validation', () => { | ||
| it('should return 400 when username is too short', () => { | ||
| return request(app.getHttpServer()) | ||
| .post('/resolver/register') | ||
| .send({ | ||
| username: 'al', | ||
| walletAddress: 'GABC1234STELLAR5678WALLETADDRESS', | ||
| commitment: '0xabc1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcd', | ||
| }) | ||
| .expect(400) | ||
| .expect((res) => { | ||
| expect(res.body.message).toContain('Username must be 3-20 characters long and contain only letters, numbers, and underscores'); | ||
| }); | ||
| }); | ||
|
|
||
| it('should return 400 when wallet address is invalid', () => { | ||
| return request(app.getHttpServer()) | ||
| .post('/resolver/register') | ||
| .send({ | ||
| username: 'alice', | ||
| walletAddress: 'INVALID_ADDRESS', | ||
| commitment: '0xabc1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcd', | ||
| }) | ||
| .expect(400) | ||
| .expect((res) => { | ||
| expect(res.body.message).toContain('Invalid Stellar wallet address format'); | ||
| }); | ||
| }); | ||
|
|
||
| it('should return 400 when commitment is not a hex string', () => { | ||
| return request(app.getHttpServer()) | ||
| .post('/resolver/register') | ||
| .send({ | ||
| username: 'alice', | ||
| walletAddress: 'GABC1234STELLAR5678WALLETADDRESS', | ||
| commitment: 'not-a-hex-string', | ||
| }) | ||
| .expect(400) | ||
| .expect((res) => { | ||
| expect(res.body.message).toContain('Commitment must be a 32-byte hex string prefixed with 0x'); | ||
| }); | ||
| }); | ||
|
|
||
| it('should return 400 when extra fields are provided (forbidNonWhitelisted)', () => { | ||
| return request(app.getHttpServer()) | ||
| .post('/resolver/register') | ||
| .send({ | ||
| username: 'alice', | ||
| walletAddress: 'GABC1234STELLAR5678WALLETADDRESS', | ||
| commitment: '0xabc1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcd', | ||
| extraField: 'should-not-be-here', | ||
| }) | ||
| .expect(400) | ||
| .expect((res) => { | ||
| expect(res.body.message).toContain('property extraField should not exist'); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Auction Bid Validation', () => { | ||
| it('should return 400 when amount is not a number string', () => { | ||
| return request(app.getHttpServer()) | ||
| .post('/auction/1/bid') | ||
| .send({ | ||
| bidder: 'GABC1234STELLAR5678WALLETADDRESS', | ||
| amount: 'not-a-number', | ||
| }) | ||
| .expect(400) | ||
| .expect((res) => { | ||
| expect(res.body.message).toContain('amount must be a number string'); | ||
| }); | ||
| }); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: Alien-Protocol/Alien-Protocol
Length of output: 906
Add
find-node-modulesto devDependencies or remove it from thetest:debugpreload.The
test:debugscript preloads-r find-node-modules, but this package is not declared in the manifest and cannot be resolved. On a clean install,npm run test:debugwill fail with MODULE_NOT_FOUND.🤖 Prompt for AI Agents