Skip to content

Commit

Permalink
Merge branch 'dockerbuild' of https://github.com/Abbhiishek/keyshade
Browse files Browse the repository at this point in the history
…into dockerbuild
  • Loading branch information
Abbhiishek committed Apr 5, 2024
2 parents 1af92f7 + 255469f commit 158fc7f
Show file tree
Hide file tree
Showing 105 changed files with 6,609 additions and 499 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GITHUB_CALLBACK_URL=

API_PORT=

GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_CALLBACK_URL=
Expand Down
5 changes: 5 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners

apps/web @kriptonian1
apps/workspace @kriptonian1
apps/api @rajdip-b
2 changes: 1 addition & 1 deletion .github/workflows/stage-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ on:
push:
branches:
- develop
paths: ['apps/api/**', '.github/workflows/stage-api.yml']
paths: ['apps/api/**', '.github/workflows/stage-api.yml', 'fly.api.toml']

env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/stage-web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ on:
push:
branches:
- develop
paths: ['apps/web/**', '.github/workflows/stage-web.yml']
paths: ['apps/web/**', '.github/workflows/stage-web.yml', 'fly.web.toml']

jobs:
deploy-stage:
Expand Down
8 changes: 0 additions & 8 deletions .prettierrc

This file was deleted.

2 changes: 1 addition & 1 deletion apps/api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ RUN pnpm db:generate-types
RUN pnpm build:api
RUN pnpm sourcemaps:api

EXPOSE 4200
EXPOSE ${API_PORT:-4200}

ENTRYPOINT ["node", "apps/api/dist/main.js"]
2 changes: 1 addition & 1 deletion apps/api/src/api-key/api-key.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ describe('Api Key Role Controller Tests', () => {
}
})

expect(response.statusCode).toBe(200)
expect(response.statusCode).toBe(204)
})

afterAll(async () => {
Expand Down
147 changes: 146 additions & 1 deletion apps/api/src/api-key/controller/api-key.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Controller,
Delete,
Get,
HttpCode,
Param,
Post,
Put,
Expand All @@ -14,19 +15,81 @@ import { CreateApiKey } from '../dto/create.api-key/create.api-key'
import { UpdateApiKey } from '../dto/update.api-key/update.api-key'
import { Authority, User } from '@prisma/client'
import { RequiredApiKeyAuthorities } from '../../decorators/required-api-key-authorities.decorator'
import {
ApiBearerAuth,
ApiCreatedResponse,
ApiForbiddenResponse,
ApiNoContentResponse,
ApiOkResponse,
ApiOperation,
ApiParam,
ApiQuery,
ApiSecurity,
ApiTags
} from '@nestjs/swagger'
import { invalidAuthenticationResponse } from '../../common/static'

const baseProperties = {
id: { type: 'string' },
name: { type: 'string' },
expiresAt: { type: 'string' },
authorities: { type: 'array', items: { type: 'string' } },
createdAt: { type: 'string' },
updatedAt: { type: 'string' }
}

const apiKeySchemaWithValue = {
type: 'object',
properties: {
...baseProperties,
value: { type: 'string' }
}
}

const apiKeySchema = {
type: 'object',
properties: baseProperties
}

@Controller('api-key')
@ApiBearerAuth()
@ApiSecurity('api_key')
@ApiTags('API Key Controller')
export class ApiKeyController {
constructor(private readonly apiKeyService: ApiKeyService) {}

@Post()
@RequiredApiKeyAuthorities(Authority.CREATE_API_KEY)
@ApiOperation({
summary: 'Create API key',
description: 'This endpoint creates a new API key'
})
@ApiCreatedResponse({
schema: apiKeySchemaWithValue,
description: 'API key created successfully'
})
@ApiForbiddenResponse(invalidAuthenticationResponse)
async createApiKey(@CurrentUser() user: User, @Body() dto: CreateApiKey) {
return this.apiKeyService.createApiKey(user, dto)
}

@Put(':id')
@RequiredApiKeyAuthorities(Authority.UPDATE_API_KEY)
@ApiOperation({
summary: 'Update API key',
description: 'This endpoint updates an existing API key'
})
@ApiParam({
name: 'id',
description: 'API key ID',
required: true,
schema: { type: 'string' }
})
@ApiOkResponse({
schema: apiKeySchema,
description: 'API key updated successfully'
})
@ApiForbiddenResponse(invalidAuthenticationResponse)
async updateApiKey(
@CurrentUser() user: User,
@Body() dto: UpdateApiKey,
Expand All @@ -37,21 +100,103 @@ export class ApiKeyController {

@Delete(':id')
@RequiredApiKeyAuthorities(Authority.DELETE_API_KEY)
@HttpCode(204)
@ApiOperation({
summary: 'Delete API key',
description: 'This endpoint deletes an existing API key'
})
@ApiParam({
name: 'id',
description: 'API key ID',
required: true,
schema: { type: 'string' }
})
@ApiNoContentResponse({
description: 'API key deleted successfully'
})
@ApiForbiddenResponse(invalidAuthenticationResponse)
async deleteApiKey(@CurrentUser() user: User, @Param('id') id: string) {
return this.apiKeyService.deleteApiKey(user, id)
}

@Get(':id')
@RequiredApiKeyAuthorities(Authority.READ_API_KEY)
@ApiOperation({
summary: 'Get API key',
description: 'This endpoint returns the details of an API key'
})
@ApiParam({
name: 'id',
description: 'API key ID',
required: true,
schema: { type: 'string' }
})
@ApiOkResponse({
schema: apiKeySchemaWithValue,
description: 'API key details'
})
@ApiForbiddenResponse(invalidAuthenticationResponse)
async getApiKey(@CurrentUser() user: User, @Param('id') id: string) {
return this.apiKeyService.getApiKeyById(user, id)
}

@Get('all')
@RequiredApiKeyAuthorities(Authority.READ_API_KEY)
@ApiOperation({
summary: 'Get all API keys',
description: 'This endpoint returns all API keys of the user'
})
@ApiQuery({
name: 'page',
description: 'Page number',
required: false,
type: Number,
example: 1,
allowEmptyValue: false
})
@ApiQuery({
name: 'limit',
description: 'Number of items per page',
required: false,
type: Number,
example: 10,
allowEmptyValue: false
})
@ApiQuery({
name: 'sort',
description: 'Sort by field',
required: false,
type: String,
example: 'name',
allowEmptyValue: false
})
@ApiQuery({
name: 'order',
description: 'Sort order',
required: false,
type: String,
example: 'asc',
allowEmptyValue: false
})
@ApiQuery({
name: 'search',
description: 'Search by name',
required: false,
type: String,
example: 'My API Key',
allowEmptyValue: false
})
@ApiOkResponse({
schema: {
type: 'array',
items: apiKeySchema
},
description: 'API keys'
})
@ApiForbiddenResponse(invalidAuthenticationResponse)
async getApiKeysOfUser(
@CurrentUser() user: User,
@Query('page') page: number = 1,
@Query('page') page: number = 0,
@Query('limit') limit: number = 10,
@Query('sort') sort: string = 'name',
@Query('order') order: string = 'asc',
Expand Down
24 changes: 24 additions & 0 deletions apps/api/src/api-key/dto/create.api-key/create.api-key.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,39 @@
import { ApiProperty } from '@nestjs/swagger'
import { ApiKey, Authority } from '@prisma/client'
import { IsArray, IsOptional, IsString } from 'class-validator'

export class CreateApiKey {
@IsString()
@ApiProperty({
name: 'name',
description: 'Name of the API key',
required: true,
type: String,
example: 'My API Key'
})
name: ApiKey['name']

@IsString()
@IsOptional()
@ApiProperty({
name: 'expiresAfter',
description: 'API key expiration time in hours',
required: false,
type: String,
example: '24',
default: 'never'
})
expiresAfter?: '24' | '168' | '720' | '8760' | 'never' = 'never'

@IsArray()
@IsOptional()
@ApiProperty({
name: 'authorities',
description: 'API key authorities',
required: false,
type: [String],
example: ['READ_SELF', 'UPDATE_SELF'],
default: []
})
authorities?: Authority[] = []
}
2 changes: 1 addition & 1 deletion apps/api/src/api-key/service/api-key.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export class ApiKeyService {
contains: search
}
},
skip: (page - 1) * limit,
skip: page * limit,
take: limit,
orderBy: {
[sort]: order
Expand Down
12 changes: 9 additions & 3 deletions apps/api/src/auth/controller/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ import {
import { AuthService } from '../service/auth.service'
import { UserAuthenticatedResponse } from '../auth.types'
import { Public } from '../../decorators/public.decorator'
import { ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger'
import {
ApiOperation,
ApiParam,
ApiQuery,
ApiResponse,
ApiTags
} from '@nestjs/swagger'
import { AuthGuard } from '@nestjs/passport'
import { GithubOAuthStrategyFactory } from '../../config/factory/github/github-strategy.factory'
import { GoogleOAuthStrategyFactory } from '../../config/factory/google/google-strategy.factory'
Expand Down Expand Up @@ -62,12 +68,12 @@ export class AuthController {
description:
'This endpoint validates OTPs. If the OTP is valid, it returns a valid token along with the user details'
})
@ApiParam({
@ApiQuery({
name: 'email',
description: 'Email to send OTP',
required: true
})
@ApiParam({
@ApiQuery({
name: 'otp',
description: 'OTP to validate',
required: true
Expand Down
40 changes: 0 additions & 40 deletions apps/api/src/common/mock-data/users.ts

This file was deleted.

3 changes: 3 additions & 0 deletions apps/api/src/common/static.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const invalidAuthenticationResponse = {
description: 'Invalid authentication header or API key'
}
8 changes: 7 additions & 1 deletion apps/api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,17 @@ async function initializeNestApp() {
}),
new QueryTransformPipe()
)
const port = 4200
const port = process.env.API_PORT || 4200
const swaggerConfig = new DocumentBuilder()
.setTitle('keyshade')
.setDescription('The keyshade API description')
.setVersion('1.0')
.addBearerAuth({ type: 'http', scheme: 'bearer', bearerFormat: 'JWT' })
.addSecurity('api_key', {
type: 'apiKey',
in: 'header',
name: 'x-keyshade-token'
})
.build()
const document = SwaggerModule.createDocument(app, swaggerConfig)
SwaggerModule.setup('docs', app, document)
Expand Down
Loading

0 comments on commit 158fc7f

Please sign in to comment.