apps/api: check and pass env variables
This commit is contained in:
parent
27ad1e96dd
commit
e6ff4ab199
@ -1,4 +0,0 @@
|
|||||||
SECRET=secret
|
|
||||||
TOKEN_TTL=3600
|
|
||||||
CACHE_TTL=3600
|
|
||||||
COOKIE_TOKEN_NAME=token
|
|
||||||
@ -1,18 +1,19 @@
|
|||||||
# The web Dockerfile is copy-pasted into our main docs at /docs/handbook/deploying-with-docker.
|
# 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.
|
# 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.
|
# 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 add --no-cache libc6-compat
|
||||||
RUN apk update
|
RUN apk update
|
||||||
# Set working directory
|
# Set working directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN yarn global add turbo
|
RUN yarn global add turbo
|
||||||
|
RUN yarn global add dotenv-cli
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN turbo prune --scope=api --docker
|
RUN turbo prune --scope=api --docker
|
||||||
|
|
||||||
# Add lockfile and package.json's of isolated subworkspace
|
# 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 add --no-cache libc6-compat
|
||||||
RUN apk update
|
RUN apk update
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@ -26,9 +27,9 @@ RUN yarn install
|
|||||||
# Build the project and its dependencies
|
# Build the project and its dependencies
|
||||||
COPY --from=builder /app/out/full/ .
|
COPY --from=builder /app/out/full/ .
|
||||||
COPY turbo.json turbo.json
|
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
|
WORKDIR /app
|
||||||
|
|
||||||
# Don't run production as root
|
# Don't run production as root
|
||||||
|
|||||||
@ -37,7 +37,8 @@
|
|||||||
"ldap-authentication": "2.3.1",
|
"ldap-authentication": "2.3.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"rxjs": "^7.8.1"
|
"rxjs": "^7.8.1",
|
||||||
|
"zod": "^3.22.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nestjs/schematics": "^10.0.2",
|
"@nestjs/schematics": "^10.0.2",
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
import { AuthModule } from './auth/auth.module';
|
import { AuthModule } from './auth/auth.module';
|
||||||
|
import { env } from './config/env';
|
||||||
import { LdapModule } from './ldap/ldap.module';
|
import { LdapModule } from './ldap/ldap.module';
|
||||||
import { UsersModule } from './users/users.module';
|
import { UsersModule } from './users/users.module';
|
||||||
import { Global, Module } from '@nestjs/common';
|
import { Global, Module } from '@nestjs/common';
|
||||||
@ -16,9 +17,9 @@ import { JwtModule } from '@nestjs/jwt';
|
|||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
}),
|
}),
|
||||||
JwtModule.register({
|
JwtModule.register({
|
||||||
secret: process.env.SECRET,
|
secret: env.SECRET,
|
||||||
signOptions: {
|
signOptions: {
|
||||||
expiresIn: process.env.TOKEN_TTL,
|
expiresIn: env.TOKEN_TTL,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
AuthModule,
|
AuthModule,
|
||||||
|
|||||||
@ -6,13 +6,14 @@ import { COOKIE_TOKEN_NAME } from './lib/constants';
|
|||||||
import { Credentials } from './types/request';
|
import { Credentials } from './types/request';
|
||||||
import { Body, Controller, Get, HttpException, HttpStatus, Post, Req, Res } from '@nestjs/common';
|
import { Body, Controller, Get, HttpException, HttpStatus, Post, Req, Res } from '@nestjs/common';
|
||||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
|
import { env } from 'src/config/env';
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
export class AuthController {
|
export class AuthController {
|
||||||
cookieOptions: { maxAge: number; path: string };
|
cookieOptions: { maxAge: number; path: string };
|
||||||
constructor(private readonly authService: AuthService) {
|
constructor(private readonly authService: AuthService) {
|
||||||
this.cookieOptions = {
|
this.cookieOptions = {
|
||||||
maxAge: Number.parseInt(process.env.TOKEN_TTL, 10),
|
maxAge: env.TOKEN_TTL,
|
||||||
path: '/',
|
path: '/',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { UsersCache } from '../users/users.cache';
|
|||||||
import type { DecodedToken, TokenPayload } from './types/jwt';
|
import type { DecodedToken, TokenPayload } from './types/jwt';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { JwtService } from '@nestjs/jwt';
|
import { JwtService } from '@nestjs/jwt';
|
||||||
|
import { env } from 'src/config/env';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
@ -19,7 +20,7 @@ export class AuthService {
|
|||||||
await this.usersCache.addUser(username, user);
|
await this.usersCache.addUser(username, user);
|
||||||
|
|
||||||
const payload: TokenPayload = {
|
const payload: TokenPayload = {
|
||||||
domain: process.env.LDAP_DOMAIN,
|
domain: env.LDAP_DOMAIN,
|
||||||
username,
|
username,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
3
apps/api/src/config/env.ts
Normal file
3
apps/api/src/config/env.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import envSchema from './schema/env';
|
||||||
|
|
||||||
|
export const env = envSchema.parse(process.env);
|
||||||
21
apps/api/src/config/schema/env.ts
Normal file
21
apps/api/src/config/schema/env.ts
Normal 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;
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { env } from '../config/env';
|
||||||
import type { User } from '../types/user';
|
import type { User } from '../types/user';
|
||||||
import type { LdapUser } from './types/user';
|
import type { LdapUser } from './types/user';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
@ -6,17 +7,17 @@ import { authenticate } from 'ldap-authentication';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LdapService {
|
export class LdapService {
|
||||||
async authenticate(login: string, password?: string) {
|
public async authenticate(login: string, password?: string) {
|
||||||
const options: AuthenticationOptions = {
|
const options: AuthenticationOptions = {
|
||||||
adminDn: process.env.LDAP_BIND_DN,
|
adminDn: env.LDAP_BIND_DN,
|
||||||
adminPassword: process.env.LDAP_BIND_CREDENTIALS,
|
adminPassword: env.LDAP_BIND_CREDENTIALS,
|
||||||
ldapOpts: {
|
ldapOpts: {
|
||||||
url: process.env.LDAP_URL,
|
url: env.LDAP_URL,
|
||||||
},
|
},
|
||||||
userPassword: password,
|
userPassword: password,
|
||||||
userSearchBase: process.env.LDAP_BASE,
|
userSearchBase: env.LDAP_BASE,
|
||||||
username: login,
|
username: login,
|
||||||
usernameAttribute: process.env.LDAP_ATTRIBUTE,
|
usernameAttribute: env.LDAP_ATTRIBUTE,
|
||||||
verifyUserExists: password === undefined,
|
verifyUserExists: password === undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -31,8 +32,8 @@ export class LdapService {
|
|||||||
const user: User = {
|
const user: User = {
|
||||||
department,
|
department,
|
||||||
displayName,
|
displayName,
|
||||||
domain: process.env.LDAP_DOMAIN,
|
domain: env.LDAP_DOMAIN,
|
||||||
domainName: `${process.env.LDAP_DOMAIN}\\${username}`,
|
domainName: `${env.LDAP_DOMAIN}\\${username}`,
|
||||||
mail,
|
mail,
|
||||||
position: title,
|
position: title,
|
||||||
username,
|
username,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
/* eslint-disable unicorn/prefer-top-level-await */
|
/* eslint-disable unicorn/prefer-top-level-await */
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
|
import { env } from './config/env';
|
||||||
import { fastifyCookie } from '@fastify/cookie';
|
import { fastifyCookie } from '@fastify/cookie';
|
||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
import type { NestFastifyApplication } from '@nestjs/platform-fastify';
|
import type { NestFastifyApplication } from '@nestjs/platform-fastify';
|
||||||
@ -14,10 +15,10 @@ async function bootstrap() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await app.register(fastifyCookie, {
|
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();
|
bootstrap();
|
||||||
|
|||||||
@ -6,16 +6,17 @@ import { CacheModule } from '@nestjs/cache-manager';
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import * as redisStore from 'cache-manager-ioredis';
|
import * as redisStore from 'cache-manager-ioredis';
|
||||||
import type { RedisOptions } from 'ioredis';
|
import type { RedisOptions } from 'ioredis';
|
||||||
|
import { env } from 'src/config/env';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [UsersController],
|
controllers: [UsersController],
|
||||||
exports: [UsersCache],
|
exports: [UsersCache],
|
||||||
imports: [
|
imports: [
|
||||||
CacheModule.register<RedisOptions>({
|
CacheModule.register<RedisOptions>({
|
||||||
host: process.env.REDIS_HOST,
|
host: env.REDIS_HOST,
|
||||||
port: Number.parseInt(process.env.REDIS_PORT, 10) || 6379,
|
port: env.REDIS_PORT,
|
||||||
store: redisStore,
|
store: redisStore,
|
||||||
ttl: Number.parseInt(process.env.CACHE_TTL, 10),
|
ttl: env.CACHE_TTL,
|
||||||
}),
|
}),
|
||||||
LdapModule,
|
LdapModule,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"target": "es2017",
|
"target": "ES2021",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user