From a9effb79703ad057a97ff6076d95f1e9c682b5a4 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Tue, 7 Jan 2025 09:03:54 +0000 Subject: [PATCH 1/4] don't send password hashes --- CHANGELOG.md | 4 ++++ jinjafx_server.py | 21 ++++++++++++++------- www/index.html | 2 +- www/jinjafx_m.js | 4 +++- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0b970b..b07a66c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## CHANGELOG +### [25.2.2] - In Development +- Fixed a potential security issue in that we no longer send the saved password hashes with the DataTemplate as they aren't needed + ### [25.2.1] - Jan 6, 2025 - Fixed a regression when adding support for "Delete Link" @@ -377,6 +380,7 @@ - Initial release +[25.2.2]: https://github.com/cmason3/jinjafx_server/compare/25.2.1...25.2.2 [25.2.1]: https://github.com/cmason3/jinjafx_server/compare/25.2.0...25.2.1 [25.2.0]: https://github.com/cmason3/jinjafx_server/compare/25.1.1...25.2.0 [25.1.1]: https://github.com/cmason3/jinjafx_server/compare/25.1.0...25.1.1 diff --git a/jinjafx_server.py b/jinjafx_server.py index 0b605dc..31a1375 100755 --- a/jinjafx_server.py +++ b/jinjafx_server.py @@ -26,7 +26,7 @@ import re, argparse, hashlib, traceback, glob, hmac, uuid, struct, binascii, gzip, requests, ctypes, subprocess import cmarkgfm, emoji -__version__ = '25.2.1' +__version__ = '25.2.2' llock = threading.RLock() rlock = threading.RLock() @@ -258,13 +258,17 @@ def do_GET(self, head=False, cache=True, versioned=False): dt = '' self.critical = True + def sanitise_dt(dt): + dt = '\n'.join([ln for ln in dt.splitlines() if not ln.startswith(('dt_password:', 'dt_mpassword:', 'remote_addr:'))]) + return dt.encode('utf-8') + if aws_s3_url or github_url or repository: if not self.ratelimit(remote_addr, 2, False): if aws_s3_url: rr = aws_s3_get(aws_s3_url, 'jfx_' + fpath[8:] + '.yml') if rr.status_code == 200: - r = [ 'application/json', 200, json.dumps({ 'dt': self.e(rr.text.encode('utf-8')).decode('utf-8') }).encode('utf-8'), sys._getframe().f_lineno ] + r = [ 'application/json', 200, json.dumps({ 'dt': self.e(sanitise_dt(rr.text)).decode('utf-8') }).encode('utf-8'), sys._getframe().f_lineno ] dt = rr.text @@ -284,7 +288,7 @@ def do_GET(self, head=False, cache=True, versioned=False): if jobj.get('encoding') and jobj.get('encoding') == 'base64': content = base64.b64decode(content).decode('utf-8') - r = [ 'application/json', 200, json.dumps({ 'dt': self.e(content.encode('utf-8')).decode('utf-8') }).encode('utf-8'), sys._getframe().f_lineno ] + r = [ 'application/json', 200, json.dumps({ 'dt': self.e(sanitise_dt(content)).decode('utf-8') }).encode('utf-8'), sys._getframe().f_lineno ] dt = content @@ -299,10 +303,10 @@ def do_GET(self, head=False, cache=True, versioned=False): if os.path.isfile(fpath): with open(fpath, 'rb') as f: - rr = f.read() - dt = rr.decode('utf-8') + #rr = f.read() + dt = f.read().decode('utf-8') - r = [ 'application/json', 200, json.dumps({ 'dt': self.e(rr).decode('utf-8') }).encode('utf-8'), sys._getframe().f_lineno ] + r = [ 'application/json', 200, json.dumps({ 'dt': self.e(sanitise_dt(dt)).decode('utf-8') }).encode('utf-8'), sys._getframe().f_lineno ] else: r = [ 'text/plain', 404, '404 Not Found\r\n'.encode('utf-8'), sys._getframe().f_lineno ] @@ -312,7 +316,7 @@ def do_GET(self, head=False, cache=True, versioned=False): if 'X-Dt-Password' in self.headers: try: dt = jinjafx.Vaulty().decrypt(dt, self.headers['X-Dt-Password']) - r = [ 'application/json', 200, json.dumps({ 'dt': self.e(dt.encode('utf-8')).decode('utf-8') }).encode('utf-8'), sys._getframe().f_lineno ] + r = [ 'application/json', 200, json.dumps({ 'dt': self.e(sanitise_dt(dt)).decode('utf-8') }).encode('utf-8'), sys._getframe().f_lineno ] except Exception: cheaders['X-Dt-Authentication'] = 'Open' @@ -752,6 +756,9 @@ def authenticate_dt(rdt, r): if dt_encrypted: dt_yml += 'encrypted: 1\n' + if dt_protected: + dt_yml += 'protected: 1\n' + def update_dt(rdt, dt_yml, r): mm, mo, r = authenticate_dt(rdt, r) diff --git a/www/index.html b/www/index.html index e26c250..ba29373 100644 --- a/www/index.html +++ b/www/index.html @@ -32,7 +32,7 @@ - +
diff --git a/www/jinjafx_m.js b/www/jinjafx_m.js index 5d0112e..7a24a53 100644 --- a/www/jinjafx_m.js +++ b/www/jinjafx_m.js @@ -886,6 +886,8 @@ function getStatusText(code) { try { var dt = jsyaml.load(d(JSON.parse(this.responseText)['dt']), jsyaml_schema); + console.log(JSON.stringify(dt)); + if (dt.hasOwnProperty('encrypted')) { dt_encrypted = (dt['encrypted'] === 1); dt_epassword = dt_password; @@ -909,7 +911,7 @@ function getStatusText(code) { document.getElementById('get').classList.add('d-none'); document.getElementById('mdd').disabled = false; - if (dt.hasOwnProperty('dt_password') || dt.hasOwnProperty('dt_mpassword')) { + if (dt.hasOwnProperty('protected') && (dt['protected'] === 1)) { document.getElementById('protect_text').innerHTML = 'Update Protection'; dt_protected = true; } From d810b20bbca82d0c94b54383324e9e06e7eed93d Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Tue, 7 Jan 2025 10:46:46 +0000 Subject: [PATCH 2/4] fix csp regression --- CHANGELOG.md | 3 ++- www/index.html | 14 +++++++------- www/jinjafx_m.js | 28 ++++++++++++---------------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b07a66c..a7e73c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ ## CHANGELOG ### [25.2.2] - In Development -- Fixed a potential security issue in that we no longer send the saved password hashes with the DataTemplate as they aren't needed +- Don't send sensitive metadata in fetched DataTemplates as it isn't needed +- Fixed an issue where we broke CSP due to our use of `javascript:void(0)` to stop hashes appearing within the URL ### [25.2.1] - Jan 6, 2025 - Fixed a regression when adding support for "Delete Link" diff --git a/www/index.html b/www/index.html index ba29373..7f65f49 100644 --- a/www/index.html +++ b/www/index.html @@ -32,7 +32,7 @@ - +
@@ -100,25 +100,25 @@
diff --git a/www/jinjafx_m.js b/www/jinjafx_m.js index 7a24a53..bc2bab0 100644 --- a/www/jinjafx_m.js +++ b/www/jinjafx_m.js @@ -197,13 +197,12 @@ function getStatusText(code) { document.getElementById('datasets').innerHTML = ''; Object.keys(datasets).sort(default_on_top).forEach(function(ds) { - var a = document.createElement('a'); - a.classList.add('dropdown-item', 'text-decoration-none'); - a.addEventListener('click', select_dataset, false); - a.href = 'javascript:void(0)'; - a.ds_name = ds; - a.innerHTML = ds; - document.getElementById('datasets').appendChild(a); + var e = document.createElement('button'); + e.classList.add('dropdown-item', 'text-decoration-none'); + e.addEventListener('click', select_dataset, false); + e.ds_name = ds; + e.innerHTML = ds; + document.getElementById('datasets').appendChild(e); }); if (Object.keys(datasets).length > 1) { @@ -250,13 +249,12 @@ function getStatusText(code) { document.getElementById('templates').innerHTML = ''; Object.keys(templates).sort(default_on_top).forEach(function(t) { - var a = document.createElement('a'); - a.classList.add('dropdown-item', 'text-decoration-none'); - a.addEventListener('click', select_template, false); - a.href = 'javascript:void(0)'; - a.t_name = t; - a.innerHTML = t; - document.getElementById('templates').appendChild(a); + var e = document.createElement('button'); + e.classList.add('dropdown-item', 'text-decoration-none'); + e.addEventListener('click', select_template, false); + e.t_name = t; + e.innerHTML = t; + document.getElementById('templates').appendChild(e); }); if (Object.keys(templates).length > 1) { @@ -886,8 +884,6 @@ function getStatusText(code) { try { var dt = jsyaml.load(d(JSON.parse(this.responseText)['dt']), jsyaml_schema); - console.log(JSON.stringify(dt)); - if (dt.hasOwnProperty('encrypted')) { dt_encrypted = (dt['encrypted'] === 1); dt_epassword = dt_password; From 4a8a90aeb6e691a0001f362c4ca89ce0065ee238 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Tue, 7 Jan 2025 11:09:03 +0000 Subject: [PATCH 3/4] fix csp regression --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7e73c3..a9cff54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## CHANGELOG -### [25.2.2] - In Development +### [25.2.2] - Jan 7, 2025 - Don't send sensitive metadata in fetched DataTemplates as it isn't needed - Fixed an issue where we broke CSP due to our use of `javascript:void(0)` to stop hashes appearing within the URL From 309b565529d47b36f390b367d121a6fe653aaa7b Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Tue, 7 Jan 2025 11:23:48 +0000 Subject: [PATCH 4/4] fix csp regression --- jinjafx_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jinjafx_server.py b/jinjafx_server.py index 31a1375..c98b30a 100755 --- a/jinjafx_server.py +++ b/jinjafx_server.py @@ -259,7 +259,8 @@ def do_GET(self, head=False, cache=True, versioned=False): self.critical = True def sanitise_dt(dt): - dt = '\n'.join([ln for ln in dt.splitlines() if not ln.startswith(('dt_password:', 'dt_mpassword:', 'remote_addr:'))]) + fields = ('dt_password:', 'dt_mpassword:', 'remote_addr:') + dt = '\n'.join([ln for ln in dt.splitlines() if not ln.startswith(fields)]) return dt.encode('utf-8') if aws_s3_url or github_url or repository: @@ -303,7 +304,6 @@ def sanitise_dt(dt): if os.path.isfile(fpath): with open(fpath, 'rb') as f: - #rr = f.read() dt = f.read().decode('utf-8') r = [ 'application/json', 200, json.dumps({ 'dt': self.e(sanitise_dt(dt)).decode('utf-8') }).encode('utf-8'), sys._getframe().f_lineno ]