From 1ec83fd492920ab4cbc21754682dea8091a87c63 Mon Sep 17 00:00:00 2001 From: Udit Sharma Date: Fri, 29 Dec 2023 02:02:33 +0530 Subject: [PATCH 01/26] invalidate older OTPs --- apps/api/src/auth/admin.guard.ts | 4 +- apps/api/src/auth/auth.controller.ts | 5 +- apps/api/src/auth/auth.guard.ts | 7 ++- apps/api/src/auth/auth.service.ts | 30 ++++++++++-- apps/api/src/decorators/user.decorator.ts | 14 +++--- apps/api/src/main.ts | 22 +++++++-- apps/api/src/prisma/prisma.repository.ts | 46 +++++++++++++++++++ apps/api/src/resend/services/mail.resend.ts | 6 ++- .../user/dto/update.user/update.user.spec.ts | 8 ++-- .../src/user/dto/update.user/update.user.ts | 8 ++-- apps/api/tsconfig.spec.json | 7 ++- 11 files changed, 129 insertions(+), 28 deletions(-) diff --git a/apps/api/src/auth/admin.guard.ts b/apps/api/src/auth/admin.guard.ts index 6f99c6fb..30ea6a80 100644 --- a/apps/api/src/auth/admin.guard.ts +++ b/apps/api/src/auth/admin.guard.ts @@ -4,7 +4,9 @@ import { Observable } from 'rxjs' @Injectable() export class AdminGuard implements CanActivate { - canActivate(context: ExecutionContext): boolean | Promise | Observable { + canActivate( + context: ExecutionContext + ): boolean | Promise | Observable { const request = context.switchToHttp().getRequest() const user: User = request.user diff --git a/apps/api/src/auth/auth.controller.ts b/apps/api/src/auth/auth.controller.ts index d361be0e..273004b2 100644 --- a/apps/api/src/auth/auth.controller.ts +++ b/apps/api/src/auth/auth.controller.ts @@ -15,7 +15,10 @@ export class AuthController { @Public() @Post('validate-otp') - async validateOtp(@Query('email') email: string, @Query('otp') otp: string): Promise { + async validateOtp( + @Query('email') email: string, + @Query('otp') otp: string + ): Promise { return await this.authService.validateOtp(email, otp) } } diff --git a/apps/api/src/auth/auth.guard.ts b/apps/api/src/auth/auth.guard.ts index a24a39cf..c88f9fe1 100644 --- a/apps/api/src/auth/auth.guard.ts +++ b/apps/api/src/auth/auth.guard.ts @@ -1,4 +1,9 @@ -import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common' +import { + CanActivate, + ExecutionContext, + ForbiddenException, + Injectable +} from '@nestjs/common' import { JwtService } from '@nestjs/jwt' import { Request } from 'express' import { PrismaRepository } from '../prisma/prisma.repository' diff --git a/apps/api/src/auth/auth.service.ts b/apps/api/src/auth/auth.service.ts index 3f7a559a..c0b6904a 100644 --- a/apps/api/src/auth/auth.service.ts +++ b/apps/api/src/auth/auth.service.ts @@ -1,9 +1,19 @@ -import { HttpException, HttpStatus, Inject, Injectable, Logger, LoggerService } from '@nestjs/common' +import { + HttpException, + HttpStatus, + Inject, + Injectable, + Logger, + LoggerService +} from '@nestjs/common' import { PrismaRepository } from '../prisma/prisma.repository' import { randomUUID } from 'crypto' import { JwtService } from '@nestjs/jwt' import { UserAuthenticatedResponse } from './auth.types' -import { IResendService, RESEND_SERVICE } from '../resend/services/resend.service.interface' +import { + IResendService, + RESEND_SERVICE +} from '../resend/services/resend.service.interface' @Injectable() export class AuthService { @@ -21,7 +31,10 @@ export class AuthService { async sendOtp(email: string): Promise { if (!email || !email.includes('@')) { this.logger.error(`Invalid email address: ${email}`) - throw new HttpException('Please enter a valid email address', HttpStatus.BAD_REQUEST) + throw new HttpException( + 'Please enter a valid email address', + HttpStatus.BAD_REQUEST + ) } // We need to create the user if it doesn't exist yet @@ -29,13 +42,20 @@ export class AuthService { await this.repository.createUser(email) } - const otp = await this.repository.createOtp(email, randomUUID().slice(0, 6).toUpperCase(), this.OTP_EXPIRY) + const otp = await this.repository.createOtp( + email, + randomUUID().slice(0, 6).toUpperCase(), + this.OTP_EXPIRY + ) await this.resend.sendOtp(email, otp.code) this.logger.log(`Login code sent to ${email}: ${otp.code}`) } - async validateOtp(email: string, otp: string): Promise { + async validateOtp( + email: string, + otp: string + ): Promise { const user = await this.repository.findUserByEmail(email) if (!user) { this.logger.error(`User not found: ${email}`) diff --git a/apps/api/src/decorators/user.decorator.ts b/apps/api/src/decorators/user.decorator.ts index bb32a758..0f122a72 100644 --- a/apps/api/src/decorators/user.decorator.ts +++ b/apps/api/src/decorators/user.decorator.ts @@ -1,9 +1,11 @@ import { createParamDecorator, ExecutionContext } from '@nestjs/common' import { User as DBUser } from '@prisma/client' -export const CurrentUser = createParamDecorator( - (_: unknown, ctx: ExecutionContext) => { - const request = ctx.switchToHttp().getRequest() - return request.user - } -) +export const CurrentUser = createParamDecorator< + unknown, + ExecutionContext, + DBUser +>((_: unknown, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest() + return request.user +}) diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index add65f4f..01a46947 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -16,15 +16,27 @@ class CustomLogger implements LoggerService { } info(message: string) { - console.info(`${chalk.green('[INFO]')} ${chalk.green(moment().format('YYYY-MM-DD HH:mm:ss'))} - ${message}`) + console.info( + `${chalk.green('[INFO]')} ${chalk.green( + moment().format('YYYY-MM-DD HH:mm:ss') + )} - ${message}` + ) } error(message: string) { - console.error(`${chalk.red('[ERROR]')} ${chalk.red(moment().format('YYYY-MM-DD HH:mm:ss'))} - ${message}`) + console.error( + `${chalk.red('[ERROR]')} ${chalk.red( + moment().format('YYYY-MM-DD HH:mm:ss') + )} - ${message}` + ) } warn(message: string) { - console.warn(`${chalk.yellow('[WARN]')} ${chalk.yellow(moment().format('YYYY-MM-DD HH:mm:ss'))} - ${message}`) + console.warn( + `${chalk.yellow('[WARN]')} ${chalk.yellow( + moment().format('YYYY-MM-DD HH:mm:ss') + )} - ${message}` + ) } } @@ -43,7 +55,9 @@ async function bootstrap() { ) const port = 4200 await app.listen(port) - logger.log(`🚀 Application is running on: http://localhost:${port}/${globalPrefix}`) + logger.log( + `🚀 Application is running on: http://localhost:${port}/${globalPrefix}` + ) } bootstrap() diff --git a/apps/api/src/prisma/prisma.repository.ts b/apps/api/src/prisma/prisma.repository.ts index bfeb1a9a..8b320b83 100644 --- a/apps/api/src/prisma/prisma.repository.ts +++ b/apps/api/src/prisma/prisma.repository.ts @@ -142,6 +142,7 @@ export class PrismaRepository { expiresAfter: number ): Promise { const timeNow = new Date() + await this.invalidateOldOtps(email) return await this.prisma.otp.create({ data: { code: otp, @@ -155,6 +156,51 @@ export class PrismaRepository { }) } + /** + * Invalidate Old OTPs for a User + * + * This method invalidates old OTPs (One-Time Passwords) associated with a user. + * It finds and deletes OTPs that belong to the user and have not expired yet. + * + * @param email - The email address of the user for whom old OTPs should be invalidated. + * + * @example + * ```typescript + * await invalidateOldOtps('user@example.com'); + * ``` + */ + private async invalidateOldOtps(email: string): Promise { + const user = await this.prisma.user.findUnique({ + where: { + email + } + }) + if (user) { + const oldOtpCodesToDelete = await this.prisma.otp + .findMany({ + where: { + userId: user.id, + expiresAt: { + gte: new Date() + } + }, + select: { + code: true + } + }) + .then((oldOtps) => oldOtps.map((otp) => otp.code)) + if (oldOtpCodesToDelete.length > 0) { + await this.prisma.otp.deleteMany({ + where: { + code: { + in: oldOtpCodesToDelete + } + } + }) + } + } + } + async deleteOtp(email: string, otp: string): Promise { await this.prisma.otp.delete({ where: { diff --git a/apps/api/src/resend/services/mail.resend.ts b/apps/api/src/resend/services/mail.resend.ts index b1be1f2d..5bdd0f13 100644 --- a/apps/api/src/resend/services/mail.resend.ts +++ b/apps/api/src/resend/services/mail.resend.ts @@ -34,7 +34,11 @@ export class MailResend implements IResendService { await this.sendEmail(email, subject, body) } - private async sendEmail(email: string, subject: string, body: string): Promise { + private async sendEmail( + email: string, + subject: string, + body: string + ): Promise { const { error } = await this.resend.emails.send({ from: process.env.FROM_EMAIL, to: email, diff --git a/apps/api/src/user/dto/update.user/update.user.spec.ts b/apps/api/src/user/dto/update.user/update.user.spec.ts index 49133470..406d6d7f 100644 --- a/apps/api/src/user/dto/update.user/update.user.spec.ts +++ b/apps/api/src/user/dto/update.user/update.user.spec.ts @@ -1,7 +1,7 @@ -import { UpdateUserDto } from './update.user'; +import { UpdateUserDto } from './update.user' describe('UpdateUser', () => { it('should be defined', () => { - expect(new UpdateUserDto()).toBeDefined(); - }); -}); + expect(new UpdateUserDto()).toBeDefined() + }) +}) diff --git a/apps/api/src/user/dto/update.user/update.user.ts b/apps/api/src/user/dto/update.user/update.user.ts index 131062c8..b14ee3a7 100644 --- a/apps/api/src/user/dto/update.user/update.user.ts +++ b/apps/api/src/user/dto/update.user/update.user.ts @@ -1,7 +1,7 @@ -import { IsOptional, IsString } from "class-validator"; +import { IsOptional, IsString } from 'class-validator' export class UpdateUserDto { - @IsString() - @IsOptional() - name: string; + @IsString() + @IsOptional() + name: string } diff --git a/apps/api/tsconfig.spec.json b/apps/api/tsconfig.spec.json index f6d8ffcc..9b2a121d 100644 --- a/apps/api/tsconfig.spec.json +++ b/apps/api/tsconfig.spec.json @@ -5,5 +5,10 @@ "module": "commonjs", "types": ["jest", "node"] }, - "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] } From cb84237fce9799d571c730877ee5406f97fb924e Mon Sep 17 00:00:00 2001 From: Lakshay saini Date: Fri, 29 Dec 2023 16:32:36 +0530 Subject: [PATCH 02/26] test:getAllUsers Controller --- apps/api/src/user/user.controller.spec.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/api/src/user/user.controller.spec.ts b/apps/api/src/user/user.controller.spec.ts index 651dde45..caf56ea8 100644 --- a/apps/api/src/user/user.controller.spec.ts +++ b/apps/api/src/user/user.controller.spec.ts @@ -95,4 +95,18 @@ describe('UserController', () => { expect(await controller.getUserById(userId)).toEqual(null) }) }) + + describe('should get all users', () => { + it('should return all users with default parameters', async () => { + jest.spyOn(service, 'getAllUsers').mockResolvedValue([user]) + expect(await controller.getAllUsers()).toEqual([user]) + }) + + it('should return all users with custom parameters', async () => { + jest.spyOn(service, 'getAllUsers').mockResolvedValue([user]) + expect(await controller.getAllUsers(1, 10, 'name', 'asc', '')).toEqual([ + user + ]) + }) + }) }) From adb6ae7f7fc53d43f7e70f7ce20a9d30859ff025 Mon Sep 17 00:00:00 2001 From: Harsh Patel Date: Fri, 29 Dec 2023 22:31:51 +0530 Subject: [PATCH 03/26] build(cli): add lint workflow --- .github/workflows/cli.yaml | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/cli.yaml diff --git a/.github/workflows/cli.yaml b/.github/workflows/cli.yaml new file mode 100644 index 00000000..621bfbb3 --- /dev/null +++ b/.github/workflows/cli.yaml @@ -0,0 +1,39 @@ +on: + push: + paths: ['apps/cli/**', '.github/workflows/cli.yaml'] + pull_request: + paths: ['apps/cli/**'] + +jobs: + validate: + runs-on: ubuntu-latest + name: Validate + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + + - name: Install pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + run_install: false + + - name: Install packages + run: | + pnpm i + + - name: Lint + run: | + pnpm run lint:web + + - name: Test + run: | + pnpm run test:web + + \ No newline at end of file From ff7f4753504f9e76ed1accc65a5cfd991a1204ba Mon Sep 17 00:00:00 2001 From: Harsh Patel Date: Fri, 29 Dec 2023 22:32:07 +0530 Subject: [PATCH 04/26] build(sdk-node): add lint workflow --- .github/workflows/sdk-node.yaml | 37 +++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/sdk-node.yaml diff --git a/.github/workflows/sdk-node.yaml b/.github/workflows/sdk-node.yaml new file mode 100644 index 00000000..6790d773 --- /dev/null +++ b/.github/workflows/sdk-node.yaml @@ -0,0 +1,37 @@ +on: + push: + paths: ['/packages/sdk-node/**', '.github/workflows/sdk-node.yaml'] + pull_request: + paths: ['packages/sdk-node'] + +jobs: + validate: + runs-on: ubuntu-latest + name: Validate + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + + - name: Install pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + run_install: false + + - name: Install packages + run: | + pnpm i + + - name: Lint + run: | + pnpm run lint:sdk-node + + - name: Test + run: | + pnpm run test:sdk-node From 587f06b4f0497df22cc5a453c8db13fe0c53f2ef Mon Sep 17 00:00:00 2001 From: Harsh Patel Date: Fri, 29 Dec 2023 22:46:43 +0530 Subject: [PATCH 05/26] fix: typo --- .github/workflows/cli.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cli.yaml b/.github/workflows/cli.yaml index 621bfbb3..1569a056 100644 --- a/.github/workflows/cli.yaml +++ b/.github/workflows/cli.yaml @@ -30,10 +30,10 @@ jobs: - name: Lint run: | - pnpm run lint:web + pnpm run lint:cli - name: Test run: | - pnpm run test:web + pnpm run test:cli - \ No newline at end of file + From 333559d60299608ad63a5a2d45fc6db5843b56c4 Mon Sep 17 00:00:00 2001 From: Lakshay saini Date: Fri, 29 Dec 2023 22:58:35 +0530 Subject: [PATCH 06/26] added more test for controller and service --- apps/api/src/mock-data/users.ts | 50 +++++++++++++++++++++++ apps/api/src/user/fake.repository.ts | 27 ++++++++++++ apps/api/src/user/user.controller.spec.ts | 42 +++++++++++++++---- apps/api/src/user/user.service.spec.ts | 47 +++++++++++++++++++++ 4 files changed, 158 insertions(+), 8 deletions(-) create mode 100644 apps/api/src/mock-data/users.ts diff --git a/apps/api/src/mock-data/users.ts b/apps/api/src/mock-data/users.ts new file mode 100644 index 00000000..133014e9 --- /dev/null +++ b/apps/api/src/mock-data/users.ts @@ -0,0 +1,50 @@ +import { User } from '@prisma/client' + +export const user: User = { + id: '1', + name: 'John Doe', + email: 'johndoe@keyshade.xyz', + profilePictureUrl: 'https://keyshade.xyz/johndoe.jpg', + isActive: true, + isOnboardingFinished: false, + isAdmin: false +} + +export const users: Array = [ + { + id: '1', + name: 'Cristobal Hessel', + email: 'cristobal@keyshade.xyz', + profilePictureUrl: 'https://keyshade.xyz/cristobal.jpg', + isActive: true, + isOnboardingFinished: false, + isAdmin: false + }, + { + id: '2', + name: 'John Doe', + email: 'johndoe@keyshade.xyz', + profilePictureUrl: 'https://keyshade.xyz/johndoe.jpg', + isActive: true, + isOnboardingFinished: false, + isAdmin: false + }, + { + id: '3', + name: 'Jocelyn Larkin', + email: 'jocelyn@keyshade.xyz', + profilePictureUrl: 'https://keyshade.xyz/jocelyn.jpg', + isActive: false, + isOnboardingFinished: false, + isAdmin: false + }, + { + id: '4', + name: 'Kadin Stiedemann', + email: 'kadin@keyshade.xyz', + profilePictureUrl: 'https://keyshade.xyz/kadin.jpg', + isActive: true, + isOnboardingFinished: false, + isAdmin: true + } +] diff --git a/apps/api/src/user/fake.repository.ts b/apps/api/src/user/fake.repository.ts index 0c975f27..20d0360d 100644 --- a/apps/api/src/user/fake.repository.ts +++ b/apps/api/src/user/fake.repository.ts @@ -1,5 +1,6 @@ import { User } from '@prisma/client' import { PrismaRepository } from '../prisma/prisma.repository' +import { users } from '../mock-data/users' export const fakeRepository: Partial = { async excludeFields( @@ -16,5 +17,31 @@ export const fakeRepository: Partial = { id, ...data }) + }, + + async findUsers( + page: number, + limit: number, + sort: string, + order: string, + search: string + ): Promise { + let user_data = [...users] + user_data.sort((a, b) => { + const comparison = a[sort].localeCompare(b[sort]) + return order === 'desc' ? -comparison : comparison + }) + + if (search.trim() !== '') { + user_data = user_data.filter((user) => + user.name.toLowerCase().includes(search.toLowerCase()) + ) + } + + const start_idx = (page - 1) * limit + const end_idx = start_idx + limit + user_data = user_data.slice(start_idx, end_idx) + + return Promise.resolve(user_data) } } diff --git a/apps/api/src/user/user.controller.spec.ts b/apps/api/src/user/user.controller.spec.ts index caf56ea8..b4e4297f 100644 --- a/apps/api/src/user/user.controller.spec.ts +++ b/apps/api/src/user/user.controller.spec.ts @@ -3,6 +3,7 @@ import { UserController } from './user.controller' import { UserService } from './user.service' import { fakeRepository } from './fake.repository' import { User } from '@prisma/client' +import { users } from '../mock-data/users' describe('UserController', () => { let controller: UserController @@ -96,17 +97,42 @@ describe('UserController', () => { }) }) - describe('should get all users', () => { + describe('get all users', () => { + const sorted_user_data: Array = users.sort((a, b) => + a.name.localeCompare(b.name) + ) + it('should return all users with default parameters', async () => { - jest.spyOn(service, 'getAllUsers').mockResolvedValue([user]) - expect(await controller.getAllUsers()).toEqual([user]) + jest.spyOn(service, 'getAllUsers').mockResolvedValue(users) + expect(await controller.getAllUsers()).toEqual(users) }) - it('should return all users with custom parameters', async () => { - jest.spyOn(service, 'getAllUsers').mockResolvedValue([user]) - expect(await controller.getAllUsers(1, 10, 'name', 'asc', '')).toEqual([ - user - ]) + it('should return only 2 users with a limit of 2', async () => { + jest.spyOn(service, 'getAllUsers').mockResolvedValue(users.slice(0, 2)) + expect(await controller.getAllUsers(1, 2)).toEqual(users.slice(0, 2)) + }) + + it('should return users sorted by name in ascending order', async () => { + jest.spyOn(service, 'getAllUsers').mockResolvedValue(sorted_user_data) + expect( + await controller.getAllUsers(undefined, undefined, 'name', 'asc') + ).toEqual(sorted_user_data) + }) + + const filtered_user_data: Array = users.filter( + (user) => user.name === 'John Doe' + ) + it('should return users, where name is "John Doe"', async () => { + jest.spyOn(service, 'getAllUsers').mockResolvedValue(filtered_user_data) + expect( + await controller.getAllUsers( + undefined, + undefined, + undefined, + undefined, + 'Jon Doe' + ) + ).toEqual(filtered_user_data) }) }) }) diff --git a/apps/api/src/user/user.service.spec.ts b/apps/api/src/user/user.service.spec.ts index f30596c3..d408d367 100644 --- a/apps/api/src/user/user.service.spec.ts +++ b/apps/api/src/user/user.service.spec.ts @@ -2,6 +2,7 @@ import { Test, TestingModule } from '@nestjs/testing' import { UserService } from './user.service' import { fakeRepository } from './fake.repository' import { User } from '@prisma/client' +import { users } from '../mock-data/users' describe('UserService', () => { let service: UserService @@ -45,6 +46,52 @@ describe('UserService', () => { }) }) + describe('should get all user', () => { + const page = 1 + const limit = 10 + const sort = 'name' + const order = 'asc' + const search = '' + + const sorted_user_data: Array = users.sort((a, b) => + a.name.localeCompare(b.name) + ) + + it('should return all users in ascending order on name key from the repository', async () => { + const result = await service.getAllUsers(page, limit, sort, order, search) + expect(result).toEqual(sorted_user_data) + }) + + it('should return 2 users as limit is 2', async () => { + const result = await service.getAllUsers(page, 2, sort, order, search) + expect(result).toEqual(sorted_user_data.slice(0, 2)) + }) + + it('should return users with name as "Jocelyn Larkin ', async () => { + const result = await service.getAllUsers( + page, + limit, + sort, + order, + 'Jocelyn Larkin' + ) + expect(result).toEqual( + sorted_user_data.filter((user) => user.name === 'Jocelyn Larkin') + ) + }) + }) + + describe('should be able to get current user', () => { + it('should exclude the isActive field from the user object', async () => { + const result = await service.getSelf(user) + expect(result).not.toHaveProperty('isActive') + expect(result).toEqual({ + ...user, + isActive: undefined + }) + }) + }) + describe('should be able to update the current user name', () => { it('should update the user with the given data', async () => { const dto = { name: 'Jane Doe' } From 399b2012bafe3ffb36584089d57e41ef37473e88 Mon Sep 17 00:00:00 2001 From: Rajdip Bhattacharya Date: Fri, 29 Dec 2023 23:08:17 +0530 Subject: [PATCH 07/26] Update pr-lint.yaml --- .github/workflows/pr-lint.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-lint.yaml b/.github/workflows/pr-lint.yaml index 3b5a8e39..e52cd555 100644 --- a/.github/workflows/pr-lint.yaml +++ b/.github/workflows/pr-lint.yaml @@ -6,6 +6,7 @@ on: jobs: pr-lint: + permissions: write-all runs-on: ubuntu-latest steps: - uses: morrisoncole/pr-lint-action@v1.7.0 From 2db196f341ad559a35db5c17098e3fa3a91e5767 Mon Sep 17 00:00:00 2001 From: Harsh Patel Date: Fri, 29 Dec 2023 23:12:50 +0530 Subject: [PATCH 08/26] build: pnpm cache setup * this will make the pnpm install way faster. (hopefully) --- .github/workflows/api.yaml | 13 +++++++++++++ .github/workflows/cli.yaml | 13 +++++++++++++ .github/workflows/sdk-node.yaml | 13 +++++++++++++ .github/workflows/web.yaml | 13 +++++++++++++ 4 files changed, 52 insertions(+) diff --git a/.github/workflows/api.yaml b/.github/workflows/api.yaml index 9e48ac2a..45af1223 100644 --- a/.github/workflows/api.yaml +++ b/.github/workflows/api.yaml @@ -23,6 +23,19 @@ jobs: with: version: 8 run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- - name: Install packages run: | diff --git a/.github/workflows/cli.yaml b/.github/workflows/cli.yaml index 1569a056..a074572b 100644 --- a/.github/workflows/cli.yaml +++ b/.github/workflows/cli.yaml @@ -24,6 +24,19 @@ jobs: version: 8 run_install: false + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + - name: Install packages run: | pnpm i diff --git a/.github/workflows/sdk-node.yaml b/.github/workflows/sdk-node.yaml index 6790d773..090ed492 100644 --- a/.github/workflows/sdk-node.yaml +++ b/.github/workflows/sdk-node.yaml @@ -24,6 +24,19 @@ jobs: version: 8 run_install: false + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + - name: Install packages run: | pnpm i diff --git a/.github/workflows/web.yaml b/.github/workflows/web.yaml index ba9412f8..1f3ce74d 100644 --- a/.github/workflows/web.yaml +++ b/.github/workflows/web.yaml @@ -24,6 +24,19 @@ jobs: version: 8 run_install: false + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + - name: Install packages run: | pnpm i From 5427d8095dce5fbb2871e75c6b0e998f7613fb48 Mon Sep 17 00:00:00 2001 From: Rajdip Bhattacharya Date: Fri, 29 Dec 2023 23:13:05 +0530 Subject: [PATCH 09/26] fix api.yaml --- .github/workflows/api.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/api.yaml b/.github/workflows/api.yaml index 9e48ac2a..a81662aa 100644 --- a/.github/workflows/api.yaml +++ b/.github/workflows/api.yaml @@ -24,7 +24,7 @@ jobs: version: 8 run_install: false - - name: Install packages + - name: Install packages run: | pnpm i @@ -32,6 +32,6 @@ jobs: run: | pnpm run lint:api - - name: Test + - name: Test run: | pnpm run test:api From 8212d591df508605d011ce0ad7e4c14162351d16 Mon Sep 17 00:00:00 2001 From: Harsh Patel Date: Fri, 29 Dec 2023 23:20:36 +0530 Subject: [PATCH 10/26] fix: indendation errors * Fix indentation in workflow file --- .github/workflows/api.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/api.yaml b/.github/workflows/api.yaml index 45af1223..5f5946ac 100644 --- a/.github/workflows/api.yaml +++ b/.github/workflows/api.yaml @@ -37,7 +37,7 @@ jobs: restore-keys: | ${{ runner.os }}-pnpm-store- - - name: Install packages + - name: Install packages run: | pnpm i @@ -45,6 +45,6 @@ jobs: run: | pnpm run lint:api - - name: Test + - name: Test run: | pnpm run test:api From 3d309504be4789bfdb056b53e80a5d64cb7831ed Mon Sep 17 00:00:00 2001 From: Rajdip Bhattacharya Date: Fri, 29 Dec 2023 23:24:24 +0530 Subject: [PATCH 11/26] Update api.yaml --- .github/workflows/api.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/api.yaml b/.github/workflows/api.yaml index a81662aa..0b25d85b 100644 --- a/.github/workflows/api.yaml +++ b/.github/workflows/api.yaml @@ -34,4 +34,5 @@ jobs: - name: Test run: | + pnpm run build:api pnpm run test:api From 92ab39dd4add1ab56db44795bd1e6005158d1a3a Mon Sep 17 00:00:00 2001 From: Rajdip Bhattacharya Date: Fri, 29 Dec 2023 23:26:19 +0530 Subject: [PATCH 12/26] Update api.yaml --- .github/workflows/api.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/api.yaml b/.github/workflows/api.yaml index 0b25d85b..221c427d 100644 --- a/.github/workflows/api.yaml +++ b/.github/workflows/api.yaml @@ -34,5 +34,5 @@ jobs: - name: Test run: | - pnpm run build:api + pnpm run db:generate-types pnpm run test:api From 0da0953fa0aa2c7295e1ed6652684c1395434631 Mon Sep 17 00:00:00 2001 From: Harsh Patel Date: Fri, 29 Dec 2023 23:35:20 +0530 Subject: [PATCH 13/26] chore: remove / for consistancy --- .github/workflows/sdk-node.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk-node.yaml b/.github/workflows/sdk-node.yaml index 090ed492..27716230 100644 --- a/.github/workflows/sdk-node.yaml +++ b/.github/workflows/sdk-node.yaml @@ -1,6 +1,6 @@ on: push: - paths: ['/packages/sdk-node/**', '.github/workflows/sdk-node.yaml'] + paths: ['packages/sdk-node/**', '.github/workflows/sdk-node.yaml'] pull_request: paths: ['packages/sdk-node'] From a7a40abea9e0c5f0722f51eab403b99383d30eab Mon Sep 17 00:00:00 2001 From: Rajdip Bhattacharya Date: Fri, 29 Dec 2023 23:38:39 +0530 Subject: [PATCH 14/26] Update pr-lint.yaml --- .github/workflows/pr-lint.yaml | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/.github/workflows/pr-lint.yaml b/.github/workflows/pr-lint.yaml index e52cd555..4768b417 100644 --- a/.github/workflows/pr-lint.yaml +++ b/.github/workflows/pr-lint.yaml @@ -1,18 +1,23 @@ -name: PR Lint +name: "Lint PR" on: pull_request: - types: [opened, edited, reopened, synchronize] + types: + - opened + - edited + - synchronize + pull_request_target: + types: + - opened + - edited + - synchronize jobs: - pr-lint: - permissions: write-all + lint-pr: + name: Validate PR title runs-on: ubuntu-latest steps: - - uses: morrisoncole/pr-lint-action@v1.7.0 - with: - repo-token: '${{ secrets.GITHUB_TOKEN }}' - title-regex: '^(fix|feat|chore|docs|style|refactor|perf|test|ci|build|breaking-change|revert):\s(?:\D)[\w\d\s\-\.\,\_]+$' - on-failed-regex-fail-action: true - on-failed-regex-create-review: true - on-failed-regex-comment: 'PR title must match: `%regex%`!' + - name: Lint PR + uses: amannn/action-semantic-pull-request@v4.6.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 832383eabd24ddd47461fb42ebe705957c5483ca Mon Sep 17 00:00:00 2001 From: Lakshay saini Date: Fri, 29 Dec 2023 23:53:53 +0530 Subject: [PATCH 15/26] refactor: move mock data folder inside common module --- apps/api/src/{ => common}/mock-data/users.ts | 12 ++---------- apps/api/src/user/fake.repository.ts | 2 +- apps/api/src/user/user.controller.spec.ts | 2 +- apps/api/src/user/user.service.spec.ts | 2 +- 4 files changed, 5 insertions(+), 13 deletions(-) rename apps/api/src/{ => common}/mock-data/users.ts (81%) diff --git a/apps/api/src/mock-data/users.ts b/apps/api/src/common/mock-data/users.ts similarity index 81% rename from apps/api/src/mock-data/users.ts rename to apps/api/src/common/mock-data/users.ts index 133014e9..a779a3c6 100644 --- a/apps/api/src/mock-data/users.ts +++ b/apps/api/src/common/mock-data/users.ts @@ -1,15 +1,5 @@ import { User } from '@prisma/client' -export const user: User = { - id: '1', - name: 'John Doe', - email: 'johndoe@keyshade.xyz', - profilePictureUrl: 'https://keyshade.xyz/johndoe.jpg', - isActive: true, - isOnboardingFinished: false, - isAdmin: false -} - export const users: Array = [ { id: '1', @@ -48,3 +38,5 @@ export const users: Array = [ isAdmin: true } ] + +export const user: User = users[0] diff --git a/apps/api/src/user/fake.repository.ts b/apps/api/src/user/fake.repository.ts index 20d0360d..5593cb7b 100644 --- a/apps/api/src/user/fake.repository.ts +++ b/apps/api/src/user/fake.repository.ts @@ -1,6 +1,6 @@ import { User } from '@prisma/client' import { PrismaRepository } from '../prisma/prisma.repository' -import { users } from '../mock-data/users' +import { users } from '../common/mock-data/users' export const fakeRepository: Partial = { async excludeFields( diff --git a/apps/api/src/user/user.controller.spec.ts b/apps/api/src/user/user.controller.spec.ts index b4e4297f..f61b110b 100644 --- a/apps/api/src/user/user.controller.spec.ts +++ b/apps/api/src/user/user.controller.spec.ts @@ -3,7 +3,7 @@ import { UserController } from './user.controller' import { UserService } from './user.service' import { fakeRepository } from './fake.repository' import { User } from '@prisma/client' -import { users } from '../mock-data/users' +import { users } from '../common/mock-data/users' describe('UserController', () => { let controller: UserController diff --git a/apps/api/src/user/user.service.spec.ts b/apps/api/src/user/user.service.spec.ts index d408d367..9baf0ee6 100644 --- a/apps/api/src/user/user.service.spec.ts +++ b/apps/api/src/user/user.service.spec.ts @@ -2,7 +2,7 @@ import { Test, TestingModule } from '@nestjs/testing' import { UserService } from './user.service' import { fakeRepository } from './fake.repository' import { User } from '@prisma/client' -import { users } from '../mock-data/users' +import { users } from '../common/mock-data/users' describe('UserService', () => { let service: UserService From ea5c504360c4cd0ad28bb5cc01fff66fccacc423 Mon Sep 17 00:00:00 2001 From: Lakshay saini Date: Sat, 30 Dec 2023 00:03:10 +0530 Subject: [PATCH 16/26] refactor: user mock data change --- apps/api/src/common/mock-data/users.ts | 2 -- apps/api/src/user/user.controller.spec.ts | 10 +--------- apps/api/src/user/user.service.spec.ts | 10 +--------- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/apps/api/src/common/mock-data/users.ts b/apps/api/src/common/mock-data/users.ts index a779a3c6..011b7404 100644 --- a/apps/api/src/common/mock-data/users.ts +++ b/apps/api/src/common/mock-data/users.ts @@ -38,5 +38,3 @@ export const users: Array = [ isAdmin: true } ] - -export const user: User = users[0] diff --git a/apps/api/src/user/user.controller.spec.ts b/apps/api/src/user/user.controller.spec.ts index f61b110b..3f351634 100644 --- a/apps/api/src/user/user.controller.spec.ts +++ b/apps/api/src/user/user.controller.spec.ts @@ -9,15 +9,7 @@ describe('UserController', () => { let controller: UserController let service: UserService - const user: User = { - id: '1', - name: 'John Doe', - email: 'johndoe@keyshade.xyz', - profilePictureUrl: 'https://keyshade.xyz/johndoe.jpg', - isActive: true, - isOnboardingFinished: false, - isAdmin: false - } + const user: User = users[0] beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ diff --git a/apps/api/src/user/user.service.spec.ts b/apps/api/src/user/user.service.spec.ts index 9baf0ee6..7bb7e9fe 100644 --- a/apps/api/src/user/user.service.spec.ts +++ b/apps/api/src/user/user.service.spec.ts @@ -7,15 +7,7 @@ import { users } from '../common/mock-data/users' describe('UserService', () => { let service: UserService - const user: User = { - id: '1', - name: 'John Doe', - email: 'johndoe@keyshade.xyz', - profilePictureUrl: 'https://keyshade.xyz/johndoe.jpg', - isActive: true, - isOnboardingFinished: false, - isAdmin: false - } + const user: User = users[0] beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ From 2797f696b5ddbe0ebae1e4e25f4875196c824684 Mon Sep 17 00:00:00 2001 From: SRINJAYDASGUPTA-Git Date: Sat, 30 Dec 2023 00:22:45 +0530 Subject: [PATCH 17/26] Make landing page mobile responsive #41: Made Landing Page Mobile responsive --- apps/web/app/page.tsx | 18 +++++++++--------- apps/web/components/Links.tsx | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 6d7df09c..31f9dc43 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -13,28 +13,28 @@ function Index() {
-
+
-
-
-
+
+
+

keyshade.xyz

-
-

+

+

Manage all your secrets securely with public key encryption and realtime based tools, that seamlessly fits into your codebase

-
+
-
+
diff --git a/apps/web/components/Links.tsx b/apps/web/components/Links.tsx index 7d1318b4..0acdfd40 100644 --- a/apps/web/components/Links.tsx +++ b/apps/web/components/Links.tsx @@ -25,7 +25,7 @@ const Links = ({ icon, description, link }: LinksProps) => { className='unselectable' draggable='false' /> -

{description}

+

{description}

) From 2afaf0dda9d164f4c3a1ed05630a1aa45acf5cda Mon Sep 17 00:00:00 2001 From: SRINJAYDASGUPTA-Git Date: Sat, 30 Dec 2023 00:22:45 +0530 Subject: [PATCH 18/26] fix(landing-page): Make mobile responsive Fixes #41 --- apps/web/app/page.tsx | 18 +++++++++--------- apps/web/components/Links.tsx | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 6d7df09c..31f9dc43 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -13,28 +13,28 @@ function Index() {
-
+
-
-
-
+
+
+

keyshade.xyz

-
-

+

+

Manage all your secrets securely with public key encryption and realtime based tools, that seamlessly fits into your codebase

-
+
-
+
diff --git a/apps/web/components/Links.tsx b/apps/web/components/Links.tsx index 7d1318b4..0acdfd40 100644 --- a/apps/web/components/Links.tsx +++ b/apps/web/components/Links.tsx @@ -25,7 +25,7 @@ const Links = ({ icon, description, link }: LinksProps) => { className='unselectable' draggable='false' /> -

{description}

+

{description}

) From 3fd5a1d51671483089da6c6390720d80798f8373 Mon Sep 17 00:00:00 2001 From: SRINJAYDASGUPTA-Git Date: Sat, 30 Dec 2023 00:36:33 +0530 Subject: [PATCH 19/26] fix(landing-page): Make mobile responsive Fixes #41 --- apps/web/app/page.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 31f9dc43..cc44de69 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -26,7 +26,6 @@ function Index() { keyshade.xyz
-

Manage all your secrets securely with public key encryption and From d920a18065b578d8c617777514d81aaabb8f60b2 Mon Sep 17 00:00:00 2001 From: Udit Sharma Date: Sat, 30 Dec 2023 01:57:49 +0530 Subject: [PATCH 20/26] updated invalidate older OTPs --- apps/api/src/prisma/prisma.repository.ts | 36 ++++++++---------------- 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/apps/api/src/prisma/prisma.repository.ts b/apps/api/src/prisma/prisma.repository.ts index 8b320b83..088e10f0 100644 --- a/apps/api/src/prisma/prisma.repository.ts +++ b/apps/api/src/prisma/prisma.repository.ts @@ -172,34 +172,22 @@ export class PrismaRepository { private async invalidateOldOtps(email: string): Promise { const user = await this.prisma.user.findUnique({ where: { - email - } - }) + email, + }, + }); + if (user) { - const oldOtpCodesToDelete = await this.prisma.otp - .findMany({ - where: { - userId: user.id, - expiresAt: { - gte: new Date() - } + await this.prisma.otp.deleteMany({ + where: { + userId: user.id, + expiresAt: { + gte: new Date(), }, - select: { - code: true - } - }) - .then((oldOtps) => oldOtps.map((otp) => otp.code)) - if (oldOtpCodesToDelete.length > 0) { - await this.prisma.otp.deleteMany({ - where: { - code: { - in: oldOtpCodesToDelete - } - } - }) - } + }, + }); } } + async deleteOtp(email: string, otp: string): Promise { await this.prisma.otp.delete({ From e252d688357c8bcb0cb4c7d360edca6f2957a945 Mon Sep 17 00:00:00 2001 From: rajdip-b Date: Sat, 30 Dec 2023 10:20:27 +0530 Subject: [PATCH 21/26] docs: add docs folder --- docs/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/.gitkeep diff --git a/docs/.gitkeep b/docs/.gitkeep new file mode 100644 index 00000000..e69de29b From 9cc83c95eaeebaf4a08a1b52164afd004e7da670 Mon Sep 17 00:00:00 2001 From: rajdip Date: Sat, 30 Dec 2023 04:55:04 +0000 Subject: [PATCH 22/26] GitBook: No commit message --- docs/README.md | 2 ++ docs/SUMMARY.md | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 docs/README.md create mode 100644 docs/SUMMARY.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..5c4b4d58 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,2 @@ +# Page + diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md new file mode 100644 index 00000000..4439a14c --- /dev/null +++ b/docs/SUMMARY.md @@ -0,0 +1,3 @@ +# Table of contents + +* [Page](README.md) From 4b9221b0bf03ccd8cf9c03c744ac2d7501ae6e57 Mon Sep 17 00:00:00 2001 From: rajdip Date: Sat, 30 Dec 2023 05:45:55 +0000 Subject: [PATCH 23/26] GITBOOK-8: re-write --- docs/README.md | 29 +++++++++++- docs/SUMMARY.md | 13 +++++- .../design-of-our-code/README.md | 13 ++++++ .../design-of-our-code/api.md | 33 ++++++++++++++ .../environment-variables.md | 17 +++++++ .../contributing-to-keyshade/prerequisites.md | 7 +++ .../running-things-locally/README.md | 16 +++++++ .../running-things-locally/running-the-api.md | 43 ++++++++++++++++++ .../setting-things-up.md | 44 +++++++++++++++++++ docs/contributing-to-keyshade/summary.md | 9 ++++ 10 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 docs/contributing-to-keyshade/design-of-our-code/README.md create mode 100644 docs/contributing-to-keyshade/design-of-our-code/api.md create mode 100644 docs/contributing-to-keyshade/environment-variables.md create mode 100644 docs/contributing-to-keyshade/prerequisites.md create mode 100644 docs/contributing-to-keyshade/running-things-locally/README.md create mode 100644 docs/contributing-to-keyshade/running-things-locally/running-the-api.md create mode 100644 docs/contributing-to-keyshade/setting-things-up.md create mode 100644 docs/contributing-to-keyshade/summary.md diff --git a/docs/README.md b/docs/README.md index 5c4b4d58..cd43f7f7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,2 +1,29 @@ -# Page +--- +description: Get to know about what we are building +--- +# ❔ What is keyshade? + +## The problem + +With the rise in security concerns, software products are being made with security as their top concern. One of the most implemented strategy is to move all the secrets that the application is using to some cloud provider, where the secrets are fetched in runtime. By doing this, applications can separate their code from their configurations, ensuring both privacy and customizability. + +But, this comes with a cost of heavy human effort. Consider this scenario: Your application is using Google OAuth to sign in its users. Now, some day, you decided to use a new email account to log in users. At the very least, you have to make these changes: + +* **Update your keys** in the runtime environment +* **Restart your servers** to pick up the change in configuration + +Along with this, you are also required to store your **sensitive data** as plain text on servers, which you own indirectly! + +## The solution + +This is what led to the development of **keyshade**. keyshade is a secret-management tool that aims to make secret management a breeze, while keeping developer compatibility and integration as its top-most priority. + +With keyshade integrated into your codebase, you don't need to worry about leaking your secrets, or micromanaging them! Here are a few points as to why keyshade would an opt-in solution for you: + +* We use **Public Key Cryptography** at our very core. For every project that you make, you are allowed to specify a **private key** that stays in your custody forever (until you specify otherwise!). We then use a **public key** generated from your private key to encrypt and store your secrets. +* Your secrets are safe! We encrypt your data both **in transition** and **at rest**, making it mathematically impossible to sniff or tamper. +* Our SDKs are developed with **real-time** experience in mind. Feel like you need to change that API key of yours? We've got you covered! All you need to do is update it in keyshade, and leave the rest to the robots! +* **Collaborating** with others on a keyshade project is as secure as it gets! None of the collaborators will be able to see the value (not even the hashed up gibberish!) of any secret, but they will be easily able to add or update the values as and when they want to. Your private key stays safe with you! +* You are the person in command! We have put a lot of effort in developing a fine-tuned system, that allows you to micromanage the roles that you give to other users or even your own API keys. +* Lastly, we allow you to rotate your secrets periodically. This is an opt-in feature, should you want that JWT secret of yours to be regenerated so that bad folks don't breach your systems! diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 4439a14c..822de279 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -1,3 +1,14 @@ # Table of contents -* [Page](README.md) +* [❔ What is keyshade?](README.md) + +## 🥰 CONTRIBUTING TO KEYSHADE + +* [Summary](contributing-to-keyshade/summary.md) +* [Prerequisites](contributing-to-keyshade/prerequisites.md) +* [Environment Variables](contributing-to-keyshade/environment-variables.md) +* [Setting things up](contributing-to-keyshade/setting-things-up.md) +* [Running things locally](contributing-to-keyshade/running-things-locally/README.md) + * [Running the API](contributing-to-keyshade/running-things-locally/running-the-api.md) +* [Design of our code](contributing-to-keyshade/design-of-our-code/README.md) + * [API](contributing-to-keyshade/design-of-our-code/api.md) diff --git a/docs/contributing-to-keyshade/design-of-our-code/README.md b/docs/contributing-to-keyshade/design-of-our-code/README.md new file mode 100644 index 00000000..de2d11f5 --- /dev/null +++ b/docs/contributing-to-keyshade/design-of-our-code/README.md @@ -0,0 +1,13 @@ +--- +description: Get to know about the core building blocks of our code +--- + +# Design of our code + +## Brief + +When it comes to developing for us, we follow very strict norms! From proper indentation to using design patterns, we do an extensive coverage. But this is really difficult for anyone to grab randomly. So we decided to compile how each of our modules undergo development and the structure they follow. + +## Compilation of designs + +* [API](api.md) diff --git a/docs/contributing-to-keyshade/design-of-our-code/api.md b/docs/contributing-to-keyshade/design-of-our-code/api.md new file mode 100644 index 00000000..be0b8e35 --- /dev/null +++ b/docs/contributing-to-keyshade/design-of-our-code/api.md @@ -0,0 +1,33 @@ +--- +description: Design of our API +--- + +# API + +This document covers how we have developed our API, the stacks, and things you should know before you get started with it! + +## Stack + +Our API is developed using the following stack: + +* **NestJS** as the base +* **Prisma** as the DDL and DML +* **Supabase** as the database and bucket storage +* **Resend** as the mail agent + +## Structure + +As per the NestJS convention, our API base is totally modularized, with each module catering to a particular part of our project. The general module structure is as follows: + +* **controller**: Stores the APIs that the clients will be interacting with. +* **service**: Holds the business logic +* **repository**: Holds the logic related to manipulating the database +* **misc**: Holds utility functions and classes localized to the particular module +* **dto**: Contains class objects for data intake from the clients + +### The `prisma` module + +This module deserves special attention since it deals with the data layer. Apart from the usual files, we have two other: + +* `schema.prisma`: This contains the data definition +* `migrations`: This folder stores the migrations generated by running the `pnpm run db:generate-migrations` command. These migrations are the state that the current prisma database is in. diff --git a/docs/contributing-to-keyshade/environment-variables.md b/docs/contributing-to-keyshade/environment-variables.md new file mode 100644 index 00000000..d58a52cc --- /dev/null +++ b/docs/contributing-to-keyshade/environment-variables.md @@ -0,0 +1,17 @@ +--- +description: Get to know the environment you are working with +--- + +# Environment Variables + +## .env.example + +Here's the description of the environment variables used in the project. You can find the values for these variables in \`.env.example\`. + +* **DATABASE\_URL**: The URL of the PSQL database to connect to. This is used by the [Prisma Client](https://www.prisma.io/docs/orm/prisma-client) to connect to the database. +* **SUPABASE\_API\_URL**: The URL of the Supabase API. This is used by the [Supabase Client](https://supabase.io/docs/reference/javascript/supabase-client) to connect to the Supabase API. Make sure you create a Supabase project and get the API URL from the project settings. +* **SUPABASE\_ANON\_KEY**: The anonymous key of the Supabase project. This is used by the Supabase Client to connect to the Supabase API. Make sure you create a Supabase project and get the anonymous key from the project settings. +* **RESEND\_API\_KEY**: The API key for the [Resend API](https://resend-api.vercel.app/). The project uses Resend API to send out emails. +* **JWT\_SECRET**: The secret used to sign the JWT tokens. It is insignificant in the development environment. +* **FROM\_EMAIL**: The email address from which the emails will be sent. This is used by the Resend API to send out emails. +* **WEB\_FRONTEND\_URL, WORKSPACE\_FRONTEND\_URL**: The URLs of the web and workspace frontend respectively. These are used in the emails sometimes and in other spaces of the application too. diff --git a/docs/contributing-to-keyshade/prerequisites.md b/docs/contributing-to-keyshade/prerequisites.md new file mode 100644 index 00000000..664e6155 --- /dev/null +++ b/docs/contributing-to-keyshade/prerequisites.md @@ -0,0 +1,7 @@ +# Prerequisites + +Of course, to get started, you will need to have the required components in place. Gladly, there isn't much that needs to be done: + +* Make sure you have Git installed and have an account in GitHub +* Have an account in Supabase along with a project +* Have an account in Resend diff --git a/docs/contributing-to-keyshade/running-things-locally/README.md b/docs/contributing-to-keyshade/running-things-locally/README.md new file mode 100644 index 00000000..0874b44f --- /dev/null +++ b/docs/contributing-to-keyshade/running-things-locally/README.md @@ -0,0 +1,16 @@ +--- +description: Compiles a list of article to help running the services locally +--- + +# Running things locally + +This document (and the sub-series) guides you on how you can run and test each of the applications on your local device. There are two categories of projects: + +* The main ones under the apps directory +* The examples of the SDKs + +## Run locally + +You can pick up any of these topics from the following and start with it. + +* [Running the API](running-the-api.md) diff --git a/docs/contributing-to-keyshade/running-things-locally/running-the-api.md b/docs/contributing-to-keyshade/running-things-locally/running-the-api.md new file mode 100644 index 00000000..612fe77e --- /dev/null +++ b/docs/contributing-to-keyshade/running-things-locally/running-the-api.md @@ -0,0 +1,43 @@ +--- +description: Get to know how you can develop the API! +--- + +# Running the API + +The API resides in the `apps/api` directory. It is a NestJS project. To run the API locally, do the following: + +* Generate the prisma types: + +```bash +pnpm run db:generate-types +``` + +* Deploy the migrations: + +```bash +pnpm run db:deploy-migrations +``` + +* Start the server in development mode: + +```bash +pnpm run dev:api +``` + +* Once you have made the changes and added tests (if any), make sure to test the code: + +```bash +pnpm run test:api +``` + +* Lint the code: + +```bash +pnpm run lint:api +``` + +* Run prettier: + +```bash +pnpm run prettier:fix:api +``` diff --git a/docs/contributing-to-keyshade/setting-things-up.md b/docs/contributing-to-keyshade/setting-things-up.md new file mode 100644 index 00000000..afe23c4b --- /dev/null +++ b/docs/contributing-to-keyshade/setting-things-up.md @@ -0,0 +1,44 @@ +# Setting things up + +## Setting up the .env file + +Make a copy of the `.env.example` file and rename it to `.env` + +```bash +cp .env.example .env +``` + +Fill in the values for the environment variables in the `.env` file. You can find the values for the variables in the [Environment Variables](environment-variables.md) section. + +## Setting up `pnpm` + +keyshade works with any version of **node (>=18)** and takes the liberty that you have it installed. The project uses `pnpm` as the package manager. To install `pnpm`, run the following command: + +```bash +npm install -g pnpm +``` + +{% hint style="info" %} +For Linux users, in case the above command fails with permission error, try running this: + +```bash +sudo npm install -g pnpm +``` +{% endhint %} + +## Installing the dependencies + +To install the dependencies, run the following command: + +```bash +pnpm install +``` + +## Installing NX + +The last step is to install NX. It is the monorepo management tool that we are using. Read more about it in [https://nx.dev](https://nx.dev). To install nx, you need to run the following command: + +```bash +pnpm i -g nx +``` + diff --git a/docs/contributing-to-keyshade/summary.md b/docs/contributing-to-keyshade/summary.md new file mode 100644 index 00000000..5c7eebe1 --- /dev/null +++ b/docs/contributing-to-keyshade/summary.md @@ -0,0 +1,9 @@ +--- +description: Be a part of the keyshade today! +--- + +# Summary + +We are an [open-source](https://github.com/keyshade-xyz/keyshade) organization. We solely rely upon the contributions made from the peer of developers out there, and we are really thankful towards them. Even the smallest of contributions (changing the name of a variable, fixing typos) are very much appreciated. + +This series of documents aim at setting up and developing keyshade in your device locally. Start anywhere you feel like! From 82ff8fe88c2ecf2dd9a46d71a7d0011e7b539bac Mon Sep 17 00:00:00 2001 From: rajdip Date: Sat, 30 Dec 2023 05:46:40 +0000 Subject: [PATCH 24/26] GITBOOK-8: re-write From 929b67660359d081fd008161cd85a22ccc01d96c Mon Sep 17 00:00:00 2001 From: Sawan Bhattacharya <74916308+kriptonian1@users.noreply.github.com> Date: Sun, 31 Dec 2023 18:30:23 +0530 Subject: [PATCH 25/26] Create SECURITY.md --- SECURITY.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..2a8a39fc --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported versions + +We always recommend using the latest version of Keyshade to ensure you get all security updates. + +## Reporting vulnerabilities + +Please do not file GitHub issues or post on our public forum for security vulnerabilities, as they are public! + +Keyshade takes security issues very seriously. If you have any concerns about Keyshade or believe you have uncovered a vulnerability, please get in touch via the e-mail address support@keyshade.xyz. In the message, try to provide a description of the issue and ideally a way of reproducing it. The security team will get back to you as soon as possible. + +Note that this security address should be used only for undisclosed vulnerabilities. Please report any security problems to us before disclosing it publicly. From 8f9a300f0393b944c84f54903faf24ef3f6735f8 Mon Sep 17 00:00:00 2001 From: Sawan Bhattacharya <74916308+kriptonian1@users.noreply.github.com> Date: Sun, 31 Dec 2023 18:33:54 +0530 Subject: [PATCH 26/26] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 128 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..87aec0b7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +support@keyshade.xyz. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations.