From b9a4e47ea26efb4764dec95d87d80dcfa1998c9c Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 6 Mar 2021 22:48:49 +0100 Subject: [PATCH] mojibake support for the spa stuff --- copyparty/authsrv.py | 4 ++-- copyparty/httpcli.py | 9 +++++++-- copyparty/u2idx.py | 5 +++++ copyparty/up2k.py | 40 ++++++++++------------------------------ copyparty/util.py | 29 +++++++++++++++++++++++++++++ copyparty/web/browser.js | 37 ++++++++++++++++++++++--------------- copyparty/web/md.js | 2 +- copyparty/web/mde.js | 2 +- copyparty/web/up2k.js | 2 +- copyparty/web/util.js | 27 ++++++++++++++++++++++++++- 10 files changed, 104 insertions(+), 53 deletions(-) diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index c4cc0c67..de370fd3 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -6,7 +6,7 @@ import re import threading from .__init__ import PY2, WINDOWS -from .util import undot, Pebkac, fsdec, fsenc, statdir, uprint +from .util import undot, Pebkac, fsdec, fsenc, statdir, nuprint class VFS(object): @@ -106,7 +106,7 @@ class VFS(object): """return user-readable [fsdir,real,virt] items at vpath""" virt_vis = {} # nodes readable by user abspath = self.canonical(rem) - real = list(statdir(uprint, scandir, lstat, abspath)) + real = list(statdir(nuprint, scandir, lstat, abspath)) real.sort() if not rem: for name, vn2 in sorted(self.nodes.items()): diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 1f903da3..02cdf54c 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -1136,7 +1136,7 @@ class HttpCli(object): vfs_ls = exclude_dotfiles(vfs_ls) for fn in [x for x in vfs_ls if x != excl]: - dirs.append(fn) + dirs.append(quotep(fn)) for x in vfs_virt.keys(): if x != excl: @@ -1275,7 +1275,12 @@ class HttpCli(object): del f["rd"] if icur: q = "select w from up where rd = ? and fn = ?" - r = icur.execute(q, (rd, fn)).fetchone() + try: + r = icur.execute(q, (rd, fn)).fetchone() + except: + args = s3enc(idx.mem_cur, rd, fn) + r = icur.execute(q, args).fetchone() + if not r: continue diff --git a/copyparty/u2idx.py b/copyparty/u2idx.py index c94a0dd3..1454ae86 100644 --- a/copyparty/u2idx.py +++ b/copyparty/u2idx.py @@ -25,6 +25,8 @@ class U2idx(object): return self.cur = {} + self.mem_cur = sqlite3.connect(":memory:") + self.mem_cur.execute(r"create table a (b text)") def log(self, msg, c=0): self.log_func("u2idx", msg, c) @@ -112,6 +114,9 @@ class U2idx(object): if lim <= 0: break + if rd.startswith("//") or fn.startswith("//"): + rd, fn = s3dec(rd, fn) + rp = os.path.join(vtop, rd, fn).replace("\\", "/") sret.append({"ts": int(ts), "sz": sz, "rp": rp, "w": w[:16]}) diff --git a/copyparty/up2k.py b/copyparty/up2k.py index 0c1349cb..c0aca5d3 100644 --- a/copyparty/up2k.py +++ b/copyparty/up2k.py @@ -25,8 +25,8 @@ from .util import ( sanitize_fn, ren_open, atomic_move, - w8b64enc, - w8b64dec, + s3enc, + s3dec, statdir, ) from .mtag import MTag @@ -110,29 +110,6 @@ class Up2k(object): def log(self, msg, c=0): self.log_func("up2k", msg + "\033[K", c) - def w8enc(self, rd, fn): - ret = [] - for v in [rd, fn]: - try: - self.mem_cur.execute("select * from a where b = ?", (v,)) - ret.append(v) - except: - ret.append("//" + w8b64enc(v)) - # self.log("mojien/{} [{}] {}".format(k, v, ret[-1][2:])) - - return tuple(ret) - - def w8dec(self, rd, fn): - ret = [] - for k, v in [["d", rd], ["f", fn]]: - if v.startswith("//"): - ret.append(w8b64dec(v[2:])) - # self.log("mojide/{} [{}] {}".format(k, ret[-1], v[2:])) - else: - ret.append(v) - - return tuple(ret) - def _vis_job_progress(self, job): perc = 100 - (len(job["need"]) * 100.0 / len(job["hash"])) path = os.path.join(job["ptop"], job["prel"], job["name"]) @@ -340,7 +317,7 @@ class Up2k(object): try: c = dbw[0].execute(sql, (rd, fn)) except: - c = dbw[0].execute(sql, self.w8enc(rd, fn)) + c = dbw[0].execute(sql, s3enc(self.mem_cur, rd, fn)) in_db = list(c.fetchall()) if in_db: @@ -394,7 +371,7 @@ class Up2k(object): for dwark, dts, dsz, drd, dfn in c: nchecked += 1 if drd.startswith("//") or dfn.startswith("//"): - drd, dfn = self.w8dec(drd, dfn) + drd, dfn = s3dec(drd, dfn) abspath = os.path.join(top, drd, dfn) # almost zero overhead dw @@ -480,6 +457,9 @@ class Up2k(object): if c2.execute(q, (w[:16],)).fetchone(): continue + if rd.startswith("//") or fn.startswith("//"): + rd, fn = s3dec(rd, fn) + abspath = os.path.join(ptop, rd, fn) self.pp.msg = "c{} {}".format(n_left, abspath) args = c3, entags, w, abspath @@ -704,7 +684,7 @@ class Up2k(object): cur = cur.execute(q, argv) for _, dtime, dsize, dp_dir, dp_fn in cur: if dp_dir.startswith("//") or dp_fn.startswith("//"): - dp_dir, dp_fn = self.w8dec(dp_dir, dp_fn) + dp_dir, dp_fn = s3dec(self.mem_cur, dp_dir, dp_fn) dp_abs = os.path.join(cj["ptop"], dp_dir, dp_fn).replace("\\", "/") # relying on path.exists to return false on broken symlinks @@ -920,7 +900,7 @@ class Up2k(object): try: db.execute(sql, (rd, fn)) except: - db.execute(sql, self.w8enc(rd, fn)) + db.execute(sql, s3enc(self.mem_cur, rd, fn)) def db_add(self, db, wark, rd, fn, ts, sz): sql = "insert into up values (?,?,?,?,?)" @@ -928,7 +908,7 @@ class Up2k(object): try: db.execute(sql, v) except: - rd, fn = self.w8enc(rd, fn) + rd, fn = s3enc(self.mem_cur, rd, fn) v = (wark, ts, sz, rd, fn) db.execute(sql, v) diff --git a/copyparty/util.py b/copyparty/util.py index 041ed32c..15008e30 100644 --- a/copyparty/util.py +++ b/copyparty/util.py @@ -135,6 +135,10 @@ def uprint(msg): print(msg.encode("ascii", "replace").decode(), end="") +def nuprint(msg): + uprint("{}\n".format(msg)) + + @contextlib.contextmanager def ren_open(fname, *args, **kwargs): fdir = kwargs.pop("fdir", None) @@ -600,6 +604,31 @@ else: fsdec = w8dec +def s3enc(mem_cur, rd, fn): + ret = [] + for v in [rd, fn]: + try: + mem_cur.execute("select * from a where b = ?", (v,)) + ret.append(v) + except: + ret.append("//" + w8b64enc(v)) + # self.log("mojien/{} [{}] {}".format(k, v, ret[-1][2:])) + + return tuple(ret) + + +def s3dec(rd, fn): + ret = [] + for k, v in [["d", rd], ["f", fn]]: + if v.startswith("//"): + ret.append(w8b64dec(v[2:])) + # self.log("mojide/{} [{}] {}".format(k, ret[-1], v[2:])) + else: + ret.append(v) + + return tuple(ret) + + def atomic_move(src, dst): if not PY2: os.replace(src, dst) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index cdf25ff3..2bc3d661 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -467,7 +467,7 @@ function play(tid, call_depth) { var o = ebi(oid); o.setAttribute('id', 'thx_js'); if (window.history && history.replaceState) { - hist_replace((document.location + '').split('#')[0] + '#' + oid); + hist_replace(document.location.pathname + '#' + oid); } else { document.location.hash = oid; @@ -510,7 +510,7 @@ function evau_error(e) { if (eplaya.error.message) err += '\n\n' + eplaya.error.message; - err += '\n\nFile: «' + decodeURIComponent(eplaya.src.split('/').slice(-1)[0]) + '»'; + err += '\n\nFile: «' + uricom_dec(eplaya.src.split('/').slice(-1)[0]) + '»'; alert(err); } @@ -545,7 +545,7 @@ function autoplay_blocked() { var na = ebi('blk_na'); var fn = mp.tracks[mp.au.tid].split(/\//).pop(); - fn = decodeURIComponent(fn.replace(/\+/g, ' ')); + fn = uricom_dec(fn.replace(/\+/g, ' ')); go.textContent = 'Play "' + fn + '"'; go.onclick = function (e) { @@ -744,7 +744,7 @@ function autoplay_blocked() { treefiles.appendChild(ebi('epi')); swrite('entreed', 'tree'); - get_tree("", get_vpath(), true); + get_tree("", get_evpath(), true); } function get_tree(top, dst, rst) { @@ -776,7 +776,7 @@ function autoplay_blocked() { ebi('treeul').setAttribute('ts', this.ts); var top = this.top == '.' ? this.dst : this.top, - name = top.split('/').slice(-2)[0], + name = uricom_dec(top.split('/').slice(-2)[0]), rtop = top.replace(/^\/+/, ""); try { @@ -827,7 +827,7 @@ function autoplay_blocked() { } function reload_tree() { - var cdir = get_vpath(); + var cdir = get_evpath(); var links = document.querySelectorAll('#treeul a+a'); for (var a = 0, aa = links.length; a < aa; a++) { var href = links[a].getAttribute('href'); @@ -912,7 +912,7 @@ function autoplay_blocked() { for (var a = 0; a < nodes.length; a++) { var r = nodes[a], ln = ['' + r.lead + '' + esc(decodeURIComponent(r.href)) + '', r.sz]; + top + r.href + '">' + esc(uricom_dec(r.href)) + '', r.sz]; for (var b = 0; b < res.taglist.length; b++) { var k = res.taglist[b], @@ -960,12 +960,14 @@ function autoplay_blocked() { keys.sort(); for (var a = 0; a < keys.length; a++) { var kk = keys[a], - k = kk.slice(1), - url = '/' + (top ? top + k : k) + '/', - ek = esc(k), + ks = kk.slice(1), + k = uricom_dec(ks), + hek = esc(k), + uek = ks == k ? k : uricom_enc(k, true), + url = '/' + (top ? top + uek : uek) + '/', sym = res[kk] ? '-' : '+', link = '' + sym + '' + ek + ''; + url + '">' + hek + ''; if (res[kk]) { var subtree = parsetree(res[kk], url.slice(1)); @@ -1019,12 +1021,17 @@ function autoplay_blocked() { window.onpopstate = function (e) { console.log("h-pop " + e.state); - get_tree("", e.state, true); - reqls(e.state); + if (!e.state) + return; + + var url = new URL(e.state, "https://" + document.location.host); + url = url.pathname; + get_tree("", url, true); + reqls(url); }; if (window.history && history.pushState) { - hist_replace(get_vpath() + window.location.hash); + hist_replace(get_evpath() + window.location.hash); } })(); @@ -1196,7 +1203,7 @@ function reload_browser(not_mp) { filecols.set_style(); makeSortable(ebi('files')); - var parts = get_vpath().split('/'); + var parts = get_evpath().split('/'); var rm = document.querySelectorAll('#path>a+a+a'); for (a = rm.length - 1; a >= 0; a--) rm[a].parentNode.removeChild(rm[a]); diff --git a/copyparty/web/md.js b/copyparty/web/md.js index 6c258b2e..7915f42c 100644 --- a/copyparty/web/md.js +++ b/copyparty/web/md.js @@ -65,7 +65,7 @@ function statify(obj) { if (a > 0) loc.push(n[a]); - var dec = hesc(decodeURIComponent(n[a])); + var dec = hesc(uricom_dec(n[a])); nav.push('' + dec + ''); } diff --git a/copyparty/web/mde.js b/copyparty/web/mde.js index 13a385ba..13edf73f 100644 --- a/copyparty/web/mde.js +++ b/copyparty/web/mde.js @@ -15,7 +15,7 @@ var dom_md = ebi('mt'); if (a > 0) loc.push(n[a]); - var dec = decodeURIComponent(n[a]).replace(/&/g, "&").replace(//g, ">"); + var dec = uricom_dec(n[a]).replace(/&/g, "&").replace(//g, ">"); nav.push('' + dec + ''); } diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js index 18df85d6..4afda02a 100644 --- a/copyparty/web/up2k.js +++ b/copyparty/web/up2k.js @@ -332,7 +332,7 @@ function up2k_init(have_crypto) { "name": fobj.name, "size": fobj.size, "lmod": lmod / 1000, - "purl": get_vpath(), + "purl": get_evpath(), "done": false, "hash": [] }; diff --git a/copyparty/web/util.js b/copyparty/web/util.js index cff90ff5..96cd563b 100644 --- a/copyparty/web/util.js +++ b/copyparty/web/util.js @@ -220,6 +220,31 @@ function linksplit(rp) { } +function uricom_enc(txt, do_fb_enc) { + try { + return encodeURIComponent(txt); + } + catch (ex) { + console.log("uce-err [" + txt + "]"); + if (do_fb_enc) + return esc(txt); + + return txt; + } +} + + +function uricom_dec(txt) { + try { + return decodeURIComponent(txt); + } + catch (ex) { + console.log("ucd-err [" + txt + "]"); + return txt; + } +} + + function get_evpath() { var ret = document.location.pathname; @@ -234,7 +259,7 @@ function get_evpath() { function get_vpath() { - return decodeURIComponent(get_evpath()); + return uricom_dec(get_evpath()); }