backend-plus 2.7.0-beta.12 → 2.7.0-beta.14
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/for-client/my-tables.js +2 -2
- package/lib/backend-plus.d.ts +4 -0
- package/lib/backend-plus.js +4 -76
- package/lib/procedures-table.js +19 -6
- package/package.json +1 -1
package/for-client/my-tables.js
CHANGED
|
@@ -687,7 +687,7 @@ myOwn.tableGrid = function tableGrid(tableName, mainElement, opts){
|
|
|
687
687
|
depot.manager.displayAsDeleted(depot, force ? 'change-ff' : 'unknown');
|
|
688
688
|
if (myOwn.config.config['grid-row-retain-moved-or-deleted']) {
|
|
689
689
|
if(!depot['$refreshed']){
|
|
690
|
-
grid.retrieveRowAndRefresh(depot,{
|
|
690
|
+
grid.retrieveRowAndRefresh(depot,{retrieveWithBroadWhere:true})
|
|
691
691
|
depot['$refreshed'] = true
|
|
692
692
|
}
|
|
693
693
|
}
|
|
@@ -2435,7 +2435,7 @@ myOwn.TableGrid.prototype.displayGrid = function displayGrid(){
|
|
|
2435
2435
|
return {fieldName:fieldName, value:depot.primaryKeyValues[i]};
|
|
2436
2436
|
}),
|
|
2437
2437
|
pick:grid.def.pick,
|
|
2438
|
-
|
|
2438
|
+
retrieveWithBroadWhere : opts?.retrieveWithBroadWhere ?? false
|
|
2439
2439
|
}).then(function(result){
|
|
2440
2440
|
grid.depotRefresh(depot,{updatedRow:result[0], sendedForUpdate:{}}, opts);
|
|
2441
2441
|
})
|
package/lib/backend-plus.d.ts
CHANGED
|
@@ -284,10 +284,12 @@ export type TableDefinition = EditableDbDefinition & {
|
|
|
284
284
|
primaryKey:string[]
|
|
285
285
|
refrescable?: boolean
|
|
286
286
|
sql?:{
|
|
287
|
+
select?: string[]
|
|
287
288
|
primaryKey4Delete?:string[]
|
|
288
289
|
isTable?:boolean
|
|
289
290
|
from?:string
|
|
290
291
|
where?:string
|
|
292
|
+
broadWhere?:string
|
|
291
293
|
postCreateSqls?:string
|
|
292
294
|
skipEnance?: boolean
|
|
293
295
|
isReferable?: boolean
|
|
@@ -338,6 +340,7 @@ export type TableDefinition = EditableDbDefinition & {
|
|
|
338
340
|
policy?:string
|
|
339
341
|
firstDisplayCount?:number
|
|
340
342
|
firstDisplayOverLimit?:number
|
|
343
|
+
forInsertOnlyMode?:boolean
|
|
341
344
|
description?:MarkdownDoc
|
|
342
345
|
exportJsonFieldAsColumns?:string
|
|
343
346
|
importCuidado?:boolean
|
|
@@ -350,6 +353,7 @@ export type TableDefinition = EditableDbDefinition & {
|
|
|
350
353
|
functionDef?:{
|
|
351
354
|
parameters?:ProcedureParameter[]
|
|
352
355
|
}
|
|
356
|
+
|
|
353
357
|
}
|
|
354
358
|
export type TableDefinitionInternal = RequireSome<TableDefinition,
|
|
355
359
|
'allow'|'sql'
|
package/lib/backend-plus.js
CHANGED
|
@@ -115,9 +115,6 @@ function md5(text){
|
|
|
115
115
|
const DEFAULT_ITERATIONS = 4096;
|
|
116
116
|
const HASH_ALGORITHM = 'sha256';
|
|
117
117
|
|
|
118
|
-
// primera version de scram sha 256. El Verifier completo tenía 64 bytes.
|
|
119
|
-
const LEGACY_KEY_LENGTH = 64;
|
|
120
|
-
|
|
121
118
|
// Formato nuevo/PG-Compatible: El Client Key tiene 32 bytes (SHA-256).
|
|
122
119
|
const SCRAM_KEY_LENGTH = 32;
|
|
123
120
|
|
|
@@ -215,57 +212,6 @@ async function verifyScramPG(password, storedScramString) {
|
|
|
215
212
|
return storedKeyMatch && serverKeyMatch;
|
|
216
213
|
}
|
|
217
214
|
|
|
218
|
-
/**
|
|
219
|
-
* Verifica una contraseña contra el hash SCRAM Legacy (64 bytes).
|
|
220
|
-
* Formato Legacy: SCRAM-SHA-256$<iteraciones>:<Salt>$<Verifier(64 bytes)>
|
|
221
|
-
* @param {string} password - Contraseña en texto plano.
|
|
222
|
-
* @param {string} storedScramString - Cadena SCRAM Legacy.
|
|
223
|
-
* @returns {Promise<boolean>} True si la contraseña es válida.
|
|
224
|
-
*/
|
|
225
|
-
async function verifyScramLegacy(password, storedScramString) {
|
|
226
|
-
if (!storedScramString.startsWith('SCRAM-SHA-256$')) {
|
|
227
|
-
// No es formato SCRAM. Debe ser MD5 u otro algoritmo.
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Parsea la cadena SCRAM
|
|
232
|
-
// Ejemplo: SCRAM-SHA-256$4096:SALT_BASE64$VERIFIER_BASE64
|
|
233
|
-
const parts = storedScramString.split('$');
|
|
234
|
-
if (parts.length !== 3) {
|
|
235
|
-
throw new Error('Formato SCRAM almacenado inválido.');
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Obtiene iteraciones y salt de la segunda parte (ej: '4096:SALT_BASE64')
|
|
239
|
-
const [storedIterations, storedSalt] = parts[1].split(':');
|
|
240
|
-
const storedVerifier = parts[2];
|
|
241
|
-
|
|
242
|
-
if (!storedSalt || !storedVerifier || isNaN(parseInt(storedIterations))) {
|
|
243
|
-
throw new Error('Datos de SCRAM incompletos o malformados.');
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const iterations = parseInt(storedIterations);
|
|
247
|
-
|
|
248
|
-
// Deriva la clave de la contraseña ingresada
|
|
249
|
-
const generatedVerifierBuffer = await deriveKey(
|
|
250
|
-
password,
|
|
251
|
-
storedSalt,
|
|
252
|
-
iterations,
|
|
253
|
-
LEGACY_KEY_LENGTH
|
|
254
|
-
);
|
|
255
|
-
const generatedVerifier = bufferToBase64(generatedVerifierBuffer);
|
|
256
|
-
|
|
257
|
-
// Compara de manera segura contra el Verificador Almacenado
|
|
258
|
-
const storedVerifierBuffer = Buffer.from(storedVerifier, 'base64');
|
|
259
|
-
const generatedVerifierBufferFromBase64 = Buffer.from(generatedVerifier, 'base64');
|
|
260
|
-
|
|
261
|
-
// Usa crypto.timingSafeEqual para evitar ataques de temporización
|
|
262
|
-
if (generatedVerifierBufferFromBase64.length !== storedVerifierBuffer.length) {
|
|
263
|
-
return false;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return crypto.timingSafeEqual(generatedVerifierBufferFromBase64, storedVerifierBuffer);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
215
|
var dist=regexpDistCheck.test(packagejson.main)?'dist/':'';
|
|
270
216
|
|
|
271
217
|
/**
|
|
@@ -1283,7 +1229,6 @@ AppBackend.prototype.start = function start(opts){
|
|
|
1283
1229
|
done(null,false,{message:be.messages.unlogged.login.userOrPassFail});
|
|
1284
1230
|
return
|
|
1285
1231
|
}else{
|
|
1286
|
-
let needsMigration = false;
|
|
1287
1232
|
const user = data.row;
|
|
1288
1233
|
if(!user[passFieldName]){
|
|
1289
1234
|
done(null,false,{message:be.messages.unlogged.login.userOrPassFail});
|
|
@@ -1291,34 +1236,20 @@ AppBackend.prototype.start = function start(opts){
|
|
|
1291
1236
|
}
|
|
1292
1237
|
const usaScramSha256 = user[passFieldName].startsWith('SCRAM-SHA-256$')
|
|
1293
1238
|
if (usaScramSha256){
|
|
1294
|
-
|
|
1295
|
-
// 1. Intento con formato PG-Compatible (Nuevo)
|
|
1296
|
-
if(await verifyScramPG(password, user[passFieldName])){
|
|
1297
|
-
isScramValid = true;
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
// 2. Intento con formato Legacy (64 bytes)
|
|
1301
|
-
else if(await verifyScramLegacy(password, user[passFieldName])){
|
|
1302
|
-
isScramValid = true;
|
|
1303
|
-
needsMigration = true;
|
|
1304
|
-
}
|
|
1305
|
-
if(!isScramValid){
|
|
1239
|
+
if(!await verifyScramPG(password, user[passFieldName])){
|
|
1306
1240
|
done(null,false,{message:be.messages.unlogged.login.userOrPassFail});
|
|
1307
1241
|
return
|
|
1308
1242
|
}
|
|
1309
1243
|
}else{
|
|
1310
1244
|
if (md5(password+username.toLowerCase()) === user[passFieldName]){
|
|
1311
|
-
|
|
1245
|
+
if (be.config.log["pass-migration"]) console.log('Ejecutando migración a SCRAM...');
|
|
1246
|
+
await updatePassword({client, username, password, setUpdateDate:false, errorIfNoResult:true});
|
|
1247
|
+
if (be.config.log["pass-migration"]) console.log('Migración completada.');
|
|
1312
1248
|
}else{
|
|
1313
1249
|
done(null,false,{message:be.messages.unlogged.login.userOrPassFail});
|
|
1314
1250
|
return
|
|
1315
1251
|
}
|
|
1316
1252
|
}
|
|
1317
|
-
if(needsMigration){
|
|
1318
|
-
if (be.config.log["pass-migration"]) console.log('Ejecutando migración a SCRAM...');
|
|
1319
|
-
await updatePassword({client, username, password, setUpdateDate:false, errorIfNoResult:true});
|
|
1320
|
-
if (be.config.log["pass-migration"]) console.log('Migración completada.');
|
|
1321
|
-
}
|
|
1322
1253
|
}
|
|
1323
1254
|
//continua validando
|
|
1324
1255
|
if(data.rowCount==1){
|
|
@@ -1388,9 +1319,6 @@ AppBackend.prototype.start = function start(opts){
|
|
|
1388
1319
|
if (oldPassword !== false) {
|
|
1389
1320
|
if (storedHash.startsWith('SCRAM-SHA-256$')) {//Intento SCRAM-SHA-256
|
|
1390
1321
|
ok = await verifyScramPG(oldPassword, storedHash);
|
|
1391
|
-
if (!ok) {
|
|
1392
|
-
ok = await verifyScramLegacy(oldPassword, storedHash);
|
|
1393
|
-
}
|
|
1394
1322
|
} else { //Intento MD5
|
|
1395
1323
|
const md5Hash = md5(oldPassword + username.toLowerCase());
|
|
1396
1324
|
ok = (md5Hash === storedHash);
|
package/lib/procedures-table.js
CHANGED
|
@@ -10,6 +10,7 @@ var likeAr=require('like-ar');
|
|
|
10
10
|
const f = require('session-file-store');
|
|
11
11
|
const { expected } = require('cast-error');
|
|
12
12
|
const bestGlobals = require('best-globals');
|
|
13
|
+
const { AppBackend } = require('backend-plus');
|
|
13
14
|
|
|
14
15
|
const PANIC_IMPORT = true;
|
|
15
16
|
|
|
@@ -85,26 +86,29 @@ ProcedureTables = [
|
|
|
85
86
|
{name: 'fixedFields', defaultValue:[]},
|
|
86
87
|
{name: 'paramfun', defaultValue:[]},
|
|
87
88
|
{name: 'pick', defaultValue:'', encoding:'plain'},
|
|
88
|
-
{name: '
|
|
89
|
+
{name: 'retrieveWithBroadWhere', defaultValue:false}
|
|
89
90
|
],
|
|
90
91
|
coreFunction:
|
|
91
92
|
/**
|
|
92
93
|
*
|
|
93
94
|
* @param {*} context
|
|
94
|
-
* @param {{table:string, fixedFields:{fieldName:string, value:any, range?:string, until?:string}[], paramfun:string
|
|
95
|
+
* @param {{table:string, fixedFields:{fieldName:string, value:any, range?:string, until?:string}[], paramfun:Record<string, string>, pick:string, retrieveWithBroadWhere:boolean}} parameters
|
|
95
96
|
*/
|
|
96
97
|
async function tableDatum(context, parameters){
|
|
98
|
+
/** @type {AppBackend} */
|
|
97
99
|
var be=context.be;
|
|
98
100
|
var tableName=parameters.table;
|
|
99
|
-
var
|
|
100
|
-
if(!
|
|
101
|
+
var defTableFun=be.tableStructures[tableName];
|
|
102
|
+
if(!defTableFun){
|
|
101
103
|
throw new Error('no table def for '+tableName+' (in table_data)')
|
|
102
104
|
}
|
|
103
|
-
defTable=
|
|
105
|
+
var defTable=defTableFun(context);
|
|
104
106
|
/** @type {string} */
|
|
105
107
|
var sql;
|
|
106
108
|
var queryValues=[];
|
|
109
|
+
/** @type {string[]} */
|
|
107
110
|
var specialFixedClause=[];
|
|
111
|
+
/** @type {string[]} */
|
|
108
112
|
var fixedClausule=[];
|
|
109
113
|
if(defTable.functionDef){
|
|
110
114
|
parameters.fixedFields.forEach(function(pair, iPair){
|
|
@@ -155,10 +159,19 @@ ProcedureTables = [
|
|
|
155
159
|
fixedClausule.push(exprClausule)
|
|
156
160
|
}
|
|
157
161
|
});
|
|
162
|
+
|
|
163
|
+
const getBaseWhere = (defTable, params) => {
|
|
164
|
+
if (params?.retrieveWithBroadWhere && defTable.sql?.broadWhere) return defTable.sql.broadWhere;
|
|
165
|
+
if (params?.retrieveWithBroadWhere) console.warn("No broadWhere found for retrieveWithBroadWhere. Using default configuration.");
|
|
166
|
+
return defTable.sql?.where || (defTable.allow?.select && !defTable.forInsertOnlyMode ? 'true' : 'false');
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const whereCondition = getBaseWhere(defTable, parameters) + fixedClausule.join("");
|
|
170
|
+
|
|
158
171
|
/** @type {string} */
|
|
159
172
|
var sql="SELECT "+[...defTable.sql.select].join(', ')+
|
|
160
173
|
"\n FROM "+defTable.sql.from+
|
|
161
|
-
"\n WHERE "+
|
|
174
|
+
"\n WHERE "+whereCondition+
|
|
162
175
|
// " ORDER BY "+defTable.primaryKey.map(be.db.quoteIdent.bind(be.db)).join(',')
|
|
163
176
|
"\n ORDER BY "+(defTable.sql.orderBy||defTable.primaryKey).map(function(fieldName){ return be.db.quoteIdent(fieldName); }).join(',')
|
|
164
177
|
if(specialFixedClause.length){
|
package/package.json
CHANGED