Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ import { SaaSGatewayModule } from './microservices/gateways/saas-gateway.ts/saas
import { SaasModule } from './microservices/saas-microservice/saas.module.js';
import { AppLoggerMiddleware } from './middlewares/logging-middleware/app-logger-middlewate.js';
import { SelfHostedOperationsModule } from './selfhosted-operations/selhosted-operations.module.js';
import { ConfigModule } from './shared/config/config.module.js';
import { DatabaseModule } from './shared/database/database.module.js';
import { SharedModule } from './shared/shared.module.js';
import { GetHelloUseCase } from './use-cases-app/get-hello.use.case.js';

@Module({
imports: [
ConfigModule,
ScheduleModule.forRoot(),
ThrottlerModule.forRoot({
throttlers: [
Expand Down
3 changes: 2 additions & 1 deletion backend/src/authorization/auth-with-api.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Messages } from '../exceptions/text/messages.js';
import { Constants } from '../helpers/constants/constants.js';
import { Encryptor } from '../helpers/encryption/encryptor.js';
import { isObjectEmpty } from '../helpers/is-object-empty.js';
import { appConfig } from '../shared/config/app-config.js';
import { IRequestWithCognitoInfo } from './cognito-decoded.interface.js';

@Injectable()
Expand Down Expand Up @@ -60,7 +61,7 @@ export class AuthWithApiMiddleware implements NestMiddleware {

private async authenticateWithToken(tokenFromCookie: string, req: IRequestWithCognitoInfo): Promise<void> {
try {
const jwtSecret = process.env.JWT_SECRET;
const jwtSecret = appConfig.auth.jwtSecret;
const data = jwt.verify(tokenFromCookie, jwtSecret) as jwt.JwtPayload;
const userId = data.id;

Expand Down
6 changes: 4 additions & 2 deletions backend/src/authorization/auth.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import { LogOutEntity } from '../entities/log-out/log-out.entity.js';
import { JwtScopesEnum } from '../entities/user/enums/jwt-scopes.enum.js';
import { UserEntity } from '../entities/user/user.entity.js';
import { Messages } from '../exceptions/text/messages.js';
import { isTest } from '../helpers/app/is-test.js';
import { Constants } from '../helpers/constants/constants.js';
import { isObjectEmpty } from '../helpers/is-object-empty.js';
import { appConfig } from '../shared/config/app-config.js';
import { IRequestWithCognitoInfo } from './cognito-decoded.interface.js';

@Injectable()
Expand All @@ -32,7 +34,7 @@ export class AuthMiddleware implements NestMiddleware {
try {
token = req.cookies[Constants.JWT_COOKIE_KEY_NAME];
} catch (_e) {
if (process.env.NODE_ENV !== 'test') {
if (!isTest()) {
throw new UnauthorizedException('JWT verification failed');
}
}
Expand All @@ -47,7 +49,7 @@ export class AuthMiddleware implements NestMiddleware {
}

try {
const jwtSecret = process.env.JWT_SECRET;
const jwtSecret = appConfig.auth.jwtSecret;
const data = jwt.verify(token, jwtSecret) as jwt.JwtPayload;
const userId = data.id;

Expand Down
5 changes: 3 additions & 2 deletions backend/src/authorization/basic-auth.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { Injectable, NestMiddleware, UnauthorizedException } from '@nestjs/commo
import auth from 'basic-auth';
import { Request, Response } from 'express';
import { Messages } from '../exceptions/text/messages.js';
import { appConfig } from '../shared/config/app-config.js';

@Injectable()
export class BasicAuthMiddleware implements NestMiddleware {
use(req: Request, _res: Response, next: (err?: any, res?: any) => void): void {
const basicAuthLogin = process.env.BASIC_AUTH_LOGIN;
const basicAuthPassword = process.env.BASIC_AUTH_PWD;
const basicAuthLogin = appConfig.auth.basicAuthLogin;
const basicAuthPassword = appConfig.auth.basicAuthPassword;
const userCredentials = auth(req);
if (!userCredentials) {
throw new UnauthorizedException(Messages.AUTHORIZATION_REQUIRED);
Expand Down
6 changes: 4 additions & 2 deletions backend/src/authorization/non-scoped-auth.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import jwt from 'jsonwebtoken';
import { Repository } from 'typeorm';
import { LogOutEntity } from '../entities/log-out/log-out.entity.js';
import { Messages } from '../exceptions/text/messages.js';
import { isTest } from '../helpers/app/is-test.js';
import { Constants } from '../helpers/constants/constants.js';
import { isObjectEmpty } from '../helpers/is-object-empty.js';
import { appConfig } from '../shared/config/app-config.js';
import { IRequestWithCognitoInfo } from './cognito-decoded.interface.js';

@Injectable()
Expand All @@ -28,7 +30,7 @@ export class NonScopedAuthMiddleware implements NestMiddleware {
try {
token = req.cookies[Constants.JWT_COOKIE_KEY_NAME];
} catch (_e) {
if (process.env.NODE_ENV !== 'test') {
if (!isTest()) {
throw new UnauthorizedException('JWT verification failed');
}
}
Expand All @@ -43,7 +45,7 @@ export class NonScopedAuthMiddleware implements NestMiddleware {
}

try {
const jwtSecret = process.env.JWT_SECRET;
const jwtSecret = appConfig.auth.jwtSecret;
const data = jwt.verify(token, jwtSecret) as jwt.JwtPayload;
const userId = data.id;
if (!userId) {
Expand Down
3 changes: 2 additions & 1 deletion backend/src/authorization/saas-auth.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable, NestMiddleware, UnauthorizedException } from '@nestjs/commo
import { Response } from 'express';
import jwt from 'jsonwebtoken';
import { Messages } from '../exceptions/text/messages.js';
import { appConfig } from '../shared/config/app-config.js';
import { IRequestWithCognitoInfo } from './cognito-decoded.interface.js';
import { extractTokenFromHeader } from './utils/extract-token-from-header.js';

Expand All @@ -14,7 +15,7 @@ export class SaaSAuthMiddleware implements NestMiddleware {
throw new UnauthorizedException('Token is missing');
}
try {
const jwtSecret = process.env.MICROSERVICE_JWT_SECRET;
const jwtSecret = appConfig.auth.microserviceJwtSecret;
const data = jwt.verify(token, jwtSecret) as jwt.JwtPayload;
const requestId = data.request_id;

Expand Down
6 changes: 4 additions & 2 deletions backend/src/authorization/temporary-auth.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import { Repository } from 'typeorm';
import { LogOutEntity } from '../entities/log-out/log-out.entity.js';
import { UserEntity } from '../entities/user/user.entity.js';
import { Messages } from '../exceptions/text/messages.js';
import { isTest } from '../helpers/app/is-test.js';
import { Constants } from '../helpers/constants/constants.js';
import { isObjectEmpty } from '../helpers/is-object-empty.js';
import { appConfig } from '../shared/config/app-config.js';
import { IRequestWithCognitoInfo } from './cognito-decoded.interface.js';

@Injectable()
Expand All @@ -30,7 +32,7 @@ export class TemporaryAuthMiddleware implements NestMiddleware {
try {
token = req.cookies[Constants.JWT_COOKIE_KEY_NAME];
} catch (_e) {
if (process.env.NODE_ENV !== 'test') {
if (!isTest()) {
throw new UnauthorizedException('JWT verification failed');
}
}
Expand All @@ -45,7 +47,7 @@ export class TemporaryAuthMiddleware implements NestMiddleware {
}

try {
const jwtSecret = process.env.TEMPORARY_JWT_SECRET;
const jwtSecret = appConfig.auth.temporaryJwtSecret;
const data = jwt.verify(token, jwtSecret) as jwt.JwtPayload;
const userId = data.id;
if (!userId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ConnectionTypeTestEnum } from '@rocketadmin/shared-code/dist/src/shared/enums/connection-types-enum.js';
import { nanoid } from 'nanoid';
import { isTest } from '../../../helpers/app/is-test.js';
import { ConnectionEntity } from '../../connection/connection.entity.js';
import { AgentEntity } from '../agent.entity.js';
import { IAgentRepository } from './agent.repository.interface.js';
Expand All @@ -12,7 +13,7 @@ export const customAgentRepositoryExtension: IAgentRepository = {

async createNewAgentForConnection(connection: ConnectionEntity): Promise<AgentEntity> {
const agent = new AgentEntity();
const token = process.env.NODE_ENV !== 'test' ? nanoid(64) : this.getTestAgentToken(connection.type);
const token = !isTest() ? nanoid(64) : this.getTestAgentToken(connection.type);
agent.setToken(token);
agent.connection = connection;
const savedAgent = await this.save(agent);
Expand Down Expand Up @@ -41,7 +42,7 @@ export const customAgentRepositoryExtension: IAgentRepository = {
},

getTestAgentToken(connectionType: ConnectionTypeTestEnum): string {
if (process.env.NODE_ENV !== 'test') throw new Error('Test agent token can only be used in test environment');
if (!isTest()) throw new Error('Test agent token can only be used in test environment');
switch (connectionType) {
case ConnectionTypeTestEnum.agent_oracledb:
return 'ORACLE-TEST-AGENT-TOKEN';
Expand Down
5 changes: 3 additions & 2 deletions backend/src/entities/ai/user-ai-requests-v2.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { UserId } from '../../decorators/user-id.decorator.js';
import { InTransactionEnum } from '../../enums/in-transaction.enum.js';
import { ConnectionEditGuard } from '../../guards/connection-edit.guard.js';
import { TableAiRequestGuard } from '../../guards/table-ai-request.guard.js';
import { isTest } from '../../helpers/app/is-test.js';
import { ValidationHelper } from '../../helpers/validators/validation-helper.js';
import { SentryInterceptor } from '../../interceptors/sentry.interceptor.js';
import { IAISettingsAndWidgetsCreation, IRequestInfoFromTableV2 } from './ai-use-cases.interface.js';
Expand Down Expand Up @@ -51,7 +52,7 @@ export class UserAIRequestsControllerV2 {
@ApiBody({ type: RequestInfoFromTableBodyDTO })
@ApiQuery({ name: 'tableName', required: true, type: String })
@ApiQuery({ name: 'threadId', required: false, type: String })
@Timeout(process.env.NODE_ENV !== 'test' ? TimeoutDefaults.AI : TimeoutDefaults.AI_TEST)
@Timeout(!isTest() ? TimeoutDefaults.AI : TimeoutDefaults.AI_TEST)
@Post('/ai/v4/request/:connectionId')
public async requestInfoFromTableWithAIWithHistory(
@SlugUuid('connectionId') connectionId: string,
Expand Down Expand Up @@ -90,7 +91,7 @@ export class UserAIRequestsControllerV2 {
description: 'AI settings and widgets creation job has been queued.',
})
@UseGuards(ConnectionEditGuard)
@Timeout(process.env.NODE_ENV !== 'test' ? TimeoutDefaults.AI : TimeoutDefaults.AI_TEST)
@Timeout(!isTest() ? TimeoutDefaults.AI : TimeoutDefaults.AI_TEST)
@Get('/ai/v2/setup/:connectionId')
public async requestAISettingsAndWidgetsCreation(
@SlugUuid('connectionId') connectionId: string,
Expand Down
9 changes: 6 additions & 3 deletions backend/src/entities/amplitude/amplitude.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Injectable, OnModuleInit } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { AmplitudeEventTypeEnum } from '../../enums/amplitude-event-type.enum.js';
import { isTest } from '../../helpers/app/is-test.js';
import { appConfig } from '../../shared/config/app-config.js';
import { UserEntity } from '../user/user.entity.js';

export interface AmplitudeLogOptions {
Expand All @@ -23,8 +25,9 @@ export class AmplitudeService implements OnModuleInit {
) {}

public onModuleInit(): void {
if (process.env.AMPLITUDE_API_KEY) {
this.client = Amplitude.init(process.env.AMPLITUDE_API_KEY);
const amplitudeApiKey = appConfig.thirdParty.amplitudeApiKey;
if (amplitudeApiKey) {
this.client = Amplitude.init(amplitudeApiKey);
}
}

Expand All @@ -34,7 +37,7 @@ export class AmplitudeService implements OnModuleInit {
options?: AmplitudeLogOptions,
): Promise<void> {
try {
if (process.env.NODE_ENV === 'test') return;
if (isTest()) return;
let user_email = (await this.userRepository.findOne({ where: { id: user_id } }))?.email;
if (!user_email && options) {
user_email = options.user_email;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { IGlobalDatabaseContext } from '../../common/application/global-database
import { BaseType } from '../../common/data-injection.tokens.js';
import { SubscriptionLevelEnum } from '../../enums/subscription-level.enum.js';
import { isSaaS } from '../../helpers/app/is-saas.js';
import { isTest } from '../../helpers/app/is-test.js';
import { Constants } from '../../helpers/constants/constants.js';
import { SaasCompanyGatewayService } from '../../microservices/gateways/saas-gateway.ts/saas-company-gateway.service.js';

Expand All @@ -15,7 +16,7 @@ export class CompanyInfoHelperService {
) {}

public async canInviteMoreUsers(companyId: string): Promise<boolean> {
if (!isSaaS() || process.env.NODE_ENV === 'test') {
if (!isSaaS() || isTest()) {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export class InviteUserInCompanyAndConnectionGroupUseCase
email: invitedUserEmail,
role: invitedUserCompanyRole,
};
if (process.env.NODE_ENV === 'test') {
if (isTest()) {
invitationRO.verificationString = rawToken;
}
return invitationRO;
Expand Down
3 changes: 2 additions & 1 deletion backend/src/entities/connection/connection.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
PrimaryColumn,
Relation,
} from 'typeorm';
import { isTest } from '../../helpers/app/is-test.js';
import { Encryptor } from '../../helpers/encryption/encryptor.js';
import { isConnectionTypeAgent } from '../../helpers/is-connection-entity-agent.js';
import { AgentEntity } from '../agent/agent.entity.js';
Expand Down Expand Up @@ -154,7 +155,7 @@ export class ConnectionEntity {
this.id = nanoid(8);
}
this.signing_key = Encryptor.generateRandomString(40);
if (process.env.NODE_ENV === 'test') {
if (isTest()) {
this.signing_key = 'test';
}
if (!isConnectionTypeAgent(this.type)) {
Expand Down
5 changes: 3 additions & 2 deletions backend/src/entities/connection/utils/is-host-allowed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import dns from 'dns';
import ipRangeCheck from 'ip-range-check';
import { Messages } from '../../../exceptions/text/messages.js';
import { isSaaS } from '../../../helpers/app/is-saas.js';
import { isTest } from '../../../helpers/app/is-test.js';
import { Constants } from '../../../helpers/constants/constants.js';
import { isConnectionTypeAgent } from '../../../helpers/is-connection-entity-agent.js';

Expand All @@ -15,10 +16,10 @@ export interface HostCheckData {
}

export async function isHostAllowed(connectionData: HostCheckData): Promise<boolean> {
if (isConnectionTypeAgent(connectionData.type) || process.env.NODE_ENV === 'test') {
if (isConnectionTypeAgent(connectionData.type) || isTest()) {
return true;
}
if (process.env.NODE_ENV !== 'test' && !isSaaS()) {
if (!isTest() && !isSaaS()) {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@rocketadmin/shared-code/dist/src/shared/enums/connection-types-enum.js';
import validator from 'validator';
import { Messages } from '../../../exceptions/text/messages.js';
import { isTest } from '../../../helpers/app/is-test.js';
import { isConnectionTypeAgent } from '../../../helpers/is-connection-entity-agent.js';
import { toPrettyErrorsMsg } from '../../../helpers/to-pretty-errors-msg.js';
import { CreateConnectionDs } from '../application/data-structures/create-connection.ds.js';
Expand Down Expand Up @@ -43,7 +44,7 @@ export async function validateCreateConnectionData(
) {
if (!database) errors.push(Messages.DATABASE_MISSING);

if (process.env.NODE_ENV !== 'test' && !ssh && host) {
if (!isTest() && !ssh && host) {
if (!host.startsWith('mongodb+srv')) {
if (!validator.isFQDN(host) && !validator.isIP(host)) {
errors.push(Messages.HOST_NAME_INVALID);
Expand Down Expand Up @@ -89,7 +90,7 @@ export async function validateCreateConnectionData(
}

function validateConnectionType(type: string): boolean {
if (process.env.NODE_ENV === 'test') {
if (isTest()) {
return !!Object.keys(ConnectionTypeTestEnum).find((key) => key === type);
}
return !!Object.keys(ConnectionTypesEnum).find((key) => key === type);
Expand Down
20 changes: 8 additions & 12 deletions backend/src/entities/email/email-config/email-config.service.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import { Injectable } from '@nestjs/common';
import { appConfig } from '../../../shared/config/app-config.js';
import { IEmailConfig, IEmailConfigService } from './email-config.interface.js';

@Injectable()
export class EmailConfigService implements IEmailConfigService {
public getEmailServiceConfig(): IEmailConfig | string {
const pullConfig = process.env.EMAIL_CONFIG_STRING;
if (pullConfig) {
return pullConfig;
const { configString, host, port, username, password, nonSecure } = appConfig.email;
if (configString) {
return configString;
}
const emailServiceHost = process.env.EMAIL_SERVICE_HOST;
const emailServicePort = parseInt(process.env.EMAIL_SERVICE_PORT, 10) || 25;
const emailServiceUserName = process.env.EMAIL_SERVICE_USERNAME;
const emailServicePassword = process.env.EMAIL_SERVICE_PASSWORD;
const nonSecure = !process.env.NON_SSL_EMAIL;
return {
host: emailServiceHost,
port: emailServicePort,
host: host,
port: port,
secure: nonSecure,
auth: {
user: emailServiceUserName,
pass: emailServicePassword,
user: username,
pass: password,
},
socketTimeout: 4 * 1000,
connectionTimeout: 4 * 1000,
Expand Down
7 changes: 4 additions & 3 deletions backend/src/entities/email/email/email.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import * as nunjucks from 'nunjucks';
import PQueue from 'p-queue';
import { BaseType } from '../../../common/data-injection.tokens.js';
import { TableActionEventEnum } from '../../../enums/table-action-event-enum.js';
import { isTest } from '../../../helpers/app/is-test.js';
import { Constants } from '../../../helpers/constants/constants.js';
import { getProcessVariable } from '../../../helpers/get-process-variable.js';
import { appConfig } from '../../../shared/config/app-config.js';
import { WinstonLogger } from '../../logging/winston-logger.js';
import { UserInfoMessageData } from '../../table-actions/table-actions-module/table-action-activation.service.js';
import { EmailLetter } from '../email-messages/email-message.js';
Expand All @@ -25,7 +26,7 @@ export interface ICronMessagingResults {

@Injectable()
export class EmailService {
private readonly emailFrom = getProcessVariable('EMAIL_FROM') || Constants.AUTOADMIN_SUPPORT_MAIL;
private readonly emailFrom = appConfig.email.from;
constructor(
@Inject(BaseType.NUNJUCKS)
private readonly nunjucksEnv: nunjucks.Environment,
Expand All @@ -34,7 +35,7 @@ export class EmailService {
) {}

public async sendEmailToUser(letterContent: IMessage): Promise<SMTPTransport.SentMessageInfo | null> {
if (process.env.NODE_ENV === 'test') return;
if (isTest()) return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Return null explicitly in test mode.

Line 38 currently returns undefined in a method contract that uses null for “no mail sent”, which can break callers that only branch on null.

Proposed fix
 	public async sendEmailToUser(letterContent: IMessage): Promise<SMTPTransport.SentMessageInfo | null> {
-		if (isTest()) return;
+		if (isTest()) return null;
 		const mailResult = await this.sendEmailWithTimeout(letterContent);
 		if (mailResult) {
 			return mailResult;
 		}
+		return null;
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (isTest()) return;
public async sendEmailToUser(letterContent: IMessage): Promise<SMTPTransport.SentMessageInfo | null> {
if (isTest()) return null;
const mailResult = await this.sendEmailWithTimeout(letterContent);
if (mailResult) {
return mailResult;
}
return null;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/entities/email/email/email.service.ts` at line 38, The test-mode
guard currently does "if (isTest()) return;" which returns undefined but callers
expect null for "no mail sent"; change that branch to "if (isTest()) return
null;" so the method in email.service.ts (the isTest() check inside the email
sending method) returns null explicitly in test mode to match the method
contract and avoid breaking null-only checks.

const mailResult = await this.sendEmailWithTimeout(letterContent);
if (mailResult) {
return mailResult;
Expand Down
Loading
Loading