Skip to content

Commit

Permalink
BC-7851 - Add tldraw-document delete api (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
bischofmax authored Sep 23, 2024
1 parent 7113ed1 commit 920d9e2
Show file tree
Hide file tree
Showing 27 changed files with 630 additions and 12 deletions.
13 changes: 13 additions & 0 deletions .env.default
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
REDIS=redis://172.18.0.5:6379
REDIS_PREFIX=y
API_HOST=http://localhost:3030
ADMIN_API__ALLOWED_API_KEYS=randomString

S3_ENDPOINT=localhost
S3_BUCKET=ydocs
S3_PORT=9000
S3_SSL=false
S3_ACCESS_KEY=miniouser
S3_SECRET_KEY=miniouser

WS_PORT="3345"
84 changes: 81 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand"
},
"dependencies": {
"@golevelup/ts-jest": "^0.5.4",
"@nestjs/common": "^10.4.1",
"@nestjs/config": "^3.2.3",
"@nestjs/core": "^10.4.1",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.4.1",
"@y/redis": "github:hpi-schul-cloud/y-redis#a5e141466a759a1d4b2876d5d5af52bc9ec4930d",
"@y/redis": "github:hpi-schul-cloud/y-redis#7d48e08d18ec78c9ab90063a7d867ec7f191319c",
"ioredis": "^5.4.1",
"passport": "^0.7.0",
"passport-headerapikey": "^1.2.2",
"prom-client": "^15.1.3",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
Expand All @@ -48,6 +52,8 @@
"@types/express": "^4.17.21",
"@types/jest": "^29.5.12",
"@types/node": "^20.3.1",
"@types/passport": "^1.0.16",
"@types/passport-strategy": "^0.2.38",
"@types/supertest": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^7.0.0",
Expand Down
3 changes: 2 additions & 1 deletion src/apps/tldraw-server.app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { MetricsModule } from '../infra/metrics/metrics.module.js';
import { ServerModule } from '../modules/server/server.module.js';

async function bootstrap(): Promise<void> {
const httpPort = 3347;
const httpPort = 3349;
const nestApp = await NestFactory.create(ServerModule);
nestApp.setGlobalPrefix('api');
nestApp.enableCors();
await nestApp.init();

Expand Down
10 changes: 10 additions & 0 deletions src/infra/auth-guard/auth-guard.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { XApiKeyStrategy } from './strategy/index.js';

@Module({
imports: [PassportModule],
providers: [XApiKeyStrategy],
exports: [],
})
export class AuthGuardModule {}
1 change: 1 addition & 0 deletions src/infra/auth-guard/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './x-api-key.config.js';
3 changes: 3 additions & 0 deletions src/infra/auth-guard/config/x-api-key.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface XApiKeyConfig {
ADMIN_API__ALLOWED_API_KEYS: string[];
}
1 change: 1 addition & 0 deletions src/infra/auth-guard/guard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './x-api-key-auth.guard.js';
6 changes: 6 additions & 0 deletions src/infra/auth-guard/guard/x-api-key-auth.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { StrategyType } from '../interface/index.js';

@Injectable()
export class ApiKeyGuard extends AuthGuard(StrategyType.API_KEY) {}
2 changes: 2 additions & 0 deletions src/infra/auth-guard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { AuthGuardModule } from './auth-guard.module.js';
export { ApiKeyGuard } from './guard/index.js';
1 change: 1 addition & 0 deletions src/infra/auth-guard/interface/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './strategy-type.js';
3 changes: 3 additions & 0 deletions src/infra/auth-guard/interface/strategy-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum StrategyType {
API_KEY = 'api-key',
}
1 change: 1 addition & 0 deletions src/infra/auth-guard/strategy/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './x-api-key.strategy.js';
75 changes: 75 additions & 0 deletions src/infra/auth-guard/strategy/x-api-key.strategy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { createMock } from '@golevelup/ts-jest';
import { UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { XApiKeyConfig } from '../config/x-api-key.config.js';
import { XApiKeyStrategy } from './x-api-key.strategy.js';

describe('XApiKeyStrategy', () => {
let module: TestingModule;
let strategy: XApiKeyStrategy;
let configService: ConfigService<XApiKeyConfig, true>;

beforeAll(async () => {
module = await Test.createTestingModule({
imports: [],
providers: [
XApiKeyStrategy,
{
provide: ConfigService,
useValue: createMock<ConfigService<XApiKeyConfig, true>>({
get: () => ['7ccd4e11-c6f6-48b0-81eb-cccf7922e7a4'],
}),
},
],
}).compile();

strategy = module.get(XApiKeyStrategy);
configService = module.get(ConfigService<XApiKeyConfig, true>);
});

afterAll(async () => {
await module.close();
});

beforeEach(() => {
jest.resetAllMocks();
});

describe('validate', () => {
const done = jest.fn(() => null);
describe('when a valid api key is provided', () => {
const setup = () => {
const CORRECT_API_KEY = '7ccd4e11-c6f6-48b0-81eb-cccf7922e7a4';

return { CORRECT_API_KEY, done };
};
it('should do nothing', () => {
const { CORRECT_API_KEY } = setup();
strategy.validate(CORRECT_API_KEY, done);
expect(done).toBeCalledWith(null, true);
});
});

describe('when a invalid api key is provided', () => {
const setup = () => {
const INVALID_API_KEY = '7ccd4e11-c6f6-48b0-81eb-cccf7922e7a4BAD';

return { INVALID_API_KEY, done };
};
it('should throw error', () => {
const { INVALID_API_KEY } = setup();
strategy.validate(INVALID_API_KEY, done);
expect(done).toBeCalledWith(new UnauthorizedException(), null);
});
});
});

describe('constructor', () => {
it('should create strategy', () => {
const ApiKeyStrategy = new XApiKeyStrategy(configService);
expect(ApiKeyStrategy).toBeDefined();
expect(ApiKeyStrategy).toBeInstanceOf(XApiKeyStrategy);
});
});
});
23 changes: 23 additions & 0 deletions src/infra/auth-guard/strategy/x-api-key.strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-headerapikey/lib/Strategy.js';
import { XApiKeyConfig } from '../config/index.js';
import { StrategyType } from '../interface/index.js';

@Injectable()
export class XApiKeyStrategy extends PassportStrategy(Strategy, StrategyType.API_KEY) {
private readonly allowedApiKeys: string[];

public constructor(private readonly configService: ConfigService<XApiKeyConfig, true>) {
super({ header: 'X-API-KEY' }, false);
this.allowedApiKeys = this.configService.get<string[]>('ADMIN_API__ALLOWED_API_KEYS');
}

public validate(apiKey: string, done: (error: Error | null, data: boolean | null) => void): void {
if (this.allowedApiKeys.includes(apiKey)) {
done(null, true);
}
done(new UnauthorizedException(), null);
}
}
Loading

0 comments on commit 920d9e2

Please sign in to comment.