fix: create_or_update_record hashea los campos editor_password (nunca texto en claro)

This commit is contained in:
Jordan Diaz
2026-07-26 11:23:58 +00:00
parent b9df5cbb54
commit fb7ed09626
2 changed files with 333 additions and 3 deletions

View File

@@ -2,9 +2,9 @@ import { z } from "zod";
import { withAuth, getSessionCredentials } from "../../auth/index.js";
import { handleToolError, validateRequired, handleApiResponse } from "../helpers/errorHandler.js";
import { AcaiHttpClient } from "../helpers/acaiHttpClient.js";
import { table } from "console";
import { withAuthParams } from "../helpers/authSchema.js";
import { canAccessTable } from "../helpers/accessControl.js";
import { applyPasswordFieldHashing } from "../helpers/passwordFields.js";
export function registerCreateOrUpdateRecordTool(server) {
server.tool(
@@ -13,7 +13,9 @@ export function registerCreateOrUpdateRecordTool(server) {
Reglas clave: tablas sin prefijo 'cms_'; PK es 'num' (nunca 'id'); foreign keys con sufijo '_num'; uploads son arrays — NO los envíes en 'fields', sube después con 'upload_record_image'; fechas en formato YYYY-MM-DD HH:mm:ss; checkboxes como 1/0 (números).
Para tablas builder (e.g. 'apartados') al crear nuevo registro: incluye num:null, builder:"[]", controlador, precontrolador, breadcrumb, enlace. NUNCA modifiques 'enlace' ni 'controlador' de un registro existente — los stripeo automáticamente en updates.`,
Para tablas builder (e.g. 'apartados') al crear nuevo registro: incluye num:null, builder:"[]", controlador, precontrolador, breadcrumb, enlace. NUNCA modifiques 'enlace' ni 'controlador' de un registro existente — los stripeo automáticamente en updates.
Contraseñas: los campos de tipo 'editor_password' (e.g. 'usuarios.clave') se hashean automáticamente con SHA1 antes de guardarse — envía la contraseña en texto plano y NO la hashees tú. Su valor no se puede leer/descifrar después (solo verás el hash), así que no intentes recuperar contraseñas existentes ni reenviarlas. Si envías el campo vacío ('' o null) se omite del guardado y la contraseña actual se mantiene.`,
withAuthParams({
tableName: z.string().describe("Nombre de la tabla sin prefijo 'cms_' (e.g. 'productos', 'apartados')"),
recordId: z.any().optional().describe("'num' del registro a actualizar. Omitir para crear nuevo. NO se usa cuando 'fields' es array."),
@@ -87,8 +89,27 @@ Para tablas builder (e.g. 'apartados') al crear nuevo registro: incluye num:null
});
}
// Prepare payload for CMS API
const credentials = await getSessionCredentials(extra.sessionId);
// Campos de contraseña (type = "editor_password"): el cmsApi no ejecuta
// hooks de plugin, así que el hasheo sha1 que haría save_pre.php hay que
// aplicarlo aquí. Regla canónica en server/password_fields.py.
const passwordResult = await applyPasswordFieldHashing({
sessionId: extra.sessionId,
credentials,
tableName,
records: processedRecords,
recordId,
});
if (passwordResult.error) {
return {
content: [{ type: "text", text: JSON.stringify({ success: false, error: passwordResult.error }, null, 2) }],
isError: true,
};
}
processedRecords = passwordResult.records;
// Prepare payload for CMS API
const recordPayload = {
tableName: tableName,
records: processedRecords,
@@ -139,6 +160,12 @@ Para tablas builder (e.g. 'apartados') al crear nuevo registro: incluye num:null
recordIds: response.data?.data || (recordId || 'new'),
recordsCount: isArray ? recordsArray.length : 1,
createdIds: response.data?.data,
// Transparencia sobre el tratamiento de contraseñas (nunca devolvemos el valor)
passwordFieldsHashed: passwordResult.hashedFields.length > 0 ? passwordResult.hashedFields : undefined,
passwordFieldsSkipped: passwordResult.omittedEmptyFields.length > 0
? `Campos de contraseña vacíos, omitidos para no borrar el valor actual: ${passwordResult.omittedEmptyFields.join(', ')}`
: undefined,
passwordWarnings: passwordResult.warnings.length > 0 ? passwordResult.warnings : undefined,
suggestion: isNewRecord && !isArray ? `You can verify the record by fetching: ${credentials.web_url}${processedRecords[0].enlace}` : undefined
}, null, 2)
}],