mirror of
https://github.com/hexastack/hexabot
synced 2025-06-26 18:27:28 +00:00
fix: load origins from settings
This commit is contained in:
parent
d9ef2152b7
commit
2694a4f802
24
api/src/app.instance.ts
Normal file
24
api/src/app.instance.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright © 2025 Hexastack. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
|
||||
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
|
||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||
*/
|
||||
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
|
||||
export class AppInstance {
|
||||
private static app: INestApplication;
|
||||
|
||||
static setApp(app: INestApplication) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
static getApp(): INestApplication {
|
||||
if (!this.app) {
|
||||
throw new Error('App instance has not been set yet.');
|
||||
}
|
||||
return this.app;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Hexastack. All rights reserved.
|
||||
* Copyright © 2025 Hexastack. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
|
||||
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
|
||||
@ -18,6 +18,7 @@ moduleAlias.addAliases({
|
||||
'@': __dirname,
|
||||
});
|
||||
|
||||
import { AppInstance } from './app.instance';
|
||||
import { HexabotModule } from './app.module';
|
||||
import { config } from './config';
|
||||
import { LoggerService } from './logger/logger.service';
|
||||
@ -36,6 +37,9 @@ async function bootstrap() {
|
||||
bodyParser: false,
|
||||
});
|
||||
|
||||
// Set the global app instance
|
||||
AppInstance.setApp(app);
|
||||
|
||||
const rawBodyBuffer = (req, res, buf, encoding) => {
|
||||
if (buf?.length) {
|
||||
req.rawBody = buf.toString(encoding || 'utf8');
|
||||
@ -45,10 +49,10 @@ async function bootstrap() {
|
||||
app.use(bodyParser.json({ verify: rawBodyBuffer }));
|
||||
|
||||
const settingService = app.get<SettingService>(SettingService);
|
||||
const allowedDomains = await settingService.getAllowedDomains();
|
||||
const allowedOrigins = await settingService.getAllowedOrigins();
|
||||
app.enableCors({
|
||||
origin: (origin, callback) => {
|
||||
if (!origin || allowedDomains.has(origin)) {
|
||||
if (!origin || allowedOrigins.has(origin)) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
callback(new Error('Not allowed by CORS'));
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Hexastack. All rights reserved.
|
||||
* Copyright © 2025 Hexastack. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
|
||||
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
|
||||
@ -15,7 +15,7 @@ import { config } from '@/config';
|
||||
import { Config } from '@/config/types';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import {
|
||||
ALLOWED_DOMAINS_CACHE_KEY,
|
||||
ALLOWED_ORIGINS_CACHE_KEY,
|
||||
SETTING_CACHE_KEY,
|
||||
} from '@/utils/constants/cache';
|
||||
import { Cacheable } from '@/utils/decorators/cacheable.decorator';
|
||||
@ -113,7 +113,7 @@ export class SettingService extends BaseService<Setting> {
|
||||
*/
|
||||
async clearCache() {
|
||||
this.cacheManager.del(SETTING_CACHE_KEY);
|
||||
this.cacheManager.del(ALLOWED_DOMAINS_CACHE_KEY);
|
||||
this.cacheManager.del(ALLOWED_ORIGINS_CACHE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,20 +126,24 @@ export class SettingService extends BaseService<Setting> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves allowed_domains from the cache if available, or loads them from the
|
||||
* repository and caches the result.
|
||||
* Retrieves a set of unique allowed origins for CORS configuration.
|
||||
*
|
||||
* @returns A promise that resolves to a Set of`allowed_domains` string.
|
||||
* This method combines all `allowed_domains` settings,
|
||||
* splits their values (comma-separated), and removes duplicates to produce a
|
||||
* whitelist of origins. The result is cached for better performance using the
|
||||
* `Cacheable` decorator with the key `ALLOWED_ORIGINS_CACHE_KEY`.
|
||||
*
|
||||
* @returns A promise that resolves to a set of allowed origins
|
||||
*/
|
||||
@Cacheable(ALLOWED_DOMAINS_CACHE_KEY)
|
||||
async getAllowedDomains() {
|
||||
// combines all allowed_doamins and whitelist them for cors
|
||||
@Cacheable(ALLOWED_ORIGINS_CACHE_KEY)
|
||||
async getAllowedOrigins() {
|
||||
const settings = await this.find({ label: 'allowed_domains' });
|
||||
|
||||
const whiteListedOrigins = new Set(
|
||||
const uniqueOrigins = new Set(
|
||||
settings.flatMap((setting) => setting.value.split(',')),
|
||||
);
|
||||
return whiteListedOrigins;
|
||||
|
||||
return uniqueOrigins;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Hexastack. All rights reserved.
|
||||
* Copyright © 2025 Hexastack. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
|
||||
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
|
||||
@ -17,4 +17,4 @@ export const LANGUAGES_CACHE_KEY = 'languages';
|
||||
|
||||
export const DEFAULT_LANGUAGE_CACHE_KEY = 'default_language';
|
||||
|
||||
export const ALLOWED_DOMAINS_CACHE_KEY = 'allowed-domains';
|
||||
export const ALLOWED_ORIGINS_CACHE_KEY = 'allowed_origins';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Hexastack. All rights reserved.
|
||||
* Copyright © 2025 Hexastack. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
|
||||
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
|
||||
@ -10,7 +10,9 @@ import util from 'util';
|
||||
|
||||
import type { ServerOptions } from 'socket.io';
|
||||
|
||||
import { AppInstance } from '@/app.instance';
|
||||
import { config } from '@/config';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
|
||||
export const buildWebSocketGatewayOptions = (): Partial<ServerOptions> => {
|
||||
const opts: Partial<ServerOptions> = {
|
||||
@ -53,16 +55,25 @@ export const buildWebSocketGatewayOptions = (): Partial<ServerOptions> => {
|
||||
...(config.sockets.onlyAllowOrigins && {
|
||||
cors: {
|
||||
origin: (origin, cb) => {
|
||||
if (origin && config.sockets.onlyAllowOrigins.includes(origin)) {
|
||||
cb(null, true);
|
||||
} else {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
`A socket was rejected via the config.sockets.onlyAllowOrigins array.\n` +
|
||||
`It attempted to connect with origin: ${origin}`,
|
||||
);
|
||||
cb(new Error('Origin not allowed'), false);
|
||||
}
|
||||
// Retrieve the allowed origins from the settings
|
||||
const app = AppInstance.getApp();
|
||||
const settingService = app.get<SettingService>(SettingService);
|
||||
|
||||
settingService
|
||||
.getAllowedOrigins()
|
||||
.then((allowedOrigins) => {
|
||||
if (origin && allowedOrigins.has(origin)) {
|
||||
cb(null, true);
|
||||
} else {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
`A socket was rejected via the config.sockets.onlyAllowOrigins array.\n` +
|
||||
`It attempted to connect with origin: ${origin}`,
|
||||
);
|
||||
cb(new Error('Origin not allowed'), false);
|
||||
}
|
||||
})
|
||||
.catch(cb);
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user