apps/api: check and pass env variables

This commit is contained in:
vchikalkin 2023-10-16 12:15:27 +03:00
parent 27ad1e96dd
commit e6ff4ab199
12 changed files with 55 additions and 27 deletions

View File

@ -1,4 +0,0 @@
SECRET=secret
TOKEN_TTL=3600
CACHE_TTL=3600
COOKIE_TOKEN_NAME=token

View File

@ -1,18 +1,19 @@
# The web Dockerfile is copy-pasted into our main docs at /docs/handbook/deploying-with-docker.
# Make sure you update this Dockerfile, the Dockerfile in the web workspace and copy that over to Dockerfile in the docs.
FROM node:16-alpine AS builder
FROM node:alpine AS builder
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
RUN apk update
# Set working directory
WORKDIR /app
RUN yarn global add turbo
RUN yarn global add dotenv-cli
COPY . .
RUN turbo prune --scope=api --docker
# Add lockfile and package.json's of isolated subworkspace
FROM node:16-alpine AS installer
FROM node:alpine AS installer
RUN apk add --no-cache libc6-compat
RUN apk update
WORKDIR /app
@ -26,9 +27,9 @@ RUN yarn install
# Build the project and its dependencies
COPY --from=builder /app/out/full/ .
COPY turbo.json turbo.json
RUN yarn turbo run build --filter=api...
RUN yarn dotenv -e .env turbo run build --filter=api...
FROM node:16-alpine AS runner
FROM node:alpine AS runner
WORKDIR /app
# Don't run production as root

View File

@ -37,7 +37,8 @@
"ldap-authentication": "2.3.1",
"reflect-metadata": "^0.1.13",
"rimraf": "^5.0.5",
"rxjs": "^7.8.1"
"rxjs": "^7.8.1",
"zod": "^3.22.4"
},
"devDependencies": {
"@nestjs/schematics": "^10.0.2",

View File

@ -1,6 +1,7 @@
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { env } from './config/env';
import { LdapModule } from './ldap/ldap.module';
import { UsersModule } from './users/users.module';
import { Global, Module } from '@nestjs/common';
@ -16,9 +17,9 @@ import { JwtModule } from '@nestjs/jwt';
isGlobal: true,
}),
JwtModule.register({
secret: process.env.SECRET,
secret: env.SECRET,
signOptions: {
expiresIn: process.env.TOKEN_TTL,
expiresIn: env.TOKEN_TTL,
},
}),
AuthModule,

View File

@ -6,13 +6,14 @@ import { COOKIE_TOKEN_NAME } from './lib/constants';
import { Credentials } from './types/request';
import { Body, Controller, Get, HttpException, HttpStatus, Post, Req, Res } from '@nestjs/common';
import { FastifyReply, FastifyRequest } from 'fastify';
import { env } from 'src/config/env';
@Controller()
export class AuthController {
cookieOptions: { maxAge: number; path: string };
constructor(private readonly authService: AuthService) {
this.cookieOptions = {
maxAge: Number.parseInt(process.env.TOKEN_TTL, 10),
maxAge: env.TOKEN_TTL,
path: '/',
};
}

View File

@ -3,6 +3,7 @@ import { UsersCache } from '../users/users.cache';
import type { DecodedToken, TokenPayload } from './types/jwt';
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { env } from 'src/config/env';
@Injectable()
export class AuthService {
@ -19,7 +20,7 @@ export class AuthService {
await this.usersCache.addUser(username, user);
const payload: TokenPayload = {
domain: process.env.LDAP_DOMAIN,
domain: env.LDAP_DOMAIN,
username,
};

View File

@ -0,0 +1,3 @@
import envSchema from './schema/env';
export const env = envSchema.parse(process.env);

View File

@ -0,0 +1,21 @@
import { z } from 'zod';
const envSchema = z.object({
API_PORT: z.number().optional().default(3001),
CACHE_TTL: z.string().transform((val) => Number.parseInt(val, 10)),
LDAP_ATTRIBUTE: z.string(),
LDAP_BASE: z.string(),
LDAP_BIND_CREDENTIALS: z.string(),
LDAP_BIND_DN: z.string(),
LDAP_DOMAIN: z.string(),
LDAP_URL: z.string().url(),
REDIS_HOST: z.string(),
REDIS_PORT: z
.string()
.transform((val) => Number.parseInt(val, 10))
.default('6379'),
SECRET: z.string(),
TOKEN_TTL: z.string().transform((val) => Number.parseInt(val, 10)),
});
export default envSchema;

View File

@ -1,3 +1,4 @@
import { env } from '../config/env';
import type { User } from '../types/user';
import type { LdapUser } from './types/user';
import { Injectable } from '@nestjs/common';
@ -6,17 +7,17 @@ import { authenticate } from 'ldap-authentication';
@Injectable()
export class LdapService {
async authenticate(login: string, password?: string) {
public async authenticate(login: string, password?: string) {
const options: AuthenticationOptions = {
adminDn: process.env.LDAP_BIND_DN,
adminPassword: process.env.LDAP_BIND_CREDENTIALS,
adminDn: env.LDAP_BIND_DN,
adminPassword: env.LDAP_BIND_CREDENTIALS,
ldapOpts: {
url: process.env.LDAP_URL,
url: env.LDAP_URL,
},
userPassword: password,
userSearchBase: process.env.LDAP_BASE,
userSearchBase: env.LDAP_BASE,
username: login,
usernameAttribute: process.env.LDAP_ATTRIBUTE,
usernameAttribute: env.LDAP_ATTRIBUTE,
verifyUserExists: password === undefined,
};
@ -31,8 +32,8 @@ export class LdapService {
const user: User = {
department,
displayName,
domain: process.env.LDAP_DOMAIN,
domainName: `${process.env.LDAP_DOMAIN}\\${username}`,
domain: env.LDAP_DOMAIN,
domainName: `${env.LDAP_DOMAIN}\\${username}`,
mail,
position: title,
username,

View File

@ -1,5 +1,6 @@
/* eslint-disable unicorn/prefer-top-level-await */
import { AppModule } from './app.module';
import { env } from './config/env';
import { fastifyCookie } from '@fastify/cookie';
import { NestFactory } from '@nestjs/core';
import type { NestFastifyApplication } from '@nestjs/platform-fastify';
@ -14,10 +15,10 @@ async function bootstrap() {
);
await app.register(fastifyCookie, {
secret: process.env.SECRET,
secret: env.SECRET,
});
await app.listen(process.env.API_PORT || 3001, '0.0.0.0');
await app.listen(env.API_PORT, '0.0.0.0');
}
bootstrap();

View File

@ -6,16 +6,17 @@ import { CacheModule } from '@nestjs/cache-manager';
import { Module } from '@nestjs/common';
import * as redisStore from 'cache-manager-ioredis';
import type { RedisOptions } from 'ioredis';
import { env } from 'src/config/env';
@Module({
controllers: [UsersController],
exports: [UsersCache],
imports: [
CacheModule.register<RedisOptions>({
host: process.env.REDIS_HOST,
port: Number.parseInt(process.env.REDIS_PORT, 10) || 6379,
host: env.REDIS_HOST,
port: env.REDIS_PORT,
store: redisStore,
ttl: Number.parseInt(process.env.CACHE_TTL, 10),
ttl: env.CACHE_TTL,
}),
LdapModule,
],

View File

@ -6,7 +6,7 @@
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"target": "ES2021",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",