Skip to content

Commit

Permalink
account-api: add extra syntax validation (#541)
Browse files Browse the repository at this point in the history
# Problem
Adding more validation in account-api
Closes #492

# Details
- added customer decorators for MsaId and SchemaId and ...
- Using these new decorators in Dtos
- Added more api descriptions

## Steps to Verify:

1. run the account-api
2. open swagger
3. try invalid inputs
  • Loading branch information
aramikm authored Sep 20, 2024
1 parent 9850994 commit 61baa84
Show file tree
Hide file tree
Showing 34 changed files with 1,101 additions and 7,157 deletions.
2 changes: 1 addition & 1 deletion apps/account-api/k6-test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Note that the default iteration count and VU count is 1. So each request in each

## Running the script

To run the script, you need to have k6 installed. You can download it from [here](https://k6.io/docs/getting-started/installation).
To run the script, you need to have k6 installed. You can download it from [here](https://grafana.com/docs/k6/latest/set-up/install-k6/).

To run the script, execute the following command:

Expand Down
8 changes: 4 additions & 4 deletions apps/account-api/src/controllers/v1/accounts-v1.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { WalletLoginResponseDto } from '#types/dtos/account/wallet.login.respons
import { Body, Controller, Get, Post, HttpCode, HttpStatus, Logger, Param, HttpException } from '@nestjs/common';
import { ApiBody, ApiOkResponse, ApiCreatedResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
import { ConfigService } from '#account-lib/config';
import { SignerPayloadRaw } from '@polkadot/types/types';
import { RetireMsaRequestDto, TransactionResponse } from '#types/dtos/account';
import { AccountIdDto, MsaIdDto } from '#types/dtos/common';

@Controller('v1/accounts')
@ApiTags('v1/accounts')
Expand Down Expand Up @@ -46,7 +46,7 @@ export class AccountsControllerV1 {
* @returns A promise that resolves to an Account object => {msaId, handle}.
* @throws An error if the account cannot be found.
*/
async getAccountForMsa(@Param('msaId') msaId: string): Promise<AccountResponseDto> {
async getAccountForMsa(@Param() { msaId }: MsaIdDto): Promise<AccountResponseDto> {
try {
this.logger.debug(`Received request to get account with msaId: ${msaId}`);
const account = await this.accountsService.getAccount(msaId);
Expand All @@ -69,7 +69,7 @@ export class AccountsControllerV1 {
* @returns A promise that resolves to an Account object => {msaId, handle}.
* @throws An error if the msaId or account cannot be found.
*/
async getAccountForAccountId(@Param('accountId') accountId: string): Promise<AccountResponseDto> {
async getAccountForAccountId(@Param() { accountId }: AccountIdDto): Promise<AccountResponseDto> {
try {
this.logger.debug(`Received request to get account with accountId: ${accountId}`);
const response = await this.accountsService.getMsaIdForAccountId(accountId);
Expand Down Expand Up @@ -114,7 +114,7 @@ export class AccountsControllerV1 {
* @returns A promise that resolves to an object consisting of a retire msa encodedExtrinsic hex string and payloadToSign hex string.
* @throws An error if the payload fails to be created.
*/
async getRetireMsaPayload(@Param('accountId') accountId: string): Promise<RetireMsaPayloadResponseDto> {
async getRetireMsaPayload(@Param() { accountId }: AccountIdDto): Promise<RetireMsaPayloadResponseDto> {
try {
const result = await this.accountsService.getRetireMsaPayload(accountId);
if (result) return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
UseGuards,
} from '@nestjs/common';
import { ApiBody, ApiCreatedResponse, ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
import { AccountIdDto, MsaIdDto, ProviderMsaIdDto } from '#types/dtos/common';

@Controller({ version: '1', path: 'delegation' })
@ApiTags('delegation')
Expand All @@ -41,7 +42,7 @@ export class DelegationControllerV1 {
* @returns A Promise that resolves to a DelegationResponse object representing the delegation.
* @throws HttpException if the delegation cannot be found.
*/
async getDelegation(@Param('msaId') msaId: string): Promise<DelegationResponse> {
async getDelegation(@Param() { msaId }: MsaIdDto): Promise<DelegationResponse> {
try {
const delegation = await this.delegationService.getDelegation(msaId);
return delegation;
Expand Down Expand Up @@ -70,8 +71,8 @@ export class DelegationControllerV1 {
* @throws {HttpException} If there is an error generating the RevokeDelegationPayload.
*/
async getRevokeDelegationPayload(
@Param('accountId') accountId: string,
@Param('providerId') providerId: string,
@Param() { accountId }: AccountIdDto,
@Param() { providerId }: ProviderMsaIdDto,
): Promise<RevokeDelegationPayloadResponseDto> {
try {
this.logger.verbose(`Getting RevokeDelegationPayload for account ${accountId} and provider ${providerId}`);
Expand Down
5 changes: 3 additions & 2 deletions apps/account-api/src/controllers/v1/handles-v1.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { HandleResponseDto } from '#types/dtos/account/accounts.response.dto';
import { ReadOnlyGuard } from '#account-api/guards/read-only.guard';
import { u8aToHex, u8aWrapBytes } from '@polkadot/util';
import { TransactionType } from '#types/account-webhook';
import { HandleDto, MsaIdDto } from '#types/dtos/common';

@Controller('v1/handles')
@ApiTags('v1/handles')
Expand Down Expand Up @@ -98,7 +99,7 @@ export class HandlesControllerV1 {
* @returns Payload is included for convenience. Encoded payload to be used when signing the transaction.
* @throws An error if the change handle payload creation fails.
*/
async getChangeHandlePayload(@Param('newHandle') newHandle: string): Promise<ChangeHandlePayloadRequest> {
async getChangeHandlePayload(@Param() { newHandle }: HandleDto): Promise<ChangeHandlePayloadRequest> {
try {
const expiration = await this.handlesService.getExpiration();
const payload = { baseHandle: newHandle, expiration };
Expand All @@ -124,7 +125,7 @@ export class HandlesControllerV1 {
* @returns A promise that resolves to a Handle object, representing the found handle.
* @throws An error if the handle cannot be found.
*/
async getHandle(@Param('msaId') msaId: string): Promise<HandleResponseDto> {
async getHandle(@Param() { msaId }: MsaIdDto): Promise<HandleResponseDto> {
try {
const handle = await this.handlesService.getHandle(msaId);
if (!handle) {
Expand Down
3 changes: 2 additions & 1 deletion apps/account-api/src/controllers/v1/keys-v1.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
PublicKeyAgreementsKeyPayload,
} from '#types/dtos/account/graphs.request.dto';
import { TransactionType } from '#types/account-webhook';
import { MsaIdDto } from '#types/dtos/common';

@Controller('v1/keys')
@ApiTags('v1/keys')
Expand Down Expand Up @@ -74,7 +75,7 @@ export class KeysControllerV1 {
* @returns A promise that resolves to an array of public keys associated with the given msaId.
* @throws An error if no public keys can be found.
*/
async getKeys(@Param('msaId') msaId: string): Promise<KeysResponse> {
async getKeys(@Param() { msaId }: MsaIdDto): Promise<KeysResponse> {
try {
const keys = await this.keysService.getKeysByMsa(msaId);
return keys;
Expand Down
7 changes: 6 additions & 1 deletion apps/account-api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ async function bootstrap() {
const configService = app.get<ConfigService>(ConfigService);

app.enableShutdownHooks();
app.useGlobalPipes(new ValidationPipe());
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
}),
);
app.useGlobalInterceptors(new TimeoutInterceptor(configService.apiTimeoutMs));
app.useBodyParser('json', { limit: configService.apiBodyJsonLimit });

Expand Down
2 changes: 1 addition & 1 deletion apps/account-api/src/metadata.ts

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions apps/account-api/test/e2e-setup.mock.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { KeyringPair } from '@polkadot/keyring/types';
import { AccountId } from '@polkadot/types/interfaces';
import { cryptoWaitReady, decodeAddress } from '@polkadot/util-crypto';
import log from 'loglevel';
import { u8aToHex } from '@polkadot/util';

export const FREQUENCY_URL = process.env.FREQUENCY_URL || 'ws://0.0.0.0:9944';
export const BASE_SEED_PHRASE = process.env.SEED_PHRASE || '//Alice';
Expand Down Expand Up @@ -74,6 +75,7 @@ export async function generateSignedAddKeyPayload(user: ChainUser, newKeys: Keyr
const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload);
const ownerProof = signPayloadSr25519(user.keypair, addKeyData);
const newKeyProof = signPayloadSr25519(newKeys, addKeyData);
payload.newPublicKey = u8aToHex(payload.newPublicKey);

return { payload, ownerProof, newKeyProof };
}
Expand Down
4 changes: 2 additions & 2 deletions apps/account-api/test/handles.controller.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ describe('Handles Controller', () => {

await request(HTTP_SERVER)
.post('/v1/handles')
.send({ accountId, payload, proof })
.send({ accountId, payload, proof: proof.Sr25519 })
.expect(200)
.expect((req) => req.text === 'Handle created successfully');
});
Expand All @@ -121,7 +121,7 @@ describe('Handles Controller', () => {
const accountId = user.keypair.address;
await request(HTTP_SERVER)
.post('/v1/handles/change')
.send({ accountId, payload, proof })
.send({ accountId, payload, proof: proof.Sr25519 })
.expect(200)
.expect((res) => res.text === 'Handle created successfully');
});
Expand Down
6 changes: 1 addition & 5 deletions apps/account-api/test/keys.controller.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,7 @@ describe('Keys Controller', () => {
},
};

await request(HTTP_SERVER)
.post('/v1/keys/add')
.send(keysRequest)
.expect(200)
.expect((req) => req.text === 'Successfully added key.');
await request(HTTP_SERVER).post('/v1/keys/add').send(keysRequest).expect(200);
});
});

Expand Down
Loading

0 comments on commit 61baa84

Please sign in to comment.