Merge branch 'main' into next

This commit is contained in:
mytharcher
2026-06-01 11:29:43 +08:00
16 changed files with 148 additions and 34 deletions
+14
View File
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v2.0.60](https://github.com/nocobase/nocobase/compare/v2.0.59...v2.0.60) - 2026-05-29
### 🚀 Improvements
- **[AI employees]** Improved the LLM Base URL field so it can use global-scope variables in create and edit forms. ([#9615](https://github.com/nocobase/nocobase/pull/9615)) by @cgyrock
### 🐛 Bug Fixes
- **[client]** Fix the badge width in the top navigation bar ([#9607](https://github.com/nocobase/nocobase/pull/9607)) by @zhangzhonghe
- **[AI employees]** Fixed AI shortcut buttons getting an empty block context after referenced table blocks are removed. ([#9617](https://github.com/nocobase/nocobase/pull/9617)) by @cgyrock
- **[Migration manager]** Fix PostgreSQL migration diffs so child inherited columns are not dropped when a local column becomes inherited. by @hongboji
## [v2.0.59](https://github.com/nocobase/nocobase/compare/v2.0.58...v2.0.59) - 2026-05-28
### 🐛 Bug Fixes
+14
View File
@@ -5,6 +5,20 @@
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
并且本项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。
## [v2.0.60](https://github.com/nocobase/nocobase/compare/v2.0.59...v2.0.60) - 2026-05-29
### 🚀 优化
- **[AI 员工]** 改进 LLM 的 Base URL 字段,使其在创建和编辑表单中都支持使用全局变量。 ([#9615](https://github.com/nocobase/nocobase/pull/9615)) by @cgyrock
### 🐛 修复
- **[client]** 修复顶部导航栏数字徽标背景过宽的问题 ([#9607](https://github.com/nocobase/nocobase/pull/9607)) by @zhangzhonghe
- **[AI 员工]** 修复引用表格区块删除后 AI 快捷操作按钮上下文变成一个空区块的问题。 ([#9617](https://github.com/nocobase/nocobase/pull/9617)) by @cgyrock
- **[迁移管理]** 修复 PostgreSQL 迁移差异计算,避免子表本地列转为继承列时错误生成删除列语句。 by @hongboji
## [v2.0.59](https://github.com/nocobase/nocobase/compare/v2.0.58...v2.0.59) - 2026-05-28
### 🐛 修复
+4 -2
View File
@@ -67,7 +67,9 @@ JavaScript 脚本节点支持两种执行引擎,通过环境变量 `WORKFLOW_S
当**配置了** `WORKFLOW_SCRIPT_MODULES` 环境变量时,脚本切换为 Node.js 内置的 `vm` 引擎执行,以获得 `require` 能力。
:::warning{title="安全警告"}
非安全模式下,脚本虽然运行在 `vm` 沙箱中并限制了可用模块,但 Node.js 的 `vm` 模块并非安全的沙箱机制。启用此模式意味着信任所有有权编辑工作流脚本的用户。管理员应当自行评估安全风险,并严格管控模块白名单和工作流编辑权限。
非安全模式仅使用 Node.js 的 `vm` 来提供 CommonJS `require` 能力。Node.js 的 `vm` 模块并非安全的沙箱机制。启用此模式意味着信任所有有权编辑、测试或运行工作流脚本的用户,等同于允许这些用户以 NocoBase 服务端进程权限执行代码。
`WORKFLOW_SCRIPT_MODULES` 不是安全边界,也不是权限模型。它只用于控制脚本执行前 `require()` 可接受的模块名称。
:::
在脚本中使用模块与 CommonJS 一致,代码中使用 `require()` 指令引入模块。
@@ -79,7 +81,7 @@ WORKFLOW_SCRIPT_MODULES=crypto,timers,lodash,dayjs
```
:::info{title="提示"}
在环境变量 `WORKFLOW_SCRIPT_MODULES` 中未声明的模块,即使是 Node.js 原生的或 `node_modules` 中已安装的,也**不能**在脚本中使用。该策略可以用于在运维层管控用户可使用的模块列表,在一些场景下避免脚本权限过高。
在环境变量 `WORKFLOW_SCRIPT_MODULES` 中未声明的模块,即使是 Node.js 原生的或 `node_modules` 中已安装的,也**不能**通过 `require()` 直接引入。该列表仅用于配置支持的模块导入,不应依赖它来降低脚本权限,也不应以此将脚本编辑能力安全地委派给较低信任级别的用户。
:::
在非源码部署的环境下,如果某个模块未在 node_modules 中安装,可以将需要的包手动安装到 storage 目录中。例如需要使用 `exceljs` 包时,可以执行如下操作:
+5 -3
View File
@@ -64,7 +64,9 @@ Dies ist der empfohlene Standardmodus, geeignet für reine Berechnungs- und Date
Wenn `WORKFLOW_SCRIPT_MODULES` **konfiguriert ist**, wechseln Skripte zur integrierten Node.js-`vm`-Engine, um die `require`-Funktionalität zu ermöglichen.
:::warning{title="Sicherheitswarnung"}
Im unsicheren Modus werden Skripte zwar in einer `vm`-Sandbox mit eingeschränkter Modul-Whitelist ausgeführt, jedoch ist das Node.js-`vm`-Modul kein sicherer Sandbox-Mechanismus. Die Aktivierung dieses Modus bedeutet, dass allen Benutzern vertraut wird, die die Berechtigung zum Bearbeiten von Workflow-Skripten haben. Administratoren sollten die Sicherheitsrisiken eigenständig bewerten und die Modul-Whitelist sowie die Berechtigungen zur Workflow-Bearbeitung streng kontrollieren.
Der unsichere Modus verwendet Node.js `vm` nur, um CommonJS-`require` zu unterstützen. Das Node.js-`vm`-Modul ist kein sicherer Sandbox-Mechanismus. Die Aktivierung dieses Modus bedeutet, dass allen Benutzern vertraut wird, die Workflow-Skripte bearbeiten, testen oder ausführen können, als könnten sie Code mit den Berechtigungen des NocoBase-Servers ausführen.
`WORKFLOW_SCRIPT_MODULES` ist keine Sicherheitsgrenze und kein Berechtigungsmodell. Es steuert nur, welche Modulnamen von `require()` akzeptiert werden, bevor der Skriptcode ausgeführt wird.
:::
Module können im Skript konsistent mit CommonJS verwendet werden. Module werden im Code mit der `require()`-Anweisung importiert.
@@ -76,7 +78,7 @@ WORKFLOW_SCRIPT_MODULES=crypto,timers,lodash,dayjs
```
:::info{title="Hinweis"}
Module, die nicht in der Umgebungsvariable `WORKFLOW_SCRIPT_MODULES` deklariert sind, können im Skript **nicht** verwendet werden, selbst wenn sie nativ in Node.js vorhanden oder bereits in `node_modules` installiert sind. Diese Richtlinie kann auf Betriebsebene genutzt werden, um die Liste der für Benutzer verfügbaren Module zu steuern und in bestimmten Szenarien zu verhindern, dass Skripte übermäßige Berechtigungen erhalten.
Module, die nicht in der Umgebungsvariable `WORKFLOW_SCRIPT_MODULES` deklariert sind, können nicht direkt mit `require()` importiert werden, selbst wenn sie nativ in Node.js vorhanden oder bereits in `node_modules` installiert sind. Diese Liste dient nur zur Konfiguration unterstützter Imports. Verlassen Sie sich nicht darauf, um Skriptberechtigungen zu reduzieren oder die Bearbeitung von Skripten sicher an weniger vertrauenswürdige Benutzer zu delegieren.
:::
In einer Umgebung, die nicht aus dem Quellcode bereitgestellt wird, können Sie ein benötigtes Modul, das nicht in `node_modules` installiert ist, manuell in das `storage`-Verzeichnis installieren. Wenn Sie beispielsweise das `exceljs`-Paket verwenden möchten, können Sie die folgenden Schritte ausführen:
@@ -162,4 +164,4 @@ async function sleep(time) {
await sleep(1000);
return 123;
```
```
+4 -2
View File
@@ -64,7 +64,9 @@ This is the recommended default mode, suitable for pure computation and data pro
When `WORKFLOW_SCRIPT_MODULES` **is configured**, scripts switch to the Node.js built-in `vm` engine to enable `require` capability.
:::warning{title="Security Warning"}
In unsafe mode, although scripts run in a `vm` sandbox with a restricted module whitelist, the Node.js `vm` module is not a secure sandbox mechanism. Enabling this mode implies trusting all users who have permission to edit workflow scripts. Administrators should assess the security risks independently and strictly control the module whitelist and workflow editing permissions.
Unsafe mode uses Node.js `vm` only to provide CommonJS `require` support. The Node.js `vm` module is not a secure sandbox mechanism. Enabling this mode means trusting every user who can edit, test, or run workflow scripts as someone who can execute code with the NocoBase server's privileges.
`WORKFLOW_SCRIPT_MODULES` is not a security boundary or a permission model. It only controls which module names are accepted by `require()` before script code runs.
:::
Modules can be used in the script consistent with CommonJS, using the `require()` directive to import modules.
@@ -76,7 +78,7 @@ WORKFLOW_SCRIPT_MODULES=crypto,timers,lodash,dayjs
```
:::info{title="Note"}
Modules not declared in the `WORKFLOW_SCRIPT_MODULES` environment variable **cannot** be used in the script, even if they are native to Node.js or already installed in `node_modules`. This policy can be used at the operational level to control the list of modules available to users, preventing scripts from having excessive permissions in some scenarios.
Modules not declared in the `WORKFLOW_SCRIPT_MODULES` environment variable **cannot** be imported directly with `require()`, even if they are native to Node.js or already installed in `node_modules`. This list is intended only to configure supported imports. Do not rely on it to reduce script permissions or to safely delegate script editing to less-trusted users.
:::
When in a non-source-deployed environment, if a module is not installed in `node_modules`, you can manually install the required package into the `storage` directory. For example, to use the `exceljs` package, you can perform the following steps:
+5 -3
View File
@@ -64,7 +64,9 @@ Este es el modo predeterminado recomendado, adecuado para lógica de cálculo pu
Cuando `WORKFLOW_SCRIPT_MODULES` **está configurada**, los scripts cambian al motor `vm` integrado de Node.js para habilitar la capacidad de `require`.
:::warning{title="Advertencia de seguridad"}
En el modo no seguro, aunque los scripts se ejecutan en un sandbox `vm` con una lista blanca de módulos restringida, el módulo `vm` de Node.js no es un mecanismo de sandbox seguro. Habilitar este modo implica confiar en todos los usuarios que tienen permiso para editar scripts de flujo de trabajo. Los administradores deben evaluar los riesgos de seguridad de forma independiente y controlar estrictamente la lista blanca de módulos y los permisos de edición de flujos de trabajo.
El modo no seguro usa el módulo `vm` de Node.js solo para proporcionar soporte de CommonJS `require`. El módulo `vm` de Node.js no es un mecanismo de sandbox seguro. Habilitar este modo significa confiar en todos los usuarios que pueden editar, probar o ejecutar scripts de flujo de trabajo como usuarios capaces de ejecutar código con los privilegios del servidor NocoBase.
`WORKFLOW_SCRIPT_MODULES` no es una frontera de seguridad ni un modelo de permisos. Solo controla qué nombres de módulos acepta `require()` antes de que se ejecute el código del script.
:::
Los módulos pueden usarse en el script de forma consistente con CommonJS, utilizando la directiva `require()` para importarlos.
@@ -76,7 +78,7 @@ WORKFLOW_SCRIPT_MODULES=crypto,timers,lodash,dayjs
```
:::info{title="Nota"}
Los módulos no declarados en la variable de entorno `WORKFLOW_SCRIPT_MODULES` **no pueden** usarse en el script, incluso si son nativos de Node.js o ya están instalados en `node_modules`. Esta política puede utilizarse a nivel operativo para controlar la lista de módulos disponibles para los usuarios, evitando que los scripts tengan permisos excesivos en algunos escenarios.
Los módulos no declarados en la variable de entorno `WORKFLOW_SCRIPT_MODULES` **no pueden** importarse directamente con `require()`, incluso si son nativos de Node.js o ya están instalados en `node_modules`. Esta lista solo sirve para configurar imports admitidos. No confíe en ella para reducir los permisos de los scripts ni para delegar de forma segura la edición de scripts a usuarios de menor confianza.
:::
En un entorno sin despliegue desde el código fuente, si un módulo no está instalado en `node_modules`, puede instalar manualmente el paquete requerido en el directorio `storage`. Por ejemplo, para usar el paquete `exceljs`, puede realizar los siguientes pasos:
@@ -162,4 +164,4 @@ async function sleep(time) {
await sleep(1000);
return 123;
```
```
+5 -3
View File
@@ -64,7 +64,9 @@ C'est le mode par défaut recommandé, adapté aux logiques de calcul pur et de
Lorsque `WORKFLOW_SCRIPT_MODULES` **est configurée**, les scripts basculent vers le moteur `vm` natif de Node.js pour activer la fonctionnalité `require`.
:::warning{title="Avertissement de sécurité"}
En mode non sécurisé, bien que les scripts s'exécutent dans un bac à sable `vm` avec une liste blanche de modules restreinte, le module `vm` de Node.js n'est pas un mécanisme de bac à sable sécurisé. L'activation de ce mode implique de faire confiance à tous les utilisateurs ayant la permission de modifier les scripts de flux de travail. Les administrateurs doivent évaluer les risques de sécurité de manière indépendante et contrôler strictement la liste blanche des modules et les permissions de modification des flux de travail.
Le mode non sécurisé utilise le module `vm` de Node.js uniquement pour fournir la prise en charge de CommonJS `require`. Le module `vm` de Node.js n'est pas un mécanisme de bac à sable sécurisé. L'activation de ce mode implique de faire confiance à tous les utilisateurs pouvant modifier, tester ou exécuter des scripts de flux de travail comme à des utilisateurs capables d'exécuter du code avec les privilèges du serveur NocoBase.
`WORKFLOW_SCRIPT_MODULES` n'est ni une frontière de sécurité ni un modèle de permissions. Il contrôle seulement les noms de modules acceptés par `require()` avant l'exécution du script.
:::
Les modules peuvent être utilisés dans le script conformément à CommonJS, en utilisant la directive `require()` pour les importer.
@@ -75,8 +77,8 @@ Prend en charge les modules natifs de Node.js et les modules installés dans `no
WORKFLOW_SCRIPT_MODULES=crypto,timers,lodash,dayjs
```
:::info{title="Conseil"}
Les modules non déclarés dans la variable d'environnement `WORKFLOW_SCRIPT_MODULES`, même s'ils sont natifs de Node.js ou installés dans `node_modules`, **ne peuvent pas** être utilisés dans le script. Cette stratégie peut être utilisée au niveau de l'exploitation et de la maintenance pour contrôler la liste des modules utilisables par les utilisateurs, évitant ainsi des permissions de script trop élevées dans certains scénarios.
:::info{title="Note"}
Les modules non déclarés dans la variable d'environnement `WORKFLOW_SCRIPT_MODULES`, même s'ils sont natifs de Node.js ou déjà installés dans `node_modules`, **ne peuvent pas** être importés directement avec `require()`. Cette liste sert uniquement à configurer les imports pris en charge. Ne l'utilisez pas pour réduire les permissions des scripts ni pour déléguer en sécurité la modification des scripts à des utilisateurs moins fiables.
:::
Dans un environnement qui n'est pas déployé à partir des sources, si un module n'est pas installé dans `node_modules`, vous pouvez installer manuellement le paquet nécessaire dans le répertoire `storage`. Par exemple, si vous avez besoin d'utiliser le paquet `exceljs`, vous pouvez effectuer les opérations suivantes :
+4 -2
View File
@@ -63,7 +63,9 @@ JavaScriptスクリプトノードは、環境変数`WORKFLOW_SCRIPT_MODULES`の
`WORKFLOW_SCRIPT_MODULES`が**設定されている**場合、`require`機能を有効にするため、スクリプトはNode.js組み込みの`vm`エンジンに切り替わります。
:::warning{title="セキュリティ警告"}
非セーフモードでは、スクリプトはモジュールホワイトリストが制限された`vm`サンドボックスで実行されますが、Node.jsの`vm`モジュールはセキュアなサンドボックスメカニズムではありません。このモードを有効にすることは、ワークフロースクリプトの編集権限を持つすべてのユーザーを信頼することを意味します。管理者はセキュリティリスクを独自に評価し、モジュールホワイトリストとワークフロー編集権限を厳密に管理する必要があります。
非セーフモードでは、CommonJS の `require` を提供するためだけに Node.js の `vm` を使用します。Node.js の `vm` モジュールはセキュアなサンドボックスメカニズムではありません。このモードを有効にすることは、ワークフロースクリプトを編集、テスト、または実行できるすべてのユーザーを、NocoBase サーバーの権限でコードを実行できるユーザーとして信頼することを意味します。
`WORKFLOW_SCRIPT_MODULES` はセキュリティ境界でも権限モデルでもありません。スクリプトコードの実行前に、`require()` が受け付けるモジュール名を制御するだけです。
:::
スクリプトでは、CommonJSと同様に、`require()`ディレクティブを使用してモジュールをインポートできます。
@@ -75,7 +77,7 @@ WORKFLOW_SCRIPT_MODULES=crypto,timers,lodash,dayjs
```
:::info{title="ヒント"}
環境変数 `WORKFLOW_SCRIPT_MODULES` で宣言されていないモジュールは、Node.js ネイティブのものや `node_modules` にインストールされているものであっても、スクリプト内で使用することは**できません**。このポリシーは、運用管理層でユーザーが使用できるモジュールリストを制御するために使用でき、一部のシナリオでスクリプトの権限が過剰になるのを防ぐことができます。
環境変数`WORKFLOW_SCRIPT_MODULES`で宣言されていないモジュールは、Node.jsネイティブのものであっても、`node_modules`にインストール済みであっても、`require()` で直接インポートすることは**できません**。このリストは、サポートするインポートを設定するためだけのものです。スクリプト権限を下げたり、信頼度の低いユーザーへスクリプト編集権限を安全に委任したりする目的で依存しないでください。
:::
ソースコードデプロイではない環境で、特定のモジュールが node_modules にインストールされていない場合、必要なパッケージを storage ディレクトリに手動でインストールできます。例えば、`exceljs` パッケージを使用する必要がある場合は、以下の操作を実行します。
+4 -2
View File
@@ -64,7 +64,9 @@ Este é o modo padrão recomendado, adequado para lógica de computação pura e
Quando `WORKFLOW_SCRIPT_MODULES` **está configurada**, os scripts utilizam o motor `vm` nativo do Node.js para habilitar a funcionalidade `require`.
:::warning{title="Aviso de segurança"}
No modo não seguro, embora os scripts sejam executados em um sandbox `vm` com uma lista restrita de módulos permitidos, o módulo `vm` do Node.js não é um mecanismo de sandbox seguro. Habilitar este modo implica confiar em todos os usuários que têm permissão para editar scripts de fluxo de trabalho. Os administradores devem avaliar os riscos de segurança de forma independente e controlar rigorosamente a lista de módulos permitidos e as permissões de edição de fluxos de trabalho.
O modo não seguro usa o módulo `vm` do Node.js apenas para fornecer suporte a CommonJS `require`. O módulo `vm` do Node.js não é um mecanismo de sandbox seguro. Habilitar este modo significa confiar em todos os usuários que podem editar, testar ou executar scripts de fluxo de trabalho como usuários capazes de executar código com os privilégios do servidor NocoBase.
`WORKFLOW_SCRIPT_MODULES` não é uma fronteira de segurança nem um modelo de permissões. Ele controla apenas quais nomes de módulos são aceitos por `require()` antes da execução do script.
:::
Os módulos podem ser usados no script de forma consistente com o CommonJS, utilizando a diretiva `require()` para importar módulos.
@@ -76,7 +78,7 @@ WORKFLOW_SCRIPT_MODULES=crypto,timers,lodash,dayjs
```
:::info{title="Dica"}
Módulos não declarados na variável de ambiente `WORKFLOW_SCRIPT_MODULES` **não podem** ser usados no script, mesmo que sejam nativos do Node.js ou já estejam instalados em `node_modules`. Essa estratégia pode ser utilizada no nível operacional para controlar a lista de módulos disponíveis para os usuários, evitando que os scripts tenham permissões excessivas em alguns cenários.
Módulos não declarados na variável de ambiente `WORKFLOW_SCRIPT_MODULES` **não podem** ser importados diretamente com `require()`, mesmo que sejam nativos do Node.js ou já estejam instalados em `node_modules`. Esta lista serve apenas para configurar imports suportados. Não confie nela para reduzir permissões de scripts nem para delegar com segurança a edição de scripts a usuários menos confiáveis.
:::
Em ambientes que não sejam de implantação por código-fonte, se um módulo não estiver instalado em `node_modules`, você pode instalar manualmente o pacote necessário no diretório `storage`. Por exemplo, para usar o pacote `exceljs`, você pode executar as seguintes operações:
+5 -3
View File
@@ -64,7 +64,9 @@ pkg: '@nocobase/plugin-workflow-javascript'
Когда `WORKFLOW_SCRIPT_MODULES` **настроена**, скрипты переключаются на встроенный движок `vm` Node.js для обеспечения возможности использования `require`.
:::warning{title="Предупреждение безопасности"}
В небезопасном режиме, хотя скрипты выполняются в песочнице `vm` с ограниченным списком разрешённых модулей, модуль `vm` Node.js не является безопасным механизмом песочницы. Включение этого режима подразумевает доверие ко всем пользователям, имеющим права на редактирование скриптов рабочих процессов. Администраторы должны самостоятельно оценить риски безопасности и строго контролировать список разрешённых модулей и права на редактирование рабочих процессов.
Небезопасный режим использует модуль Node.js `vm` только для поддержки CommonJS `require`. Модуль Node.js `vm` не является безопасным механизмом песочницы. Включение этого режима означает, что всем пользователям, которые могут редактировать, тестировать или запускать скрипты рабочих процессов, доверяют как пользователям, способным выполнять код с привилегиями сервера NocoBase.
`WORKFLOW_SCRIPT_MODULES` не является границей безопасности или моделью разрешений. Он только управляет тем, какие имена модулей принимаются `require()` перед выполнением кода скрипта.
:::
В скрипте можно использовать модули в соответствии со стандартом CommonJS, используя директиву `require()` для импорта модулей.
@@ -76,7 +78,7 @@ WORKFLOW_SCRIPT_MODULES=crypto,timers,lodash,dayjs
```
:::info{title="Примечание"}
Модули, не объявленные в переменной среды `WORKFLOW_SCRIPT_MODULES`, **не могут** быть использованы в скрипте, даже если они являются нативными для Node.js или уже установлены в `node_modules`. Эта политика позволяет на уровне эксплуатации контролировать список модулей, доступных пользователям, и в некоторых сценариях предотвращать чрезмерные права доступа скриптов.
Модули, не объявленные в переменной среды `WORKFLOW_SCRIPT_MODULES`, **не могут** быть импортированы напрямую через `require()`, даже если они являются нативными для Node.js или уже установлены в `node_modules`. Этот список предназначен только для настройки поддерживаемых импортов. Не полагайтесь на него для снижения прав скриптов или безопасного делегирования редактирования скриптов менее доверенным пользователям.
:::
В среде, где развертывание выполнено не из исходного кода, если какой-либо модуль не установлен в `node_modules`, вы можете вручную установить необходимый пакет в каталог `storage`. Например, для использования пакета `exceljs` выполните следующие действия:
@@ -162,4 +164,4 @@ async function sleep(time) {
await sleep(1000);
return 123;
```
```
+3
View File
@@ -30,6 +30,9 @@ server {
client_max_body_size 0;
access_log /var/log/nginx/nocobase.log apm;
include /etc/nginx/mime.types;
types { application/javascript mjs; }
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
@@ -61,4 +61,25 @@ describe('password field', () => {
const user = await User.model.findOne({ where: { name: 'zhangsan' } });
expect(await pwd.verify('123456', user.password)).toBeTruthy();
});
it('should hash numeric password values', async () => {
const User = db.collection({
name: 'users',
fields: [
{ type: 'string', name: 'name' },
{ type: 'password', name: 'password' },
],
});
await db.sync();
const user = await User.repository.create({
values: {
name: 'zhangsan',
password: 123456,
},
});
const pwd = User.getField<PasswordField>('password');
expect(await pwd.verify('123456', user.password)).toBeTruthy();
});
});
@@ -24,30 +24,33 @@ export interface PasswordFieldOptions extends BaseColumnFieldOptions {
randomBytesSize?: number;
}
type PasswordValue = string | number;
export class PasswordField extends Field {
get dataType() {
return DataTypes.STRING;
}
async verify(password: string, hash: string) {
password = password || '';
async verify(password: PasswordValue, hash: string) {
const passwordString = password === null || password === undefined ? '' : String(password);
hash = hash || '';
const { length = 64, randomBytesSize = 8 } = this.options;
return new Promise((resolve, reject) => {
const salt = hash.substring(0, randomBytesSize * 2);
const key = hash.substring(randomBytesSize * 2);
crypto.scrypt(password, salt, length / 2 - randomBytesSize, (err, derivedKey) => {
crypto.scrypt(passwordString, salt, length / 2 - randomBytesSize, (err, derivedKey) => {
if (err) reject(err);
resolve(key == derivedKey.toString('hex'));
});
});
}
async hash(password: string) {
async hash(password: PasswordValue) {
const passwordString = String(password);
const { length = 64, randomBytesSize = 8 } = this.options;
return new Promise((resolve, reject) => {
const salt = crypto.randomBytes(randomBytesSize).toString('hex');
crypto.scrypt(password, salt, length / 2 - randomBytesSize, (err, derivedKey) => {
crypto.scrypt(passwordString, salt, length / 2 - randomBytesSize, (err, derivedKey) => {
if (err) reject(err);
resolve(salt + derivedKey.toString('hex'));
});
@@ -56,18 +59,20 @@ export class PasswordField extends Field {
init() {
const { name } = this.options;
const fieldName = name as string;
this.listener = async (instances: Model[]) => {
instances = Array.isArray(instances) ? instances : [instances];
for (const instance of instances) {
if (!instance.changed(name as any)) {
if (!instance.changed(fieldName)) {
continue;
}
const value = instance.get(name) as string;
if (value) {
const hash = await this.hash(value);
instance.set(name, hash);
const value = instance.get(fieldName);
if (value !== null && value !== undefined && value !== '') {
const password = typeof value === 'number' ? value : String(value);
const hash = await this.hash(password);
instance.set(fieldName, hash);
} else {
instance.set(name, instance.previous(name));
instance.set(fieldName, instance.previous(fieldName));
}
}
};
@@ -11,6 +11,8 @@ import Database from '@nocobase/database';
import UsersPlugin from '@nocobase/plugin-users';
import { createMockServer, MockServer } from '@nocobase/test';
import { vi } from 'vitest';
import { UNION_ROLE_KEY } from '../constants';
import { SystemRoleMode } from '../enum';
import { setCurrentRole } from '../middlewares/setCurrentRole';
import { prepareApp } from './prepare';
@@ -67,6 +69,45 @@ describe('role', () => {
expect(ctx.state.currentRole).toBe('root');
});
it('should keep all roles when the default role is union and X-Role is empty', async () => {
await db.getRepository('roles').create({
values: {
name: 'r1',
},
});
const user = await db.getRepository('users').create({
values: {
name: 'u1',
roles: ['member', 'r1'],
},
});
await db.getRepository('systemSettings').update({
filter: { id: 1 },
values: {
roleMode: SystemRoleMode.allowUseUnion,
},
});
await db.getRepository('rolesUsers').create({
values: {
userId: user.id,
roleName: UNION_ROLE_KEY,
default: true,
},
});
ctx.state.currentUser = user;
ctx.get = function (name) {
if (name === 'X-Role') {
return '';
}
};
await setCurrentRole(ctx, () => {});
expect(ctx.state.currentRole).toBe(UNION_ROLE_KEY);
expect(ctx.state.currentRoles).toEqual(expect.arrayContaining(['member', 'r1']));
expect(ctx.state.currentRoles).toHaveLength(2);
});
it('should throw error', async () => {
ctx.state.currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
@@ -92,7 +92,7 @@ export async function setCurrentRole(ctx: Context, next) {
role = defaultRoleModel?.roleName || userRoles[0]?.name;
}
ctx.state.currentRole = role;
ctx.state.currentRoles = role === UNION_ROLE_KEY ? [userRoles[0]?.name] : [role];
ctx.state.currentRoles = role === UNION_ROLE_KEY ? userRoles.map((role) => role.name) : [role];
if (!ctx.state.currentRoles.length) {
return ctx.throw(401, {
code: 'ROLE_NOT_FOUND_ERR',
@@ -2717,7 +2717,7 @@ describe('basic importer', () => {
await expect(importer.run()).rejects.toThrow();
});
it('should import password field, insert data is encrypt', async () => {
it('should import numeric password field values as strings', async () => {
const User = app.db.collection({
name: 'users',
fields: [
@@ -2743,7 +2743,7 @@ describe('basic importer', () => {
const template = (await templateCreator.run({ returnXLSXWorkbook: true })) as XLSX.WorkBook;
const worksheet = template.Sheets[template.SheetNames[0]];
XLSX.utils.sheet_add_aoa(worksheet, [['zhangsan', '123456']], {
XLSX.utils.sheet_add_aoa(worksheet, [['zhangsan', 123456]], {
origin: 'A2',
});