|
|
@@ -12,6 +12,7 @@ import { configManager } from '~/server/service/config-manager';
|
|
|
import { growiInfoService } from '~/server/service/growi-info';
|
|
|
import loggerFactory from '~/utils/logger';
|
|
|
|
|
|
+import { assertFileNameSafeForBaseDir } from '../util/safe-path-utils';
|
|
|
import type { GlobalNotificationEventVars } from './types';
|
|
|
|
|
|
const _logger = loggerFactory('growi:service:GlobalNotificationMailService');
|
|
|
@@ -89,7 +90,7 @@ class GlobalNotificationMailService {
|
|
|
triggeredBy: IUser,
|
|
|
{ comment, oldPath }: GlobalNotificationEventVars,
|
|
|
): MailOption {
|
|
|
- const locale = configManager.getConfig('app:globalLang');
|
|
|
+ let locale = configManager.getConfig('app:globalLang');
|
|
|
// validate for all events
|
|
|
if (event == null || page == null || triggeredBy == null) {
|
|
|
throw new Error(
|
|
|
@@ -97,6 +98,15 @@ class GlobalNotificationMailService {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ try {
|
|
|
+ assertFileNameSafeForBaseDir(locale, this.crowi.localeDir);
|
|
|
+ } catch (err) {
|
|
|
+ _logger.error(
|
|
|
+ `Path traversal attempt detected in app:globalLang: '${locale}'. Fallback to 'en_US'.`,
|
|
|
+ );
|
|
|
+ locale = 'en_US';
|
|
|
+ }
|
|
|
+
|
|
|
const template = nodePath.join(
|
|
|
this.crowi.localeDir,
|
|
|
`${locale}/notifications/${event}.ejs`,
|