|
|
@@ -1,4 +1,3 @@
|
|
|
-import nodePath from 'node:path';
|
|
|
import { SCOPE } from '@growi/core/dist/interfaces';
|
|
|
import { ErrorV3 } from '@growi/core/dist/models';
|
|
|
import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
|
|
|
@@ -6,7 +5,6 @@ import { userHomepagePath } from '@growi/core/dist/utils/page-path-utils';
|
|
|
import escapeStringRegexp from 'escape-string-regexp';
|
|
|
import express from 'express';
|
|
|
import { body, query } from 'express-validator';
|
|
|
-import path from 'pathe';
|
|
|
import { isEmail } from 'validator';
|
|
|
|
|
|
import ExternalUserGroupRelation from '~/features/external-user-group/server/models/external-user-group-relation';
|
|
|
@@ -27,7 +25,7 @@ import loggerFactory from '~/utils/logger';
|
|
|
|
|
|
import { generateAddActivityMiddleware } from '../../middlewares/add-activity';
|
|
|
import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';
|
|
|
-import { assertFileNameSafeForBaseDir } from '../../util/safe-path-utils';
|
|
|
+import { resolveLocalePath } from '../../util/safe-path-utils';
|
|
|
|
|
|
const logger = loggerFactory('growi:routes:apiv3:users');
|
|
|
|
|
|
@@ -208,38 +206,12 @@ module.exports = (crowi) => {
|
|
|
const sendEmailByUserList = async (userList) => {
|
|
|
const { appService, mailService } = crowi;
|
|
|
const appTitle = appService.getAppTitle();
|
|
|
- const SUPPORTED_LOCALES = ['en_US', 'ja_JP', 'zh_CN'];
|
|
|
- let locale = configManager.getConfig('app:globalLang');
|
|
|
-
|
|
|
- if (!SUPPORTED_LOCALES.includes(locale)) {
|
|
|
- logger.warn(
|
|
|
- `Invalid or untrusted locale detected: '${locale}'. Falling back to 'en_US' for safety.`,
|
|
|
- );
|
|
|
- locale = 'en_US';
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- assertFileNameSafeForBaseDir(locale, crowi.localeDir);
|
|
|
- } catch (_err) {
|
|
|
- logger.error(
|
|
|
- `Path traversal attempt detected in locale: '${locale}'. Fallback to 'en_US'.`,
|
|
|
- );
|
|
|
- locale = 'en_US';
|
|
|
- }
|
|
|
-
|
|
|
- const templatePath = path.join(
|
|
|
+ const locale = configManager.getConfig('app:globalLang');
|
|
|
+ const templatePath = resolveLocalePath(
|
|
|
+ locale,
|
|
|
crowi.localeDir,
|
|
|
- `${locale}/admin/userInvitation.ejs`,
|
|
|
+ 'admin/userInvitation.ejs',
|
|
|
);
|
|
|
- const normalizedTemplatePath = nodePath.resolve(templatePath);
|
|
|
- const baseDir = nodePath.resolve(crowi.localeDir);
|
|
|
-
|
|
|
- if (!normalizedTemplatePath.startsWith(baseDir)) {
|
|
|
- logger.error(
|
|
|
- `Security Alert: Path traversal attempted! Resolved path: ${normalizedTemplatePath}`,
|
|
|
- );
|
|
|
- throw new Error('Path traversal detected! Blocking template access.');
|
|
|
- }
|
|
|
|
|
|
const failedToSendEmailList = [];
|
|
|
|
|
|
@@ -273,38 +245,12 @@ module.exports = (crowi) => {
|
|
|
const sendEmailByUser = async (user) => {
|
|
|
const { appService, mailService } = crowi;
|
|
|
const appTitle = appService.getAppTitle();
|
|
|
- const SUPPORTED_LOCALES = ['en_US', 'ja_JP', 'zh_CN'];
|
|
|
- let locale = configManager.getConfig('app:globalLang');
|
|
|
-
|
|
|
- if (!SUPPORTED_LOCALES.includes(locale)) {
|
|
|
- logger.warn(
|
|
|
- `Invalid or untrusted locale detected: '${locale}'. Falling back to 'en_US' for safety.`,
|
|
|
- );
|
|
|
- locale = 'en_US';
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- assertFileNameSafeForBaseDir(locale, crowi.localeDir);
|
|
|
- } catch (_err) {
|
|
|
- logger.error(
|
|
|
- `Path traversal attempt detected in locale: '${locale}'. Fallback to 'en_US'.`,
|
|
|
- );
|
|
|
- locale = 'en_US';
|
|
|
- }
|
|
|
-
|
|
|
- const templatePath = path.join(
|
|
|
+ const locale = configManager.getConfig('app:globalLang');
|
|
|
+ const templatePath = resolveLocalePath(
|
|
|
+ locale,
|
|
|
crowi.localeDir,
|
|
|
- `${locale}/admin/userResetPassword.ejs`,
|
|
|
+ 'admin/userResetPassword.ejs',
|
|
|
);
|
|
|
- const normalizedTemplatePath = nodePath.resolve(templatePath);
|
|
|
- const baseDir = nodePath.resolve(crowi.localeDir);
|
|
|
-
|
|
|
- if (!normalizedTemplatePath.startsWith(baseDir)) {
|
|
|
- logger.error(
|
|
|
- `Security Alert: Path traversal attempted! Resolved path: ${normalizedTemplatePath}`,
|
|
|
- );
|
|
|
- throw new Error('Path traversal detected! Blocking template access.');
|
|
|
- }
|
|
|
|
|
|
await mailService.send({
|
|
|
to: user.email,
|