added readme and improved config
This commit is contained in:
parent
8389db4367
commit
a6524d7f65
|
|
@ -1,3 +1,3 @@
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
./local-aws.sqlite
|
data
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Local AWS
|
||||||
|
|
||||||
|
## Running
|
||||||
|
### Environment Variables
|
||||||
|
| Variable | Description | Default |
|
||||||
|
| -------------- | --------------------------------------------------- | -------------- |
|
||||||
|
| AWS_ACCOUNT_ID | AWS Account ID resources will default to | 000000000000 |
|
||||||
|
| AWS_REGION | AWS Region resources will default to | us-east-1 |
|
||||||
|
| DB_DATABASE | SQLITE database to write to, defaults to in memory | :memory: |
|
||||||
|
| DEBUG | Whether or not to reveal sql and other audit trails | false |
|
||||||
|
| HOST | Used in URL generation | localhost |
|
||||||
|
| PORT | Used in URL generation & runtime port binding | 8081 |
|
||||||
|
| PROTO | Used in URL generation | http |
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
### Design Pattern
|
||||||
|
Handler / Visitor Pattern
|
||||||
|
|
||||||
|
Relying on Nest.js's dependency tree and injection, handlers are loaded as singletons and pulled in to a map key'd by AWS's own Action names.
|
||||||
|
|
||||||
|
Actions are defined in src/action.enum.ts
|
||||||
|
|
||||||
|
app.controller.ts is the entry point for all AWS API calls
|
||||||
|
|
||||||
|
Each action is implemented via it's respective handler. Use `aws sns create-topic` as an example:
|
||||||
|
app.module.ts loads sns.module.ts
|
||||||
|
app.module.ts injects SnsHandlers
|
||||||
|
SnsHandlers is a a map of implemented and mocked handlers based on its list of `actions` provided by the sns.module.ts module
|
||||||
|
sns.module.ts has a list of handlers that have been implemented, including create-topic.handler.ts
|
||||||
|
create-topic.handler.ts extends abstract-action.handler.ts
|
||||||
|
|
||||||
|
abstract-action.handler.ts
|
||||||
|
* format: the format for output (XML or JSON)
|
||||||
|
* action: the action the handler is implementing (will be use to key by)
|
||||||
|
* validator: the Joi validator to be executed to check for required params
|
||||||
|
* handle(queryParams: T, awsProperties: AwsProperties): Record<string, any> | void
|
||||||
|
* the method that implements the AWS action
|
||||||
|
|
@ -1,5 +1,57 @@
|
||||||
export enum Action {
|
export enum Action {
|
||||||
|
|
||||||
|
// KMS
|
||||||
|
KmsCancelKeyDeletion = 'CancelKeyDeletion',
|
||||||
|
KmsConnectCustomKeyStore = 'ConnectCustomKeyStore',
|
||||||
|
KmsCreateAlias = 'CreateAlias',
|
||||||
|
KmsCreateCustomKeyStore = 'CreateCustomKeyStore',
|
||||||
|
KmsCreateGrant = 'CreateGrant',
|
||||||
|
KmsCreateKey = 'CreateKey',
|
||||||
|
KmsDecrypt = 'Decrypt',
|
||||||
|
KmsDeleteAlias = 'DeleteAlias',
|
||||||
|
KmsDeleteCustomKeyStore = 'DeleteCustomKeyStore',
|
||||||
|
KmsDeleteImportedKeyMaterial = 'DeleteImportedKeyMaterial',
|
||||||
|
KmsDescribeCustomKeyStores = 'DescribeCustomKeyStores',
|
||||||
|
KmsDescribeKey = 'DescribeKey',
|
||||||
|
KmsDisableKey = 'DisableKey',
|
||||||
|
KmsDisableKeyRotation = 'DisableKeyRotation',
|
||||||
|
KmsDisconnectCustomKeyStore = 'DisconnectCustomKeyStore',
|
||||||
|
KmsEnableKey = 'EnableKey',
|
||||||
|
KmsEnableKeyRotation = 'EnableKeyRotation',
|
||||||
|
KmsEncrypt = 'Encrypt',
|
||||||
|
KmsGenerateDataKey = 'GenerateDataKey',
|
||||||
|
KmsGenerateDataKeyPair = 'GenerateDataKeyPair',
|
||||||
|
KmsGenerateDataKeyPairWithoutPlaintext = 'GenerateDataKeyPairWithoutPlaintext',
|
||||||
|
KmsGenerateDataKeyWithoutPlaintext = 'GenerateDataKeyWithoutPlaintext',
|
||||||
|
KmsGenerateMac = 'GenerateMac',
|
||||||
|
KmsGenerateRandom = 'GenerateRandom',
|
||||||
|
KmsGetKeyPolicy = 'GetKeyPolicy',
|
||||||
|
KmsGetKeyRotationStatus = 'GetKeyRotationStatus',
|
||||||
|
KmsGetParametersForImport = 'GetParametersForImport',
|
||||||
|
KmsGetPublicKey = 'GetPublicKey',
|
||||||
|
KmsImportKeyMaterial = 'ImportKeyMaterial',
|
||||||
|
KmsListAliases = 'ListAliases',
|
||||||
|
KmsListGrants = 'ListGrants',
|
||||||
|
KmsListKeyPolicies = 'ListKeyPolicies',
|
||||||
|
KmsListKeys = 'ListKeys',
|
||||||
|
KmsListResourceTags = 'ListResourceTags',
|
||||||
|
KmsListRetirableGrants = 'ListRetirableGrants',
|
||||||
|
KmsPutKeyPolicy = 'PutKeyPolicy',
|
||||||
|
KmsReEncrypt = 'ReEncrypt',
|
||||||
|
KmsReplicateKey = 'ReplicateKey',
|
||||||
|
KmsRetireGrant = 'RetireGrant',
|
||||||
|
KmsRevokeGrant = 'RevokeGrant',
|
||||||
|
KmsScheduleKeyDeletion = 'ScheduleKeyDeletion',
|
||||||
|
KmsSign = 'Sign',
|
||||||
|
KmsTagResource = 'TagResource',
|
||||||
|
KmsUntagResource = 'UntagResource',
|
||||||
|
KmsUpdateAlias = 'UpdateAlias',
|
||||||
|
KmsUpdateCustomKeyStore = 'UpdateCustomKeyStore',
|
||||||
|
KmsUpdateKeyDescription = 'UpdateKeyDescription',
|
||||||
|
KmsUpdatePrimaryRegion = 'UpdatePrimaryRegion',
|
||||||
|
KmsVerify = 'Verify',
|
||||||
|
KmsVerifyMac = 'VerifyMac',
|
||||||
|
|
||||||
// SecretsManager
|
// SecretsManager
|
||||||
SecretsManagerCancelRotateSecret = 'secretsmanager.CancelRotateSecret',
|
SecretsManagerCancelRotateSecret = 'secretsmanager.CancelRotateSecret',
|
||||||
SecretsManagerCreateSecret = 'secretsmanager.CreateSecret',
|
SecretsManagerCreateSecret = 'secretsmanager.CreateSecret',
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { BadRequestException, Body, Controller, Inject, Post, Headers, Header, Req, HttpStatus, HttpCode, UseInterceptors } from '@nestjs/common';
|
import { BadRequestException, Body, Controller, Inject, Post, Headers, Req, HttpCode, UseInterceptors } from '@nestjs/common';
|
||||||
import { ActionHandlers } from './app.constants';
|
import { ActionHandlers } from './app.constants';
|
||||||
import * as Joi from 'joi';
|
import * as Joi from 'joi';
|
||||||
import { Action } from './action.enum';
|
import { Action } from './action.enum';
|
||||||
|
|
@ -6,7 +6,6 @@ import { AbstractActionHandler, Format } from './abstract-action.handler';
|
||||||
import * as js2xmlparser from 'js2xmlparser';
|
import * as js2xmlparser from 'js2xmlparser';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { CommonConfig } from './config/common-config.interface';
|
import { CommonConfig } from './config/common-config.interface';
|
||||||
import * as uuid from 'uuid';
|
|
||||||
import { Request } from 'express';
|
import { Request } from 'express';
|
||||||
import { AuditInterceptor } from './audit/audit.interceptor';
|
import { AuditInterceptor } from './audit/audit.interceptor';
|
||||||
|
|
||||||
|
|
@ -34,9 +33,7 @@ export class AppController {
|
||||||
}, {})
|
}, {})
|
||||||
|
|
||||||
const queryParams = { __path: request.path, ...body, ...lowerCasedHeaders };
|
const queryParams = { __path: request.path, ...body, ...lowerCasedHeaders };
|
||||||
console.log({queryParams})
|
|
||||||
const actionKey = queryParams['x-amz-target'] ? 'x-amz-target' : 'Action';
|
const actionKey = queryParams['x-amz-target'] ? 'x-amz-target' : 'Action';
|
||||||
|
|
||||||
const { error: actionError } = Joi.object({
|
const { error: actionError } = Joi.object({
|
||||||
[actionKey]: Joi.string().valid(...Object.values(Action)).required(),
|
[actionKey]: Joi.string().valid(...Object.values(Action)).required(),
|
||||||
}).validate(queryParams, { allowUnknown: true });
|
}).validate(queryParams, { allowUnknown: true });
|
||||||
|
|
@ -47,7 +44,6 @@ export class AppController {
|
||||||
|
|
||||||
const action = queryParams[actionKey];
|
const action = queryParams[actionKey];
|
||||||
const handler: AbstractActionHandler = this.actionHandlers[action];
|
const handler: AbstractActionHandler = this.actionHandlers[action];
|
||||||
|
|
||||||
const { error: validatorError, value: validQueryParams } = handler.validator.validate(queryParams, { allowUnknown: true, abortEarly: false });
|
const { error: validatorError, value: validQueryParams } = handler.validator.validate(queryParams, { allowUnknown: true, abortEarly: false });
|
||||||
|
|
||||||
if (validatorError) {
|
if (validatorError) {
|
||||||
|
|
@ -57,14 +53,12 @@ export class AppController {
|
||||||
const awsProperties = {
|
const awsProperties = {
|
||||||
accountId: this.configService.get('AWS_ACCOUNT_ID'),
|
accountId: this.configService.get('AWS_ACCOUNT_ID'),
|
||||||
region: this.configService.get('AWS_REGION'),
|
region: this.configService.get('AWS_REGION'),
|
||||||
host: this.configService.get('HOST'),
|
host: `${this.configService.get('PROTO')}://${this.configService.get('HOST')}:${this.configService.get('PORT')}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const jsonResponse = await handler.getResponse(validQueryParams, awsProperties);
|
const jsonResponse = await handler.getResponse(validQueryParams, awsProperties);
|
||||||
if (handler.format === Format.Xml) {
|
if (handler.format === Format.Xml) {
|
||||||
const xmlResponse = js2xmlparser.parse(`${handler.action}Response`, jsonResponse);
|
return js2xmlparser.parse(`${handler.action}Response`, jsonResponse);
|
||||||
// console.log({xmlResponse})
|
|
||||||
return xmlResponse;
|
|
||||||
}
|
}
|
||||||
return jsonResponse;
|
return jsonResponse;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,25 +14,29 @@ import { SqsModule } from './sqs/sqs.module';
|
||||||
import { SqsHandlers } from './sqs/sqs.constants';
|
import { SqsHandlers } from './sqs/sqs.constants';
|
||||||
import { Audit } from './audit/audit.entity';
|
import { Audit } from './audit/audit.entity';
|
||||||
import { AuditInterceptor } from './audit/audit.interceptor';
|
import { AuditInterceptor } from './audit/audit.interceptor';
|
||||||
|
import { KmsModule } from './kms/kms.module';
|
||||||
|
import { KMSHandlers } from './kms/kms.constants';
|
||||||
|
import { configValidator } from './config/config.validator';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
load: [localConfig],
|
load: [localConfig],
|
||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
// validationSchema: configValidator,
|
validationSchema: configValidator,
|
||||||
}),
|
}),
|
||||||
TypeOrmModule.forRootAsync({
|
TypeOrmModule.forRootAsync({
|
||||||
inject: [ConfigService],
|
inject: [ConfigService],
|
||||||
useFactory: (configService: ConfigService<CommonConfig>) => ({
|
useFactory: (configService: ConfigService<CommonConfig>) => ({
|
||||||
type: 'sqlite',
|
type: 'sqlite',
|
||||||
database: configService.get('DB_DATABASE'),
|
database: configService.get('DB_DATABASE') === ':memory:' ? configService.get('DB_DATABASE') : `${__dirname}/../data/${configService.get('DB_DATABASE')}`,
|
||||||
logging: configService.get('DB_LOGGING'),
|
logging: configService.get('DB_LOGGING'),
|
||||||
synchronize: configService.get('DB_SYNCHRONIZE'),
|
synchronize: configService.get('DB_SYNCHRONIZE'),
|
||||||
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
TypeOrmModule.forFeature([Audit]),
|
TypeOrmModule.forFeature([Audit]),
|
||||||
|
KmsModule,
|
||||||
SecretsManagerModule,
|
SecretsManagerModule,
|
||||||
SnsModule,
|
SnsModule,
|
||||||
SqsModule,
|
SqsModule,
|
||||||
|
|
@ -50,6 +54,7 @@ import { AuditInterceptor } from './audit/audit.interceptor';
|
||||||
SnsHandlers,
|
SnsHandlers,
|
||||||
SqsHandlers,
|
SqsHandlers,
|
||||||
SecretsManagerHandlers,
|
SecretsManagerHandlers,
|
||||||
|
KMSHandlers,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import { Observable, tap } from 'rxjs';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { Audit } from './audit.entity';
|
import { Audit } from './audit.entity';
|
||||||
import * as uuid from 'uuid';
|
import * as uuid from 'uuid';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { CommonConfig } from '../config/common-config.interface';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuditInterceptor<T> implements NestInterceptor<T, Response> {
|
export class AuditInterceptor<T> implements NestInterceptor<T, Response> {
|
||||||
|
|
@ -11,10 +13,15 @@ export class AuditInterceptor<T> implements NestInterceptor<T, Response> {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Audit)
|
@InjectRepository(Audit)
|
||||||
private readonly auditRepo: Repository<Audit>,
|
private readonly auditRepo: Repository<Audit>,
|
||||||
|
private readonly configService: ConfigService<CommonConfig>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
intercept(context: ExecutionContext, next: CallHandler<T>): Observable<any> {
|
intercept(context: ExecutionContext, next: CallHandler<T>): Observable<any> {
|
||||||
|
|
||||||
|
if (!this.configService.get('AUDIT')) {
|
||||||
|
return next.handle();
|
||||||
|
}
|
||||||
|
|
||||||
const requestId = uuid.v4();
|
const requestId = uuid.v4();
|
||||||
const httpContext = context.switchToHttp();
|
const httpContext = context.switchToHttp();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
export interface CommonConfig {
|
export interface CommonConfig {
|
||||||
|
AUDIT: boolean;
|
||||||
AWS_ACCOUNT_ID: string;
|
AWS_ACCOUNT_ID: string;
|
||||||
AWS_REGION: string;
|
AWS_REGION: string;
|
||||||
DB_DATABASE: string;
|
DB_DATABASE: string;
|
||||||
DB_LOGGING?: boolean;
|
DB_LOGGING?: boolean;
|
||||||
DB_SYNCHRONIZE?: boolean;
|
DB_SYNCHRONIZE?: boolean;
|
||||||
HOST: string;
|
HOST: string;
|
||||||
|
PORT: number;
|
||||||
|
PROTO: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import * as Joi from 'joi';
|
||||||
|
import { CommonConfig } from './common-config.interface';
|
||||||
|
|
||||||
|
export const configValidator = Joi.object<CommonConfig, true>({
|
||||||
|
AUDIT: Joi.boolean().default(false),
|
||||||
|
AWS_ACCOUNT_ID: Joi.string().default('000000000000'),
|
||||||
|
AWS_REGION: Joi.string().default('us-east-1'),
|
||||||
|
DB_DATABASE: Joi.string().default(':memory:'),
|
||||||
|
DB_LOGGING: Joi.boolean().default(false),
|
||||||
|
DB_SYNCHRONIZE: Joi.boolean().default(true),
|
||||||
|
HOST: Joi.string().default('localhost'),
|
||||||
|
PORT: Joi.number().default(8081),
|
||||||
|
PROTO: Joi.string().valid('http', 'https').default('http'),
|
||||||
|
});
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
import { CommonConfig } from "./common-config.interface";
|
import { CommonConfig } from "./common-config.interface";
|
||||||
|
|
||||||
export default (): CommonConfig => ({
|
export default (): CommonConfig => ({
|
||||||
AWS_ACCOUNT_ID: '000000000000',
|
AUDIT: process.env.DEBUG ? true : false,
|
||||||
AWS_REGION: 'us-east-1',
|
AWS_ACCOUNT_ID: process.env.AWS_ACCOUNT_ID,
|
||||||
// DB_DATABASE: ':memory:',
|
AWS_REGION: process.env.AWS_REGION,
|
||||||
DB_DATABASE: 'local-aws.sqlite',
|
DB_DATABASE: process.env.PERSISTANCE,
|
||||||
DB_LOGGING: true,
|
DB_LOGGING: process.env.DEBUG ? true : false,
|
||||||
DB_SYNCHRONIZE: true,
|
DB_SYNCHRONIZE: true,
|
||||||
HOST: 'http://localhost:8081',
|
HOST: process.env.HOST,
|
||||||
|
PROTO: process.env.PROTOCOL,
|
||||||
|
PORT: Number(process.env.PORT),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
export enum Group {
|
|
||||||
Legacy = 'legacy',
|
|
||||||
SecretsManager = 'secretsmanager',
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { AbstractActionHandler } from '../abstract-action.handler';
|
||||||
|
import { Action } from '../action.enum';
|
||||||
|
|
||||||
|
export type KMSHandlers = Record<Action, AbstractActionHandler>;
|
||||||
|
export const KMSHandlers = Symbol.for('KMSHandlers');
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { Format } from '../abstract-action.handler';
|
||||||
|
import { Action } from '../action.enum';
|
||||||
|
import { AwsSharedEntitiesModule } from '../aws-shared-entities/aws-shared-entities.module';
|
||||||
|
import { DefaultActionHandlerProvider } from '../default-action-handler/default-action-handler.provider';
|
||||||
|
import { ExistingActionHandlersProvider } from '../default-action-handler/existing-action-handlers.provider';
|
||||||
|
import { KMSHandlers } from './kms.constants';
|
||||||
|
|
||||||
|
const handlers = [
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
const actions = [
|
||||||
|
Action.KmsCancelKeyDeletion,
|
||||||
|
Action.KmsConnectCustomKeyStore,
|
||||||
|
Action.KmsCreateAlias,
|
||||||
|
Action.KmsCreateCustomKeyStore,
|
||||||
|
Action.KmsCreateGrant,
|
||||||
|
Action.KmsCreateKey,
|
||||||
|
Action.KmsDecrypt,
|
||||||
|
Action.KmsDeleteAlias,
|
||||||
|
Action.KmsDeleteCustomKeyStore,
|
||||||
|
Action.KmsDeleteImportedKeyMaterial,
|
||||||
|
Action.KmsDescribeCustomKeyStores,
|
||||||
|
Action.KmsDescribeKey,
|
||||||
|
Action.KmsDisableKey,
|
||||||
|
Action.KmsDisableKeyRotation,
|
||||||
|
Action.KmsDisconnectCustomKeyStore,
|
||||||
|
Action.KmsEnableKey,
|
||||||
|
Action.KmsEnableKeyRotation,
|
||||||
|
Action.KmsEncrypt,
|
||||||
|
Action.KmsGenerateDataKey,
|
||||||
|
Action.KmsGenerateDataKeyPair,
|
||||||
|
Action.KmsGenerateDataKeyPairWithoutPlaintext,
|
||||||
|
Action.KmsGenerateDataKeyWithoutPlaintext,
|
||||||
|
Action.KmsGenerateMac,
|
||||||
|
Action.KmsGenerateRandom,
|
||||||
|
Action.KmsGetKeyPolicy,
|
||||||
|
Action.KmsGetKeyRotationStatus,
|
||||||
|
Action.KmsGetParametersForImport,
|
||||||
|
Action.KmsGetPublicKey,
|
||||||
|
Action.KmsImportKeyMaterial,
|
||||||
|
Action.KmsListAliases,
|
||||||
|
Action.KmsListGrants,
|
||||||
|
Action.KmsListKeyPolicies,
|
||||||
|
Action.KmsListKeys,
|
||||||
|
Action.KmsListResourceTags,
|
||||||
|
Action.KmsListRetirableGrants,
|
||||||
|
Action.KmsPutKeyPolicy,
|
||||||
|
Action.KmsReEncrypt,
|
||||||
|
Action.KmsReplicateKey,
|
||||||
|
Action.KmsRetireGrant,
|
||||||
|
Action.KmsRevokeGrant,
|
||||||
|
Action.KmsScheduleKeyDeletion,
|
||||||
|
Action.KmsSign,
|
||||||
|
Action.KmsTagResource,
|
||||||
|
Action.KmsUntagResource,
|
||||||
|
Action.KmsUpdateAlias,
|
||||||
|
Action.KmsUpdateCustomKeyStore,
|
||||||
|
Action.KmsUpdateKeyDescription,
|
||||||
|
Action.KmsUpdatePrimaryRegion,
|
||||||
|
Action.KmsVerify,
|
||||||
|
Action.KmsVerifyMac,
|
||||||
|
]
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
TypeOrmModule.forFeature([]),
|
||||||
|
AwsSharedEntitiesModule,
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
...handlers,
|
||||||
|
ExistingActionHandlersProvider(handlers),
|
||||||
|
DefaultActionHandlerProvider(KMSHandlers, Format.Json, actions),
|
||||||
|
],
|
||||||
|
exports: [KMSHandlers],
|
||||||
|
})
|
||||||
|
export class KmsModule {}
|
||||||
|
|
@ -2,15 +2,18 @@ import { ClassSerializerInterceptor } from '@nestjs/common';
|
||||||
import { NestFactory, Reflector } from '@nestjs/core';
|
import { NestFactory, Reflector } from '@nestjs/core';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
import * as morgan from 'morgan';
|
import * as morgan from 'morgan';
|
||||||
|
import { CommonConfig } from './config/common-config.interface';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
||||||
const port = 8081;
|
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
app.use(morgan('dev'));
|
app.use(morgan('dev'));
|
||||||
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
|
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
|
||||||
app.use(bodyParser.json({ type: 'application/x-amz-json-1.1'}));
|
app.use(bodyParser.json({ type: 'application/x-amz-json-1.1'}));
|
||||||
|
|
||||||
await app.listen(port, () => console.log(`Listening on port ${port}`));
|
const configService: ConfigService<CommonConfig> = app.get(ConfigService)
|
||||||
|
|
||||||
|
await app.listen(configService.get('PORT'), () => console.log(`Listening on port ${configService.get('PORT')}`));
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -27,19 +27,24 @@ export class SetQueueAttributesHandler extends AbstractActionHandler<QueryParams
|
||||||
format = Format.Xml;
|
format = Format.Xml;
|
||||||
action = Action.SqsSetQueueAttributes;
|
action = Action.SqsSetQueueAttributes;
|
||||||
validator = Joi.object<QueryParams, true>({
|
validator = Joi.object<QueryParams, true>({
|
||||||
'Attribute.Name': Joi.string().required(),
|
'Attribute.Name': Joi.string(),
|
||||||
'Attribute.Value': Joi.string().required(),
|
'Attribute.Value': Joi.string(),
|
||||||
__path: Joi.string().required(),
|
__path: Joi.string().required(),
|
||||||
});
|
});
|
||||||
|
|
||||||
protected async handle(params: QueryParams, awsProperties: AwsProperties) {
|
protected async handle(params: QueryParams, awsProperties: AwsProperties) {
|
||||||
const [accountId, name] = SqsQueue.getAccountIdAndNameFromPath(params.__path);
|
const [accountId, name] = SqsQueue.getAccountIdAndNameFromPath(params.__path);
|
||||||
const queue = await this.sqsQueueRepo.findOne({ where: { accountId , name } });
|
const queue = await this.sqsQueueRepo.findOne({ where: { accountId , name } });
|
||||||
|
const attributes = SqsQueue.attributePairs(params);
|
||||||
|
|
||||||
|
if (params['Attribute.Name'] && params['Attribute.Value']) {
|
||||||
|
attributes.push({ key: params['Attribute.Name'], value: params['Attribute.Value'] });
|
||||||
|
}
|
||||||
|
|
||||||
if(!queue) {
|
if(!queue) {
|
||||||
throw new BadRequestException('ResourceNotFoundException');
|
throw new BadRequestException('ResourceNotFoundException');
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.attributeService.create({ name: params['Attribute.Name'], value: params['Attribute.Value'], arn: queue.arn });
|
await this.attributeService.createMany(queue.arn, attributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue