diff --git a/decrypt.js b/decrypt.js new file mode 100644 index 0000000..ecc1acd --- /dev/null +++ b/decrypt.js @@ -0,0 +1,175 @@ +function TS_decrypt(input, secret, callback, table, id) { + // Accept objects or plaintext strings. Also support legacy RSA{...} AES-encrypted entries. + var __ts_sync = true; + if (typeof input !== "string") { + try { + callback(input, false); + } catch (e) { + console.error(e); + } + return __ts_sync; + } + + // Legacy encrypted format: RSA{...} + if ( + input.startsWith("RSA{") && + input.endsWith("}") && + typeof CryptoJS !== "undefined" + ) { + try { + var data = input.slice(4, -1); + var words = CryptoJS.AES.decrypt(data, secret); + var decryptedUtf8 = null; + try { + decryptedUtf8 = words.toString(CryptoJS.enc.Utf8); + } catch (utfErr) { + // Malformed UTF-8 — try Latin1 fallback + try { + decryptedUtf8 = words.toString(CryptoJS.enc.Latin1); + } catch (latinErr) { + console.warn( + "TS_decrypt: failed to decode decrypted bytes", + utfErr, + latinErr + ); + try { + callback(input, false); + } catch (ee) {} + return; + } + } + var parsed = null; + try { + parsed = JSON.parse(decryptedUtf8); + } catch (pe) { + // If JSON parsing fails, the decrypted string may be raw Latin1 bytes. + // Try to convert Latin1 byte string -> UTF-8 and parse again. + try { + if ( + typeof TextDecoder !== "undefined" && + typeof decryptedUtf8 === "string" + ) { + var bytes = new Uint8Array(decryptedUtf8.length); + for (var _i = 0; _i < decryptedUtf8.length; _i++) + bytes[_i] = decryptedUtf8.charCodeAt(_i) & 0xff; + var converted = new TextDecoder("utf-8").decode(bytes); + try { + parsed = JSON.parse(converted); + decryptedUtf8 = converted; + } catch (e2) { + parsed = decryptedUtf8; + } + } else { + parsed = decryptedUtf8; + } + } catch (convErr) { + parsed = decryptedUtf8; + } + } + try { + callback(parsed, true); + } catch (e) { + console.error(e); + } + // Migrate to plaintext in DB if table/id provided + if (table && id && window.DB && DB.put && typeof parsed !== "string") { + DB.put(table, id, parsed).catch(() => {}); + } + return; + } catch (e) { + console.error("TS_decrypt: invalid encrypted payload", e); + try { + callback(input, false); + } catch (ee) {} + return; + } + } + if (input.startsWith("SEA{") && input.endsWith("}")) { + __ts_sync = false; + SEA.decrypt(input, secret, (decrypted) => { + try { + callback(decrypted, true); + } catch (e) { + console.error(e); + } + }); + return __ts_sync; + } + + // Try to parse JSON strings and migrate to object + try { + var parsed = JSON.parse(input); + try { + callback(parsed, false); + } catch (e) { + console.error(e); + } + if (table && id && window.DB && DB.put) { + DB.put(table, id, parsed).catch(() => {}); + } + } catch (e) { + // Not JSON, return raw string + try { + callback(input, false); + } catch (err) { + console.error(err); + } + } + return __ts_sync; +} + +function recursiveTSDecrypt(input, secret = "") { + // Skip null values (do not show on decrypted output) + if (input === null) return null; + if (typeof input === "string") { + let result = null; + let resolver = null; + const promise = new Promise((resolve) => { + resolver = resolve; + }); + const sync = TS_decrypt(input, secret, (decrypted) => { + result = decrypted; + if (resolver) resolver(decrypted); + }); + if (sync === false) return promise; + return result; + } else if (Array.isArray(input)) { + const mapped = input.map((item) => recursiveTSDecrypt(item, secret)); + if (mapped.some((v) => v && typeof v.then === "function")) { + return Promise.all(mapped).then((values) => values.filter((v) => v !== null && typeof v !== 'undefined')); + } + return mapped.filter((v) => v !== null && typeof v !== 'undefined'); + } else if (typeof input === "object" && input !== null) { + const keys = Object.keys(input); + const mapped = keys.map((k) => recursiveTSDecrypt(input[k], secret)); + if (mapped.some((v) => v && typeof v.then === "function")) { + return Promise.all(mapped).then((values) => { + const out = {}; + for (let i = 0; i < keys.length; i++) { + const val = values[i]; + if (val !== null && typeof val !== 'undefined') out[keys[i]] = val; + } + return out; + }); + } else { + const out = {}; + for (let i = 0; i < keys.length; i++) { + const val = mapped[i]; + if (val !== null && typeof val !== 'undefined') out[keys[i]] = val; + } + return out; + } + } else { + return input; + } +} + +gun.get(TABLE).load((DATA) => { + var plain2 = recursiveTSDecrypt(DATA, SECRET); + plain2.then(function (result) { + download( + `Export TeleSec ${GROUPID} Decrypted.json.txt`, + JSON.stringify(result) + ); + }); +}); diff --git a/src/app_logic.js b/src/app_logic.js index ebdb404..3cd6bd5 100644 --- a/src/app_logic.js +++ b/src/app_logic.js @@ -9,10 +9,12 @@ function tableScroll(query) { var container = document.getElementById("container"); function LinkAccount(LinkAccount_secret, refresh = false) { - // Store group id for backward compatibility and keep secret - localStorage.setItem("TELESEC_AUTO", "YES"); - SECRET = LinkAccount_secret.toUpperCase(); - localStorage.setItem("TELESEC_secret", SECRET); + // Group identifier (no encryption). Secret usage removed. + if (LinkAccount_secret) { + SECRET = String(LinkAccount_secret).toUpperCase(); + } else { + SECRET = ""; + } if (refresh == true) { location.reload(); @@ -30,17 +32,6 @@ function LinkAccount(LinkAccount_secret, refresh = false) { console.warn('DB.init failed or not available yet', e); } } -if (localStorage.getItem("TELESEC_AUTO") == "YES") { - LinkAccount( - localStorage.getItem("TELESEC_secret") - ); -} -if (urlParams.get("login") != null) { - LinkAccount( - urlParams.get("enc_password"), - ); - //location.search = ""; -} function open_page(params) { // Clear stored event listeners and timers @@ -153,11 +144,11 @@ function fixGunLocalStorage() { } // Heartbeat: store a small "last seen" doc locally and replicate to remote when available -setInterval(() => { - if (typeof DB !== 'undefined') { - DB.put('heartbeat', getDBName() || 'heartbeat', 'heartbeat-' + CurrentISOTime()); - } -}, 5000); +// setInterval(() => { +// if (typeof DB !== 'undefined') { +// DB.put('heartbeat', getDBName() || 'heartbeat', 'heartbeat-' + CurrentISOTime()); +// } +// }, 5000); function betterSorter(a, b) { diff --git a/src/app_modules.js b/src/app_modules.js index 7c28b31..ba37bf7 100644 --- a/src/app_modules.js +++ b/src/app_modules.js @@ -313,6 +313,15 @@ function addCategory_Personas( btn.append(br2); var img = document.createElement("img"); img.src = value.Foto || "static/ico/user_generic.png"; + // Prefer attachment 'foto' for this persona + try { + const personaKey = key; + if (personaKey) { + DB.getAttachment('personas', personaKey, 'foto').then((durl) => { + if (durl) img.src = durl; + }).catch(() => {}); + } + } catch (e) {} img.style.height = "60px"; img.style.padding = "5px"; img.style.backgroundColor = "white"; @@ -330,7 +339,16 @@ function addCategory_Personas( defaultval = key; span_0.innerText = ""; var img_5 = document.createElement("img"); - img_5.src = value.Foto; + img_5.src = value.Foto || "static/ico/user_generic.png"; + // Prefer attachment 'foto' when available + try { + const personaKey2 = key; + if (personaKey2) { + DB.getAttachment('personas', personaKey2, 'foto').then((durl) => { + if (durl) img_5.src = durl; + }).catch(() => {}); + } + } catch (e) {} img_5.style.height = "30px"; span_0.append(img_5, value.Nombre); change_cb(defaultval); @@ -537,29 +555,62 @@ const SC_actions = { ], }; // Listado precargado de personas: -function TS_decrypt(input, secret, callback) { - // Only support AES-based encrypted payloads in the format: RSA{} or plain objects/strings - if (typeof input != "string") { - callback(input); - } else if (input.startsWith("RSA{") && input.endsWith("}")) { - var data = input.slice(4, -1); - var decrypted = CryptoJS.AES.decrypt(data, secret).toString(CryptoJS.enc.Utf8); - try { - callback(JSON.parse(decrypted)); - } catch (e) { - console.error('TS_decrypt: invalid JSON', e); - callback(null); - } - } else { - // plain string (settings, etc.) - callback(input); +function TS_decrypt(input, secret, callback, table, id) { + // Accept objects or plaintext strings. Also support legacy RSA{...} AES-encrypted entries. + if (typeof input !== "string") { + try { callback(input, false); } catch (e) { console.error(e); } + return; } -} + + // Legacy encrypted format: RSA{...} + if (input.startsWith("RSA{") && input.endsWith("}") && typeof CryptoJS !== 'undefined') { + try { + var data = input.slice(4, -1); + var words = CryptoJS.AES.decrypt(data, secret); + var decryptedUtf8 = null; + try { + decryptedUtf8 = words.toString(CryptoJS.enc.Utf8); + } catch (utfErr) { + // Malformed UTF-8 — try Latin1 fallback + try { + decryptedUtf8 = words.toString(CryptoJS.enc.Latin1); + } catch (latinErr) { + console.warn('TS_decrypt: failed to decode decrypted bytes', utfErr, latinErr); + try { callback(input, false); } catch (ee) { } + return; + } + } + var parsed = null; + try { parsed = JSON.parse(decryptedUtf8); } catch (pe) { parsed = decryptedUtf8; } + try { callback(parsed, true); } catch (e) { console.error(e); } + // Migrate to plaintext in DB if table/id provided + if (table && id && window.DB && DB.put && typeof parsed !== 'string') { + DB.put(table, id, parsed).catch(() => {}); + } + return; + } catch (e) { + console.error('TS_decrypt: invalid encrypted payload', e); + try { callback(input, false); } catch (ee) { } + return; + } + } + + // Try to parse JSON strings and migrate to object + try { + var parsed = JSON.parse(input); + try { callback(parsed, false); } catch (e) { console.error(e); } + if (table && id && window.DB && DB.put) { + DB.put(table, id, parsed).catch(() => {}); + } + } catch (e) { + // Not JSON, return raw string + try { callback(input, false); } catch (err) { console.error(err); } + } +} function TS_encrypt(input, secret, callback, mode = "RSA") { - // Use AES symmetric encryption (RSA{} envelope for backwards compatibility) - var encrypted = CryptoJS.AES.encrypt(JSON.stringify(input), secret).toString(); - callback("RSA{" + encrypted + "}"); -} + // Encryption removed: store plaintext objects directly + try { callback(input); } catch (e) { console.error(e); } +} // Populate SC_Personas from DB (PouchDB) DB.map('personas', (data, key) => { function add_row(data, key) { @@ -571,9 +622,9 @@ DB.map('personas', (data, key) => { } } if (typeof data == "string") { - TS_decrypt(data, SECRET, (data) => { + TS_decrypt(data, SECRET, (data, wasEncrypted) => { add_row(data, key); - }); + }, 'personas', key); } else { add_row(data, key); } @@ -903,21 +954,19 @@ function TS_IndexElement( event.preventDefault(); event.stopPropagation(); data.Estado = state; - TS_encrypt(data, SECRET, (encrypted) => { - if (typeof ref === 'string') { - DB.put(ref, data._key, encrypted).then(() => { - toastr.success("Guardado!"); - }); - } else { - try { - // legacy - ref.get(data._key).put(encrypted); - toastr.success("Guardado!"); - } catch (e) { - console.warn('Could not save item', e); - } + if (typeof ref === 'string') { + DB.put(ref, data._key, data).then(() => { + toastr.success("Guardado!"); + }).catch((e) => { console.warn('DB.put error', e); }); + } else { + try { + // legacy + ref.get(data._key).put(data); + toastr.success("Guardado!"); + } catch (e) { + console.warn('Could not save item', e); } - }); + } return false; }; return button; @@ -992,6 +1041,17 @@ function TS_IndexElement( infoSpan.style.color = "black"; const img = document.createElement("img"); img.src = persona.Foto || "static/ico/user_generic.png"; + // Prefer attachment 'foto' stored in PouchDB if available + try { + const personaId = key.self === true ? (data._key || data._id || data.id) : data[key.key]; + if (personaId) { + DB.getAttachment('personas', personaId, 'foto').then((durl) => { + if (durl) img.src = durl; + }).catch(() => {}); + } + } catch (e) { + // ignore + } img.height = 70; infoSpan.appendChild(img); infoSpan.appendChild(document.createElement("br")); @@ -1033,9 +1093,9 @@ function TS_IndexElement( debounce(debounce_load, render, 300, [rows]); } if (typeof data == "string") { - TS_decrypt(data, SECRET, (data) => { + TS_decrypt(data, SECRET, (data, wasEncrypted) => { add_row(data, key); - }); + }, ref, key); } else { add_row(data, key); } @@ -1054,9 +1114,9 @@ function TS_IndexElement( debounce(debounce_load, render, 300, [rows]); } if (typeof data == "string") { - TS_decrypt(data, SECRET, (data) => { + TS_decrypt(data, SECRET, (data, wasEncrypted) => { add_row(data, key); - }); + }, undefined, undefined); } else { add_row(data, key); } @@ -1127,7 +1187,7 @@ function SetPages() { document.getElementById("appendApps2").append(a); } var Booted = false; -var TimeoutBoot = 6; +var TimeoutBoot = 3; // in loops of 750ms var BootLoops = 0; function getPeers() { @@ -1220,12 +1280,10 @@ var BootIntervalID = setInterval(() => { } if (!data) { const persona = { Nombre: 'Admin (bypass)', Roles: 'ADMIN,' }; - TS_encrypt(persona, SECRET, (encrypted) => { - DB.put('personas', bypassId, encrypted).then(() => finish(persona, bypassId)).catch((e) => { console.warn('AC_BYPASS create error', e); open_page('login'); }); - }); + DB.put('personas', bypassId, persona).then(() => finish(persona, bypassId)).catch((e) => { console.warn('AC_BYPASS create error', e); open_page('login'); }); } else { if (typeof data === 'string') { - TS_decrypt(data, SECRET, (pdata) => finish(pdata, bypassId)); + TS_decrypt(data, SECRET, (pdata) => finish(pdata, bypassId), 'personas', bypassId); } else { finish(data, bypassId); } diff --git a/src/db.js b/src/db.js index 3581dff..6483398 100644 --- a/src/db.js +++ b/src/db.js @@ -10,6 +10,20 @@ var DB = (function () { let changes = null; let callbacks = {}; // table -> [cb] + function ensureLocal() { + if (local) return; + try { + const localName = localStorage.getItem('TELESEC_COUCH_DBNAME') || 'telesec'; + local = new PouchDB(localName); + if (changes) { + try { changes.cancel(); } catch (e) {} + changes = local.changes({ live: true, since: 'now', include_docs: true }).on('change', onChange); + } + } catch (e) { + console.warn('ensureLocal error', e); + } + } + function makeId(table, id) { return table + ':' + id; } @@ -47,6 +61,7 @@ var DB = (function () { } function replicateToRemote() { + ensureLocal(); if (!local || !remote) return; PouchDB.replicate(local, remote, { live: true, retry: true }).on('error', function (err) { console.warn('Replication error', err); @@ -67,6 +82,7 @@ var DB = (function () { } async function put(table, id, data) { + ensureLocal(); const _id = makeId(table, id); try { const existing = await local.get(_id).catch(() => null); @@ -89,6 +105,7 @@ var DB = (function () { } async function get(table, id) { + ensureLocal(); const _id = makeId(table, id); try { const doc = await local.get(_id); @@ -103,6 +120,7 @@ var DB = (function () { } async function list(table) { + ensureLocal(); try { const res = await local.allDocs({ include_docs: true, startkey: table + ':', endkey: table + ':\uffff' }); return res.rows.map(r => { @@ -112,7 +130,62 @@ var DB = (function () { } catch (e) { return []; } } + // Convert data URL to Blob + function dataURLtoBlob(dataurl) { + const arr = dataurl.split(','); + const mime = arr[0].match(/:(.*?);/)[1]; + const bstr = atob(arr[1]); + let n = bstr.length; + const u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new Blob([u8arr], { type: mime }); + } + + async function putAttachment(table, id, name, dataUrlOrBlob, contentType) { + ensureLocal(); + const _id = makeId(table, id); + try { + let doc = await local.get(_id).catch(() => null); + if (!doc) { + // create a minimal doc so attachments can be put + await local.put({ _id: _id, table: table, ts: new Date().toISOString(), data: {} }); + doc = await local.get(_id); + } + let blob = dataUrlOrBlob; + if (typeof dataUrlOrBlob === 'string' && dataUrlOrBlob.indexOf('data:') === 0) { + blob = dataURLtoBlob(dataUrlOrBlob); + } + const type = contentType || (blob && blob.type) || 'application/octet-stream'; + await local.putAttachment(_id, name, doc._rev, blob, type); + return true; + } catch (e) { + console.error('putAttachment error', e); + return false; + } + } + + async function getAttachment(table, id, name) { + ensureLocal(); + const _id = makeId(table, id); + try { + const blob = await local.getAttachment(_id, name); + if (!blob) return null; + // convert blob to data URL + return await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = function (e) { resolve(e.target.result); }; + reader.onerror = function (e) { reject(e); }; + reader.readAsDataURL(blob); + }); + } catch (e) { + return null; + } + } + function map(table, cb) { + ensureLocal(); callbacks[table] = callbacks[table] || []; callbacks[table].push(cb); // initial load @@ -131,8 +204,27 @@ var DB = (function () { list, map, replicateToRemote, + putAttachment, + getAttachment, _internal: { local } }; })(); window.DB = DB; + +// Auto-initialize DB on startup using saved settings (non-blocking) +(function autoInitDB() { + try { + const remoteServer = localStorage.getItem('TELESEC_COUCH_URL') || ''; + const username = localStorage.getItem('TELESEC_COUCH_USER') || ''; + const password = localStorage.getItem('TELESEC_COUCH_PASS') || ''; + const dbname = localStorage.getItem('TELESEC_COUCH_DBNAME') || undefined; + const secret = localStorage.getItem('TELESEC_secret') || ''; + // Call init but don't await; DB functions are safe-guarded with ensureLocal() + DB.init({ secret, remoteServer, username, password, dbname }).catch((e) => { + console.warn('DB.autoInit error', e); + }); + } catch (e) { + console.warn('DB.autoInit unexpected error', e); + } +})(); diff --git a/src/page/aulas.js b/src/page/aulas.js index 2ed6848..2f050ec 100644 --- a/src/page/aulas.js +++ b/src/page/aulas.js @@ -73,9 +73,9 @@ PAGES.aulas = { ); } if (typeof data == "string") { - TS_decrypt(data, SECRET, (data) => { + TS_decrypt(data, SECRET, (data, wasEncrypted) => { add_row(data || {}); - }); + }, 'comedor', CurrentISODate()); } else { add_row(data || {}); } @@ -93,9 +93,9 @@ PAGES.aulas = { ); } if (typeof data == "string") { - TS_decrypt(data, SECRET, (data) => { + TS_decrypt(data, SECRET, (data, wasEncrypted) => { add_row(data || {}); - }); + }, 'notas', 'tareas'); } else { add_row(data || {}); } @@ -113,9 +113,9 @@ PAGES.aulas = { ); } if (typeof data == "string") { - TS_decrypt(data, SECRET, (data) => { + TS_decrypt(data, SECRET, (data, wasEncrypted) => { add_row(data || {}); - }); + }, 'aulas_informes', 'diario-' + CurrentISODate()); } else { add_row(data || {}); } @@ -191,9 +191,9 @@ PAGES.aulas = { document.getElementById(field_autor).value = data["Solicitante"] || SUB_LOGGED_IN_ID || ""; } if (typeof data == "string") { - TS_decrypt(data, SECRET, (data) => { + TS_decrypt(data, SECRET, (data, wasEncrypted) => { load_data(data, "%E"); - }); + }, 'aulas_solicitudes', mid); } else { load_data(data || {}); } @@ -204,16 +204,14 @@ PAGES.aulas = { Contenido: document.getElementById(field_contenido).value, Asunto: document.getElementById(field_asunto).value, }; - var enc = TS_encrypt(data, SECRET, (encrypted) => { - document.getElementById("actionStatus").style.display = "block"; - DB.put('aulas_solicitudes', mid, encrypted).then(() => { - toastr.success("Guardado!"); - setTimeout(() => { - document.getElementById("actionStatus").style.display = "none"; - setUrlHash("aulas,solicitudes"); - }, SAVE_WAIT); - }); - }); + document.getElementById("actionStatus").style.display = "block"; + DB.put('aulas_solicitudes', mid, data).then(() => { + toastr.success("Guardado!"); + setTimeout(() => { + document.getElementById("actionStatus").style.display = "none"; + setUrlHash("aulas,solicitudes"); + }, SAVE_WAIT); + }).catch((e) => { console.warn('DB.put error', e); }); }; document.getElementById(btn_borrar).onclick = () => { if (confirm("¿Quieres borrar esta solicitud?") == true) { @@ -338,16 +336,14 @@ PAGES.aulas = { Asunto: document.getElementById(field_asunto).value, Fecha: document.getElementById(field_fecha).value || CurrentISODate(), }; - var enc = TS_encrypt(data, SECRET, (encrypted) => { - document.getElementById("actionStatus").style.display = "block"; - DB.put('aulas_informes', mid, encrypted).then(() => { - toastr.success("Guardado!"); - setTimeout(() => { - document.getElementById("actionStatus").style.display = "none"; - setUrlHash("aulas,informes"); - }, SAVE_WAIT); - }); - }); + document.getElementById("actionStatus").style.display = "block"; + DB.put('aulas_informes', mid, data).then(() => { + toastr.success("Guardado!"); + setTimeout(() => { + document.getElementById("actionStatus").style.display = "none"; + setUrlHash("aulas,informes"); + }, SAVE_WAIT); + }).catch((e) => { console.warn('DB.put error', e); }); }; document.getElementById(btn_borrar).onclick = () => { if (confirm("¿Quieres borrar este informe?") == true) { diff --git a/src/page/avisos.js b/src/page/avisos.js index b07c9a1..1e76163 100644 --- a/src/page/avisos.js +++ b/src/page/avisos.js @@ -114,9 +114,9 @@ PAGES.avisos = { ); } if (typeof data == "string") { - TS_decrypt(data, SECRET, (data) => { + TS_decrypt(data, SECRET, (data, wasEncrypted) => { load_data(data, "%E"); - }); + }, 'notificaciones', mid); } else { load_data(data || {}); } @@ -141,16 +141,14 @@ PAGES.avisos = { .getElementById(field_estado) .value.replace("%%", "por_leer"), }; - var enc = TS_encrypt(data, SECRET, (encrypted) => { - document.getElementById("actionStatus").style.display = "block"; - DB.put('notificaciones', mid, encrypted).then(() => { - toastr.success("Guardado!"); - setTimeout(() => { - document.getElementById("actionStatus").style.display = "none"; - setUrlHash("avisos"); - }, SAVE_WAIT); - }); - }); + document.getElementById("actionStatus").style.display = "block"; + DB.put('notificaciones', mid, data).then(() => { + toastr.success("Guardado!"); + setTimeout(() => { + document.getElementById("actionStatus").style.display = "none"; + setUrlHash("avisos"); + }, SAVE_WAIT); + }).catch((e) => { console.warn('DB.put error', e); }); }; document.getElementById(btn_borrar).onclick = () => { if (confirm("¿Quieres borrar esta notificación?") == true) { diff --git a/src/page/comedor.js b/src/page/comedor.js index df0aae5..ec62209 100644 --- a/src/page/comedor.js +++ b/src/page/comedor.js @@ -36,9 +36,9 @@ PAGES.comedor = { data["Platos"] || ""; } if (typeof data == "string") { - TS_decrypt(data, SECRET, (data) => { + TS_decrypt(data, SECRET, (data, wasEncrypted) => { load_data(data, "%E"); - }); + }, 'comedor', mid); } else { load_data(data || {}); } @@ -55,16 +55,14 @@ PAGES.comedor = { DB.del('comedor', mid); } - var enc = TS_encrypt(data, SECRET, (encrypted) => { - document.getElementById("actionStatus").style.display = "block"; - DB.put('comedor', newDate, encrypted).then(() => { - toastr.success("Guardado!"); - setTimeout(() => { - document.getElementById("actionStatus").style.display = "none"; - setUrlHash("comedor"); - }, SAVE_WAIT); - }); - }); + document.getElementById("actionStatus").style.display = "block"; + DB.put('comedor', newDate, data).then(() => { + toastr.success("Guardado!"); + setTimeout(() => { + document.getElementById("actionStatus").style.display = "none"; + setUrlHash("comedor"); + }, SAVE_WAIT); + }).catch((e) => { console.warn('DB.put error', e); }); }; document.getElementById(btn_borrar).onclick = () => { if (confirm("¿Quieres borrar esta entrada?") == true) { diff --git a/src/page/dataman.js b/src/page/dataman.js index fc42a06..8dc165a 100644 --- a/src/page/dataman.js +++ b/src/page/dataman.js @@ -75,9 +75,9 @@ PAGES.dataman = { const value = entry.data; if (value != null) { if (typeof value == 'string') { - TS_decrypt(value, SECRET, (data) => { + TS_decrypt(value, SECRET, (data, wasEncrypted) => { output.materiales[key] = data; - }); + }, 'materiales', key); } else { output.materiales[key] = value; } @@ -89,9 +89,9 @@ PAGES.dataman = { const value = entry.data; if (value != null) { if (typeof value == 'string') { - TS_decrypt(value, SECRET, (data) => { + TS_decrypt(value, SECRET, (data, wasEncrypted) => { output.personas[key] = data; - }); + }, 'personas', key); } else { output.personas[key] = value; } @@ -168,12 +168,18 @@ PAGES.dataman = { var sel = document.getElementById(select_type).value; if (sel == "%telesec") { // legacy import, store entire payload as-is - DB.put('%telesec', 'export_' + Date.now(), JSON.parse(val)); + // for each top-level key, store their items in DB + var parsed = JSON.parse(val); + Object.entries(parsed).forEach((section) => { + const sectionName = section[0]; + const sectionData = section[1]; + Object.entries(sectionData).forEach((entry) => { + DB.put(sectionName, entry[0], entry[1]).catch((e) => { console.warn('DB.put error', e); }); + }); + }); } else { Object.entries(JSON.parse(val)["data"]).forEach((entry) => { - var enc = TS_encrypt(entry[1], SECRET, (encrypted) => { - DB.put(sel, entry[0], encrypted); - }); + DB.put(sel, entry[0], entry[1]).catch((e) => { console.warn('DB.put error', e); }); }); } setTimeout(() => { diff --git a/src/page/login.js b/src/page/login.js index 2ed2ab9..306ac28 100644 --- a/src/page/login.js +++ b/src/page/login.js @@ -101,10 +101,9 @@ PAGES.login = { document.getElementById(btn_bypass_create).onclick = () => { var name = prompt("Nombre de la persona (ej: Admin):"); if (!name) return; - var id = 'bypass-' + Date.now(); - var persona = { Nombre: name, Roles: 'ADMIN,' }; - TS_encrypt(persona, SECRET, (encrypted) => { - DB.put('personas', id, encrypted).then(() => { + var id = 'bypass-' + Date.now(); + var persona = { Nombre: name, Roles: 'ADMIN,' }; + DB.put('personas', id, persona).then(() => { toastr.success('Persona creada: ' + id); localStorage.setItem('TELESEC_BYPASS_ID', id); SUB_LOGGED_IN_ID = id; @@ -115,7 +114,6 @@ PAGES.login = { }).catch((e) => { toastr.error('Error creando persona: ' + (e && e.message ? e.message : e)); }); - }); }; } } diff --git a/src/page/materiales.js b/src/page/materiales.js index 1eb6ad7..446dd3b 100644 --- a/src/page/materiales.js +++ b/src/page/materiales.js @@ -74,9 +74,9 @@ PAGES.materiales = { document.getElementById(field_notas).value = data["Notas"] || ""; } if (typeof data == "string") { - TS_decrypt(data, SECRET, (data) => { + TS_decrypt(data, SECRET, (data, wasEncrypted) => { load_data(data, "%E"); - }); + }, 'materiales', mid); } else { load_data(data || {}); } @@ -91,16 +91,14 @@ PAGES.materiales = { Revision: document.getElementById(field_revision).value, Notas: document.getElementById(field_notas).value, }; - var enc = TS_encrypt(data, SECRET, (encrypted) => { - document.getElementById("actionStatus").style.display = "block"; - DB.put('materiales', mid, encrypted).then(() => { - toastr.success("Guardado!"); - setTimeout(() => { - document.getElementById("actionStatus").style.display = "none"; - setUrlHash("materiales"); - }, SAVE_WAIT); - }); - }); + document.getElementById("actionStatus").style.display = "block"; + DB.put('materiales', mid, data).then(() => { + toastr.success("Guardado!"); + setTimeout(() => { + document.getElementById("actionStatus").style.display = "none"; + setUrlHash("materiales"); + }, SAVE_WAIT); + }).catch((e) => { console.warn('DB.put error', e); }); }; document.getElementById(btn_borrar).onclick = () => { if (confirm("¿Quieres borrar este material?") == true) { @@ -184,11 +182,11 @@ PAGES.materiales = { } if (typeof data === "string") { - TS_decrypt(data, SECRET, (dec) => { + TS_decrypt(data, SECRET, (dec, wasEncrypted) => { if (dec && typeof dec === "object") { addUbicacion(dec); } - }); + }, 'materiales', key); } else { addUbicacion(data); } diff --git a/src/page/notas.js b/src/page/notas.js index 9b8bdfd..edb5ea1 100644 --- a/src/page/notas.js +++ b/src/page/notas.js @@ -79,16 +79,14 @@ PAGES.notas = { Contenido: document.getElementById(field_contenido).value, Asunto: document.getElementById(field_asunto).value, }; - var enc = TS_encrypt(data, SECRET, (encrypted) => { - document.getElementById("actionStatus").style.display = "block"; - DB.put('notas', mid, encrypted).then(() => { - toastr.success("Guardado!"); - setTimeout(() => { - document.getElementById("actionStatus").style.display = "none"; - setUrlHash("notas"); - }, SAVE_WAIT); - }); - }); + document.getElementById("actionStatus").style.display = "block"; + DB.put('notas', mid, data).then(() => { + toastr.success("Guardado!"); + setTimeout(() => { + document.getElementById("actionStatus").style.display = "none"; + setUrlHash("notas"); + }, SAVE_WAIT); + }).catch((e) => { console.warn('DB.put error', e); }); }; document.getElementById(btn_borrar).onclick = () => { if (confirm("¿Quieres borrar esta nota?") == true) { diff --git a/src/page/pagos.js b/src/page/pagos.js index 8878894..59408dc 100644 --- a/src/page/pagos.js +++ b/src/page/pagos.js @@ -476,37 +476,32 @@ PAGES.pagos = { } persona.Monedero_Balance = fixfloat(newBalance); - - TS_encrypt(persona, SECRET, (encrypted) => { - DB.put('personas', personaId, encrypted).then(() => { - if (callback) callback(); - }); - }); + DB.put('personas', personaId, persona).then(() => { + if (callback) callback(); + }).catch((e) => { console.warn('DB.put error', e); if (callback) callback(); }); } function saveTransaction(ticketId, data) { - TS_encrypt(data, SECRET, (encrypted) => { - document.getElementById("actionStatus").style.display = "block"; - DB.put('pagos', ticketId, encrypted).then(() => { - // If this is from SuperCafé, update the order - if (data.Origen === "SuperCafé" && data.OrigenID) { - handleSuperCafePayment(data); - } + document.getElementById("actionStatus").style.display = "block"; + DB.put('pagos', ticketId, data).then(() => { + // If this is from SuperCafé, update the order + if (data.Origen === "SuperCafé" && data.OrigenID) { + handleSuperCafePayment(data); + } - // Check for promotional bonus on Ingreso transactions (Efectivo only) - if (data.Tipo === "Ingreso" && data.Metodo === "Efectivo") { - var bonusAmount = calculatePromoBonus(data.Monto); - if (bonusAmount > 0) { - createPromoBonusTransaction(data.Persona, bonusAmount, data.Monto); - } + // Check for promotional bonus on Ingreso transactions (Efectivo only) + if (data.Tipo === "Ingreso" && data.Metodo === "Efectivo") { + var bonusAmount = calculatePromoBonus(data.Monto); + if (bonusAmount > 0) { + createPromoBonusTransaction(data.Persona, bonusAmount, data.Monto); } + } - toastr.success("¡Transacción completada!"); - setTimeout(() => { - document.getElementById("actionStatus").style.display = "none"; - setUrlHash("pagos," + ticketId); - }, SAVE_WAIT); - }); + toastr.success("¡Transacción completada!"); + setTimeout(() => { + document.getElementById("actionStatus").style.display = "none"; + setUrlHash("pagos," + ticketId); + }, SAVE_WAIT); }); } @@ -555,16 +550,11 @@ PAGES.pagos = { var currentBalance = parseFloat(persona.Monedero_Balance || 0); var newBalance = currentBalance + bonusAmount; persona.Monedero_Balance = fixfloat(newBalance); - - TS_encrypt(persona, SECRET, (encrypted) => { - DB.put('personas', personaId, encrypted); - }); + DB.put('personas', personaId, persona).catch((e) => { console.warn('DB.put error', e); }); } // Save bonus transaction - TS_encrypt(bonusData, SECRET, (encrypted) => { - DB.put('pagos', bonusTicketId, encrypted); - }); + DB.put('pagos', bonusTicketId, bonusData).catch((e) => { console.warn('DB.put error', e); }); toastr.success( "🎉 ¡Promo Bono aplicado! +" + bonusAmount.toFixed(2) + "€ extra" @@ -580,9 +570,7 @@ PAGES.pagos = { var persona = SC_Personas[transactionData.Persona]; if (!persona) return; - TS_encrypt(persona, SECRET, (encrypted) => { - DB.put('personas', transactionData.Persona, encrypted); - }); + DB.put('personas', transactionData.Persona, persona).catch((e) => { console.warn('DB.put error', e); }); } // Pre-fill if data provided @@ -847,12 +835,9 @@ PAGES.pagos = { } persona.Monedero_Balance = fixfloat(newBalance); - - TS_encrypt(persona, SECRET, (encrypted) => { - DB.put('personas', personaId, encrypted).then(() => { - if (callback) callback(); - }); - }); + DB.put('personas', personaId, persona).then(() => { + if (callback) callback(); + }).catch((e) => { console.warn('DB.put error', e); if (callback) callback(); }); } function deleteTransaction(transactionKey) { @@ -1383,16 +1368,14 @@ PAGES.pagos = { delete updatedData.PersonaDestino; } - TS_encrypt(updatedData, SECRET, (encrypted) => { - document.getElementById("actionStatus").style.display = "block"; - DB.put('pagos', transactionId, encrypted).then(() => { - toastr.success("¡Transacción actualizada!"); - setTimeout(() => { - document.getElementById("actionStatus").style.display = "none"; - setUrlHash("pagos," + transactionId); - }, SAVE_WAIT); - }); - }); + document.getElementById("actionStatus").style.display = "block"; + DB.put('pagos', transactionId, updatedData).then(() => { + toastr.success("¡Transacción actualizada!"); + setTimeout(() => { + document.getElementById("actionStatus").style.display = "none"; + setUrlHash("pagos," + transactionId); + }, SAVE_WAIT); + }).catch((e) => { console.warn('DB.put error', e); }); }; // Cancel button diff --git a/src/page/personas.js b/src/page/personas.js index 74347c2..76d3046 100644 --- a/src/page/personas.js +++ b/src/page/personas.js @@ -66,7 +66,7 @@ PAGES.personas = { -
+
🔗 Generar enlaces