Skip to content

Commit

Permalink
added pagination to getRevisionsOfSecret
Browse files Browse the repository at this point in the history
  • Loading branch information
anudeeps352 committed Jun 28, 2024
2 parents 54427b4 + b5a0637 commit 762dae7
Show file tree
Hide file tree
Showing 16 changed files with 635 additions and 224 deletions.
62 changes: 53 additions & 9 deletions apps/api/src/api-key/api-key.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe('Api Key Role Controller Tests', () => {
method: 'POST',
url: '/api-key',
payload: {
name: 'Test Key',
name: 'Test',
expiresAfter: '24',
authorities: ['READ_API_KEY']
},
Expand All @@ -81,7 +81,7 @@ describe('Api Key Role Controller Tests', () => {

expect(response.statusCode).toBe(201)
expect(response.json().id).toBeDefined()
expect(response.json().name).toBe('Test Key')
expect(response.json().name).toBe('Test')
expect(response.json().value).toMatch(/^ks_*/)
expect(response.json().authorities).toEqual(['READ_API_KEY'])

Expand All @@ -92,15 +92,32 @@ describe('Api Key Role Controller Tests', () => {
})

expect(apiKey).toBeDefined()
expect(apiKey!.name).toBe('Test Key')
expect(apiKey!.name).toBe('Test')
})

it('should not be able to create api key with same name', async () => {
const response = await app.inject({
method: 'POST',
url: '/api-key',
payload: {
name: 'Test Key',
expiresAfter: '24',
authorities: ['READ_API_KEY']
},
headers: {
'x-e2e-user-email': user.email
}
})

expect(response.statusCode).toBe(409)
})

it('should not have any authorities if none are provided', async () => {
const response = await app.inject({
method: 'POST',
url: '/api-key',
payload: {
name: 'Test Key 1',
name: 'Test',
expiresAfter: '24'
},
headers: {
Expand All @@ -110,24 +127,39 @@ describe('Api Key Role Controller Tests', () => {

expect(response.statusCode).toBe(201)
expect(response.json().id).toBeDefined()
expect(response.json().name).toBe('Test Key 1')
expect(response.json().name).toBe('Test')
expect(response.json().value).toMatch(/^ks_*/)
expect(response.json().authorities).toEqual([])
})

it('should be able to update the api key without without changing the authorities', async () => {
it('should not be able to update an api key with the same name', async () => {
const response = await app.inject({
method: 'PUT',
url: `/api-key/${apiKey.id}`,
payload: {
name: 'Updated Test Key',
name: 'Test Key',
expiresAfter: '168'
},
headers: {
'x-e2e-user-email': user.email
}
})

expect(response.statusCode).toBe(409)
})

it('should be able to update the api key without without changing the authorities', async () => {
const response = await app.inject({
method: 'PUT',
url: `/api-key/${apiKey.id}`,
payload: {
name: 'Updated Test Key'
},
headers: {
'x-e2e-user-email': user.email
}
})

expect(response.statusCode).toBe(200)
expect(response.json().id).toBe(apiKey.id)
expect(response.json().name).toBe('Updated Test Key')
Expand Down Expand Up @@ -203,7 +235,7 @@ describe('Api Key Role Controller Tests', () => {
it('should be able to get all the api keys of the user', async () => {
const response = await app.inject({
method: 'GET',
url: '/api-key/all',
url: '/api-key',
headers: {
'x-e2e-user-email': user.email
}
Expand All @@ -221,7 +253,7 @@ describe('Api Key Role Controller Tests', () => {
it('should be able to get all api keys using the API key', async () => {
const response = await app.inject({
method: 'GET',
url: '/api-key/all',
url: '/api-key',
headers: {
'x-keyshade-token': apiKey.value
}
Expand Down Expand Up @@ -300,6 +332,18 @@ describe('Api Key Role Controller Tests', () => {
expect(response.statusCode).toBe(204)
})

it('should not be able to delete an api key that does not exist', async () => {
const response = await app.inject({
method: 'DELETE',
url: `/api-key/ks_1234567890`,
headers: {
'x-e2e-user-email': user.email
}
})

expect(response.statusCode).toBe(404)
})

afterAll(async () => {
await app.close()
})
Expand Down
14 changes: 7 additions & 7 deletions apps/api/src/api-key/controller/api-key.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,7 @@ export class ApiKeyController {
return this.apiKeyService.deleteApiKey(user, id)
}

@Get(':id')
@RequiredApiKeyAuthorities(Authority.READ_API_KEY)
async getApiKey(@CurrentUser() user: User, @Param('id') id: string) {
return this.apiKeyService.getApiKeyById(user, id)
}

@Get('all')
@Get('/')
@RequiredApiKeyAuthorities(Authority.READ_API_KEY)
async getApiKeysOfUser(
@CurrentUser() user: User,
Expand All @@ -69,6 +63,12 @@ export class ApiKeyController {
)
}

@Get(':id')
@RequiredApiKeyAuthorities(Authority.READ_API_KEY)
async getApiKey(@CurrentUser() user: User, @Param('id') id: string) {
return this.apiKeyService.getApiKeyById(user, id)
}

@Get('/access/live-updates')
@RequiredApiKeyAuthorities(
Authority.READ_SECRET,
Expand Down
56 changes: 43 additions & 13 deletions apps/api/src/api-key/service/api-key.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Injectable, Logger, NotFoundException } from '@nestjs/common'
import {
ConflictException,
Injectable,
Logger,
NotFoundException
} from '@nestjs/common'
import { PrismaService } from '../../prisma/prisma.service'
import { CreateApiKey } from '../dto/create.api-key/create.api-key'
import { addHoursToDate } from '../../common/add-hours-to-date'
import { generateApiKey } from '../../common/api-key-generator'
import { toSHA256 } from '../../common/to-sha256'
import { UpdateApiKey } from '../dto/update.api-key/update.api-key'
import { User } from '@prisma/client'
import { ApiKey, User } from '@prisma/client'

@Injectable()
export class ApiKeyService {
Expand All @@ -14,6 +19,8 @@ export class ApiKeyService {
constructor(private readonly prisma: PrismaService) {}

async createApiKey(user: User, dto: CreateApiKey) {
await this.isApiKeyUnique(user, dto.name)

const plainTextApiKey = generateApiKey()
const hashedApiKey = toSHA256(plainTextApiKey)
const apiKey = await this.prisma.apiKey.create({
Expand Down Expand Up @@ -43,6 +50,8 @@ export class ApiKeyService {
}

async updateApiKey(user: User, apiKeyId: string, dto: UpdateApiKey) {
await this.isApiKeyUnique(user, dto.name)

const apiKey = await this.prisma.apiKey.findUnique({
where: {
id: apiKeyId,
Expand All @@ -54,10 +63,6 @@ export class ApiKeyService {
throw new NotFoundException(`API key with id ${apiKeyId} not found`)
}

const existingAuthorities = new Set(apiKey.authorities)
dto.authorities &&
dto.authorities.forEach((auth) => existingAuthorities.add(auth))

const updatedApiKey = await this.prisma.apiKey.update({
where: {
id: apiKeyId,
Expand All @@ -66,7 +71,7 @@ export class ApiKeyService {
data: {
name: dto.name,
authorities: {
set: Array.from(existingAuthorities)
set: dto.authorities ? dto.authorities : apiKey.authorities
},
expiresAt: dto.expiresAfter
? addHoursToDate(dto.expiresAfter)
Expand All @@ -88,12 +93,16 @@ export class ApiKeyService {
}

async deleteApiKey(user: User, apiKeyId: string) {
await this.prisma.apiKey.delete({
where: {
id: apiKeyId,
userId: user.id
}
})
try {
await this.prisma.apiKey.delete({
where: {
id: apiKeyId,
userId: user.id
}
})
} catch (error) {
throw new NotFoundException(`API key with id ${apiKeyId} not found`)
}

this.logger.log(`User ${user.id} deleted API key ${apiKeyId}`)
}
Expand Down Expand Up @@ -151,4 +160,25 @@ export class ApiKeyService {
}
})
}

private async isApiKeyUnique(user: User, apiKeyName: string) {
let apiKey: ApiKey | null = null

try {
apiKey = await this.prisma.apiKey.findUnique({
where: {
userId_name: {
userId: user.id,
name: apiKeyName
}
}
})
} catch (_error) {}

if (apiKey) {
throw new ConflictException(
`API key with name ${apiKeyName} already exists`
)
}
}
}
2 changes: 1 addition & 1 deletion apps/api/src/auth/guard/auth/auth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export class AuthGuard implements CanActivate {
private extractApiKeyFromHeader(request: any): string | undefined {
const headers = this.getHeaders(request)
if (Array.isArray(headers[X_KEYSHADE_TOKEN])) {
throw new Error('Bad auth')
throw new ForbiddenException('Bad auth')
}
return headers[X_KEYSHADE_TOKEN]
}
Expand Down
13 changes: 7 additions & 6 deletions apps/api/src/common/authority-checker.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { VariableWithProjectAndVersion } from '../variable/variable.types'
import {
Injectable,
InternalServerErrorException,
NotFoundException,
UnauthorizedException
} from '@nestjs/common'
Expand Down Expand Up @@ -53,7 +54,7 @@ export class AuthorityCheckerService {
}
} catch (error) {
this.customLoggerService.error(error)
throw new Error(error)
throw new InternalServerErrorException(error)
}

// Check if the workspace exists or not
Expand Down Expand Up @@ -111,7 +112,7 @@ export class AuthorityCheckerService {
}
} catch (error) {
this.customLoggerService.error(error)
throw new Error(error)
throw new InternalServerErrorException(error)
}

// If the project is not found, throw an error
Expand Down Expand Up @@ -209,7 +210,7 @@ export class AuthorityCheckerService {
}
} catch (error) {
this.customLoggerService.error(error)
throw new Error(error)
throw new InternalServerErrorException(error)
}

if (!environment) {
Expand Down Expand Up @@ -268,7 +269,7 @@ export class AuthorityCheckerService {
}
} catch (error) {
this.customLoggerService.error(error)
throw new Error(error)
throw new InternalServerErrorException(error)
}

if (!variable) {
Expand Down Expand Up @@ -328,7 +329,7 @@ export class AuthorityCheckerService {
}
} catch (error) {
this.customLoggerService.error(error)
throw new Error(error)
throw new InternalServerErrorException(error)
}

if (!secret) {
Expand Down Expand Up @@ -380,7 +381,7 @@ export class AuthorityCheckerService {
}
} catch (error) {
this.customLoggerService.error(error)
throw new Error(error)
throw new InternalServerErrorException(error)
}

if (!integration) {
Expand Down
4 changes: 3 additions & 1 deletion apps/api/src/common/create-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ export default async function createEvent(
prisma: PrismaClient
) {
if (data.triggerer !== EventTriggerer.SYSTEM && !data.triggeredBy) {
throw new Error('User must be provided for non-system events')
throw new InternalServerErrorException(
'User must be provided for non-system events'
)
}

const event = await prisma.event.create({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IntegrationType } from '@prisma/client'
import { BaseIntegration } from '../base.integration'
import { DiscordIntegration } from '../discord/discord.integration'
import { InternalServerErrorException } from '@nestjs/common'

/**
* Factory class to create integrations. This class will be called to create an integration,
Expand All @@ -20,7 +21,7 @@ export default class IntegrationFactory {
case IntegrationType.DISCORD:
return new DiscordIntegration()
default:
throw new Error('Integration type not found')
throw new InternalServerErrorException('Integration type not found')
}
}
}
10 changes: 8 additions & 2 deletions apps/api/src/mail/services/mail.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Injectable, Logger } from '@nestjs/common'
import {
Injectable,
InternalServerErrorException,
Logger
} from '@nestjs/common'
import { IMailService } from './interface.service'
import { Transporter, createTransport } from 'nodemailer'

Expand Down Expand Up @@ -169,7 +173,9 @@ export class MailService implements IMailService {
this.log.log(`Email sent to ${email}`)
} catch (error) {
this.log.error(`Error sending email to ${email}: ${error.message}`)
throw new Error(`Error sending email to ${email}: ${error.message}`)
throw new InternalServerErrorException(
`Error sending email to ${email}: ${error.message}`
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
Warnings:
- A unique constraint covering the columns `[userId,name]` on the table `ApiKey` will be added. If there are existing duplicate values, this will fail.
*/
-- CreateIndex
CREATE UNIQUE INDEX "ApiKey_userId_name_key" ON "ApiKey"("userId", "name");
Loading

0 comments on commit 762dae7

Please sign in to comment.