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.
@@ -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,{retrieveIgnoringWhere:true})
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
- retrieveIgnoringWhere: opts?opts.retrieveIgnoringWhere:false
2438
+ retrieveWithBroadWhere : opts?.retrieveWithBroadWhere ?? false
2439
2439
  }).then(function(result){
2440
2440
  grid.depotRefresh(depot,{updatedRow:result[0], sendedForUpdate:{}}, opts);
2441
2441
  })
@@ -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'
@@ -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
- let isScramValid = false;
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
- needsMigration = true;
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);
@@ -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: 'retrieveIgnoringWhere', defaultValue:false}
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[], pick:string, retrieveIgnoringWhere:boolean}} parameters
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 defTable=be.tableStructures[tableName];
100
- if(!defTable){
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=defTable(context);
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 "+((parameters.retrieveIgnoringWhere?'true':defTable.sql.where)||(defTable.allow.select && !defTable.forInsertOnlyMode?'true':'false'))+fixedClausule.join("")+
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "backend-plus",
3
3
  "description": "Backend for the anti Pareto rule",
4
- "version": "2.7.0-beta.12",
4
+ "version": "2.7.0-beta.14",
5
5
  "author": "Codenautas <codenautas@googlegroups.com>",
6
6
  "license": "MIT",
7
7
  "repository": "codenautas/backend-plus",