Added environment config. Added logging serializers. Updated logs to use serializers.

This commit is contained in:
Tom
2025-02-12 22:08:07 +00:00
parent abb8bec0cf
commit 16f208480d
5 changed files with 117 additions and 4 deletions

View File

@ -11,6 +11,7 @@ import { UsersModule } from './users/users.module';
import { UserEntity } from './users/users.entity';
import { AuthModule } from './auth/auth.module';
import { LoggerModule } from 'nestjs-pino';
import { serialize_token, serialize_user_short, serialize_user_long, serialize_res, serialize_req } from './logging.serializers';
@Module({
imports: [
@ -30,6 +31,19 @@ import { LoggerModule } from 'nestjs-pino';
pinoHttp: {
level: config.get('LOG_LEVEL') ?? 'info',
autoLogging: true,
serializers: config.get('ENVIRONMENT', 'production') == 'development' ? {
user: value => serialize_user_long(value),
access_token: value => serialize_token(value),
refresh_token: value => serialize_token(value),
req: value => serialize_req(value),
res: value => serialize_res(value),
} : {
user: value => serialize_user_short(value),
access_token: value => serialize_token(value),
refresh_token: value => serialize_token(value),
req: value => serialize_req(value),
res: value => serialize_res(value),
},
stream: pino.destination({
dest: path.join(config.get('LOG_DIRECTORY') ?? 'logs', 'backend.api.log'),
minLength: 512,

View File

@ -34,7 +34,9 @@ export class AuthAccessService {
this.logger.debug({
class: AuthAccessService.name,
method: this.generate.name,
user_login: user.userLogin,
user,
access_token: token,
exp: expiration,
msg: 'User generated an access token.',
});

View File

@ -38,6 +38,7 @@ export class AuthController {
this.logger.error({
class: AuthController.name,
method: this.login.name,
user: req.user,
msg: 'Failed to login.',
error: err,
});
@ -62,7 +63,9 @@ export class AuthController {
this.logger.info({
class: AuthController.name,
method: this.login.name,
user_login: req.user.userLogin,
user: req.user,
access_token: data.access_token,
refresh_token: data.refresh_token,
msg: 'User logged in.',
});
@ -87,7 +90,7 @@ export class AuthController {
this.logger.info({
class: AuthController.name,
method: this.logout.name,
user_login: req.user.userLogin,
user: req.user,
msg: 'User logged off',
});
@ -112,6 +115,8 @@ export class AuthController {
this.logger.debug({
class: AuthController.name,
method: this.refresh.name,
user: req.user,
access_token: data.access_token,
msg: 'Updated Authentication cookie for access token.',
});
@ -124,6 +129,8 @@ export class AuthController {
this.logger.debug({
class: AuthController.name,
method: this.refresh.name,
user: req.user,
refresh_token: data.refresh_token,
msg: 'Updated Refresh cookie for refresh token.',
});
}
@ -133,6 +140,7 @@ export class AuthController {
this.logger.error({
class: AuthController.name,
method: this.refresh.name,
user: req.user,
msg: 'Failed to refresh tokens.',
error: err,
});
@ -158,7 +166,7 @@ export class AuthController {
this.logger.info({
class: AuthController.name,
method: this.register.name,
user_login: user.userLogin,
user: req.user,
msg: 'User registered',
});
} catch (err) {
@ -167,6 +175,7 @@ export class AuthController {
this.logger.warn({
class: AuthController.name,
method: this.register.name,
user: req.user,
msg: 'Failed to register due to duplicate userLogin.',
});
return {
@ -178,6 +187,7 @@ export class AuthController {
this.logger.error({
class: AuthController.name,
method: this.register.name,
user: req.user,
msg: 'Failed to register.',
error: err,
});
@ -190,6 +200,14 @@ export class AuthController {
try {
data = await this.auth.login(user);
if (!data.access_token || !data.refresh_token || !data.refresh_exp) {
this.logger.error({
class: AuthController.name,
method: this.register.name,
user: req.user,
access_token: data.access_token,
refresh_token: data.refresh_token,
msg: 'Failed to generate tokens after registering.',
});
return {
success: false,
error_message: 'Something went wrong with tokens while logging in.',
@ -199,6 +217,7 @@ export class AuthController {
this.logger.error({
class: AuthController.name,
method: this.register.name,
user: req.user,
msg: 'Failed to login after registering.',
error: err,
});

View File

@ -29,6 +29,8 @@ export class AuthRefreshService {
this.logger.warn({
class: AuthRefreshService.name,
method: this.generate.name,
user,
refresh_token: refreshToken,
msg: 'Refresh token given is invalid.',
});
throw new UnauthorizedException('Invalid refresh token.');
@ -37,6 +39,9 @@ export class AuthRefreshService {
this.logger.warn({
class: AuthRefreshService.name,
method: this.generate.name,
user,
refresh_token: refreshToken,
exp: expiration,
msg: 'Refresh token given has expired.',
});
throw new UnauthorizedException('Invalid refresh token.');
@ -61,6 +66,9 @@ export class AuthRefreshService {
this.logger.debug({
class: AuthRefreshService.name,
method: this.generate.name,
user,
refresh_token: refreshToken,
exp: expiration,
msg: 'Deleted previous refresh token.',
});
}
@ -83,6 +91,9 @@ export class AuthRefreshService {
this.logger.debug({
class: AuthRefreshService.name,
method: this.generate.name,
user,
refresh_token: refreshToken,
exp: expiration,
msg: 'Generated a new refresh token.',
});
@ -95,6 +106,9 @@ export class AuthRefreshService {
this.logger.debug({
class: AuthRefreshService.name,
method: this.generate.name,
user,
refresh_token: refreshToken,
exp: expiration,
msg: 'Inserted the new refresh token.',
});
}

View File

@ -0,0 +1,64 @@
import { UserEntity } from "./users/users.entity";
export function serialize_user_short(value: UserEntity) {
if (!value) {
return value;
}
return value.userLogin;
}
export function serialize_user_long(value: UserEntity) {
if (!value) {
return value;
}
return {
user_id: value.userId,
user_login: value.userLogin,
is_admin: value.isAdmin,
}
}
export function serialize_token(value: string) {
return '...' + value.substring(Math.max(value.length - 12, value.length / 2) | 0);
}
export function serialize_req(value) {
if (!value) {
return value;
}
delete value['remoteAddress']
delete value['remotePort']
if (value.headers) {
const headers = value.headers;
if (headers['Authorization']) {
headers['Authorization'] = headers['Authorization'].substring(Math.max(0, headers['Authorization'].length - 12))
}
}
return value;
}
export function serialize_res(value) {
if (!value || !value.headers) {
return value;
}
const headers = value.headers;
delete headers['x-powered-by'];
if (headers['set-cookie']) {
const cookies = headers['set-cookie'];
for (let i in cookies) {
const cookie: string = cookies[i];
if (cookie.startsWith('Authentication=')) {
cookies[i] = 'Authentication=...' + cookie.substring(Math.max(0, cookie.indexOf(';') - 12));
} else if (cookie.startsWith('Refresh=')) {
cookies[i] = 'Refresh=...' + cookie.substring(Math.max(0, cookie.indexOf(';') - 12));
}
}
}
return value;
}