Add local users

This commit is contained in:
2023-12-11 18:27:33 -07:00
parent d00fe6fdb7
commit 6b2fd89ab2
8 changed files with 61 additions and 18 deletions

View File

@@ -1,7 +1,8 @@
JWT_SECRET=#jBhALXeYXC3$#e9 NODE_ENV=development
JWT_SECRET=jBhALXeYXC3$
RAPID_API_KEY= RAPID_API_KEY=
IRC_SERVER=irc.libera.chat IRC_SERVER=
IRC_CHANNEL="##usdev-dev" IRC_CHANNEL=
REDIS_HOST=localhost REDIS_HOST=localhost
REDIS_PASS=password REDIS_PASS=password

View File

@@ -16,13 +16,22 @@ cp .env.example .env
yarn yarn
# Start local services # Start local services
docker compose up -d docker compose up -d
# Copy default data into local minio
cp -r default/* data/minio/devbucket
# Start Application # Start Application
yarn start:dev 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 ## Configuration

View File

@@ -10,12 +10,26 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { AuthGuard } from './auth.guard'; 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') @ApiTags('auth')
@Controller('auth') @Controller('auth')
export class AuthController { export class AuthController {
constructor(private authService: AuthService) {} constructor(private authService: AuthService) { }
@HttpCode(HttpStatus.OK) @HttpCode(HttpStatus.OK)
@Post('login') @Post('login')
@@ -25,8 +39,10 @@ export class AuthController {
@UseGuards(AuthGuard) @UseGuards(AuthGuard)
@Post('hash') @Post('hash')
hash(@Body() hashDto: { pass: string; rounds?: number }) { @ApiBody({ type: HashDto })
return this.authService.hash(hashDto.pass, hashDto.rounds); @ApiBearerAuth()
hash(@Body() hashDto: HashDto) {
return this.authService.hash(hashDto.password, hashDto.rounds);
} }
@UseGuards(AuthGuard) @UseGuards(AuthGuard)

View File

@@ -1,10 +1,13 @@
require('dotenv').config();
export default () => ({ export default () => ({
port: parseInt(process.env.PORT ?? '', 10) || 3000, 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 should be added to calls made to third party apis
userAgent: 'api.us.dev/@chip@talking.dev', userAgent: 'api.us.dev/@chip@talking.dev',
rapidApiKey: process.env.RAPID_API_KEY || '', rapidApiKey: process.env.RAPID_API_KEY || '',
irc: { irc: {
enabled: process.env.IRC_SERVER !== undefined, enabled: process.env.IRC_SERVER === "" ? false : true,
server: process.env.IRC_SERVER, server: process.env.IRC_SERVER,
tls: process.env.IRC_TLS === 'true', tls: process.env.IRC_TLS === 'true',
port: parseInt(process.env.IRC_PORT ?? '6697'), port: parseInt(process.env.IRC_PORT ?? '6697'),

View File

@@ -1,6 +1,5 @@
import { Controller, Get, Res } from '@nestjs/common'; import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express'; import { Response } from 'express';
import { identity, prop } from 'ramda';
import * as xml from 'xml'; import * as xml from 'xml';
import { InjectMetric } from '@willsoto/nestjs-prometheus'; import { InjectMetric } from '@willsoto/nestjs-prometheus';
import { Gauge, Histogram } from 'prom-client'; import { Gauge, Histogram } from 'prom-client';
@@ -148,7 +147,7 @@ export class DinosaurwetController {
@InjectMetric('weekly_count') public weeklyCount: Gauge<string>, @InjectMetric('weekly_count') public weeklyCount: Gauge<string>,
@InjectMetric('daily_count') public dailyCount: Gauge<string>, @InjectMetric('daily_count') public dailyCount: Gauge<string>,
@InjectMetric('rss_query_count') public queryCount: Gauge<string>, @InjectMetric('rss_query_count') public queryCount: Gauge<string>,
) {} ) { }
@Get('') @Get('')
getAllAtOnce(@Res() response: Response) { getAllAtOnce(@Res() response: Response) {

View File

@@ -17,7 +17,10 @@ export class IrcbotService {
public readonly configService: ConfigService, public readonly configService: ConfigService,
public readonly domainrProxy: DomainrproxyService, public readonly domainrProxy: DomainrproxyService,
) { ) {
if (!this.configService.get<boolean>('irc.enabled')) return; if (!this.configService.get<boolean>('irc.enabled')) {
this.logger.verbose('IRC disabled, not connecting');
return;
};
const nick = this.configService.get<string>('irc.nick') || 'us-dev'; const nick = this.configService.get<string>('irc.nick') || 'us-dev';
const ircPassword = this.configService.get<string>('irc.password'); const ircPassword = this.configService.get<string>('irc.password');
this.socket = connect({ this.socket = connect({
@@ -68,7 +71,7 @@ export class IrcbotService {
this.client.send(channel, `Dunno what ${command} means`); this.client.send(channel, `Dunno what ${command} means`);
return; return;
} }
} catch {} } catch { }
}); });
} }
} }

View File

@@ -13,13 +13,12 @@ import {
import { KvService } from './kv.service'; import { KvService } from './kv.service';
import { Request } from 'express'; import { Request } from 'express';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import exp from 'constants';
import { FileInterceptor } from '@nestjs/platform-express'; import { FileInterceptor } from '@nestjs/platform-express';
@Controller('kv') @Controller('kv')
@ApiTags('kv') @ApiTags('kv')
export class KvController { export class KvController {
constructor(private readonly kvService: KvService) {} constructor(private readonly kvService: KvService) { }
@Get(':namespace/:key/metadata') @Get(':namespace/:key/metadata')
async getMetadata( async getMetadata(

View File

@@ -2,7 +2,6 @@ import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { Cron } from '@nestjs/schedule'; import { Cron } from '@nestjs/schedule';
import { MinioService } from 'src/minio/minio.service'; import { MinioService } from 'src/minio/minio.service';
require('dotenv').config();
// This should be a real class/interface representing a user entity // This should be a real class/interface representing a user entity
export type User = { export type User = {
@@ -11,6 +10,15 @@ export type User = {
password: string; password: string;
}; };
const developmentUsers: User[] = [
{
userId: 1,
username: 'admin',
// "password"
password: '$2b$10$c3d3JacaYw3KZ9qy4HniMeum5MXSj1VOOz8EWL5K23ZTL5aPnMNhS',
}
]
@Injectable() @Injectable()
export class UsersService { export class UsersService {
private users: User[] = []; private users: User[] = [];
@@ -28,6 +36,11 @@ export class UsersService {
@Cron('* * * * *') @Cron('* * * * *')
async refreshUsers(): Promise<void> { async refreshUsers(): Promise<void> {
this.logger.verbose('Refreshing users'); this.logger.verbose('Refreshing users');
if (this.configService.get<boolean>('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'); const buffer = await this.minioService.getBuffer(this.bucket, 'users.json');
this.users = JSON.parse(buffer.toString()); this.users = JSON.parse(buffer.toString());
if (this.users === undefined) { if (this.users === undefined) {