diff --git a/.env.example b/.env.example index 846f97f..da5ba53 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,8 @@ -JWT_SECRET=#jBhALXeYXC3$#e9 +NODE_ENV=development +JWT_SECRET=jBhALXeYXC3$ RAPID_API_KEY= -IRC_SERVER=irc.libera.chat -IRC_CHANNEL="##usdev-dev" +IRC_SERVER= +IRC_CHANNEL= REDIS_HOST=localhost REDIS_PASS=password diff --git a/README.md b/README.md index cbd9ea2..207037f 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,22 @@ cp .env.example .env yarn # Start local services docker compose up -d -# Copy default data into local minio -cp -r default/* data/minio/devbucket # Start Application yarn start:dev +# Log in with development user (admin) and dev password (password) +curl --request POST \ + --url http://localhost:3000/auth/login \ + --header 'Content-Type: application/json' \ + --data '{ + "username":"admin", + "password":"password" +}' ``` -Visit http://localhost:3000/api +The Login command will return a JSON object with `access_token`. You can then +head over to http://localhost:3000/api, click the "Authorize" button, and enter +the `access_token`. This will then be applied to all of the endpoints that +require auth on the API page. ## Configuration diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index d97aa63..d481c83 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -10,12 +10,26 @@ import { } from '@nestjs/common'; import { AuthService } from './auth.service'; import { AuthGuard } from './auth.guard'; -import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiBody, ApiProperty, ApiTags } from '@nestjs/swagger'; + +class HashDto { + @ApiProperty({ + description: 'The password to hash', + default: 'password', + }) + password: string; + + @ApiProperty({ + description: 'The number of bcrypt hashing rounds', + default: 10, + }) + rounds?: number; +} @ApiTags('auth') @Controller('auth') export class AuthController { - constructor(private authService: AuthService) {} + constructor(private authService: AuthService) { } @HttpCode(HttpStatus.OK) @Post('login') @@ -25,8 +39,10 @@ export class AuthController { @UseGuards(AuthGuard) @Post('hash') - hash(@Body() hashDto: { pass: string; rounds?: number }) { - return this.authService.hash(hashDto.pass, hashDto.rounds); + @ApiBody({ type: HashDto }) + @ApiBearerAuth() + hash(@Body() hashDto: HashDto) { + return this.authService.hash(hashDto.password, hashDto.rounds); } @UseGuards(AuthGuard) diff --git a/src/config/configuration.ts b/src/config/configuration.ts index 3036d94..5891938 100644 --- a/src/config/configuration.ts +++ b/src/config/configuration.ts @@ -1,10 +1,13 @@ +require('dotenv').config(); + export default () => ({ port: parseInt(process.env.PORT ?? '', 10) || 3000, + isProduction: process.env.NODE_ENV === 'production', // UserAgent should be added to calls made to third party apis userAgent: 'api.us.dev/@chip@talking.dev', rapidApiKey: process.env.RAPID_API_KEY || '', irc: { - enabled: process.env.IRC_SERVER !== undefined, + enabled: process.env.IRC_SERVER === "" ? false : true, server: process.env.IRC_SERVER, tls: process.env.IRC_TLS === 'true', port: parseInt(process.env.IRC_PORT ?? '6697'), diff --git a/src/dinosaurwet/dinosaurwet.controller.ts b/src/dinosaurwet/dinosaurwet.controller.ts index b92d853..1fddd36 100644 --- a/src/dinosaurwet/dinosaurwet.controller.ts +++ b/src/dinosaurwet/dinosaurwet.controller.ts @@ -1,6 +1,5 @@ import { Controller, Get, Res } from '@nestjs/common'; import { Response } from 'express'; -import { identity, prop } from 'ramda'; import * as xml from 'xml'; import { InjectMetric } from '@willsoto/nestjs-prometheus'; import { Gauge, Histogram } from 'prom-client'; @@ -148,7 +147,7 @@ export class DinosaurwetController { @InjectMetric('weekly_count') public weeklyCount: Gauge, @InjectMetric('daily_count') public dailyCount: Gauge, @InjectMetric('rss_query_count') public queryCount: Gauge, - ) {} + ) { } @Get('') getAllAtOnce(@Res() response: Response) { diff --git a/src/ircbot/ircbot.service.ts b/src/ircbot/ircbot.service.ts index b24e230..471dde8 100644 --- a/src/ircbot/ircbot.service.ts +++ b/src/ircbot/ircbot.service.ts @@ -17,7 +17,10 @@ export class IrcbotService { public readonly configService: ConfigService, public readonly domainrProxy: DomainrproxyService, ) { - if (!this.configService.get('irc.enabled')) return; + if (!this.configService.get('irc.enabled')) { + this.logger.verbose('IRC disabled, not connecting'); + return; + }; const nick = this.configService.get('irc.nick') || 'us-dev'; const ircPassword = this.configService.get('irc.password'); this.socket = connect({ @@ -68,7 +71,7 @@ export class IrcbotService { this.client.send(channel, `Dunno what ${command} means`); return; } - } catch {} + } catch { } }); } } diff --git a/src/kv/kv.controller.ts b/src/kv/kv.controller.ts index 3b821b7..720924e 100644 --- a/src/kv/kv.controller.ts +++ b/src/kv/kv.controller.ts @@ -13,13 +13,12 @@ import { import { KvService } from './kv.service'; import { Request } from 'express'; import { ApiTags } from '@nestjs/swagger'; -import exp from 'constants'; import { FileInterceptor } from '@nestjs/platform-express'; @Controller('kv') @ApiTags('kv') export class KvController { - constructor(private readonly kvService: KvService) {} + constructor(private readonly kvService: KvService) { } @Get(':namespace/:key/metadata') async getMetadata( diff --git a/src/users/users.service.ts b/src/users/users.service.ts index aa904b8..38f9212 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -2,7 +2,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { Cron } from '@nestjs/schedule'; import { MinioService } from 'src/minio/minio.service'; -require('dotenv').config(); // This should be a real class/interface representing a user entity export type User = { @@ -11,6 +10,15 @@ export type User = { password: string; }; +const developmentUsers: User[] = [ + { + userId: 1, + username: 'admin', + // "password" + password: '$2b$10$c3d3JacaYw3KZ9qy4HniMeum5MXSj1VOOz8EWL5K23ZTL5aPnMNhS', + } +] + @Injectable() export class UsersService { private users: User[] = []; @@ -28,6 +36,11 @@ export class UsersService { @Cron('* * * * *') async refreshUsers(): Promise { this.logger.verbose('Refreshing users'); + if (this.configService.get('isProduction', false) === false) { + this.logger.verbose('Development environment, using development users'); + this.users = developmentUsers; + return; + } const buffer = await this.minioService.getBuffer(this.bucket, 'users.json'); this.users = JSON.parse(buffer.toString()); if (this.users === undefined) {