@abtnode/core 1.17.8-beta-20260119-102944-6ba93a16 → 1.17.8-beta-20260125-093329-64b43854
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/team/org-crud-manager.js +29 -1
- package/lib/api/team/user-query-manager.js +1 -0
- package/lib/blocklet/manager/disk/settings-manager.js +36 -1
- package/lib/blocklet/manager/disk.js +2 -2
- package/lib/blocklet/migration-dist/migration.cjs +1036 -960
- package/lib/event/index.js +7 -3
- package/lib/router/helper.js +72 -0
- package/lib/router/index.js +6 -1
- package/lib/states/user.js +10 -2
- package/lib/validators/org.js +2 -0
- package/package.json +34 -34
|
@@ -2,6 +2,8 @@ const logger = require('@abtnode/logger')('@abtnode/core:api:team:org-crud');
|
|
|
2
2
|
const { CustomError } = require('@blocklet/error');
|
|
3
3
|
const md5 = require('@abtnode/util/lib/md5');
|
|
4
4
|
const { sanitizeTag } = require('@abtnode/util/lib/sanitize');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs-extra');
|
|
5
7
|
|
|
6
8
|
const { createOrgValidators } = require('../../util/org');
|
|
7
9
|
const { createOrgInputSchema, updateOrgInputSchema } = require('../../validators/org');
|
|
@@ -159,7 +161,33 @@ async function updateOrg(api, { teamDid, org }, context) {
|
|
|
159
161
|
}
|
|
160
162
|
|
|
161
163
|
const state = await api.getOrgState(teamDid);
|
|
162
|
-
|
|
164
|
+
|
|
165
|
+
// 获取旧的 org 数据,用于比对 avatar 是否发生变化
|
|
166
|
+
const oldOrg = await state.getOrg(org.id);
|
|
167
|
+
|
|
168
|
+
const result = await state.updateOrg({ org: sanitizedOrg }, context);
|
|
169
|
+
|
|
170
|
+
// 如果 avatar 发生变化,删除旧的 avatar 文件(不影响主流程)
|
|
171
|
+
try {
|
|
172
|
+
if (oldOrg?.avatar && result.avatar && oldOrg.avatar !== result.avatar) {
|
|
173
|
+
const blocklet = await getBlocklet({
|
|
174
|
+
did: teamDid,
|
|
175
|
+
states: api.states,
|
|
176
|
+
dataDirs: api.dataDirs,
|
|
177
|
+
useCache: true,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const oldAvatarPath = path.resolve(blocklet.env.dataDir, 'orgs', oldOrg.avatar);
|
|
181
|
+
if (fs.existsSync(oldAvatarPath)) {
|
|
182
|
+
await fs.remove(oldAvatarPath);
|
|
183
|
+
logger.info('Successfully removed old org avatar', { teamDid, orgId: result.id, oldAvatar: oldOrg.avatar });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
} catch (err) {
|
|
187
|
+
logger.error('remove org avatar file', { err, teamDid, orgId: result.id, avatar: result.avatar });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return result;
|
|
163
191
|
} catch (err) {
|
|
164
192
|
logger.error('Failed to update org', { err, teamDid });
|
|
165
193
|
throw err;
|
|
@@ -65,7 +65,11 @@ async function getBlockletBlurhash(manager, { did }) {
|
|
|
65
65
|
* @param {Object} context
|
|
66
66
|
* @returns {Promise<Object>}
|
|
67
67
|
*/
|
|
68
|
-
async function updateBlockletSettings(
|
|
68
|
+
async function updateBlockletSettings(
|
|
69
|
+
manager,
|
|
70
|
+
{ did, enableSessionHardening, invite, gateway, aigne, org, subService },
|
|
71
|
+
context
|
|
72
|
+
) {
|
|
69
73
|
const params = {};
|
|
70
74
|
if (!isNil(enableSessionHardening)) {
|
|
71
75
|
params.enableSessionHardening = enableSessionHardening;
|
|
@@ -98,6 +102,37 @@ async function updateBlockletSettings(manager, { did, enableSessionHardening, in
|
|
|
98
102
|
};
|
|
99
103
|
}
|
|
100
104
|
|
|
105
|
+
if (!isNil(subService)) {
|
|
106
|
+
// Security: Validate subService configuration to prevent path traversal
|
|
107
|
+
const SUB_SERVICE_SCHEMA = Joi.object({
|
|
108
|
+
enabled: Joi.boolean().required(),
|
|
109
|
+
domain: Joi.when('enabled', {
|
|
110
|
+
is: true,
|
|
111
|
+
then: Joi.string().required(),
|
|
112
|
+
otherwise: Joi.string().optional().allow(''),
|
|
113
|
+
}),
|
|
114
|
+
staticRoot: Joi.when('enabled', {
|
|
115
|
+
is: true,
|
|
116
|
+
then: Joi.string()
|
|
117
|
+
.required()
|
|
118
|
+
// Reject paths containing ".." or starting with "/"
|
|
119
|
+
.pattern(/^[^/]/, { name: 'no-absolute-path' })
|
|
120
|
+
.pattern(/^(?!.*\.\.).*$/, { name: 'no-parent-reference' })
|
|
121
|
+
.messages({
|
|
122
|
+
'string.pattern.name': 'Invalid path. Path cannot contain ".." or start with "/"',
|
|
123
|
+
}),
|
|
124
|
+
otherwise: Joi.string().optional().allow(''),
|
|
125
|
+
}),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const { error } = SUB_SERVICE_SCHEMA.validate(subService);
|
|
129
|
+
if (error) {
|
|
130
|
+
throw new CustomError(400, error.message);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
params.subService = subService;
|
|
134
|
+
}
|
|
135
|
+
|
|
101
136
|
let shouldRotateSession = false;
|
|
102
137
|
if (!isNil(org)) {
|
|
103
138
|
const ORG_SCHEMA = Joi.object({
|
|
@@ -826,10 +826,10 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
826
826
|
return summary;
|
|
827
827
|
}
|
|
828
828
|
|
|
829
|
-
updateBlockletSettings({ did, enableSessionHardening, invite, gateway, aigne, org }, context) {
|
|
829
|
+
updateBlockletSettings({ did, enableSessionHardening, invite, gateway, aigne, org, subService }, context) {
|
|
830
830
|
return settingsManager.updateBlockletSettings(
|
|
831
831
|
this,
|
|
832
|
-
{ did, enableSessionHardening, invite, gateway, aigne, org },
|
|
832
|
+
{ did, enableSessionHardening, invite, gateway, aigne, org, subService },
|
|
833
833
|
context
|
|
834
834
|
);
|
|
835
835
|
}
|