Browse Source

Merge pull request #5680 from nocodb/fix/5679-jwt-init-bug

fix: Load JWT secret from store on app init
pull/5686/head
Pranav C 2 years ago committed by GitHub
parent
commit
9894d51733
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 66
      packages/nocodb/src/Noco.ts
  2. 51
      packages/nocodb/src/app.module.ts
  3. 20
      packages/nocodb/src/modules/global/global.module.ts
  4. 19
      packages/nocodb/src/services/app-init.service.spec.ts
  5. 68
      packages/nocodb/src/services/app-init.service.ts
  6. 10
      packages/nocodb/src/utils/NcConfigFactory.ts

66
packages/nocodb/src/Noco.ts

@ -1,4 +1,5 @@
// import * as Sentry from '@sentry/node';
import Sentry, { Handlers } from '@sentry/node';
import { Logger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import clear from 'clear';
import * as express from 'express';
@ -6,10 +7,12 @@ import NcToolGui from 'nc-lib-gui';
import { IoAdapter } from '@nestjs/platform-socket.io';
import requestIp from 'request-ip';
import cookieParser from 'cookie-parser';
import { T } from 'nc-help';
import { v4 as uuidv4 } from 'uuid';
import { AppModule } from './app.module';
import { NC_LICENSE_KEY } from './constants';
import Store from './models/Store';
import { MetaTable } from './utils/globals';
import type { IEventEmitter } from './modules/event-emitter/event-emitter.interface';
import type { Express } from 'express';
import type * as http from 'http';
@ -20,6 +23,7 @@ export default class Noco {
public static readonly env: string = '_noco';
private static _httpServer: http.Server;
private static _server: Express;
private static logger = new Logger(Noco.name);
public static get dashboardUrl(): string {
let siteUrl = `http://localhost:${process.env.PORT || 8080}`;
@ -42,7 +46,6 @@ export default class Noco {
public readonly metaMgrv2: any;
public env: string;
private ncToolApi;
private config: any;
private requestContext: any;
@ -102,6 +105,8 @@ export default class Noco {
const nestApp = await NestFactory.create(AppModule);
this.initSentry(nestApp);
nestApp.useWebSocketAdapter(new IoAdapter(httpServer));
nestApp.use(requestIp.mw());
@ -115,6 +120,9 @@ export default class Noco {
const dashboardPath = process.env.NC_DASHBOARD_URL || '/dashboard';
server.use(NcToolGui.expressMiddleware(dashboardPath));
server.get('/', (_req, res) => res.redirect(dashboardPath));
this.initSentryErrorHandler(server);
return nestApp.getHttpAdapter().getInstance();
}
@ -125,4 +133,56 @@ export default class Noco {
public static get server(): Express {
return Noco._server;
}
public static async initJwt(): Promise<any> {
if (this.config?.auth?.jwt) {
if (!this.config.auth.jwt.secret) {
let secret = (
await Noco._ncMeta.metaGet('', '', MetaTable.STORE, {
key: 'nc_auth_jwt_secret',
})
)?.value;
if (!secret) {
await Noco._ncMeta.metaInsert('', '', MetaTable.STORE, {
key: 'nc_auth_jwt_secret',
value: (secret = uuidv4()),
});
}
this.config.auth.jwt.secret = secret;
}
this.config.auth.jwt.options = this.config.auth.jwt.options || {};
if (!this.config.auth.jwt.options?.expiresIn) {
this.config.auth.jwt.options.expiresIn =
process.env.NC_JWT_EXPIRES_IN ?? '10h';
}
}
let serverId = (
await Noco._ncMeta.metaGet('', '', MetaTable.STORE, {
key: 'nc_server_id',
})
)?.value;
if (!serverId) {
await Noco._ncMeta.metaInsert('', '', MetaTable.STORE, {
key: 'nc_server_id',
value: (serverId = T.id),
});
}
process.env.NC_SERVER_UUID = serverId;
}
private static initSentryErrorHandler(router) {
if (process.env.NC_SENTRY_DSN) {
router.use(Handlers.errorHandler());
}
}
private static initSentry(router) {
if (process.env.NC_SENTRY_DSN) {
Sentry.init({ dsn: process.env.NC_SENTRY_DSN });
// The request handler must be the first middleware on the app
router.use(Handlers.requestHandler());
}
}
}

51
packages/nocodb/src/app.module.ts

@ -1,35 +1,25 @@
import { Inject, Module, RequestMethod } from '@nestjs/common';
import { Module, RequestMethod } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { BullModule } from '@nestjs/bull';
import { EventEmitterModule as NestJsEventEmitter } from '@nestjs/event-emitter';
import { Connection } from './connection/connection';
import { GlobalExceptionFilter } from './filters/global-exception/global-exception.filter';
import NcPluginMgrv2 from './helpers/NcPluginMgrv2';
import { GlobalMiddleware } from './middlewares/global/global.middleware';
import { GuiMiddleware } from './middlewares/gui/gui.middleware';
import { PublicMiddleware } from './middlewares/public/public.middleware';
import { DatasModule } from './modules/datas/datas.module';
import { IEventEmitter } from './modules/event-emitter/event-emitter.interface';
import { EventEmitterModule } from './modules/event-emitter/event-emitter.module';
import { AuthService } from './services/auth.service';
import { UsersModule } from './modules/users/users.module';
import { MetaService } from './meta/meta.service';
import Noco from './Noco';
import { TestModule } from './modules/test/test.module';
import { GlobalModule } from './modules/global/global.module';
import { HookHandlerService } from './services/hook-handler.service';
import { LocalStrategy } from './strategies/local.strategy';
import { AuthTokenStrategy } from './strategies/authtoken.strategy/authtoken.strategy';
import { BaseViewStrategy } from './strategies/base-view.strategy/base-view.strategy';
import NcConfigFactory from './utils/NcConfigFactory';
import NcUpgrader from './version-upgrader/NcUpgrader';
import { MetasModule } from './modules/metas/metas.module';
import NocoCache from './cache/NocoCache';
import { JobsModule } from './modules/jobs/jobs.module';
import type {
MiddlewareConsumer,
OnApplicationBootstrap,
} from '@nestjs/common';
import { AppInitService } from './services/app-init.service';
import type { MiddlewareConsumer } from '@nestjs/common';
@Module({
imports: [
@ -60,15 +50,10 @@ import type {
AuthTokenStrategy,
BaseViewStrategy,
HookHandlerService,
AppInitService,
],
})
export class AppModule implements OnApplicationBootstrap {
constructor(
private readonly connection: Connection,
private readonly metaService: MetaService,
@Inject('IEventEmitter') private readonly eventEmitter: IEventEmitter,
) {}
export class AppModule {
// Global Middleware
configure(consumer: MiddlewareConsumer) {
consumer
@ -79,30 +64,4 @@ export class AppModule implements OnApplicationBootstrap {
.apply(GlobalMiddleware)
.forRoutes({ path: '*', method: RequestMethod.ALL });
}
// app init
async onApplicationBootstrap(): Promise<void> {
process.env.NC_VERSION = '0105004';
await NocoCache.init();
await this.connection.init();
await NcConfigFactory.metaDbCreateIfNotExist(this.connection.config);
await this.metaService.init();
// todo: remove
// temporary hack
Noco._ncMeta = this.metaService;
Noco.config = this.connection.config;
Noco.eventEmitter = this.eventEmitter;
// init plugin manager
await NcPluginMgrv2.init(Noco.ncMeta);
await Noco.loadEEState();
// run upgrader
await NcUpgrader.upgrade({ ncMeta: Noco._ncMeta });
}
}

20
packages/nocodb/src/modules/global/global.module.ts

@ -1,19 +1,27 @@
import { Global, Module } from '@nestjs/common';
import { JwtModule, JwtService } from '@nestjs/jwt';
import { ExtractJwt } from 'passport-jwt';
import {
AppInitService,
appInitServiceProvider,
} from '../../services/app-init.service';
import { SocketGateway } from '../../gateways/socket.gateway';
import { Connection } from '../../connection/connection';
import { GlobalGuard } from '../../guards/global/global.guard';
import { MetaService } from '../../meta/meta.service';
import Noco from '../../Noco';
import { JwtStrategy } from '../../strategies/jwt.strategy';
import NcConfigFactory from '../../utils/NcConfigFactory';
import { UsersService } from '../../services/users/users.service';
import type { Provider } from '@nestjs/common';
export const JwtStrategyProvider: Provider = {
provide: JwtStrategy,
useFactory: async (usersService: UsersService) => {
const config = await NcConfigFactory.make();
useFactory: async (
usersService: UsersService,
appInitService: AppInitService,
) => {
const config = appInitService.appConfig;
await Noco.initJwt();
const options = {
// ignoreExpiration: false,
@ -26,13 +34,14 @@ export const JwtStrategyProvider: Provider = {
return new JwtStrategy(options, usersService);
},
inject: [UsersService],
inject: [UsersService, AppInitService],
};
@Global()
@Module({
imports: [],
providers: [
appInitServiceProvider,
Connection,
MetaService,
UsersService,
@ -41,6 +50,7 @@ export const JwtStrategyProvider: Provider = {
SocketGateway,
],
exports: [
AppInitService,
Connection,
MetaService,
JwtStrategyProvider,

19
packages/nocodb/src/services/app-init.service.spec.ts

@ -0,0 +1,19 @@
import { Test } from '@nestjs/testing';
import { AppInitService } from './app-init.service';
import type { TestingModule } from '@nestjs/testing';
describe('AppInitService', () => {
let service: AppInitService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AppInitService],
}).compile();
service = module.get<AppInitService>(AppInitService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

68
packages/nocodb/src/services/app-init.service.ts

@ -0,0 +1,68 @@
import { Inject, Injectable } from '@nestjs/common';
import NocoCache from '../cache/NocoCache';
import { Connection } from '../connection/connection';
import NcPluginMgrv2 from '../helpers/NcPluginMgrv2';
import { MetaService } from '../meta/meta.service';
import Noco from '../Noco';
import NcConfigFactory from '../utils/NcConfigFactory';
import NcUpgrader from '../version-upgrader/NcUpgrader';
import type { IEventEmitter } from '../modules/event-emitter/event-emitter.interface';
import type { Provider } from '@nestjs/common';
export class AppInitService {
private readonly config: any;
constructor(config) {
this.config = config;
}
get appConfig(): any {
return this.config;
}
}
export const appInitServiceProvider: Provider = {
provide: AppInitService,
// initialize app,
// 1. init cache
// 2. init db connection and create if not exist
// 3. init meta and set to Noco
// 4. init jwt
// 5. init plugin manager
// 6. run upgrader
useFactory: async (
connection: Connection,
metaService: MetaService,
eventEmitter: IEventEmitter,
) => {
process.env.NC_VERSION = '0105004';
await NocoCache.init();
await connection.init();
await NcConfigFactory.metaDbCreateIfNotExist(connection.config);
await metaService.init();
// todo: remove
// temporary hack
Noco._ncMeta = metaService;
Noco.config = connection.config;
Noco.eventEmitter = eventEmitter;
// init jwt secret
await Noco.initJwt();
// init plugin manager
await NcPluginMgrv2.init(Noco.ncMeta);
await Noco.loadEEState();
// run upgrader
await NcUpgrader.upgrade({ ncMeta: Noco._ncMeta });
// todo: move app config to app-init service
return new AppInitService(connection.config);
},
inject: [Connection, MetaService, 'IEventEmitter'],
};

10
packages/nocodb/src/utils/NcConfigFactory.ts

@ -100,7 +100,7 @@ export default class NcConfigFactory {
ncConfig.auth = {
jwt: {
secret: process.env.NC_AUTH_JWT_SECRET ?? 'temporary-key',
secret: process.env.NC_AUTH_JWT_SECRET,
},
};
@ -421,7 +421,7 @@ export default class NcConfigFactory {
if (process.env.NC_AUTH_ADMIN_SECRET) {
config.auth = {
masterKey: {
secret: process.env.NC_AUTH_ADMIN_SECRET ?? 'temporary-key',
secret: process.env.NC_AUTH_ADMIN_SECRET,
},
};
} else if (process.env.NC_NO_AUTH) {
@ -436,7 +436,7 @@ export default class NcConfigFactory {
dbAlias:
process.env.NC_AUTH_JWT_DB_ALIAS ||
config.envs['_noco'].db[0].meta.dbAlias,
secret: process.env.NC_AUTH_JWT_SECRET ?? 'temporary-key',
secret: process.env.NC_AUTH_JWT_SECRET,
},
};
}
@ -536,7 +536,7 @@ export default class NcConfigFactory {
if (process.env.NC_AUTH_ADMIN_SECRET) {
config.auth = {
masterKey: {
secret: process.env.NC_AUTH_ADMIN_SECRET ?? 'temporary-key',
secret: process.env.NC_AUTH_ADMIN_SECRET,
},
};
} else if (process.env.NC_NO_AUTH) {
@ -551,7 +551,7 @@ export default class NcConfigFactory {
dbAlias:
process.env.NC_AUTH_JWT_DB_ALIAS ||
config.envs['_noco'].db[0].meta.dbAlias,
secret: process.env.NC_AUTH_JWT_SECRET ?? 'temporary-key',
secret: process.env.NC_AUTH_JWT_SECRET,
},
};
}

Loading…
Cancel
Save