diff --git a/README.md b/README.md index 68b03614..31f5172d 100644 --- a/README.md +++ b/README.md @@ -757,7 +757,7 @@ this feature was made with [identity providers](#identity-providers) in mind -- when creating a share, the creator can choose any of the following options: * password-protection -* expire after a certain time +* expire after a certain time; `0` or blank means infinite * allow visitors to upload (if the user who creates the share has write-access) semi-intentional limitations: @@ -768,7 +768,10 @@ semi-intentional limitations: * when linking something to discord (for example) it'll get accessed by their scraper and that would count as a hit * browsers wouldn't be able to resume a broken download unless the requester's IP gets allowlisted for X minutes (ref. tricky) -the links are created inside a specific toplevel folder which must be specified with server-config `--shr`, for example `--shr /share/` (this also enables the feature) +specify `--shr /foobar` to enable this feature; a toplevel virtual folder named `foobar` is then created, and that's where all the shares will be served from + +* you can name it whatever, `foobar` is just an example +* if you're using config files, put `shr: /foobar` inside the `[global]` section instead users can delete their own shares in the controlpanel, and a list of privileged users (`--shr-adm`) are allowed to see and/or delet any share on the server diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 08e34367..c1533a30 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -975,8 +975,8 @@ def add_fs(ap): def add_share(ap): db_path = os.path.join(E.cfg, "shares.db") ap2 = ap.add_argument_group('share-url options') - ap2.add_argument("--shr", metavar="URL", default="", help="base url for shared files, for example [\033[32m/share\033[0m] (must be a toplevel subfolder)") - ap2.add_argument("--shr-db", metavar="PATH", default=db_path, help="database to store shares in") + ap2.add_argument("--shr", metavar="DIR", default="", help="toplevel virtual folder for shared files/folders, for example [\033[32m/share\033[0m]") + ap2.add_argument("--shr-db", metavar="FILE", default=db_path, help="database to store shares in") ap2.add_argument("--shr-adm", metavar="U,U", default="", help="comma-separated list of users allowed to view/delete any share") ap2.add_argument("--shr-v", action="store_true", help="debug") diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index d09f7089..592e7972 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -1508,7 +1508,6 @@ class AuthSrv(object): import sqlite3 shv = VFS(self.log_func, "", shr, AXS(), {"d2d": True}) - par = vfs.all_vols[""] db_path = self.args.shr_db db = sqlite3.connect(db_path) @@ -1539,7 +1538,7 @@ class AuthSrv(object): # don't know the abspath yet + wanna ensure the user # still has the privs they granted, so nullmap it shv.nodes[s_k] = VFS( - self.log_func, "", "%s/%s" % (shr, s_k), s_axs, par.flags.copy() + self.log_func, "", "%s/%s" % (shr, s_k), s_axs, shv.flags.copy() ) vfs.nodes[shr] = vfs.all_vols[shr] = shv diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index bd2c37fc..5432dcd3 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -3958,6 +3958,7 @@ class HttpCli(object): rvol=rvol, wvol=wvol, avol=avol, + in_shr=self.args.shr and self.vpath.startswith(self.args.shr[1:]), vstate=vstate, scanning=vs["scanning"], hashq=vs["hashq"], @@ -4006,10 +4007,10 @@ class HttpCli(object): def tx_404(self, is_403: bool = False) -> bool: rc = 404 if self.args.vague_403: - t = '
or maybe you don\'t have access -- try logging in or go home
' - pt = "404 not found ┐( ´ -`)┌ (or maybe you don't have access -- try logging in)" + t = 'or maybe you don\'t have access -- try a password or go home
' + pt = "404 not found ┐( ´ -`)┌ (or maybe you don't have access -- try a password)" elif is_403: - t = 'you\'ll have to log in or go home
' + t = 'use a password or go home
' pt = "403 forbiddena ~┻━┻ (you'll have to log in)" rc = 403 else: @@ -4026,7 +4027,8 @@ class HttpCli(object): t = t.format(self.args.SR) qv = quotep(self.vpaths) + self.ourlq() - html = self.j2s("splash", this=self, qvpath=qv, msg=t) + in_shr = self.args.shr and self.vpath.startswith(self.args.shr[1:]) + html = self.j2s("splash", this=self, qvpath=qv, in_shr=in_shr, msg=t) self.reply(html.encode("utf-8"), status=rc) return True @@ -4382,7 +4384,8 @@ class HttpCli(object): pw = req.get("pw") or "" now = int(time.time()) sexp = req["exp"] - exp = now + int(sexp) * 60 if sexp else 0 + exp = int(sexp) if sexp else 0 + exp = now + exp * 60 if exp else 0 pr = "".join(zc for zc, zb in zip("rwmd", (s_rd, s_wr, s_mv, s_del)) if zb) q = "insert into sh values (?,?,?,?,?,?,?,?)" diff --git a/copyparty/svchub.py b/copyparty/svchub.py index b67359e3..3d18eacf 100644 --- a/copyparty/svchub.py +++ b/copyparty/svchub.py @@ -376,7 +376,13 @@ class SvcHub(object): import sqlite3 - al.shr = "/%s/" % (al.shr.strip("/")) + al.shr = al.shr.strip("/") + if "/" in al.shr: + t = "config error: --shr must be the name of a virtual toplevel directory to put shares inside" + self.log("root", t, 1) + raise Exception(t) + + al.shr = "/%s/" % (al.shr,) create = True db_path = self.args.shr_db diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index ac01fa72..81c8a806 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -3820,13 +3820,14 @@ var fileman = (function () { '', '', '', - 'delete | sharekey | pw | @@ -33,7 +33,7 @@expires | min | hrs | -||
---|---|---|---|---|---|---|---|
delete | @@ -45,11 +45,11 @@{{ un|e }} | {{ t0 }} | {{ t1 }} | -{{ (t1 - now) // 60 if t1 else "never" }} | -{{ (t1 - now) // 3600 if t1 else "never" }} | +{{ ((t1 - now) / 60) | round(1) if t1 else "inf" }} | +{{ ((t1 - now) / 3600) | round(1) if t1 else "inf" }} |
welcome back, {{ this.uname|e }}
{%- endif %} + {%- endif %} {%- if msg %}