Compare commits
3 Commits
main
...
copilot/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9e79e8d3a | ||
|
|
c9125e5b75 | ||
|
|
dadbfb56a4 |
553
src/db.js
553
src/db.js
@@ -1,84 +1,45 @@
|
|||||||
// Simple PouchDB wrapper for TeleSec
|
// TeleSec Database Layer - Supports both PouchDB and remoteStorage.js
|
||||||
// - Uses PouchDB for local storage and optional replication to a CouchDB server
|
// - Users can choose their preferred backend via login settings
|
||||||
|
// - Provides unified API: init, put, get, del, map, list, replicate
|
||||||
// - Stores records as docs with _id = "<table>:<id>" and field `data` containing either plain object or encrypted string
|
// - Stores records as docs with _id = "<table>:<id>" and field `data` containing either plain object or encrypted string
|
||||||
// - Exposes: init, put, get, del, map, list, replicate
|
|
||||||
|
|
||||||
var DB = (function () {
|
var DB = (function () {
|
||||||
let local = null;
|
// Constants
|
||||||
let remote = null;
|
const ENCRYPTED_PREFIX = 'RSA{';
|
||||||
let changes = null;
|
const ENCRYPTED_SUFFIX = '}';
|
||||||
let repPush = null;
|
|
||||||
let repPull = null;
|
let backend = null; // 'pouchdb' or 'remotestorage'
|
||||||
let callbacks = {}; // table -> [cb]
|
let callbacks = {}; // table -> [cb]
|
||||||
let docCache = {}; // _id -> last data snapshot (stringified)
|
let docCache = {}; // _id -> last data snapshot (stringified)
|
||||||
|
|
||||||
function ensureLocal() {
|
// PouchDB-specific state
|
||||||
if (local) return;
|
let pouchLocal = null;
|
||||||
|
let pouchRemote = null;
|
||||||
|
let pouchChanges = null;
|
||||||
|
let pouchRepPush = null;
|
||||||
|
let pouchRepPull = null;
|
||||||
|
|
||||||
|
// remoteStorage-specific state
|
||||||
|
let rsClient = null;
|
||||||
|
let rsModule = null;
|
||||||
|
|
||||||
|
// ==================== PouchDB Backend Implementation ====================
|
||||||
|
|
||||||
|
function ensurePouchLocal() {
|
||||||
|
if (pouchLocal) return;
|
||||||
try {
|
try {
|
||||||
const localName = 'telesec';
|
const localName = 'telesec';
|
||||||
local = new PouchDB(localName);
|
pouchLocal = new PouchDB(localName);
|
||||||
if (changes) {
|
if (pouchChanges) {
|
||||||
try { changes.cancel(); } catch (e) {}
|
try { pouchChanges.cancel(); } catch (e) {}
|
||||||
}
|
}
|
||||||
changes = local.changes({ live: true, since: 'now', include_docs: true }).on('change', onChange);
|
pouchChanges = pouchLocal.changes({ live: true, since: 'now', include_docs: true }).on('change', onPouchChange);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('ensureLocal error', e);
|
console.warn('ensurePouchLocal error', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeId(table, id) {
|
function onPouchChange(change) {
|
||||||
return table + ':' + id;
|
|
||||||
}
|
|
||||||
|
|
||||||
function init(opts) {
|
|
||||||
const localName = 'telesec';
|
|
||||||
try {
|
|
||||||
if (opts && opts.secret) {
|
|
||||||
SECRET = opts.secret;
|
|
||||||
try { localStorage.setItem('TELESEC_SECRET', SECRET); } catch (e) {}
|
|
||||||
}
|
|
||||||
} catch (e) {}
|
|
||||||
local = new PouchDB(localName);
|
|
||||||
|
|
||||||
if (opts.remoteServer) {
|
|
||||||
try {
|
|
||||||
const server = opts.remoteServer.replace(/\/$/, '');
|
|
||||||
const dbname = encodeURIComponent((opts.dbname || localName));
|
|
||||||
let authPart = '';
|
|
||||||
if (opts.username) authPart = opts.username + ':' + (opts.password || '') + '@';
|
|
||||||
const remoteUrl = server.replace(/https?:\/\//, (m) => m) + '/' + dbname;
|
|
||||||
if (opts.username) remote = new PouchDB(remoteUrl.replace(/:\/\//, '://' + authPart));
|
|
||||||
else remote = new PouchDB(remoteUrl);
|
|
||||||
replicateToRemote();
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('Remote DB init error', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changes) changes.cancel();
|
|
||||||
changes = local.changes({ live: true, since: 'now', include_docs: true }).on('change', onChange);
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
function replicateToRemote() {
|
|
||||||
ensureLocal();
|
|
||||||
if (!local || !remote) return;
|
|
||||||
try { if (repPush && repPush.cancel) repPush.cancel(); } catch (e) {}
|
|
||||||
try { if (repPull && repPull.cancel) repPull.cancel(); } catch (e) {}
|
|
||||||
|
|
||||||
repPush = PouchDB.replicate(local, remote, { live: true, retry: true })
|
|
||||||
.on('error', function (err) { console.warn('Replication push error', err); });
|
|
||||||
repPull = PouchDB.replicate(remote, local, { live: true, retry: true })
|
|
||||||
.on('error', function (err) { console.warn('Replication pull error', err); });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
||||||
window.addEventListener('online', function () {
|
|
||||||
try { setTimeout(replicateToRemote, 1000); } catch (e) {}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function onChange(change) {
|
|
||||||
const doc = change.doc;
|
const doc = change.doc;
|
||||||
if (!doc || !doc._id) return;
|
if (!doc || !doc._id) return;
|
||||||
const [table, id] = doc._id.split(':');
|
const [table, id] = doc._id.split(':');
|
||||||
@@ -109,19 +70,61 @@ var DB = (function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function put(table, id, data) {
|
async function initPouchDB(opts) {
|
||||||
ensureLocal();
|
const localName = 'telesec';
|
||||||
const _id = makeId(table, id);
|
|
||||||
try {
|
try {
|
||||||
const existing = await local.get(_id).catch(() => null);
|
if (opts && opts.secret) {
|
||||||
|
SECRET = opts.secret;
|
||||||
|
try { localStorage.setItem('TELESEC_SECRET', SECRET); } catch (e) {}
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
pouchLocal = new PouchDB(localName);
|
||||||
|
|
||||||
|
if (opts.remoteServer) {
|
||||||
|
try {
|
||||||
|
const server = opts.remoteServer.replace(/\/$/, '');
|
||||||
|
const dbname = encodeURIComponent((opts.dbname || localName));
|
||||||
|
let authPart = '';
|
||||||
|
if (opts.username) authPart = opts.username + ':' + (opts.password || '') + '@';
|
||||||
|
const remoteUrl = server.replace(/https?:\/\//, (m) => m) + '/' + dbname;
|
||||||
|
if (opts.username) pouchRemote = new PouchDB(remoteUrl.replace(/:\/\//, '://' + authPart));
|
||||||
|
else pouchRemote = new PouchDB(remoteUrl);
|
||||||
|
replicatePouchToRemote();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('PouchDB Remote init error', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pouchChanges) pouchChanges.cancel();
|
||||||
|
pouchChanges = pouchLocal.changes({ live: true, since: 'now', include_docs: true }).on('change', onPouchChange);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
function replicatePouchToRemote() {
|
||||||
|
ensurePouchLocal();
|
||||||
|
if (!pouchLocal || !pouchRemote) return;
|
||||||
|
try { if (pouchRepPush && pouchRepPush.cancel) pouchRepPush.cancel(); } catch (e) {}
|
||||||
|
try { if (pouchRepPull && pouchRepPull.cancel) pouchRepPull.cancel(); } catch (e) {}
|
||||||
|
|
||||||
|
pouchRepPush = PouchDB.replicate(pouchLocal, pouchRemote, { live: true, retry: true })
|
||||||
|
.on('error', function (err) { console.warn('Replication push error', err); });
|
||||||
|
pouchRepPull = PouchDB.replicate(pouchRemote, pouchLocal, { live: true, retry: true })
|
||||||
|
.on('error', function (err) { console.warn('Replication pull error', err); });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function pouchPut(table, id, data) {
|
||||||
|
ensurePouchLocal();
|
||||||
|
const _id = table + ':' + id;
|
||||||
|
try {
|
||||||
|
const existing = await pouchLocal.get(_id).catch(() => null);
|
||||||
if (data === null) {
|
if (data === null) {
|
||||||
if (existing) await local.remove(existing);
|
if (existing) await pouchLocal.remove(existing);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const doc = existing || { _id: _id };
|
const doc = existing || { _id: _id };
|
||||||
var toStore = data;
|
var toStore = data;
|
||||||
try {
|
try {
|
||||||
var isEncryptedString = (typeof data === 'string' && data.startsWith('RSA{') && data.endsWith('}'));
|
var isEncryptedString = (typeof data === 'string' && data.startsWith(ENCRYPTED_PREFIX) && data.endsWith(ENCRYPTED_SUFFIX));
|
||||||
if (!isEncryptedString && typeof TS_encrypt === 'function' && typeof SECRET !== 'undefined' && SECRET) {
|
if (!isEncryptedString && typeof TS_encrypt === 'function' && typeof SECRET !== 'undefined' && SECRET) {
|
||||||
toStore = await new Promise(resolve => {
|
toStore = await new Promise(resolve => {
|
||||||
try { TS_encrypt(data, SECRET, enc => resolve(enc)); } catch (e) { resolve(data); }
|
try { TS_encrypt(data, SECRET, enc => resolve(enc)); } catch (e) { resolve(data); }
|
||||||
@@ -132,32 +135,28 @@ var DB = (function () {
|
|||||||
doc.table = table;
|
doc.table = table;
|
||||||
doc.ts = new Date().toISOString();
|
doc.ts = new Date().toISOString();
|
||||||
if (existing) doc._rev = existing._rev;
|
if (existing) doc._rev = existing._rev;
|
||||||
await local.put(doc);
|
await pouchLocal.put(doc);
|
||||||
|
|
||||||
// FIX: manually trigger map() callbacks for local update
|
|
||||||
// onChange will update docCache and notify all subscribers
|
|
||||||
onChange({ doc: doc });
|
|
||||||
|
|
||||||
|
// manually trigger callbacks for local update
|
||||||
|
onPouchChange({ doc: doc });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('DB.put error', e);
|
console.error('PouchDB.put error', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function get(table, id) {
|
async function pouchGet(table, id) {
|
||||||
ensureLocal();
|
ensurePouchLocal();
|
||||||
const _id = makeId(table, id);
|
const _id = table + ':' + id;
|
||||||
try {
|
try {
|
||||||
const doc = await local.get(_id);
|
const doc = await pouchLocal.get(_id);
|
||||||
return doc.data;
|
return doc.data;
|
||||||
} catch (e) { return null; }
|
} catch (e) { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function del(table, id) { return put(table, id, null); }
|
async function pouchList(table) {
|
||||||
|
ensurePouchLocal();
|
||||||
async function list(table) {
|
|
||||||
ensureLocal();
|
|
||||||
try {
|
try {
|
||||||
const res = await local.allDocs({ include_docs: true, startkey: table + ':', endkey: table + ':\uffff' });
|
const res = await pouchLocal.allDocs({ include_docs: true, startkey: table + ':', endkey: table + ':\uffff' });
|
||||||
return res.rows.map(r => {
|
return res.rows.map(r => {
|
||||||
const id = r.id.split(':')[1];
|
const id = r.id.split(':')[1];
|
||||||
try { docCache[r.id] = typeof r.doc.data === 'string' ? r.doc.data : JSON.stringify(r.doc.data); } catch (e) {}
|
try { docCache[r.id] = typeof r.doc.data === 'string' ? r.doc.data : JSON.stringify(r.doc.data); } catch (e) {}
|
||||||
@@ -166,6 +165,15 @@ var DB = (function () {
|
|||||||
} catch (e) { return []; }
|
} catch (e) { return []; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pouchMap(table, cb) {
|
||||||
|
ensurePouchLocal();
|
||||||
|
callbacks[table] = callbacks[table] || [];
|
||||||
|
callbacks[table].push(cb);
|
||||||
|
pouchList(table).then(rows => rows.forEach(r => cb(r.data, r.id)));
|
||||||
|
return () => { callbacks[table] = callbacks[table].filter(x => x !== cb); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// PouchDB Attachment methods
|
||||||
function dataURLtoBlob(dataurl) {
|
function dataURLtoBlob(dataurl) {
|
||||||
const arr = dataurl.split(',');
|
const arr = dataurl.split(',');
|
||||||
const mime = arr[0].match(/:(.*?);/)[1];
|
const mime = arr[0].match(/:(.*?);/)[1];
|
||||||
@@ -176,28 +184,28 @@ var DB = (function () {
|
|||||||
return new Blob([u8arr], { type: mime });
|
return new Blob([u8arr], { type: mime });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function putAttachment(table, id, name, dataUrlOrBlob, contentType) {
|
async function pouchPutAttachment(table, id, name, dataUrlOrBlob, contentType) {
|
||||||
ensureLocal();
|
ensurePouchLocal();
|
||||||
const _id = makeId(table, id);
|
const _id = table + ':' + id;
|
||||||
try {
|
try {
|
||||||
let doc = await local.get(_id).catch(() => null);
|
let doc = await pouchLocal.get(_id).catch(() => null);
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
await local.put({ _id: _id, table: table, ts: new Date().toISOString(), data: {} });
|
await pouchLocal.put({ _id: _id, table: table, ts: new Date().toISOString(), data: {} });
|
||||||
doc = await local.get(_id);
|
doc = await pouchLocal.get(_id);
|
||||||
}
|
}
|
||||||
let blob = dataUrlOrBlob;
|
let blob = dataUrlOrBlob;
|
||||||
if (typeof dataUrlOrBlob === 'string' && dataUrlOrBlob.indexOf('data:') === 0) blob = dataURLtoBlob(dataUrlOrBlob);
|
if (typeof dataUrlOrBlob === 'string' && dataUrlOrBlob.indexOf('data:') === 0) blob = dataURLtoBlob(dataUrlOrBlob);
|
||||||
const type = contentType || (blob && blob.type) || 'application/octet-stream';
|
const type = contentType || (blob && blob.type) || 'application/octet-stream';
|
||||||
await local.putAttachment(_id, name, doc._rev, blob, type);
|
await pouchLocal.putAttachment(_id, name, doc._rev, blob, type);
|
||||||
return true;
|
return true;
|
||||||
} catch (e) { console.error('putAttachment error', e); return false; }
|
} catch (e) { console.error('putAttachment error', e); return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAttachment(table, id, name) {
|
async function pouchGetAttachment(table, id, name) {
|
||||||
ensureLocal();
|
ensurePouchLocal();
|
||||||
const _id = makeId(table, id);
|
const _id = table + ':' + id;
|
||||||
try {
|
try {
|
||||||
const blob = await local.getAttachment(_id, name);
|
const blob = await pouchLocal.getAttachment(_id, name);
|
||||||
if (!blob) return null;
|
if (!blob) return null;
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
@@ -208,11 +216,11 @@ var DB = (function () {
|
|||||||
} catch (e) { return null; }
|
} catch (e) { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listAttachments(table, id) {
|
async function pouchListAttachments(table, id) {
|
||||||
ensureLocal();
|
ensurePouchLocal();
|
||||||
const _id = makeId(table, id);
|
const _id = table + ':' + id;
|
||||||
try {
|
try {
|
||||||
const doc = await local.get(_id, { attachments: true });
|
const doc = await pouchLocal.get(_id, { attachments: true });
|
||||||
if (!doc || !doc._attachments) return [];
|
if (!doc || !doc._attachments) return [];
|
||||||
const out = [];
|
const out = [];
|
||||||
for (const name of Object.keys(doc._attachments)) {
|
for (const name of Object.keys(doc._attachments)) {
|
||||||
@@ -226,7 +234,7 @@ var DB = (function () {
|
|||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
try {
|
try {
|
||||||
const durl = await getAttachment(table, id, name);
|
const durl = await pouchGetAttachment(table, id, name);
|
||||||
out.push({ name: name, dataUrl: durl, content_type: null });
|
out.push({ name: name, dataUrl: durl, content_type: null });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
out.push({ name: name, dataUrl: null, content_type: null });
|
out.push({ name: name, dataUrl: null, content_type: null });
|
||||||
@@ -235,12 +243,12 @@ var DB = (function () {
|
|||||||
return out;
|
return out;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
try {
|
try {
|
||||||
const doc = await local.get(_id).catch(() => null);
|
const doc = await pouchLocal.get(_id).catch(() => null);
|
||||||
if (!doc || !doc._attachments) return [];
|
if (!doc || !doc._attachments) return [];
|
||||||
const out = [];
|
const out = [];
|
||||||
for (const name of Object.keys(doc._attachments)) {
|
for (const name of Object.keys(doc._attachments)) {
|
||||||
try {
|
try {
|
||||||
const durl = await getAttachment(table, id, name);
|
const durl = await pouchGetAttachment(table, id, name);
|
||||||
out.push({ name: name, dataUrl: durl, content_type: null });
|
out.push({ name: name, dataUrl: durl, content_type: null });
|
||||||
} catch (e) { out.push({ name: name, dataUrl: null, content_type: null }); }
|
} catch (e) { out.push({ name: name, dataUrl: null, content_type: null }); }
|
||||||
}
|
}
|
||||||
@@ -249,26 +257,317 @@ var DB = (function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteAttachment(table, id, name) {
|
async function pouchDeleteAttachment(table, id, name) {
|
||||||
ensureLocal();
|
ensurePouchLocal();
|
||||||
const _id = makeId(table, id);
|
const _id = table + ':' + id;
|
||||||
try {
|
try {
|
||||||
const doc = await local.get(_id);
|
const doc = await pouchLocal.get(_id);
|
||||||
if (!doc || !doc._attachments || !doc._attachments[name]) return false;
|
if (!doc || !doc._attachments || !doc._attachments[name]) return false;
|
||||||
delete doc._attachments[name];
|
delete doc._attachments[name];
|
||||||
await local.put(doc);
|
await pouchLocal.put(doc);
|
||||||
return true;
|
return true;
|
||||||
} catch (e) { console.error('deleteAttachment error', e); return false; }
|
} catch (e) { console.error('deleteAttachment error', e); return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
function map(table, cb) {
|
// ==================== remoteStorage Backend Implementation ====================
|
||||||
ensureLocal();
|
|
||||||
|
function initRemoteStorage(opts) {
|
||||||
|
try {
|
||||||
|
if (opts && opts.secret) {
|
||||||
|
SECRET = opts.secret;
|
||||||
|
try { localStorage.setItem('TELESEC_SECRET', SECRET); } catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize RemoteStorage client
|
||||||
|
rsClient = new RemoteStorage({ logging: opts.logging || false });
|
||||||
|
|
||||||
|
// Define TeleSec data module
|
||||||
|
rsClient.access.claim('telesec', 'rw');
|
||||||
|
rsClient.caching.enable('/telesec/');
|
||||||
|
|
||||||
|
// Define module to handle our data structure
|
||||||
|
rsModule = rsClient.scope('/telesec/');
|
||||||
|
|
||||||
|
// Listen for changes
|
||||||
|
rsModule.on('change', onRemoteStorageChange);
|
||||||
|
|
||||||
|
// Auto-connect if user address is provided
|
||||||
|
if (opts.rsUserAddress) {
|
||||||
|
rsClient.connect(opts.rsUserAddress, opts.rsToken || undefined).then(() => {
|
||||||
|
console.log('RemoteStorage connected successfully');
|
||||||
|
}).catch((err) => {
|
||||||
|
console.warn('RemoteStorage connection error', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('RemoteStorage init error', e);
|
||||||
|
return Promise.reject(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRemoteStorageChange(event) {
|
||||||
|
try {
|
||||||
|
if (!event || !event.path) return;
|
||||||
|
|
||||||
|
// Parse path: /telesec/table/id
|
||||||
|
const pathParts = event.path.split('/').filter(p => p);
|
||||||
|
if (pathParts.length < 3 || pathParts[0] !== 'telesec') return;
|
||||||
|
|
||||||
|
const table = pathParts[1];
|
||||||
|
const id = pathParts[2];
|
||||||
|
const _id = table + ':' + id;
|
||||||
|
|
||||||
|
// Handle deletion
|
||||||
|
if (!event.newValue) {
|
||||||
|
delete docCache[_id];
|
||||||
|
if (callbacks[table]) {
|
||||||
|
callbacks[table].forEach(cb => {
|
||||||
|
try { cb(null, id); } catch (e) { console.error(e); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle insert/update
|
||||||
|
try {
|
||||||
|
const data = event.newValue;
|
||||||
|
const now = typeof data === 'string' ? data : JSON.stringify(data);
|
||||||
|
const prev = docCache[_id];
|
||||||
|
if (prev === now) return; // no meaningful change
|
||||||
|
docCache[_id] = now;
|
||||||
|
|
||||||
|
if (callbacks[table]) {
|
||||||
|
callbacks[table].forEach(cb => {
|
||||||
|
try { cb(data, id); } catch (e) { console.error(e); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('RemoteStorage change handler error', e);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('onRemoteStorageChange error', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function rsPut(table, id, data) {
|
||||||
|
if (!rsModule) throw new Error('RemoteStorage not initialized');
|
||||||
|
try {
|
||||||
|
const path = table + '/' + id;
|
||||||
|
if (data === null) {
|
||||||
|
await rsModule.remove(path);
|
||||||
|
// Trigger change manually
|
||||||
|
onRemoteStorageChange({ path: '/telesec/' + path, newValue: null });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var toStore = data;
|
||||||
|
try {
|
||||||
|
var isEncryptedString = (typeof data === 'string' && data.startsWith(ENCRYPTED_PREFIX) && data.endsWith(ENCRYPTED_SUFFIX));
|
||||||
|
if (!isEncryptedString && typeof TS_encrypt === 'function' && typeof SECRET !== 'undefined' && SECRET) {
|
||||||
|
toStore = await new Promise(resolve => {
|
||||||
|
try { TS_encrypt(data, SECRET, enc => resolve(enc)); } catch (e) { resolve(data); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) { toStore = data; }
|
||||||
|
|
||||||
|
await rsModule.storeObject('application/json', path, toStore);
|
||||||
|
// Trigger change manually for immediate UI update
|
||||||
|
onRemoteStorageChange({ path: '/telesec/' + path, newValue: toStore });
|
||||||
|
} catch (e) {
|
||||||
|
console.error('RemoteStorage.put error', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function rsGet(table, id) {
|
||||||
|
if (!rsModule) return null;
|
||||||
|
try {
|
||||||
|
const path = table + '/' + id;
|
||||||
|
const data = await rsModule.getObject(path);
|
||||||
|
return data || null;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function rsList(table) {
|
||||||
|
if (!rsModule) return [];
|
||||||
|
try {
|
||||||
|
const listing = await rsModule.getListing(table + '/');
|
||||||
|
if (!listing) return [];
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
for (const filename of Object.keys(listing)) {
|
||||||
|
// Remove trailing slash if present, otherwise use as-is
|
||||||
|
const id = filename.endsWith('/') ? filename.slice(0, -1) : filename;
|
||||||
|
try {
|
||||||
|
const data = await rsGet(table, id);
|
||||||
|
if (data !== null) {
|
||||||
|
results.push({ id: id, data: data });
|
||||||
|
const _id = table + ':' + id;
|
||||||
|
try { docCache[_id] = typeof data === 'string' ? data : JSON.stringify(data); } catch (e) {}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Error loading item ' + id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('RemoteStorage.list error', e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rsMap(table, cb) {
|
||||||
|
if (!rsModule) return () => {};
|
||||||
callbacks[table] = callbacks[table] || [];
|
callbacks[table] = callbacks[table] || [];
|
||||||
callbacks[table].push(cb);
|
callbacks[table].push(cb);
|
||||||
list(table).then(rows => rows.forEach(r => cb(r.data, r.id)));
|
rsList(table).then(rows => rows.forEach(r => cb(r.data, r.id)));
|
||||||
return () => { callbacks[table] = callbacks[table].filter(x => x !== cb); }
|
return () => { callbacks[table] = callbacks[table].filter(x => x !== cb); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoteStorage doesn't have built-in attachment support, store as base64 strings
|
||||||
|
async function rsPutAttachment(table, id, name, dataUrlOrBlob, contentType) {
|
||||||
|
if (!rsModule) return false;
|
||||||
|
try {
|
||||||
|
let dataUrl = dataUrlOrBlob;
|
||||||
|
if (dataUrlOrBlob instanceof Blob) {
|
||||||
|
dataUrl = await new Promise((resolve) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = e => resolve(e.target.result);
|
||||||
|
reader.readAsDataURL(dataUrlOrBlob);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const path = table + '/' + id + '/attachments/' + name;
|
||||||
|
await rsModule.storeObject('application/json', path, { dataUrl: dataUrl, contentType: contentType });
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('RemoteStorage putAttachment error', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function rsGetAttachment(table, id, name) {
|
||||||
|
if (!rsModule) return null;
|
||||||
|
try {
|
||||||
|
const path = table + '/' + id + '/attachments/' + name;
|
||||||
|
const obj = await rsModule.getObject(path);
|
||||||
|
return obj ? obj.dataUrl : null;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function rsListAttachments(table, id) {
|
||||||
|
if (!rsModule) return [];
|
||||||
|
try {
|
||||||
|
const path = table + '/' + id + '/attachments/';
|
||||||
|
const listing = await rsModule.getListing(path);
|
||||||
|
if (!listing) return [];
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
for (const filename of Object.keys(listing)) {
|
||||||
|
// Remove trailing slash if present, otherwise use as-is
|
||||||
|
const name = filename.endsWith('/') ? filename.slice(0, -1) : filename;
|
||||||
|
try {
|
||||||
|
const att = await rsGetAttachment(table, id, name);
|
||||||
|
results.push({ name: name, dataUrl: att, content_type: null });
|
||||||
|
} catch (e) {
|
||||||
|
results.push({ name: name, dataUrl: null, content_type: null });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function rsDeleteAttachment(table, id, name) {
|
||||||
|
if (!rsModule) return false;
|
||||||
|
try {
|
||||||
|
const path = table + '/' + id + '/attachments/' + name;
|
||||||
|
await rsModule.remove(path);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('RemoteStorage deleteAttachment error', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Unified Public API ====================
|
||||||
|
|
||||||
|
async function init(opts) {
|
||||||
|
backend = opts.backend || localStorage.getItem('TELESEC_BACKEND') || 'pouchdb';
|
||||||
|
|
||||||
|
// Save backend preference
|
||||||
|
try {
|
||||||
|
localStorage.setItem('TELESEC_BACKEND', backend);
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
if (backend === 'remotestorage') {
|
||||||
|
return initRemoteStorage(opts);
|
||||||
|
} else {
|
||||||
|
return initPouchDB(opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function put(table, id, data) {
|
||||||
|
if (backend === 'remotestorage') return rsPut(table, id, data);
|
||||||
|
else return pouchPut(table, id, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function get(table, id) {
|
||||||
|
if (backend === 'remotestorage') return rsGet(table, id);
|
||||||
|
else return pouchGet(table, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function del(table, id) {
|
||||||
|
return put(table, id, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function list(table) {
|
||||||
|
if (backend === 'remotestorage') return rsList(table);
|
||||||
|
else return pouchList(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
function map(table, cb) {
|
||||||
|
if (backend === 'remotestorage') return rsMap(table, cb);
|
||||||
|
else return pouchMap(table, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
function replicateToRemote() {
|
||||||
|
if (backend === 'pouchdb') replicatePouchToRemote();
|
||||||
|
// remoteStorage syncs automatically
|
||||||
|
}
|
||||||
|
|
||||||
|
async function putAttachment(table, id, name, dataUrlOrBlob, contentType) {
|
||||||
|
if (backend === 'remotestorage') return rsPutAttachment(table, id, name, dataUrlOrBlob, contentType);
|
||||||
|
else return pouchPutAttachment(table, id, name, dataUrlOrBlob, contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAttachment(table, id, name) {
|
||||||
|
if (backend === 'remotestorage') return rsGetAttachment(table, id, name);
|
||||||
|
else return pouchGetAttachment(table, id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function listAttachments(table, id) {
|
||||||
|
if (backend === 'remotestorage') return rsListAttachments(table, id);
|
||||||
|
else return pouchListAttachments(table, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteAttachment(table, id, name) {
|
||||||
|
if (backend === 'remotestorage') return rsDeleteAttachment(table, id, name);
|
||||||
|
else return pouchDeleteAttachment(table, id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for online event (PouchDB only)
|
||||||
|
if (typeof window !== 'undefined' && window.addEventListener) {
|
||||||
|
window.addEventListener('online', function () {
|
||||||
|
try { setTimeout(replicateToRemote, 1000); } catch (e) {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init,
|
init,
|
||||||
put,
|
put,
|
||||||
@@ -281,7 +580,11 @@ var DB = (function () {
|
|||||||
deleteAttachment,
|
deleteAttachment,
|
||||||
putAttachment,
|
putAttachment,
|
||||||
getAttachment,
|
getAttachment,
|
||||||
_internal: { local }
|
getBackend: () => backend,
|
||||||
|
_internal: {
|
||||||
|
pouchLocal: () => pouchLocal,
|
||||||
|
rsClient: () => rsClient
|
||||||
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@@ -290,11 +593,27 @@ window.DB = DB;
|
|||||||
// Auto-initialize DB on startup using saved settings (non-blocking)
|
// Auto-initialize DB on startup using saved settings (non-blocking)
|
||||||
(function autoInitDB() {
|
(function autoInitDB() {
|
||||||
try {
|
try {
|
||||||
|
const savedBackend = localStorage.getItem('TELESEC_BACKEND') || 'pouchdb';
|
||||||
const remoteServer = localStorage.getItem('TELESEC_COUCH_URL') || '';
|
const remoteServer = localStorage.getItem('TELESEC_COUCH_URL') || '';
|
||||||
const username = localStorage.getItem('TELESEC_COUCH_USER') || '';
|
const username = localStorage.getItem('TELESEC_COUCH_USER') || '';
|
||||||
const password = localStorage.getItem('TELESEC_COUCH_PASS') || '';
|
const password = localStorage.getItem('TELESEC_COUCH_PASS') || '';
|
||||||
const dbname = localStorage.getItem('TELESEC_COUCH_DBNAME') || undefined;
|
const dbname = localStorage.getItem('TELESEC_COUCH_DBNAME') || undefined;
|
||||||
|
const rsUserAddress = localStorage.getItem('TELESEC_RS_USER') || '';
|
||||||
|
const rsToken = localStorage.getItem('TELESEC_RS_TOKEN') || '';
|
||||||
|
|
||||||
try { SECRET = localStorage.getItem('TELESEC_SECRET') || ''; } catch (e) { SECRET = ''; }
|
try { SECRET = localStorage.getItem('TELESEC_SECRET') || ''; } catch (e) { SECRET = ''; }
|
||||||
DB.init({ remoteServer, username, password, dbname }).catch(e => console.warn('DB.autoInit error', e));
|
|
||||||
|
const opts = {
|
||||||
|
backend: savedBackend,
|
||||||
|
secret: SECRET,
|
||||||
|
remoteServer,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
dbname,
|
||||||
|
rsUserAddress,
|
||||||
|
rsToken
|
||||||
|
};
|
||||||
|
|
||||||
|
DB.init(opts).catch(e => console.warn('DB.autoInit error', e));
|
||||||
} catch (e) { console.warn('DB.autoInit unexpected error', e); }
|
} catch (e) { console.warn('DB.autoInit unexpected error', e); }
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -75,6 +75,7 @@
|
|||||||
<script src="static/qrcode/barcode.js"></script>
|
<script src="static/qrcode/barcode.js"></script>
|
||||||
<script src="static/jquery.js"></script>
|
<script src="static/jquery.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/pouchdb@7.3.1/dist/pouchdb.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/pouchdb@7.3.1/dist/pouchdb.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/remotestoragejs@2.0.0/release/remotestorage.min.js"></script>
|
||||||
<!--<script src="static/synchronous.js"></script>-->
|
<!--<script src="static/synchronous.js"></script>-->
|
||||||
<!--<script src="static/axe.js"></script>-->
|
<!--<script src="static/axe.js"></script>-->
|
||||||
<script src="static/toastr.min.js"></script>
|
<script src="static/toastr.min.js"></script>
|
||||||
|
|||||||
@@ -2,36 +2,72 @@ PAGES.login = {
|
|||||||
Esconder: true,
|
Esconder: true,
|
||||||
Title: "Login",
|
Title: "Login",
|
||||||
edit: function (mid) {
|
edit: function (mid) {
|
||||||
// Setup form to configure CouchDB remote and initial group/secret
|
// Setup form to configure backend (PouchDB or remoteStorage) and credentials
|
||||||
|
var field_backend = safeuuid();
|
||||||
var field_couch = safeuuid();
|
var field_couch = safeuuid();
|
||||||
var field_couch_dbname = safeuuid();
|
var field_couch_dbname = safeuuid();
|
||||||
var field_couch_user = safeuuid();
|
var field_couch_user = safeuuid();
|
||||||
var field_couch_pass = safeuuid();
|
var field_couch_pass = safeuuid();
|
||||||
|
var field_rs_user = safeuuid();
|
||||||
|
var field_rs_token = safeuuid();
|
||||||
var field_secret = safeuuid();
|
var field_secret = safeuuid();
|
||||||
var btn_import_json = safeuuid();
|
var btn_import_json = safeuuid();
|
||||||
var div_import_area = safeuuid();
|
var div_import_area = safeuuid();
|
||||||
var field_json = safeuuid();
|
var field_json = safeuuid();
|
||||||
var field_file = safeuuid();
|
var field_file = safeuuid();
|
||||||
var btn_parse_json = safeuuid();
|
var btn_parse_json = safeuuid();
|
||||||
var btn_start_scan = safeuuid();
|
var btn_start_scan = safeuuid();
|
||||||
var div_scan = safeuuid();
|
var div_scan = safeuuid();
|
||||||
|
var div_pouchdb_fields = safeuuid();
|
||||||
|
var div_remotestorage_fields = safeuuid();
|
||||||
var btn_save = safeuuid();
|
var btn_save = safeuuid();
|
||||||
|
|
||||||
|
var savedBackend = localStorage.getItem('TELESEC_BACKEND') || 'pouchdb';
|
||||||
|
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<h1>Configuración del servidor CouchDB</h1>
|
<h1>Configuración de almacenamiento</h1>
|
||||||
<b>Aviso: Después de guardar, la aplicación intentará sincronizar con el servidor CouchDB en segundo plano. Puede que falten registros hasta que se termine. Tenga paciencia.</b>
|
<b>Aviso: Después de guardar, la aplicación intentará sincronizar en segundo plano. Tenga paciencia.</b>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label>Servidor CouchDB (ej: couch.example.com)
|
<legend>Tipo de almacenamiento</legend>
|
||||||
<input type="text" id="${field_couch}" value="${(localStorage.getItem('TELESEC_COUCH_URL') || '').replace(/^https?:\/\//, '')}"><br><br>
|
<label>
|
||||||
</label>
|
<input type="radio" name="${field_backend}" value="pouchdb" ${savedBackend === 'pouchdb' ? 'checked' : ''}>
|
||||||
<label>Nombre de la base (opcional, por defecto usa telesec-<grupo>)
|
PouchDB + CouchDB (sincronización con servidor CouchDB)
|
||||||
<input type="text" id="${field_couch_dbname}" value="${localStorage.getItem('TELESEC_COUCH_DBNAME') || ''}"><br><br>
|
</label><br>
|
||||||
</label>
|
<label>
|
||||||
<label>Usuario
|
<input type="radio" name="${field_backend}" value="remotestorage" ${savedBackend === 'remotestorage' ? 'checked' : ''}>
|
||||||
<input type="text" id="${field_couch_user}" value="${localStorage.getItem('TELESEC_COUCH_USER') || ''}"><br><br>
|
remoteStorage (sincronización con servidor remoteStorage)
|
||||||
</label>
|
</label><br><br>
|
||||||
<label>Contraseña
|
|
||||||
<input type="password" id="${field_couch_pass}" value="${localStorage.getItem('TELESEC_COUCH_PASS') || ''}"><br><br>
|
<div id="${div_pouchdb_fields}" style="display:${savedBackend === 'pouchdb' ? 'block' : 'none'};">
|
||||||
</label>
|
<fieldset>
|
||||||
|
<legend>Configuración CouchDB</legend>
|
||||||
|
<label>Servidor CouchDB (ej: couch.example.com)
|
||||||
|
<input type="text" id="${field_couch}" value="${(localStorage.getItem('TELESEC_COUCH_URL') || '').replace(/^https?:\/\//, '')}"><br><br>
|
||||||
|
</label>
|
||||||
|
<label>Nombre de la base (opcional, por defecto usa telesec)
|
||||||
|
<input type="text" id="${field_couch_dbname}" value="${localStorage.getItem('TELESEC_COUCH_DBNAME') || ''}"><br><br>
|
||||||
|
</label>
|
||||||
|
<label>Usuario
|
||||||
|
<input type="text" id="${field_couch_user}" value="${localStorage.getItem('TELESEC_COUCH_USER') || ''}"><br><br>
|
||||||
|
</label>
|
||||||
|
<label>Contraseña
|
||||||
|
<input type="password" id="${field_couch_pass}" value="${localStorage.getItem('TELESEC_COUCH_PASS') || ''}"><br><br>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="${div_remotestorage_fields}" style="display:${savedBackend === 'remotestorage' ? 'block' : 'none'};">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Configuración remoteStorage</legend>
|
||||||
|
<label>Dirección de usuario (ej: user@5apps.com o user@example.com)
|
||||||
|
<input type="text" id="${field_rs_user}" value="${localStorage.getItem('TELESEC_RS_USER') || ''}"><br><br>
|
||||||
|
</label>
|
||||||
|
<label>Token de acceso (opcional, se pedirá al conectar si no se proporciona)
|
||||||
|
<input type="password" id="${field_rs_token}" value="${localStorage.getItem('TELESEC_RS_TOKEN') || ''}"><br><br>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
|
||||||
<label>Clave de encriptación (opcional) - usada para cifrar datos en reposo
|
<label>Clave de encriptación (opcional) - usada para cifrar datos en reposo
|
||||||
<input type="password" id="${field_secret}" value="${localStorage.getItem('TELESEC_SECRET') || ''}"><br><br>
|
<input type="password" id="${field_secret}" value="${localStorage.getItem('TELESEC_SECRET') || ''}"><br><br>
|
||||||
</label>
|
</label>
|
||||||
@@ -40,7 +76,7 @@ PAGES.login = {
|
|||||||
</div>
|
</div>
|
||||||
<div id="${div_import_area}" style="display:none;margin-top:10px;border:1px solid #eee;padding:8px;">
|
<div id="${div_import_area}" style="display:none;margin-top:10px;border:1px solid #eee;padding:8px;">
|
||||||
<label>Pegar JSON de configuración (o usar archivo / QR):</label><br>
|
<label>Pegar JSON de configuración (o usar archivo / QR):</label><br>
|
||||||
<textarea id="${field_json}" style="width:100%;height:120px;margin-top:6px;" placeholder='{"server":"couch.example.com","dbname":"telesec-test","username":"user","password":"pass","secret":"SECRET123"}'></textarea>
|
<textarea id="${field_json}" style="width:100%;height:120px;margin-top:6px;" placeholder='{"backend":"pouchdb","server":"couch.example.com","dbname":"telesec-test","username":"user","password":"pass","secret":"SECRET123"}'></textarea>
|
||||||
<div style="margin-top:6px;">
|
<div style="margin-top:6px;">
|
||||||
<input type="file" id="${field_file}" accept="application/json">
|
<input type="file" id="${field_file}" accept="application/json">
|
||||||
<button id="${btn_parse_json}" class="btn5">Aplicar JSON</button>
|
<button id="${btn_parse_json}" class="btn5">Aplicar JSON</button>
|
||||||
@@ -52,25 +88,54 @@ PAGES.login = {
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
<p>Después de guardar, el navegador intentará sincronizar en segundo plano con el servidor.</p>
|
<p>Después de guardar, el navegador intentará sincronizar en segundo plano con el servidor.</p>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// Toggle fields based on backend selection
|
||||||
|
var radios = document.getElementsByName(field_backend);
|
||||||
|
for (var i = 0; i < radios.length; i++) {
|
||||||
|
radios[i].addEventListener('change', function() {
|
||||||
|
var selectedBackend = document.querySelector('input[name="' + field_backend + '"]:checked').value;
|
||||||
|
document.getElementById(div_pouchdb_fields).style.display = selectedBackend === 'pouchdb' ? 'block' : 'none';
|
||||||
|
document.getElementById(div_remotestorage_fields).style.display = selectedBackend === 'remotestorage' ? 'block' : 'none';
|
||||||
|
});
|
||||||
|
}
|
||||||
// Helper: normalize and apply config object
|
// Helper: normalize and apply config object
|
||||||
function applyConfig(cfg) {
|
function applyConfig(cfg) {
|
||||||
try {
|
try {
|
||||||
if (!cfg) throw new Error('JSON vacío');
|
if (!cfg) throw new Error('JSON vacío');
|
||||||
var url = cfg.server || cfg.couch || cfg.url || cfg.host || cfg.hostname || cfg.server_url;
|
|
||||||
var dbname = cfg.dbname || cfg.database || cfg.db || cfg.name;
|
var backend = cfg.backend || 'pouchdb';
|
||||||
var user = cfg.username || cfg.user || cfg.u;
|
|
||||||
var pass = cfg.password || cfg.pass || cfg.p;
|
|
||||||
var secret = (cfg.secret || cfg.key || cfg.secretKey || cfg.SECRET || '').toString();
|
var secret = (cfg.secret || cfg.key || cfg.secretKey || cfg.SECRET || '').toString();
|
||||||
if (!url) throw new Error('Falta campo "server" en JSON');
|
|
||||||
localStorage.setItem('TELESEC_COUCH_URL', 'https://' + url.replace(/^https?:\/\//, ''));
|
localStorage.setItem('TELESEC_BACKEND', backend);
|
||||||
if (dbname) localStorage.setItem('TELESEC_COUCH_DBNAME', dbname);
|
|
||||||
if (user) localStorage.setItem('TELESEC_COUCH_USER', user);
|
if (backend === 'remotestorage') {
|
||||||
if (pass) localStorage.setItem('TELESEC_COUCH_PASS', pass);
|
var rsUser = cfg.rsUserAddress || cfg.rsUser || cfg.rs_user || cfg.user || '';
|
||||||
if (secret) {
|
var rsToken = cfg.rsToken || cfg.rs_token || cfg.token || '';
|
||||||
localStorage.setItem('TELESEC_SECRET', secret.toUpperCase());
|
if (!rsUser) throw new Error('Falta campo "rsUserAddress" o "user" en JSON para remoteStorage');
|
||||||
SECRET = secret.toUpperCase();
|
localStorage.setItem('TELESEC_RS_USER', rsUser);
|
||||||
|
if (rsToken) localStorage.setItem('TELESEC_RS_TOKEN', rsToken);
|
||||||
|
if (secret) {
|
||||||
|
localStorage.setItem('TELESEC_SECRET', secret.toUpperCase());
|
||||||
|
SECRET = secret.toUpperCase();
|
||||||
|
}
|
||||||
|
DB.init({ backend: 'remotestorage', secret: SECRET, rsUserAddress: rsUser, rsToken: rsToken });
|
||||||
|
} else {
|
||||||
|
var url = cfg.server || cfg.couch || cfg.url || cfg.host || cfg.hostname || cfg.server_url;
|
||||||
|
var dbname = cfg.dbname || cfg.database || cfg.db || cfg.name;
|
||||||
|
var user = cfg.username || cfg.user || cfg.u;
|
||||||
|
var pass = cfg.password || cfg.pass || cfg.p;
|
||||||
|
if (!url) throw new Error('Falta campo "server" en JSON para PouchDB');
|
||||||
|
localStorage.setItem('TELESEC_COUCH_URL', 'https://' + url.replace(/^https?:\/\//, ''));
|
||||||
|
if (dbname) localStorage.setItem('TELESEC_COUCH_DBNAME', dbname);
|
||||||
|
if (user) localStorage.setItem('TELESEC_COUCH_USER', user);
|
||||||
|
if (pass) localStorage.setItem('TELESEC_COUCH_PASS', pass);
|
||||||
|
if (secret) {
|
||||||
|
localStorage.setItem('TELESEC_SECRET', secret.toUpperCase());
|
||||||
|
SECRET = secret.toUpperCase();
|
||||||
|
}
|
||||||
|
DB.init({ backend: 'pouchdb', secret: SECRET, remoteServer: 'https://' + url.replace(/^https?:\/\//, ''), username: user, password: pass, dbname: dbname || undefined });
|
||||||
}
|
}
|
||||||
DB.init({ secret: SECRET, remoteServer: 'https://' + url.replace(/^https?:\/\//, ''), username: user, password: pass, dbname: dbname || undefined });
|
|
||||||
toastr.success('Configuración aplicada e iniciando sincronización');
|
toastr.success('Configuración aplicada e iniciando sincronización');
|
||||||
location.hash = '#login';
|
location.hash = '#login';
|
||||||
setTimeout(function(){ location.reload(); }, 400);
|
setTimeout(function(){ location.reload(); }, 400);
|
||||||
@@ -167,20 +232,38 @@ PAGES.login = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
document.getElementById(btn_save).onclick = () => {
|
document.getElementById(btn_save).onclick = () => {
|
||||||
var url = document.getElementById(field_couch).value.trim();
|
var backend = document.querySelector('input[name="' + field_backend + '"]:checked').value;
|
||||||
var dbname = document.getElementById(field_couch_dbname).value.trim();
|
|
||||||
var user = document.getElementById(field_couch_user).value.trim();
|
|
||||||
var pass = document.getElementById(field_couch_pass).value;
|
|
||||||
var secret = document.getElementById(field_secret).value || '';
|
var secret = document.getElementById(field_secret).value || '';
|
||||||
localStorage.setItem('TELESEC_COUCH_URL', "https://" + url);
|
|
||||||
localStorage.setItem('TELESEC_COUCH_DBNAME', dbname);
|
localStorage.setItem('TELESEC_BACKEND', backend);
|
||||||
localStorage.setItem('TELESEC_COUCH_USER', user);
|
|
||||||
localStorage.setItem('TELESEC_COUCH_PASS', pass);
|
|
||||||
localStorage.setItem('TELESEC_SECRET', secret.toUpperCase());
|
localStorage.setItem('TELESEC_SECRET', secret.toUpperCase());
|
||||||
SECRET = secret.toUpperCase();
|
SECRET = secret.toUpperCase();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DB.init({ secret: SECRET, remoteServer: "https://" + url, username: user, password: pass, dbname: dbname || undefined });
|
if (backend === 'remotestorage') {
|
||||||
toastr.success('Iniciando sincronización con CouchDB');
|
var rsUser = document.getElementById(field_rs_user).value.trim();
|
||||||
|
var rsToken = document.getElementById(field_rs_token).value || '';
|
||||||
|
if (!rsUser) {
|
||||||
|
toastr.error('Debe proporcionar una dirección de usuario remoteStorage');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
localStorage.setItem('TELESEC_RS_USER', rsUser);
|
||||||
|
localStorage.setItem('TELESEC_RS_TOKEN', rsToken);
|
||||||
|
DB.init({ backend: 'remotestorage', secret: SECRET, rsUserAddress: rsUser, rsToken: rsToken });
|
||||||
|
toastr.success('Iniciando sincronización con remoteStorage');
|
||||||
|
} else {
|
||||||
|
var url = document.getElementById(field_couch).value.trim();
|
||||||
|
var dbname = document.getElementById(field_couch_dbname).value.trim();
|
||||||
|
var user = document.getElementById(field_couch_user).value.trim();
|
||||||
|
var pass = document.getElementById(field_couch_pass).value;
|
||||||
|
localStorage.setItem('TELESEC_COUCH_URL', "https://" + url);
|
||||||
|
localStorage.setItem('TELESEC_COUCH_DBNAME', dbname);
|
||||||
|
localStorage.setItem('TELESEC_COUCH_USER', user);
|
||||||
|
localStorage.setItem('TELESEC_COUCH_PASS', pass);
|
||||||
|
DB.init({ backend: 'pouchdb', secret: SECRET, remoteServer: "https://" + url, username: user, password: pass, dbname: dbname || undefined });
|
||||||
|
toastr.success('Iniciando sincronización con CouchDB');
|
||||||
|
}
|
||||||
|
|
||||||
location.hash = "#login";
|
location.hash = "#login";
|
||||||
location.reload();
|
location.reload();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user