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
5 changes: 5 additions & 0 deletions .changeset/stupid-trains-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@quassel/backend": patch
---

Add authentication and authorization
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,16 @@
"name": "user",
"schema": "public",
"indexes": [
{
"columnNames": [
"email"
],
"composite": false,
"keyName": "user_email_unique",
"constraint": true,
"primary": false,
"unique": true
},
{
"keyName": "user_pkey",
"columnNames": [
Expand Down
11 changes: 11 additions & 0 deletions apps/backend/db/migrations/Migration20241025082939.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Migration } from "@mikro-orm/migrations";

export class Migration20241025082939 extends Migration {
override async up(): Promise<void> {
this.addSql(`alter table "user" add constraint "user_email_unique" unique ("email");`);
}

override async down(): Promise<void> {
this.addSql(`alter table "user" drop constraint "user_email_unique";`);
}
}
16 changes: 16 additions & 0 deletions apps/backend/db/seeds/DatabaseSeeder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { EntityManager } from "@mikro-orm/core";
import { Seeder } from "@mikro-orm/seeder";
import { User, UserRole } from "../../src/users/entities/user.entity";
import { bcrypt } from "hash-wasm";

export class DatabaseSeeder extends Seeder {
async run(em: EntityManager): Promise<void> {
const salt = new Uint8Array(16);
crypto.getRandomValues(salt);
em.create(User, {
role: UserRole.ADMIN,
email: "administrator@example.ch",
password: await bcrypt({ password: "quassel*1234", salt, costFactor: 10 }),
});
}
}
24 changes: 16 additions & 8 deletions apps/backend/mikro-orm.config.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
import { defineConfig, PostgreSqlDriver } from "@mikro-orm/postgresql";
import { Migrator } from "@mikro-orm/migrations";
import { TsMorphMetadataProvider } from "@mikro-orm/reflection";
import { SeedManager } from "@mikro-orm/seeder";
import { configuration } from "./src/config/configuration";

const c = configuration();

export default defineConfig({
entities: ["./dist/src/entities"],
entitiesTs: ["./src/entities"],
host: "db",
dbName: "postgres",
password: "postgres",
user: "postgres",
entities: ["./dist/src/**/*.entity.js"],
entitiesTs: ["./src/**/*.entity.ts"],
host: c.database.host,
port: c.database.port,
dbName: c.database.name,
user: c.database.user,
password: c.database.password,
driver: PostgreSqlDriver,
metadataProvider: TsMorphMetadataProvider,
extensions: [Migrator],
extensions: [Migrator, SeedManager],
migrations: {
pathTs: "./migrations",
pathTs: "./db/migrations",
},
seeder: {
pathTs: "./db/seeds",
},
});
13 changes: 11 additions & 2 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"start": "nest start",
"dev": "nest start --watch --preserveWatchOutput",
"db": "mikro-orm",
"nest": "nest",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
Expand All @@ -23,24 +24,32 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@fastify/secure-session": "^7.5.1",
"@fastify/static": "^7.0.4",
"@mikro-orm/core": "^6.3.11",
"@mikro-orm/nestjs": "^6.0.2",
"@mikro-orm/postgresql": "^6.3.11",
"@mikro-orm/reflection": "^6.3.11",
"@nestjs/common": "^10.4.4",
"@nestjs/config": "^3.3.0",
"@nestjs/core": "^10.4.4",
"@nestjs/platform-express": "^10.4.4",
"@nestjs/jwt": "^10.2.0",
"@nestjs/platform-fastify": "^10.4.6",
"@nestjs/swagger": "^7.4.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"fastify": "^4.28.0",
"hash-wasm": "^4.11.0",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@mikro-orm/cli": "^6.3.11",
"@mikro-orm/migrations": "^6.3.11",
"@mikro-orm/seeder": "^6.3.13",
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.2.2",
"@nestjs/testing": "^10.4.4",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
"@types/node": "^20.17.0",
"@types/supertest": "^6.0.0",
Expand Down
22 changes: 0 additions & 22 deletions apps/backend/src/app.controller.spec.ts

This file was deleted.

12 changes: 0 additions & 12 deletions apps/backend/src/app.controller.ts

This file was deleted.

9 changes: 3 additions & 6 deletions apps/backend/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { Module } from "@nestjs/common";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { MikroOrmModule } from "@mikro-orm/nestjs";
import { UserModule } from "./user/user.module";
import { ConfigModule } from "./config/config.module";
import { UsersModule } from "./users/users.module";

Check warning on line 4 in apps/backend/src/app.module.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/app.module.ts#L3-L4

Added lines #L3 - L4 were not covered by tests

@Module({
imports: [MikroOrmModule.forRoot(), UserModule],
controllers: [AppController],
providers: [AppService],
imports: [MikroOrmModule.forRoot(), ConfigModule, UsersModule],
})
export class AppModule {}
8 changes: 0 additions & 8 deletions apps/backend/src/app.service.ts

This file was deleted.

11 changes: 11 additions & 0 deletions apps/backend/src/config/config.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from "@nestjs/common";
import { configuration } from "./configuration";
import { ConfigModule as NestConfigModule } from "@nestjs/config";
import { ConfigService } from "./config.service";

Check warning on line 4 in apps/backend/src/config/config.module.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/config/config.module.ts#L1-L4

Added lines #L1 - L4 were not covered by tests

@Module({
imports: [NestConfigModule.forRoot({ load: [configuration] })],
providers: [ConfigService],
exports: [ConfigService],
})
export class ConfigModule {}

Check warning on line 11 in apps/backend/src/config/config.module.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/config/config.module.ts#L11

Added line #L11 was not covered by tests
12 changes: 12 additions & 0 deletions apps/backend/src/config/config.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Injectable } from "@nestjs/common";
import { ConfigService as NestConfigService } from "@nestjs/config";

Check warning on line 2 in apps/backend/src/config/config.service.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/config/config.service.ts#L1-L2

Added lines #L1 - L2 were not covered by tests
import { Configuration } from "./configuration";

@Injectable()
export class ConfigService {
constructor(private configService: NestConfigService) {}

Check warning on line 7 in apps/backend/src/config/config.service.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/config/config.service.ts#L6-L7

Added lines #L6 - L7 were not covered by tests

get<T extends Leaves<Configuration>>(propertyPath: T): LeaveTypes<Configuration, T> {
return this.configService.get(propertyPath);

Check warning on line 10 in apps/backend/src/config/config.service.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/config/config.service.ts#L9-L10

Added lines #L9 - L10 were not covered by tests
}
}
16 changes: 16 additions & 0 deletions apps/backend/src/config/configuration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const configuration = () => ({
port: parseInt(process.env.PORT) || 3000,

Check warning on line 2 in apps/backend/src/config/configuration.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/config/configuration.ts#L1-L2

Added lines #L1 - L2 were not covered by tests
session: {
secret: process.env.SESSION_SECRET || "2722badd029fa3bbe29f7ebeee0dcaeb82a91c1088d348354c6e7172996368fd",
salt: process.env.SESSION_SALT || "332535f60da28f8f",
},
database: {
host: process.env.DATABASE_HOST || "db",
port: parseInt(process.env.DATABASE_PORT) || 5432,
name: process.env.DATABASE_NAME || "postgres",
user: process.env.DATABASE_USER || "postgres",
password: process.env.DATABASE_PASSWORD || "postgres",
},
});

export type Configuration = ReturnType<typeof configuration>;
2 changes: 1 addition & 1 deletion apps/backend/src/entities/carer.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Collection, Entity, ManyToOne, OneToMany, Property } from "@mikro-orm/core";
import { BaseEntity } from "./base.entity";
import { BaseEntity } from "../common/entities/base.entity";
import { Participant } from "./participant.entity";
import { Entry } from "./entry.entity";

Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/entities/entry.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Check, Collection, Entity, ManyToOne, OneToMany, Opt, Property } from "@mikro-orm/core";
import { BaseEntity } from "./base.entity";
import { BaseEntity } from "../common/entities/base.entity";

Check warning on line 2 in apps/backend/src/entities/entry.entity.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/entities/entry.entity.ts#L2

Added line #L2 was not covered by tests
import { EntryLanguage } from "./entryLanguage.entity";
import { Carer } from "./carer.entity";
import { Questionnaire } from "./questionnaire.entity";
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/entities/entryLanguage.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Check, Entity, ManyToOne, Property } from "@mikro-orm/core";
import { BaseEntity } from "./base.entity";
import { BaseEntity } from "../common/entities/base.entity";

Check warning on line 2 in apps/backend/src/entities/entryLanguage.entity.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/entities/entryLanguage.entity.ts#L2

Added line #L2 was not covered by tests
import { Entry } from "./entry.entity";
import { Language } from "./language.entity";

Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/entities/language.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Collection, Entity, ManyToOne, OneToMany, Property } from "@mikro-orm/core";
import { BaseEntity } from "./base.entity";
import { BaseEntity } from "../common/entities/base.entity";

Check warning on line 2 in apps/backend/src/entities/language.entity.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/entities/language.entity.ts#L2

Added line #L2 was not covered by tests
import { Participant } from "./participant.entity";
import { EntryLanguage } from "./entryLanguage.entity";

Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/entities/participant.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Collection, Entity, OneToMany, Property } from "@mikro-orm/core";
import { BaseEntity } from "./base.entity";
import { BaseEntity } from "../common/entities/base.entity";

Check warning on line 2 in apps/backend/src/entities/participant.entity.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/entities/participant.entity.ts#L2

Added line #L2 was not covered by tests
import { Questionnaire } from "./questionnaire.entity";
import { Carer } from "./carer.entity";
import { Language } from "./language.entity";
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/entities/questionnaire.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Collection, Entity, ManyToOne, OneToMany, Property } from "@mikro-orm/core";
import { BaseEntity } from "./base.entity";
import { BaseEntity } from "../common/entities/base.entity";

Check warning on line 2 in apps/backend/src/entities/questionnaire.entity.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/entities/questionnaire.entity.ts#L2

Added line #L2 was not covered by tests
import { Study } from "./study.entity";
import { Participant } from "./participant.entity";
import { Entry } from "./entry.entity";
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/entities/study.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Collection, Entity, OneToMany, Property } from "@mikro-orm/core";
import { BaseEntity } from "./base.entity";
import { BaseEntity } from "../common/entities/base.entity";

Check warning on line 2 in apps/backend/src/entities/study.entity.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/entities/study.entity.ts#L2

Added line #L2 was not covered by tests
import { Questionnaire } from "./questionnaire.entity";

@Entity()
Expand Down
22 changes: 18 additions & 4 deletions apps/backend/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
import { NestFactory } from "@nestjs/core";
import { NestFactory, Reflector } from "@nestjs/core";

Check warning on line 1 in apps/backend/src/main.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/main.ts#L1

Added line #L1 was not covered by tests
import { AppModule } from "./app.module";
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
import { version } from "../package.json";
import { ClassSerializerInterceptor, ValidationPipe } from "@nestjs/common";
import { FastifyAdapter, NestFastifyApplication } from "@nestjs/platform-fastify";
import { fastifySecureSession } from "@fastify/secure-session";
import { ConfigService } from "./config/config.service";

Check warning on line 8 in apps/backend/src/main.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/main.ts#L4-L8

Added lines #L4 - L8 were not covered by tests

async function bootstrap() {
const app = await NestFactory.create(AppModule, { cors: true });
const app = await NestFactory.create<NestFastifyApplication>(AppModule, new FastifyAdapter());
const configService = app.get(ConfigService);
app.enableCors();
app.useGlobalPipes(new ValidationPipe());
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));

Check warning on line 15 in apps/backend/src/main.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/main.ts#L11-L15

Added lines #L11 - L15 were not covered by tests

const config = new DocumentBuilder().build();
await app.register(fastifySecureSession, {

Check warning on line 17 in apps/backend/src/main.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/main.ts#L17

Added line #L17 was not covered by tests
secret: configService.get("session.secret"),
salt: configService.get("session.salt"),
});

const config = new DocumentBuilder().setTitle("Quassel API").setVersion(version).setDescription("Gather language exposure data").build();

Check warning on line 22 in apps/backend/src/main.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/main.ts#L22

Added line #L22 was not covered by tests
const document = SwaggerModule.createDocument(app, config);

SwaggerModule.setup("api", app, document);

await app.listen(3000);
await app.listen({ port: configService.get("port") });

Check warning on line 27 in apps/backend/src/main.ts

View check run for this annotation

Codecov / codecov/patch

apps/backend/src/main.ts#L27

Added line #L27 was not covered by tests
}
bootstrap();
28 changes: 28 additions & 0 deletions apps/backend/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { SessionData as FastifySessionData } from "@fastify/secure-session";
import { User } from "./users/entities/user.entity";

declare module "@fastify/secure-session" {
interface SessionData extends FastifySessionData {
userId?: number;
}
}

declare module "fastify" {
interface FastifyRequest {
user?: User;
}
}

declare global {
type Leaves<T> = T extends object
? { [K in keyof T]: `${Exclude<K, symbol>}${Leaves<T[K]> extends never ? "" : `.${Leaves<T[K]>}`}` }[keyof T]
: never;

type LeaveTypes<T, S extends string> = S extends `${infer T1}.${infer T2}`
? T1 extends keyof T
? LeaveTypes<T[T1], T2>
: never
: S extends keyof T
? T[S]
: never;
}
36 changes: 0 additions & 36 deletions apps/backend/src/user/user.controller.ts

This file was deleted.

10 changes: 0 additions & 10 deletions apps/backend/src/user/user.module.ts

This file was deleted.

4 changes: 4 additions & 0 deletions apps/backend/src/users/decorators/public.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { SetMetadata } from "@nestjs/common";

export const IS_PUBLIC_KEY = "isPublic";
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
Loading