Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"arrowParens": "avoid",
"singleQuote": true,
"trailingComma": "all"
"semi": false,
"tabWidth": 2,
"useTabs": false,
"trailingComma": "all",
"endOfLine": "auto"
}
24 changes: 19 additions & 5 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// @ts-check
import eslint from '@eslint/js';
import * as eslintPluginImport from 'eslint-plugin-import';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
import globals from 'globals';
import tseslint from 'typescript-eslint';

export default tseslint.config(
{
ignores: ['eslint.config.mjs'],
ignores: ['eslint.config.mjs', '.prettierrc'],
},
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
Expand All @@ -26,10 +26,24 @@ export default tseslint.config(
},
},
{
plugins: {
import: eslintPluginImport,
},
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-unsafe-argument': 'warn'
'prettier/prettier': 'error',
'import/order': [
'error',
{
groups: [
'builtin',
'external',
['internal', 'parent', 'sibling'],
'index',
'object',
'type'
]
}
]
},
},
);
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "qv-be",
"version": "0.0.1",
"description": "",
"author": "",
"name": "worldview-be",
"version": "0.1.0",
"description": "Worldview backend",
"author": "General Magic Contributors",
"private": true,
"license": "UNLICENSED",
"scripts": {
Expand Down Expand Up @@ -58,6 +58,7 @@
"@types/supertest": "^6.0.2",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-prettier": "^5.2.2",
"globals": "^15.14.0",
"jest": "^29.7.0",
Expand Down Expand Up @@ -90,4 +91,4 @@
"testEnvironment": "node"
},
"packageManager": "yarn@1.22.19+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447"
}
}
22 changes: 11 additions & 11 deletions src/app.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { Test, TestingModule } from '@nestjs/testing'
import { AppController } from './app.controller'
import { AppService } from './app.service'

describe('AppController', () => {
let appController: AppController;
let appController: AppController

beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
controllers: [AppController],
providers: [AppService],
}).compile();
}).compile()

appController = app.get<AppController>(AppController);
});
appController = app.get<AppController>(AppController)
})

describe('root', () => {
it('should return "Hello World!"', () => {
expect(appController.getHello()).toBe('Hello World!');
});
});
});
expect(appController.getHello()).toBe('Hello World!')
})
})
})
8 changes: 4 additions & 4 deletions src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { Public } from './auth/jwt-auth.guard';
import { Controller, Get } from '@nestjs/common'
import { AppService } from './app.service'
import { Public } from './auth/jwt-auth.guard'

@Controller()
export class AppController {
Expand All @@ -9,6 +9,6 @@ export class AppController {
@Public()
@Get()
getHello(): string {
return this.appService.getHello();
return this.appService.getHello()
}
}
20 changes: 10 additions & 10 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DatabaseService } from './database/database.service';
import { DatabaseModule } from './database/database.module';
import { PollModule } from './poll/poll.module';
import { VoteModule } from './vote/vote.module';
import { AuthModule } from './auth/auth.module';
import { AuthService } from './auth/auth.service';
import { UserModule } from './user/user.module';
import { Module } from '@nestjs/common'
import { AppController } from './app.controller'
import { AppService } from './app.service'
import { DatabaseService } from './database/database.service'
import { DatabaseModule } from './database/database.module'
import { PollModule } from './poll/poll.module'
import { VoteModule } from './vote/vote.module'
import { AuthModule } from './auth/auth.module'
import { AuthService } from './auth/auth.service'
import { UserModule } from './user/user.module'

@Module({
imports: [DatabaseModule, PollModule, VoteModule, UserModule, AuthModule],
Expand Down
4 changes: 2 additions & 2 deletions src/app.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Injectable } from '@nestjs/common';
import { Injectable } from '@nestjs/common'

@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
return 'Hello World!'
}
}
52 changes: 26 additions & 26 deletions src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,46 @@
import { Body, Controller, Get, Post, Req, Res } from '@nestjs/common';
import { Request, Response } from 'express';
import { AuthService } from './auth.service';
import { JwtService } from './jwt.service';
import { Public } from './jwt-auth.guard';
import { VerifyWorldIdDto } from './auth.dto';
import { Body, Controller, Get, Post, Req, Res } from '@nestjs/common'
import { Request, Response } from 'express'
import {
InsufficientVerificationLevelException,
SignatureVerificationFailureException,
} from 'src/common/exceptions';
import { BadRequestException } from '@nestjs/common';
import { VerificationLevel } from '@worldcoin/minikit-js';
} from 'src/common/exceptions'
import { BadRequestException } from '@nestjs/common'
import { VerificationLevel } from '@worldcoin/minikit-js'
import { AuthService } from './auth.service'
import { JwtService } from './jwt.service'
import { Public } from './jwt-auth.guard'
import { VerifyWorldIdDto } from './auth.dto'
function isHttps(req: Request) {
return (
req.protocol === 'https' || req.headers['x-forwarded-proto'] === 'https'
);
)
}

@Controller('auth')
export class AuthController {
private readonly systemVerificationLevel: VerificationLevel;
private readonly systemVerificationLevel: VerificationLevel

constructor(
private readonly authService: AuthService,
private readonly jwtService: JwtService,
) {
this.systemVerificationLevel =
(process.env.VERIFICATION_LEVEL?.toLowerCase() as VerificationLevel) ||
VerificationLevel.Device;
VerificationLevel.Device
}

@Public()
@Get('nonce')
generateNonce(@Req() req: Request, @Res() res: Response) {
const nonce = this.authService.generateNonce();
const nonce = this.authService.generateNonce()
res.cookie('siwe', nonce, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production' || isHttps(req),
sameSite: 'none',
maxAge: 2 * 60 * 1000, //2 minutes
});
})

return res.json({ nonce });
return res.json({ nonce })
}

@Public()
Expand All @@ -56,42 +56,42 @@ export class AuthController {
userDetails,
nonce,
verificationLevel,
} = body;
} = body

const isValid = await this.authService.verifyPayload(walletPayload, nonce);
const isValid = await this.authService.verifyPayload(walletPayload, nonce)

if (!isValid) {
throw new SignatureVerificationFailureException();
throw new SignatureVerificationFailureException()
}

if (verificationLevel !== this.systemVerificationLevel) {
throw new InsufficientVerificationLevelException();
throw new InsufficientVerificationLevelException()
}

const worldID = worldIdProof?.nullifier_hash;
const walletAddress = walletPayload?.address;
const worldID = worldIdProof?.nullifier_hash
const walletAddress = walletPayload?.address

const user = await this.authService.createUser(
worldID,
userDetails.username,
userDetails.profilePictureUrl,
);
)

if (!user) {
throw new BadRequestException('Failed to create user');
throw new BadRequestException('Failed to create user')
}

const token = this.jwtService.sign({
userId: user.id,
worldID,
verificationLevel,
address: walletAddress,
});
})

if (!token) {
throw new BadRequestException('Failed to generate token');
throw new BadRequestException('Failed to generate token')
}

return res.status(200).json({ isValid: true, token });
return res.status(200).json({ isValid: true, token })
}
}
24 changes: 12 additions & 12 deletions src/auth/auth.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,53 @@ import {
IsString,
IsEnum,
ValidateNested,
} from 'class-validator';
} from 'class-validator'
import {
MiniAppWalletAuthSuccessPayload,
ISuccessResult,
VerificationLevel,
} from '@worldcoin/minikit-js';
import { Transform, Type } from 'class-transformer';
} from '@worldcoin/minikit-js'
import { Transform, Type } from 'class-transformer'

export class UserDetailsDto {
@IsString()
username: string;
username: string

@IsOptional()
@IsString()
profilePictureUrl: string;
profilePictureUrl: string
}
export class VerifyWorldIdDto {
@IsNotEmpty()
@ValidateNested()
@Type(() => Object)
walletPayload: MiniAppWalletAuthSuccessPayload;
walletPayload: MiniAppWalletAuthSuccessPayload

@IsNotEmpty()
@ValidateNested()
@Type(() => Object)
worldIdProof: ISuccessResult;
worldIdProof: ISuccessResult

@IsNotEmpty()
@ValidateNested()
@Type(() => Object)
userDetails: UserDetailsDto;
userDetails: UserDetailsDto

@IsNotEmpty()
@IsString()
nonce: string;
nonce: string

@IsOptional()
@Transform(({ value }) => {
if (typeof value === 'string') {
value = value.toLowerCase();
value = value.toLowerCase()
}
return Object.values(VerificationLevel).includes(value as VerificationLevel)
? (value as VerificationLevel)
: VerificationLevel.Device;
: VerificationLevel.Device
})
@IsEnum(VerificationLevel, {
message: `Verification level must be one of: ${Object.values(VerificationLevel).join(', ')}`,
})
verificationLevel: VerificationLevel = VerificationLevel.Device;
verificationLevel: VerificationLevel = VerificationLevel.Device
}
8 changes: 4 additions & 4 deletions src/auth/auth.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { JwtService } from './jwt.service';
import { AuthService } from './auth.service';
import { Module } from '@nestjs/common'
import { AuthController } from './auth.controller'
import { JwtService } from './jwt.service'
import { AuthService } from './auth.service'

@Module({
controllers: [AuthController],
Expand Down
Loading