diff --git a/copyparty/__main__.py b/copyparty/__main__.py index efc8ecb4..8d6fdbce 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1229,6 +1229,7 @@ def add_upload(ap): ap2 = ap.add_argument_group("upload options") ap2.add_argument("--dotpart", action="store_true", help="dotfile incomplete uploads, hiding them from clients unless \033[33m-ed\033[0m") ap2.add_argument("--plain-ip", action="store_true", help="when avoiding filename collisions by appending the uploader's ip to the filename: append the plaintext ip instead of salting and hashing the ip") + ap2.add_argument("--up-site", metavar="URL", type=u, default="--site", help="public URL to assume when creating links to uploaded files; example: [\033[32mhttps://example.com/\033[0m]") ap2.add_argument("--put-name", metavar="TXT", type=u, default="put-{now.6f}-{cip}.bin", help="filename for nameless uploads (when uploader doesn't provide a name); default is [\033[32mput-UNIXTIME-IP.bin\033[0m] (the \033[32m.6f\033[0m means six decimal places) (volflag=put_name)") ap2.add_argument("--put-ck", metavar="ALG", type=u, default="sha512", help="default checksum-hasher for PUT/WebDAV uploads: no / md5 / sha1 / sha256 / sha512 / b2 / blake2 / b2s / blake2s (volflag=put_ck)") ap2.add_argument("--bup-ck", metavar="ALG", type=u, default="sha512", help="default checksum-hasher for bup/basic-uploader: no / md5 / sha1 / sha256 / sha512 / b2 / blake2 / b2s / blake2s (volflag=bup_ck)") diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index b5098830..9d8092c2 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -2684,11 +2684,20 @@ class HttpCli(object): vpath = "/".join([x for x in [vfs.vpath, rem, fn] if x]) vpath = quotep(vpath) - url = "{}://{}/{}".format( - "https" if self.is_https else "http", - self.host, - self.args.RS + vpath + vsuf, - ) + if self.args.up_site: + url = "%s%s%s" % ( + self.args.up_site, + vpath, + vsuf, + ) + else: + url = "%s://%s/%s%s%s" % ( + "https" if self.is_https else "http", + self.host, + self.args.RS, + vpath, + vsuf, + ) return post_sz, halg, sha_hex, sha_b64, remains, path, url @@ -2962,7 +2971,7 @@ class HttpCli(object): raise Pebkac(500, t % zt) ret["purl"] = vp_req + ret["purl"][len(vp_vfs) :] - if self.is_vproxied: + if self.is_vproxied and not self.args.up_site: if "purl" in ret: ret["purl"] = self.args.SR + ret["purl"] @@ -3840,9 +3849,9 @@ class HttpCli(object): errmsg = "ERROR: " + errmsg if halg: - file_fmt = '{0}: {1} // {2} // {3} bytes // {5} {6}\n' + file_fmt = '{0}: {1} // {2} // {3} bytes // {5} {6}\n' else: - file_fmt = '{3} bytes // {5} {6}\n' + file_fmt = '{3} bytes // {5} {6}\n' for sz, sha_hex, sha_b64, ofn, lfn, ap in files: vsuf = "" @@ -3860,25 +3869,31 @@ class HttpCli(object): if "media" in self.uparam or "medialinks" in vfs.flags: vsuf += "&v" if vsuf else "?v" - vpath = "{}/{}".format(upload_vpath, lfn).strip("/") - rel_url = quotep(self.args.RS + vpath) + vsuf + vpath = vjoin(upload_vpath, lfn) + if self.args.up_site: + ah_url = j_url = self.args.up_site + quotep(vpath) + vsuf + rel_url = "/" + j_url.split("//", 1)[-1].split("/", 1)[-1] + else: + ah_url = rel_url = "/%s%s%s" % (self.args.RS, quotep(vpath), vsuf) + j_url = "%s://%s%s" % ( + "https" if self.is_https else "http", + self.host, + rel_url, + ) + msg += file_fmt.format( halg, sha_hex[:56], sha_b64, sz, - rel_url, + ah_url, html_escape(ofn, crlf=True), vsuf, ) # truncated SHA-512 prevents length extension attacks; # using SHA-512/224, optionally SHA-512/256 = :64 jpart = { - "url": "{}://{}/{}".format( - "https" if self.is_https else "http", - self.host, - rel_url, - ), + "url": j_url, "sz": sz, "fn": lfn, "fn_orig": ofn, diff --git a/copyparty/svchub.py b/copyparty/svchub.py index d919d9f2..98d907bc 100644 --- a/copyparty/svchub.py +++ b/copyparty/svchub.py @@ -315,7 +315,7 @@ class SvcHub(object): args.doctitle = args.doctitle.replace("--name", args.vname) args.bname = args.bname.replace("--name", args.vname) or args.vname - for zs in ("shr_site",): + for zs in "shr_site up_site".split(): if getattr(args, zs) == "--site": setattr(args, zs, args.site) diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 4cf0d581..fd206caa 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -6525,7 +6525,7 @@ var search_ui = (function () { if (ext.length > 8) ext = '%'; - var links = linksplit(r.rp + '', id).join('/'), + var links = linksplit(r.rp + '', null, id).join('/'), nodes = ['-
' + links + '
' + hsz]; diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js index 1a9f3d67..bee1602a 100644 --- a/copyparty/web/up2k.js +++ b/copyparty/web/up2k.js @@ -1535,7 +1535,7 @@ function up2k_init(subtle) { pvis.addfile([ uc.fsearch ? esc(entry.name) : linksplit( - entry.purl + uricom_enc(entry.name)).join(' / '), + entry.purl + uricom_enc(entry.name), window.up_site).join(' / '), '📐 ' + L.u_hashing, '' ], entry.size, draw_each); @@ -1575,8 +1575,8 @@ function up2k_init(subtle) { more_one_file(); function linklist() { - var ret = [], - base = location.origin.replace(/\/$/, ''); + var ret = [], + base = (window.up_site || location.origin).replace(/\/$/, ''); for (var a = 0; a < st.files.length; a++) { var t = st.files[a], @@ -2562,7 +2562,7 @@ function up2k_init(subtle) { cdiff = (Math.abs(diff) <= 2) ? '3c0' : 'f0b', sdiff = 'diff ' + diff; - msg.push(linksplit(hit.rp).join(' / ') + '
' + tr + ' (srv), ' + tu + ' (You), ' + sdiff + '
'); + msg.push(linksplit(hit.rp, window.up_site).join(' / ') + '
' + tr + ' (srv), ' + tu + ' (You), ' + sdiff + ''); } msg = msg.join('
\n'); } @@ -2596,7 +2596,7 @@ function up2k_init(subtle) { url += '?k=' + fk; } - pvis.seth(t.n, 0, linksplit(url).join(' / ')); + pvis.seth(t.n, 0, linksplit(url, window.up_site).join(' / ')); } var chunksize = get_chunksize(t.size), diff --git a/copyparty/web/util.js b/copyparty/web/util.js index 226d2358..ec896d74 100644 --- a/copyparty/web/util.js +++ b/copyparty/web/util.js @@ -766,9 +766,9 @@ function assert_vp(path) { } -function linksplit(rp, id) { +function linksplit(rp, base, id) { var ret = [], - apath = '/', + apath = base || '/', q = null; if (rp && rp.indexOf('?') + 1) { diff --git a/tests/util.py b/tests/util.py index bc66512c..f3ccca87 100644 --- a/tests/util.py +++ b/tests/util.py @@ -164,7 +164,7 @@ class Cfg(Namespace): ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle qr_pin qr_wait re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs" ka.update(**{k: 0 for k in ex.split()}) - ex = "ah_alg bname chdir chmod_f chpw_db db_xattr doctitle df epilogues exit favico ipa ipar html_head html_head_d html_head_s idp_login idp_logout lg_sba lg_sbf log_date log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i opds_exts preadmes prologues readmes shr tcolor textfiles txt_eol ufavico ufavico_h unlist vname xff_src zipmaxt R RS SR" + ex = "ah_alg bname chdir chmod_f chpw_db db_xattr doctitle df epilogues exit favico ipa ipar html_head html_head_d html_head_s idp_login idp_logout lg_sba lg_sbf log_date log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i opds_exts preadmes prologues readmes shr shr_site site tcolor textfiles txt_eol ufavico ufavico_h unlist up_site vname xff_src zipmaxt R RS SR" ka.update(**{k: "" for k in ex.split()}) ex = "apnd_who ban_403 ban_404 ban_422 ban_pw ban_pwc ban_url dont_ban cachectl http_vary rss_fmt_d rss_fmt_t spinner"