copyparty 1.19.16__py3-none-any.whl → 1.19.17__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- copyparty/__init__.py +19 -0
- copyparty/__main__.py +31 -9
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +31 -6
- copyparty/bos/bos.py +5 -1
- copyparty/cfg.py +20 -0
- copyparty/ftpd.py +5 -3
- copyparty/httpcli.py +105 -20
- copyparty/mtag.py +2 -2
- copyparty/smbd.py +1 -1
- copyparty/svchub.py +3 -0
- copyparty/tftpd.py +1 -1
- copyparty/up2k.py +39 -15
- copyparty/util.py +15 -5
- copyparty/web/baguettebox.js.gz +0 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.html +3 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/splash.html +3 -0
- copyparty/web/splash.js.gz +0 -0
- copyparty/web/tl/chi.js.gz +0 -0
- copyparty/web/tl/cze.js.gz +0 -0
- copyparty/web/tl/deu.js.gz +0 -0
- copyparty/web/tl/epo.js.gz +0 -0
- copyparty/web/tl/fin.js.gz +0 -0
- copyparty/web/tl/fra.js.gz +0 -0
- copyparty/web/tl/grc.js.gz +0 -0
- copyparty/web/tl/ita.js.gz +0 -0
- copyparty/web/tl/kor.js.gz +0 -0
- copyparty/web/tl/nld.js.gz +0 -0
- copyparty/web/tl/nno.js.gz +0 -0
- copyparty/web/tl/nor.js.gz +0 -0
- copyparty/web/tl/pol.js.gz +0 -0
- copyparty/web/tl/por.js.gz +0 -0
- copyparty/web/tl/rus.js.gz +0 -0
- copyparty/web/tl/spa.js.gz +0 -0
- copyparty/web/tl/swe.js.gz +0 -0
- copyparty/web/tl/tur.js.gz +0 -0
- copyparty/web/tl/ukr.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.19.16.dist-info → copyparty-1.19.17.dist-info}/METADATA +10 -2
- {copyparty-1.19.16.dist-info → copyparty-1.19.17.dist-info}/RECORD +46 -27
- {copyparty-1.19.16.dist-info → copyparty-1.19.17.dist-info}/WHEEL +0 -0
- {copyparty-1.19.16.dist-info → copyparty-1.19.17.dist-info}/entry_points.txt +0 -0
- {copyparty-1.19.16.dist-info → copyparty-1.19.17.dist-info}/licenses/LICENSE +0 -0
- {copyparty-1.19.16.dist-info → copyparty-1.19.17.dist-info}/top_level.txt +0 -0
copyparty/__init__.py
CHANGED
|
@@ -97,6 +97,25 @@ web/splash.html
|
|
|
97
97
|
web/splash.js
|
|
98
98
|
web/svcs.html
|
|
99
99
|
web/svcs.js
|
|
100
|
+
web/tl/chi.js
|
|
101
|
+
web/tl/cze.js
|
|
102
|
+
web/tl/deu.js
|
|
103
|
+
web/tl/epo.js
|
|
104
|
+
web/tl/fin.js
|
|
105
|
+
web/tl/fra.js
|
|
106
|
+
web/tl/grc.js
|
|
107
|
+
web/tl/ita.js
|
|
108
|
+
web/tl/kor.js
|
|
109
|
+
web/tl/nld.js
|
|
110
|
+
web/tl/nno.js
|
|
111
|
+
web/tl/nor.js
|
|
112
|
+
web/tl/pol.js
|
|
113
|
+
web/tl/por.js
|
|
114
|
+
web/tl/rus.js
|
|
115
|
+
web/tl/spa.js
|
|
116
|
+
web/tl/swe.js
|
|
117
|
+
web/tl/tur.js
|
|
118
|
+
web/tl/ukr.js
|
|
100
119
|
web/ui.css
|
|
101
120
|
web/up2k.js
|
|
102
121
|
web/util.js
|
copyparty/__main__.py
CHANGED
|
@@ -641,8 +641,11 @@ def get_sects():
|
|
|
641
641
|
if no accounts or volumes are configured,
|
|
642
642
|
current folder will be read/write for everyone
|
|
643
643
|
|
|
644
|
-
the group @acct will always have every user with an account
|
|
645
|
-
(the name of that group can be changed with --grp-all)
|
|
644
|
+
the group \033[33m@acct\033[0m will always have every user with an account
|
|
645
|
+
(the name of that group can be changed with \033[32m--grp-all\033[0m)
|
|
646
|
+
|
|
647
|
+
to hide a volume from authenticated users, specify \033[33m*,-@acct\033[0m
|
|
648
|
+
to subtract \033[33m@acct\033[0m from \033[33m*\033[0m (can subtract users from groups too)
|
|
646
649
|
|
|
647
650
|
consider the config file for more flexible account/volume management,
|
|
648
651
|
including dynamic reload at runtime (and being more readable w)
|
|
@@ -664,12 +667,12 @@ def get_sects():
|
|
|
664
667
|
|
|
665
668
|
send the password in the '\033[36mPW\033[0m' http-header:
|
|
666
669
|
\033[36mPW: \033[35mhunter2\033[0m
|
|
667
|
-
or if you have \033[33m--
|
|
670
|
+
or if you have \033[33m--usernames\033[0m enabled,
|
|
668
671
|
\033[36mPW: \033[35med:hunter2\033[0m
|
|
669
672
|
|
|
670
673
|
send the password in the URL itself:
|
|
671
674
|
\033[36mhttp://127.0.0.1:3923/\033[35m?pw=hunter2\033[0m
|
|
672
|
-
or if you have \033[33m--
|
|
675
|
+
or if you have \033[33m--usernames\033[0m enabled,
|
|
673
676
|
\033[36mhttp://127.0.0.1:3923/\033[35m?pw=ed:hunter2\033[0m
|
|
674
677
|
|
|
675
678
|
use basic-authentication:
|
|
@@ -1166,6 +1169,7 @@ def add_general(ap, nc, srvname):
|
|
|
1166
1169
|
ap2.add_argument("--rmagic", action="store_true", help="do expensive analysis to improve accuracy of returned mimetypes; will make file-downloads, rss, and webdav slower (volflag=rmagic)")
|
|
1167
1170
|
ap2.add_argument("--license", action="store_true", help="show licenses and exit")
|
|
1168
1171
|
ap2.add_argument("--version", action="store_true", help="show versions and exit")
|
|
1172
|
+
ap2.add_argument("--versionb", action="store_true", help="show version and exit")
|
|
1169
1173
|
|
|
1170
1174
|
|
|
1171
1175
|
def add_qr(ap, tty):
|
|
@@ -1233,6 +1237,7 @@ def add_upload(ap):
|
|
|
1233
1237
|
ap2.add_argument("--hardlink-only", action="store_true", help="do not fallback to symlinks when a hardlink cannot be made (volflag=hardlinkonly)")
|
|
1234
1238
|
ap2.add_argument("--reflink", action="store_true", help="enable reflink-based dedup; will fallback on full copies when that is impossible (non-CoW filesystem) (volflag=reflink)")
|
|
1235
1239
|
ap2.add_argument("--no-dupe", action="store_true", help="reject duplicate files during upload; only matches within the same volume (volflag=nodupe)")
|
|
1240
|
+
ap2.add_argument("--no-dupe-m", action="store_true", help="also reject dupes when moving a file into another volume (volflag=nodupem)")
|
|
1236
1241
|
ap2.add_argument("--no-clone", action="store_true", help="do not use existing data on disk to satisfy dupe uploads; reduces server HDD reads in exchange for much more network load (volflag=noclone)")
|
|
1237
1242
|
ap2.add_argument("--no-snap", action="store_true", help="disable snapshots -- forget unfinished uploads on shutdown; don't create .hist/up2k.snap files -- abandoned/interrupted uploads must be cleaned up manually")
|
|
1238
1243
|
ap2.add_argument("--snap-wri", metavar="SEC", type=int, default=300, help="write upload state to ./hist/up2k.snap every \033[33mSEC\033[0m seconds; allows resuming incomplete uploads after a server crash")
|
|
@@ -1520,6 +1525,7 @@ def add_optouts(ap):
|
|
|
1520
1525
|
ap2.add_argument("--no-pipe", action="store_true", help="disable race-the-beam (lockstep download of files which are currently being uploaded) (volflag=nopipe)")
|
|
1521
1526
|
ap2.add_argument("--no-tail", action="store_true", help="disable streaming a growing files with ?tail (volflag=notail)")
|
|
1522
1527
|
ap2.add_argument("--no-db-ip", action="store_true", help="do not write uploader-IP into the database; will also disable unpost, you may want \033[32m--forget-ip\033[0m instead (volflag=no_db_ip)")
|
|
1528
|
+
ap2.add_argument("--no-zls", action="store_true", help="disable browsing the contents of zip/cbz files, does not affect thumbnails")
|
|
1523
1529
|
|
|
1524
1530
|
|
|
1525
1531
|
def add_safety(ap):
|
|
@@ -1538,6 +1544,7 @@ def add_safety(ap):
|
|
|
1538
1544
|
ap2.add_argument("--force-js", action="store_true", help="don't send folder listings as HTML, force clients to use the embedded json instead -- slight protection against misbehaving search engines which ignore \033[33m--no-robots\033[0m")
|
|
1539
1545
|
ap2.add_argument("--no-robots", action="store_true", help="adds http and html headers asking search engines to not index anything (volflag=norobots)")
|
|
1540
1546
|
ap2.add_argument("--logout", metavar="H", type=float, default=8086.0, help="logout clients after \033[33mH\033[0m hours of inactivity; [\033[32m0.0028\033[0m]=10sec, [\033[32m0.1\033[0m]=6min, [\033[32m24\033[0m]=day, [\033[32m168\033[0m]=week, [\033[32m720\033[0m]=month, [\033[32m8760\033[0m]=year)")
|
|
1547
|
+
ap2.add_argument("--dont-ban", metavar="TXT", type=u, default="no", help="anyone at this accesslevel or above will not get banned: [\033[32mav\033[0m]=admin-in-volume, [\033[32maa\033[0m]=has-admin-anywhere, [\033[32mrw\033[0m]=read-write, [\033[32mauth\033[0m]=authenticated, [\033[32many\033[0m]=disable-all-bans, [\033[32mno\033[0m]=anyone-can-get-banned")
|
|
1541
1548
|
ap2.add_argument("--ban-pw", metavar="N,W,B", type=u, default="9,60,1440", help="more than \033[33mN\033[0m wrong passwords in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
|
|
1542
1549
|
ap2.add_argument("--ban-pwc", metavar="N,W,B", type=u, default="5,60,1440", help="more than \033[33mN\033[0m password-changes in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
|
|
1543
1550
|
ap2.add_argument("--ban-404", metavar="N,W,B", type=u, default="50,60,1440", help="hitting more than \033[33mN\033[0m 404's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; only affects users who cannot see directory listings because their access is either g/G/h")
|
|
@@ -1602,12 +1609,14 @@ def add_admin(ap):
|
|
|
1602
1609
|
ap2 = ap.add_argument_group("admin panel options")
|
|
1603
1610
|
ap2.add_argument("--no-reload", action="store_true", help="disable ?reload=cfg (reload users/volumes/volflags from config file)")
|
|
1604
1611
|
ap2.add_argument("--no-rescan", action="store_true", help="disable ?scan (volume reindexing)")
|
|
1605
|
-
ap2.add_argument("--no-stack", action="store_true", help="disable ?stack (list all stacks)")
|
|
1612
|
+
ap2.add_argument("--no-stack", action="store_true", help="disable ?stack (list all stacks); same as --stack-who=no")
|
|
1606
1613
|
ap2.add_argument("--no-ups-page", action="store_true", help="disable ?ru (list of recent uploads)")
|
|
1607
1614
|
ap2.add_argument("--no-up-list", action="store_true", help="don't show list of incoming files in controlpanel")
|
|
1608
1615
|
ap2.add_argument("--dl-list", metavar="LVL", type=int, default=2, help="who can see active downloads in the controlpanel? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=everyone")
|
|
1609
1616
|
ap2.add_argument("--ups-who", metavar="LVL", type=int, default=2, help="who can see recent uploads on the ?ru page? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=everyone (volflag=ups_who)")
|
|
1610
1617
|
ap2.add_argument("--ups-when", action="store_true", help="let everyone see upload timestamps on the ?ru page, not just admins")
|
|
1618
|
+
ap2.add_argument("--stack-who", metavar="LVL", type=u, default="a", help="who can see the ?stack page (list of threads)? [\033[32mno\033[0m]=nobody, [\033[32ma\033[0m]=admins, [\033[32mrw\033[0m]=read+write, [\033[32mall\033[0m]=everyone")
|
|
1619
|
+
ap2.add_argument("--stack-v", action="store_true", help="verbose ?stack")
|
|
1611
1620
|
|
|
1612
1621
|
|
|
1613
1622
|
def add_thumbnail(ap):
|
|
@@ -1805,6 +1814,15 @@ def add_ui(ap, retry ):
|
|
|
1805
1814
|
ap2.add_argument("--lg-sba", metavar="TXT", type=u, default="", help="the value of the iframe 'allow' attribute for prologue/epilogue docs (volflag=lg_sba); see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy#iframes")
|
|
1806
1815
|
ap2.add_argument("--no-sb-md", action="store_true", help="don't sandbox README/PREADME.md documents (volflags: no_sb_md | sb_md)")
|
|
1807
1816
|
ap2.add_argument("--no-sb-lg", action="store_true", help="don't sandbox prologue/epilogue docs (volflags: no_sb_lg | sb_lg); enables non-js support")
|
|
1817
|
+
ap2.add_argument("--ui-nombar", action="store_true", help="hide top-menu in the UI (volflag=ui_nombar)")
|
|
1818
|
+
ap2.add_argument("--ui-noacci", action="store_true", help="hide account-info in the UI (volflag=ui_noacci)")
|
|
1819
|
+
ap2.add_argument("--ui-nosrvi", action="store_true", help="hide server-info in the UI (volflag=ui_nosrvi)")
|
|
1820
|
+
ap2.add_argument("--ui-nonav", action="store_true", help="hide navpane+breadcrumbs (volflag=ui_nonav)")
|
|
1821
|
+
ap2.add_argument("--ui-notree", action="store_true", help="hide navpane in the UI (volflag=ui_nonav)")
|
|
1822
|
+
ap2.add_argument("--ui-nocpla", action="store_true", help="hide cpanel-link in the UI (volflag=ui_nocpla)")
|
|
1823
|
+
ap2.add_argument("--ui-nolbar", action="store_true", help="hide link-bar in the UI (volflag=ui_nolbar)")
|
|
1824
|
+
ap2.add_argument("--ui-noctxb", action="store_true", help="hide context-buttons in the UI (volflag=ui_noctxb)")
|
|
1825
|
+
ap2.add_argument("--ui-norepl", action="store_true", help="hide repl-button in the UI (volflag=ui_norepl)")
|
|
1808
1826
|
ap2.add_argument("--have-unlistc", action="store_true", help=argparse.SUPPRESS)
|
|
1809
1827
|
|
|
1810
1828
|
|
|
@@ -1932,15 +1950,19 @@ def run_argparse(
|
|
|
1932
1950
|
|
|
1933
1951
|
|
|
1934
1952
|
def main(argv = None) :
|
|
1953
|
+
if argv is None:
|
|
1954
|
+
argv = sys.argv
|
|
1955
|
+
|
|
1956
|
+
if "--versionb" in argv:
|
|
1957
|
+
print(S_VERSION)
|
|
1958
|
+
sys.exit(0)
|
|
1959
|
+
|
|
1935
1960
|
time.strptime("19970815", "%Y%m%d") # python#7980
|
|
1936
1961
|
if WINDOWS:
|
|
1937
1962
|
os.system("rem") # enables colors
|
|
1938
1963
|
|
|
1939
1964
|
init_E(E)
|
|
1940
1965
|
|
|
1941
|
-
if argv is None:
|
|
1942
|
-
argv = sys.argv
|
|
1943
|
-
|
|
1944
1966
|
f = '\033[36mcopyparty v{} "\033[35m{}\033[36m" ({})\n{}\033[0;36m\n sqlite {} | jinja {} | pyftpd {} | tftp {}\n\033[0m'
|
|
1945
1967
|
f = f.format(
|
|
1946
1968
|
S_VERSION,
|
|
@@ -2067,7 +2089,7 @@ def main(argv = None) :
|
|
|
2067
2089
|
|
|
2068
2090
|
# propagate implications
|
|
2069
2091
|
for k1, k2 in IMPLICATIONS:
|
|
2070
|
-
if getattr(al, k1):
|
|
2092
|
+
if getattr(al, k1, None):
|
|
2071
2093
|
setattr(al, k2, True)
|
|
2072
2094
|
|
|
2073
2095
|
# propagate unplications
|
copyparty/__version__.py
CHANGED
copyparty/authsrv.py
CHANGED
|
@@ -1961,9 +1961,18 @@ class AuthSrv(object):
|
|
|
1961
1961
|
axs_key = "u" + perm
|
|
1962
1962
|
for vp, vol in vfs.all_vols.items():
|
|
1963
1963
|
zx = getattr(vol.axs, axs_key)
|
|
1964
|
-
if "*" in zx:
|
|
1964
|
+
if "*" in zx and "-@acct" not in zx:
|
|
1965
1965
|
for usr in unames:
|
|
1966
1966
|
zx.add(usr)
|
|
1967
|
+
for zs in list(zx):
|
|
1968
|
+
if zs.startswith("-"):
|
|
1969
|
+
zx.discard(zs)
|
|
1970
|
+
zs = zs[1:]
|
|
1971
|
+
zx.discard(zs)
|
|
1972
|
+
if zs.startswith("@"):
|
|
1973
|
+
zs = zs[1:]
|
|
1974
|
+
for zs in grps.get(zs) or []:
|
|
1975
|
+
zx.discard(zs)
|
|
1967
1976
|
|
|
1968
1977
|
# aread,... = dict[uname, list[volnames] or []]
|
|
1969
1978
|
umap = {x: [] for x in unames}
|
|
@@ -2577,6 +2586,15 @@ class AuthSrv(object):
|
|
|
2577
2586
|
for x in drop:
|
|
2578
2587
|
vol.flags.pop(x)
|
|
2579
2588
|
|
|
2589
|
+
zi = vol.flags.get("lifetime") or 0
|
|
2590
|
+
zi2 = time.time() // (86400 * 365)
|
|
2591
|
+
zi3 = zi2 * 86400 * 365
|
|
2592
|
+
if zi < 0 or zi > zi3:
|
|
2593
|
+
t = "the lifetime of volume [/%s] (%d) exceeds max value (%d years; %d)"
|
|
2594
|
+
t = t % (vol.vpath, zi, zi2, zi3)
|
|
2595
|
+
self.log(t, 1)
|
|
2596
|
+
raise Exception(t)
|
|
2597
|
+
|
|
2580
2598
|
# verify tags mentioned by -mt[mp] are used by -mte
|
|
2581
2599
|
local_mtp = {}
|
|
2582
2600
|
local_only_mtp = {}
|
|
@@ -2743,9 +2761,13 @@ class AuthSrv(object):
|
|
|
2743
2761
|
["uadmin", "uadmin"],
|
|
2744
2762
|
]:
|
|
2745
2763
|
u = list(sorted(getattr(zv.axs, attr)))
|
|
2746
|
-
u
|
|
2747
|
-
|
|
2748
|
-
|
|
2764
|
+
if u == ["*"] and acct:
|
|
2765
|
+
u = ["\033[35monly-anonymous\033[0m"]
|
|
2766
|
+
elif "*" in u:
|
|
2767
|
+
u = ["\033[35meverybody\033[0m"]
|
|
2768
|
+
if not u:
|
|
2769
|
+
u = ["\033[36m--none--\033[0m"]
|
|
2770
|
+
u = ", ".join(u)
|
|
2749
2771
|
t += "\n| {}: {}".format(txt, u)
|
|
2750
2772
|
|
|
2751
2773
|
if "e2d" in zv.flags:
|
|
@@ -2857,8 +2879,6 @@ class AuthSrv(object):
|
|
|
2857
2879
|
|
|
2858
2880
|
if have_reflink:
|
|
2859
2881
|
t = "WARNING: Reflink-based dedup was requested, but %s. This will not work; files will be full copies instead."
|
|
2860
|
-
if sys.version_info < (3, 14):
|
|
2861
|
-
self.log(t % "your python version is not new enough", 1)
|
|
2862
2882
|
if not sys.platform.startswith("linux"):
|
|
2863
2883
|
self.log(t % "your OS is not Linux", 1)
|
|
2864
2884
|
|
|
@@ -3016,6 +3036,7 @@ class AuthSrv(object):
|
|
|
3016
3036
|
"have_shr": self.args.shr,
|
|
3017
3037
|
"shr_who": vf["shr_who"],
|
|
3018
3038
|
"have_zip": not self.args.no_zip,
|
|
3039
|
+
"have_zls": not self.args.no_zls,
|
|
3019
3040
|
"have_mv": not self.args.no_mv,
|
|
3020
3041
|
"have_del": not self.args.no_del,
|
|
3021
3042
|
"have_unpost": int(self.args.unpost),
|
|
@@ -3052,6 +3073,10 @@ class AuthSrv(object):
|
|
|
3052
3073
|
"lifetime": vn.js_ls["lifetime"],
|
|
3053
3074
|
"u2sort": self.args.u2sort,
|
|
3054
3075
|
}
|
|
3076
|
+
zs = "ui_noacci ui_nocpla ui_noctxb ui_nolbar ui_nombar ui_nonav ui_notree ui_norepl ui_nosrvi"
|
|
3077
|
+
for zs in zs.split():
|
|
3078
|
+
if vf.get(zs):
|
|
3079
|
+
js_htm[zs] = 1
|
|
3055
3080
|
vn.js_htm = json_hesc(json.dumps(js_htm))
|
|
3056
3081
|
|
|
3057
3082
|
vols = list(vfs.all_nodes.values())
|
copyparty/bos/bos.py
CHANGED
copyparty/cfg.py
CHANGED
|
@@ -19,6 +19,7 @@ def vf_bmap() :
|
|
|
19
19
|
"no_clone": "noclone",
|
|
20
20
|
"no_dirsz": "nodirsz",
|
|
21
21
|
"no_dupe": "nodupe",
|
|
22
|
+
"no_dupe_m": "nodupem",
|
|
22
23
|
"no_forget": "noforget",
|
|
23
24
|
"no_pipe": "nopipe",
|
|
24
25
|
"no_robots": "norobots",
|
|
@@ -58,6 +59,15 @@ def vf_bmap() :
|
|
|
58
59
|
"rm_partial",
|
|
59
60
|
"rmagic",
|
|
60
61
|
"rss",
|
|
62
|
+
"ui_noacci",
|
|
63
|
+
"ui_nocpla",
|
|
64
|
+
"ui_nolbar",
|
|
65
|
+
"ui_nombar",
|
|
66
|
+
"ui_nonav",
|
|
67
|
+
"ui_notree",
|
|
68
|
+
"ui_norepl",
|
|
69
|
+
"ui_nosrvi",
|
|
70
|
+
"ui_noctxb",
|
|
61
71
|
"wo_up_readme",
|
|
62
72
|
"wram",
|
|
63
73
|
"xdev",
|
|
@@ -189,6 +199,7 @@ flagcats = {
|
|
|
189
199
|
"safededup": "verify on-disk data before using it for dedup",
|
|
190
200
|
"noclone": "take dupe data from clients, even if available on HDD",
|
|
191
201
|
"nodupe": "rejects existing files (instead of linking/cloning them)",
|
|
202
|
+
"nodupem": "rejects existing files during moves as well",
|
|
192
203
|
"chmod_d=755": "unix-permission for new dirs/folders",
|
|
193
204
|
"chmod_f=644": "unix-permission for new files",
|
|
194
205
|
"uid=573": "change owner of new files/folders to unix-user 573",
|
|
@@ -325,6 +336,15 @@ flagcats = {
|
|
|
325
336
|
"md_sba": "value of iframe allow-prop for markdown-sandbox",
|
|
326
337
|
"lg_sba": "value of iframe allow-prop for *logue-sandbox",
|
|
327
338
|
"nohtml": "return html and markdown as text/html",
|
|
339
|
+
"ui_noacci": "hide account-info in the UI",
|
|
340
|
+
"ui_nocpla": "hide cpanel-link in the UI",
|
|
341
|
+
"ui_nolbar": "hide link-bar in the UI",
|
|
342
|
+
"ui_nombar": "hide top-menu in the UI",
|
|
343
|
+
"ui_nonav": "hide navpane+breadcrumbs in the UI",
|
|
344
|
+
"ui_notree": "hide navpane in the UI",
|
|
345
|
+
"ui_norepl": "hide repl-button in the UI",
|
|
346
|
+
"ui_nosrvi": "hide server-info in the UI",
|
|
347
|
+
"ui_noctxb": "hide context-buttons in the UI",
|
|
328
348
|
},
|
|
329
349
|
"opengraph (discord embeds)": {
|
|
330
350
|
"og": "enable OG (disables hotlinking)",
|
copyparty/ftpd.py
CHANGED
|
@@ -247,7 +247,7 @@ class FtpFs(AbstractedFS):
|
|
|
247
247
|
|
|
248
248
|
if w and need_unlink:
|
|
249
249
|
if td >= -1 and td <= self.args.ftp_wt:
|
|
250
|
-
# within permitted timeframe;
|
|
250
|
+
# within permitted timeframe; allow overwrite or resume
|
|
251
251
|
do_it = True
|
|
252
252
|
elif self.args.no_del or self.args.ftp_no_ow:
|
|
253
253
|
# file too old, or overwrite not allowed; reject
|
|
@@ -264,7 +264,9 @@ class FtpFs(AbstractedFS):
|
|
|
264
264
|
if not do_it:
|
|
265
265
|
raise FSE("File already exists")
|
|
266
266
|
|
|
267
|
-
|
|
267
|
+
# Don't unlink file for append mode
|
|
268
|
+
elif "a" not in mode:
|
|
269
|
+
wunlink(self.log, ap, VF_CAREFUL)
|
|
268
270
|
|
|
269
271
|
ret = open(fsenc(ap), mode, self.args.iobuf)
|
|
270
272
|
if w and "fperms" in vfs.flags:
|
|
@@ -505,7 +507,7 @@ class FtpHandler(FTPHandler):
|
|
|
505
507
|
0,
|
|
506
508
|
self.cli_ip,
|
|
507
509
|
time.time(),
|
|
508
|
-
|
|
510
|
+
None,
|
|
509
511
|
)
|
|
510
512
|
t = hr.get("rejectmsg") or ""
|
|
511
513
|
if t or not hr:
|
copyparty/httpcli.py
CHANGED
|
@@ -270,7 +270,7 @@ class HttpCli(object):
|
|
|
270
270
|
tpl = self.conn.hsrv.j2[name]
|
|
271
271
|
ka["r"] = self.args.SR if self.is_vproxied else ""
|
|
272
272
|
ka["ts"] = self.conn.hsrv.cachebuster()
|
|
273
|
-
ka["lang"] = self.args.lang
|
|
273
|
+
ka["lang"] = self.cookies.get("cplng") or self.args.lang
|
|
274
274
|
ka["favico"] = self.args.favico
|
|
275
275
|
ka["s_doctitle"] = self.args.doctitle
|
|
276
276
|
ka["tcolor"] = self.vn.flags["tcolor"]
|
|
@@ -857,6 +857,16 @@ class HttpCli(object):
|
|
|
857
857
|
return self.conn.iphash.s(self.ip)
|
|
858
858
|
|
|
859
859
|
def cbonk(self, g , v , reason , descr ) :
|
|
860
|
+
cond = self.args.dont_ban
|
|
861
|
+
if (
|
|
862
|
+
cond == "any"
|
|
863
|
+
or (cond == "auth" and self.uname != "*")
|
|
864
|
+
or (cond == "aa" and self.avol)
|
|
865
|
+
or (cond == "av" and self.can_admin)
|
|
866
|
+
or (cond == "rw" and self.can_read and self.can_write)
|
|
867
|
+
):
|
|
868
|
+
return False
|
|
869
|
+
|
|
860
870
|
self.conn.hsrv.nsus += 1
|
|
861
871
|
if not g.lim:
|
|
862
872
|
return False
|
|
@@ -881,7 +891,7 @@ class HttpCli(object):
|
|
|
881
891
|
0,
|
|
882
892
|
self.ip,
|
|
883
893
|
time.time(),
|
|
884
|
-
reason,
|
|
894
|
+
[reason, reason],
|
|
885
895
|
):
|
|
886
896
|
self.log("client banned: %s" % (descr,), 1)
|
|
887
897
|
self.conn.hsrv.bans[ip] = bonk
|
|
@@ -1516,6 +1526,64 @@ class HttpCli(object):
|
|
|
1516
1526
|
self.log("rss: %d hits, %d bytes" % (len(hits), len(bret)))
|
|
1517
1527
|
return True
|
|
1518
1528
|
|
|
1529
|
+
def tx_zls(self, abspath) :
|
|
1530
|
+
if self.do_log:
|
|
1531
|
+
self.log("zls %s @%s" % (self.req, self.uname))
|
|
1532
|
+
if self.args.no_zls:
|
|
1533
|
+
raise Pebkac(405, "zip browsing is disabled in server config")
|
|
1534
|
+
|
|
1535
|
+
import zipfile
|
|
1536
|
+
|
|
1537
|
+
try:
|
|
1538
|
+
with zipfile.ZipFile(abspath, "r") as zf:
|
|
1539
|
+
filelist = [{"fn": f.filename} for f in zf.infolist()]
|
|
1540
|
+
ret = json.dumps(filelist).encode("utf-8", "replace")
|
|
1541
|
+
self.reply(ret, mime="application/json")
|
|
1542
|
+
return True
|
|
1543
|
+
except (zipfile.BadZipfile, RuntimeError):
|
|
1544
|
+
raise Pebkac(404, "requested file is not a valid zip file")
|
|
1545
|
+
|
|
1546
|
+
def tx_zget(self, abspath) :
|
|
1547
|
+
maxsz = 1024 * 1024 * 64
|
|
1548
|
+
|
|
1549
|
+
inner_path = self.uparam.get("zget")
|
|
1550
|
+
if not inner_path:
|
|
1551
|
+
raise Pebkac(405, "inner path is required")
|
|
1552
|
+
if self.do_log:
|
|
1553
|
+
self.log(
|
|
1554
|
+
"zget %s \033[35m%s\033[0m @%s" % (self.req, inner_path, self.uname)
|
|
1555
|
+
)
|
|
1556
|
+
if self.args.no_zls:
|
|
1557
|
+
raise Pebkac(405, "zip browsing is disabled in server config")
|
|
1558
|
+
|
|
1559
|
+
import zipfile
|
|
1560
|
+
|
|
1561
|
+
try:
|
|
1562
|
+
with zipfile.ZipFile(abspath, "r") as zf:
|
|
1563
|
+
zi = zf.getinfo(inner_path)
|
|
1564
|
+
if zi.file_size >= maxsz:
|
|
1565
|
+
raise Pebkac(404, "zip bomb defused")
|
|
1566
|
+
with zf.open(zi, "r") as fi:
|
|
1567
|
+
self.send_headers(length=zi.file_size, mime=guess_mime(inner_path))
|
|
1568
|
+
|
|
1569
|
+
sendfile_py(
|
|
1570
|
+
self.log,
|
|
1571
|
+
0,
|
|
1572
|
+
zi.file_size,
|
|
1573
|
+
fi,
|
|
1574
|
+
self.s,
|
|
1575
|
+
self.args.s_wr_sz,
|
|
1576
|
+
self.args.s_wr_slp,
|
|
1577
|
+
not self.args.no_poll,
|
|
1578
|
+
{},
|
|
1579
|
+
"",
|
|
1580
|
+
)
|
|
1581
|
+
except KeyError:
|
|
1582
|
+
raise Pebkac(404, "no such file in archive")
|
|
1583
|
+
except (zipfile.BadZipfile, RuntimeError):
|
|
1584
|
+
raise Pebkac(404, "requested file is not a valid zip file")
|
|
1585
|
+
return True
|
|
1586
|
+
|
|
1519
1587
|
def handle_propfind(self) :
|
|
1520
1588
|
if self.do_log:
|
|
1521
1589
|
self.log("PFIND %s @%s" % (self.req, self.uname))
|
|
@@ -2079,7 +2147,7 @@ class HttpCli(object):
|
|
|
2079
2147
|
t = "urlform_raw %d @ %r\n %r\n"
|
|
2080
2148
|
self.log(t % (len(orig), "/" + self.vpath, orig))
|
|
2081
2149
|
try:
|
|
2082
|
-
zb = unquote(buf.replace(b"+", b" "))
|
|
2150
|
+
zb = unquote(buf.replace(b"+", b" ").replace(b"&", b"\n"))
|
|
2083
2151
|
plain = zb.decode("utf-8", "replace")
|
|
2084
2152
|
if buf.startswith(b"msg="):
|
|
2085
2153
|
plain = plain[4:]
|
|
@@ -2100,7 +2168,7 @@ class HttpCli(object):
|
|
|
2100
2168
|
len(buf),
|
|
2101
2169
|
self.ip,
|
|
2102
2170
|
time.time(),
|
|
2103
|
-
plain,
|
|
2171
|
+
[plain, orig],
|
|
2104
2172
|
)
|
|
2105
2173
|
|
|
2106
2174
|
t = "urlform_dec %d @ %r\n %r\n"
|
|
@@ -2259,7 +2327,7 @@ class HttpCli(object):
|
|
|
2259
2327
|
remains,
|
|
2260
2328
|
self.ip,
|
|
2261
2329
|
at,
|
|
2262
|
-
|
|
2330
|
+
None,
|
|
2263
2331
|
)
|
|
2264
2332
|
t = hr.get("rejectmsg") or ""
|
|
2265
2333
|
if t or not hr:
|
|
@@ -2394,7 +2462,7 @@ class HttpCli(object):
|
|
|
2394
2462
|
post_sz,
|
|
2395
2463
|
self.ip,
|
|
2396
2464
|
at,
|
|
2397
|
-
|
|
2465
|
+
None,
|
|
2398
2466
|
)
|
|
2399
2467
|
t = hr.get("rejectmsg") or ""
|
|
2400
2468
|
if t or not hr:
|
|
@@ -3226,7 +3294,7 @@ class HttpCli(object):
|
|
|
3226
3294
|
0,
|
|
3227
3295
|
self.ip,
|
|
3228
3296
|
time.time(),
|
|
3229
|
-
|
|
3297
|
+
None,
|
|
3230
3298
|
)
|
|
3231
3299
|
t = hr.get("rejectmsg") or ""
|
|
3232
3300
|
if t or not hr:
|
|
@@ -3398,7 +3466,7 @@ class HttpCli(object):
|
|
|
3398
3466
|
0,
|
|
3399
3467
|
self.ip,
|
|
3400
3468
|
at,
|
|
3401
|
-
|
|
3469
|
+
None,
|
|
3402
3470
|
)
|
|
3403
3471
|
t = hr.get("rejectmsg") or ""
|
|
3404
3472
|
if t or not hr:
|
|
@@ -3505,7 +3573,7 @@ class HttpCli(object):
|
|
|
3505
3573
|
sz,
|
|
3506
3574
|
self.ip,
|
|
3507
3575
|
at,
|
|
3508
|
-
|
|
3576
|
+
None,
|
|
3509
3577
|
)
|
|
3510
3578
|
t = hr.get("rejectmsg") or ""
|
|
3511
3579
|
if t or not hr:
|
|
@@ -3816,7 +3884,7 @@ class HttpCli(object):
|
|
|
3816
3884
|
0,
|
|
3817
3885
|
self.ip,
|
|
3818
3886
|
time.time(),
|
|
3819
|
-
|
|
3887
|
+
None,
|
|
3820
3888
|
)
|
|
3821
3889
|
t = hr.get("rejectmsg") or ""
|
|
3822
3890
|
if t or not hr:
|
|
@@ -3864,7 +3932,7 @@ class HttpCli(object):
|
|
|
3864
3932
|
sz,
|
|
3865
3933
|
self.ip,
|
|
3866
3934
|
new_lastmod,
|
|
3867
|
-
|
|
3935
|
+
None,
|
|
3868
3936
|
)
|
|
3869
3937
|
t = hr.get("rejectmsg") or ""
|
|
3870
3938
|
if t or not hr:
|
|
@@ -4998,7 +5066,7 @@ class HttpCli(object):
|
|
|
4998
5066
|
"edit": "edit" in self.uparam,
|
|
4999
5067
|
"title": html_escape(self.vpath, crlf=True),
|
|
5000
5068
|
"lastmod": int(ts_md * 1000),
|
|
5001
|
-
"lang": self.args.lang,
|
|
5069
|
+
"lang": self.cookies.get("cplng") or self.args.lang,
|
|
5002
5070
|
"favico": self.args.favico,
|
|
5003
5071
|
"have_emp": int(self.args.emp),
|
|
5004
5072
|
"md_no_br": int(vn.flags.get("md_no_br") or 0),
|
|
@@ -5383,13 +5451,20 @@ class HttpCli(object):
|
|
|
5383
5451
|
return self.redirect("", "?h", x.get(), "return to", False)
|
|
5384
5452
|
|
|
5385
5453
|
def tx_stack(self) :
|
|
5386
|
-
|
|
5454
|
+
zs = self.args.stack_who
|
|
5455
|
+
if zs == "all" or (
|
|
5456
|
+
(zs == "a" and self.avol)
|
|
5457
|
+
or (zs == "rw" and [x for x in self.wvol if x in self.rvol])
|
|
5458
|
+
):
|
|
5459
|
+
pass
|
|
5460
|
+
else:
|
|
5387
5461
|
raise Pebkac(403, "'stack' not allowed for user " + self.uname)
|
|
5388
5462
|
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5463
|
+
ret = html_escape(alltrace(self.args.stack_v))
|
|
5464
|
+
if self.args.stack_v:
|
|
5465
|
+
ret = "<pre>%s\n%s" % (time.time(), ret)
|
|
5466
|
+
else:
|
|
5467
|
+
ret = "<pre>%s" % (ret,)
|
|
5393
5468
|
self.reply(ret.encode("utf-8"))
|
|
5394
5469
|
return True
|
|
5395
5470
|
|
|
@@ -6456,14 +6531,23 @@ class HttpCli(object):
|
|
|
6456
6531
|
):
|
|
6457
6532
|
return self.tx_md(vn, abspath)
|
|
6458
6533
|
|
|
6534
|
+
if "zls" in self.uparam:
|
|
6535
|
+
return self.tx_zls(abspath)
|
|
6536
|
+
if "zget" in self.uparam:
|
|
6537
|
+
return self.tx_zget(abspath)
|
|
6538
|
+
|
|
6459
6539
|
if not add_og or not og_fn:
|
|
6460
|
-
|
|
6461
|
-
abspath, None
|
|
6462
|
-
|
|
6540
|
+
if st.st_size or "nopipe" in vn.flags:
|
|
6541
|
+
return self.tx_file(abspath, None)
|
|
6542
|
+
else:
|
|
6543
|
+
return self.tx_file(abspath, vn.get_dbv("")[0].realpath)
|
|
6463
6544
|
|
|
6464
6545
|
elif is_dir and not self.can_read:
|
|
6465
6546
|
if use_dirkey:
|
|
6466
6547
|
is_dk = True
|
|
6548
|
+
elif self.can_get and "doc" in self.uparam:
|
|
6549
|
+
zs = vjoin(self.vpath, self.uparam["doc"]) + "?v"
|
|
6550
|
+
return self.redirect(zs, flavor="redirecting to", use302=True)
|
|
6467
6551
|
elif not self.can_write:
|
|
6468
6552
|
return self.tx_404(True)
|
|
6469
6553
|
|
|
@@ -6545,6 +6629,7 @@ class HttpCli(object):
|
|
|
6545
6629
|
"acct": self.uname,
|
|
6546
6630
|
"perms": perms,
|
|
6547
6631
|
}
|
|
6632
|
+
# also see `js_htm` in authsrv.py
|
|
6548
6633
|
j2a = {
|
|
6549
6634
|
"cgv1": vn.js_htm,
|
|
6550
6635
|
"cgv": cgv,
|
copyparty/mtag.py
CHANGED
|
@@ -162,12 +162,12 @@ def au_unpk(
|
|
|
162
162
|
znil = [x for x in znil if "cover" in x[0]] or znil
|
|
163
163
|
znil = [x for x in znil if CBZ_01.search(x[0])] or znil
|
|
164
164
|
t = "cbz: %d files, %d hits" % (nf, len(znil))
|
|
165
|
+
if not znil:
|
|
166
|
+
raise Exception("no images inside cbz")
|
|
165
167
|
using = sorted(znil)[0][1].filename
|
|
166
168
|
if znil:
|
|
167
169
|
t += ", using " + using
|
|
168
170
|
log(t)
|
|
169
|
-
if not znil:
|
|
170
|
-
raise Exception("no images inside cbz")
|
|
171
171
|
fi = zf.open(using)
|
|
172
172
|
|
|
173
173
|
elif pk == "epub":
|
copyparty/smbd.py
CHANGED
copyparty/svchub.py
CHANGED
|
@@ -285,6 +285,9 @@ class SvcHub(object):
|
|
|
285
285
|
ch = "abcdefghijklmnopqrstuvwx"[int(args.theme / 2)]
|
|
286
286
|
args.theme = "{0}{1} {0} {1}".format(ch, bri)
|
|
287
287
|
|
|
288
|
+
if args.no_stack:
|
|
289
|
+
args.stack_who = "no"
|
|
290
|
+
|
|
288
291
|
if args.nid:
|
|
289
292
|
args.du_who = "no"
|
|
290
293
|
args.du_iwho = n_du_who(args.du_who)
|
copyparty/tftpd.py
CHANGED
copyparty/up2k.py
CHANGED
|
@@ -10,6 +10,7 @@ import re
|
|
|
10
10
|
import shutil
|
|
11
11
|
import stat
|
|
12
12
|
import subprocess as sp
|
|
13
|
+
import sys
|
|
13
14
|
import tempfile
|
|
14
15
|
import threading
|
|
15
16
|
import time
|
|
@@ -27,6 +28,7 @@ from .mtag import MParser, MTag
|
|
|
27
28
|
from .util import (
|
|
28
29
|
E_FS_CRIT,
|
|
29
30
|
E_FS_MEH,
|
|
31
|
+
HAVE_FICLONE,
|
|
30
32
|
HAVE_SQLITE3,
|
|
31
33
|
SYMTIME,
|
|
32
34
|
VF_CAREFUL,
|
|
@@ -85,6 +87,10 @@ DB_VER = 6
|
|
|
85
87
|
if TYPE_CHECKING:
|
|
86
88
|
from .svchub import SvcHub
|
|
87
89
|
|
|
90
|
+
USE_FICLONE = HAVE_FICLONE and sys.version_info < (3, 14)
|
|
91
|
+
if USE_FICLONE:
|
|
92
|
+
import fcntl
|
|
93
|
+
|
|
88
94
|
zsg = "avif,avifs,bmp,gif,heic,heics,heif,heifs,ico,j2p,j2k,jp2,jpeg,jpg,jpx,png,tga,tif,tiff,webp"
|
|
89
95
|
ICV_EXTS = set(zsg.split(","))
|
|
90
96
|
|
|
@@ -3282,7 +3288,7 @@ class Up2k(object):
|
|
|
3282
3288
|
job["size"],
|
|
3283
3289
|
job["addr"],
|
|
3284
3290
|
job["at"],
|
|
3285
|
-
|
|
3291
|
+
None,
|
|
3286
3292
|
)
|
|
3287
3293
|
t = hr.get("rejectmsg") or ""
|
|
3288
3294
|
if t or not hr:
|
|
@@ -3514,11 +3520,26 @@ class Up2k(object):
|
|
|
3514
3520
|
|
|
3515
3521
|
linked = False
|
|
3516
3522
|
try:
|
|
3517
|
-
if
|
|
3518
|
-
|
|
3523
|
+
if rm and bos.path.exists(dst):
|
|
3524
|
+
wunlink(self.log, dst, flags)
|
|
3525
|
+
|
|
3519
3526
|
if not is_mv and not flags.get("dedup"):
|
|
3520
3527
|
raise Exception("dedup is disabled in config")
|
|
3521
3528
|
|
|
3529
|
+
if "reflink" in flags:
|
|
3530
|
+
if not USE_FICLONE:
|
|
3531
|
+
raise Exception("reflink") # python 3.14 or newer; no need
|
|
3532
|
+
try:
|
|
3533
|
+
with open(fsenc(src), "rb") as fi, open(fsenc(dst), "wb") as fo:
|
|
3534
|
+
fcntl.ioctl(fo.fileno(), fcntl.FICLONE, fi.fileno())
|
|
3535
|
+
except:
|
|
3536
|
+
if bos.path.exists(dst):
|
|
3537
|
+
wunlink(self.log, dst, flags)
|
|
3538
|
+
raise
|
|
3539
|
+
if lmod:
|
|
3540
|
+
bos.utime_c(self.log, dst, int(lmod), False)
|
|
3541
|
+
return
|
|
3542
|
+
|
|
3522
3543
|
lsrc = src
|
|
3523
3544
|
ldst = dst
|
|
3524
3545
|
fs1 = bos.stat(os.path.dirname(src)).st_dev
|
|
@@ -3545,9 +3566,6 @@ class Up2k(object):
|
|
|
3545
3566
|
lsrc = lsrc.replace("/", "\\")
|
|
3546
3567
|
ldst = ldst.replace("/", "\\")
|
|
3547
3568
|
|
|
3548
|
-
if rm and bos.path.exists(dst):
|
|
3549
|
-
wunlink(self.log, dst, flags)
|
|
3550
|
-
|
|
3551
3569
|
try:
|
|
3552
3570
|
if "hardlink" in flags:
|
|
3553
3571
|
os.link(fsenc(absreal(src)), fsenc(dst))
|
|
@@ -3962,7 +3980,7 @@ class Up2k(object):
|
|
|
3962
3980
|
sz,
|
|
3963
3981
|
ip,
|
|
3964
3982
|
at or time.time(),
|
|
3965
|
-
|
|
3983
|
+
None,
|
|
3966
3984
|
)
|
|
3967
3985
|
t = hr.get("rejectmsg") or ""
|
|
3968
3986
|
if t or not hr:
|
|
@@ -4197,7 +4215,7 @@ class Up2k(object):
|
|
|
4197
4215
|
st.st_size,
|
|
4198
4216
|
ip,
|
|
4199
4217
|
time.time(),
|
|
4200
|
-
|
|
4218
|
+
None,
|
|
4201
4219
|
):
|
|
4202
4220
|
t = "delete blocked by xbd server config: %r"
|
|
4203
4221
|
self.log(t % (abspath,), 1)
|
|
@@ -4237,7 +4255,7 @@ class Up2k(object):
|
|
|
4237
4255
|
st.st_size,
|
|
4238
4256
|
ip,
|
|
4239
4257
|
time.time(),
|
|
4240
|
-
|
|
4258
|
+
None,
|
|
4241
4259
|
)
|
|
4242
4260
|
|
|
4243
4261
|
if is_dir:
|
|
@@ -4365,7 +4383,7 @@ class Up2k(object):
|
|
|
4365
4383
|
fsize,
|
|
4366
4384
|
ip,
|
|
4367
4385
|
time.time(),
|
|
4368
|
-
|
|
4386
|
+
None,
|
|
4369
4387
|
):
|
|
4370
4388
|
t = "copy blocked by xbr server config: %r" % (svp,)
|
|
4371
4389
|
self.log(t, 1)
|
|
@@ -4465,7 +4483,7 @@ class Up2k(object):
|
|
|
4465
4483
|
fsize,
|
|
4466
4484
|
ip,
|
|
4467
4485
|
time.time(),
|
|
4468
|
-
|
|
4486
|
+
None,
|
|
4469
4487
|
)
|
|
4470
4488
|
|
|
4471
4489
|
return "k"
|
|
@@ -4616,7 +4634,7 @@ class Up2k(object):
|
|
|
4616
4634
|
fsize,
|
|
4617
4635
|
ip,
|
|
4618
4636
|
time.time(),
|
|
4619
|
-
|
|
4637
|
+
None,
|
|
4620
4638
|
):
|
|
4621
4639
|
t = "move blocked by xbr server config: %r" % (svp,)
|
|
4622
4640
|
self.log(t, 1)
|
|
@@ -4656,7 +4674,7 @@ class Up2k(object):
|
|
|
4656
4674
|
fsize,
|
|
4657
4675
|
ip,
|
|
4658
4676
|
time.time(),
|
|
4659
|
-
|
|
4677
|
+
None,
|
|
4660
4678
|
)
|
|
4661
4679
|
|
|
4662
4680
|
return "k"
|
|
@@ -4667,6 +4685,12 @@ class Up2k(object):
|
|
|
4667
4685
|
has_dupes = False
|
|
4668
4686
|
if w:
|
|
4669
4687
|
if c2 and c2 != c1:
|
|
4688
|
+
if "nodupem" in dvn.flags:
|
|
4689
|
+
q = "select w from up where substr(w,1,16) = ?"
|
|
4690
|
+
for (w2,) in c2.execute(q, (w[:16],)):
|
|
4691
|
+
if w == w2:
|
|
4692
|
+
t = "file exists in target volume, and dupes are forbidden in config"
|
|
4693
|
+
raise Pebkac(400, t)
|
|
4670
4694
|
self._copy_tags(c1, c2, w)
|
|
4671
4695
|
|
|
4672
4696
|
xlink = bool(svn.flags.get("xlink"))
|
|
@@ -4775,7 +4799,7 @@ class Up2k(object):
|
|
|
4775
4799
|
fsize,
|
|
4776
4800
|
ip,
|
|
4777
4801
|
time.time(),
|
|
4778
|
-
|
|
4802
|
+
None,
|
|
4779
4803
|
)
|
|
4780
4804
|
|
|
4781
4805
|
return "k"
|
|
@@ -5112,7 +5136,7 @@ class Up2k(object):
|
|
|
5112
5136
|
job["size"],
|
|
5113
5137
|
job["addr"],
|
|
5114
5138
|
job["t0"],
|
|
5115
|
-
|
|
5139
|
+
None,
|
|
5116
5140
|
)
|
|
5117
5141
|
t = hr.get("rejectmsg") or ""
|
|
5118
5142
|
if t or not hr:
|
copyparty/util.py
CHANGED
|
@@ -129,8 +129,10 @@ try:
|
|
|
129
129
|
import fcntl
|
|
130
130
|
|
|
131
131
|
HAVE_FCNTL = True
|
|
132
|
+
HAVE_FICLONE = hasattr(fcntl, "FICLONE")
|
|
132
133
|
except:
|
|
133
134
|
HAVE_FCNTL = False
|
|
135
|
+
HAVE_FICLONE = False
|
|
134
136
|
|
|
135
137
|
try:
|
|
136
138
|
import ctypes
|
|
@@ -335,6 +337,8 @@ IMPLICATIONS = [
|
|
|
335
337
|
["hardlink_only", "hardlink"],
|
|
336
338
|
["hardlink", "dedup"],
|
|
337
339
|
["tftpvv", "tftpv"],
|
|
340
|
+
["nodupem", "nodupe"],
|
|
341
|
+
["no_dupe_m", "no_dupe"],
|
|
338
342
|
["smbw", "smb"],
|
|
339
343
|
["smb1", "smb"],
|
|
340
344
|
["smbvvv", "smbvv"],
|
|
@@ -1416,20 +1420,24 @@ def trace(*args , **kwargs ) :
|
|
|
1416
1420
|
nuprint(msg)
|
|
1417
1421
|
|
|
1418
1422
|
|
|
1419
|
-
def alltrace() :
|
|
1423
|
+
def alltrace(verbose = True) :
|
|
1420
1424
|
threads = {}
|
|
1421
1425
|
names = dict([(t.ident, t.name) for t in threading.enumerate()])
|
|
1422
1426
|
for tid, stack in sys._current_frames().items():
|
|
1423
|
-
|
|
1427
|
+
if verbose:
|
|
1428
|
+
name = "%s (%x)" % (names.get(tid), tid)
|
|
1429
|
+
else:
|
|
1430
|
+
name = str(names.get(tid))
|
|
1424
1431
|
threads[name] = stack
|
|
1425
1432
|
|
|
1426
1433
|
rret = []
|
|
1427
1434
|
bret = []
|
|
1435
|
+
np = -3 if verbose else -2
|
|
1428
1436
|
for name, stack in sorted(threads.items()):
|
|
1429
1437
|
ret = ["\n\n# %s" % (name,)]
|
|
1430
1438
|
pad = None
|
|
1431
1439
|
for fn, lno, name, line in traceback.extract_stack(stack):
|
|
1432
|
-
fn = os.sep.join(fn.split(os.sep)[
|
|
1440
|
+
fn = os.sep.join(fn.split(os.sep)[np:])
|
|
1433
1441
|
ret.append('File: "%s", line %d, in %s' % (fn, lno, name))
|
|
1434
1442
|
if line:
|
|
1435
1443
|
ret.append(" " + str(line.strip()))
|
|
@@ -3814,15 +3822,17 @@ def _runhook(
|
|
|
3814
3822
|
"user": uname,
|
|
3815
3823
|
"perms": perms,
|
|
3816
3824
|
"src": src,
|
|
3817
|
-
"txt": txt,
|
|
3818
3825
|
}
|
|
3826
|
+
if txt:
|
|
3827
|
+
ja["txt"] = txt[0]
|
|
3828
|
+
ja["body"] = txt[1]
|
|
3819
3829
|
if imp:
|
|
3820
3830
|
ja["log"] = log
|
|
3821
3831
|
mod = loadpy(acmd[0], False)
|
|
3822
3832
|
return mod.main(ja)
|
|
3823
3833
|
arg = json.dumps(ja)
|
|
3824
3834
|
else:
|
|
3825
|
-
arg = txt
|
|
3835
|
+
arg = txt[0] if txt else ap
|
|
3826
3836
|
|
|
3827
3837
|
if acmd[0].startswith("zmq:"):
|
|
3828
3838
|
zi, zs = _zmq_hook(log, verbose, src, acmd[0][4:].lower(), arg, wait, sp_ka)
|
copyparty/web/baguettebox.js.gz
CHANGED
|
Binary file
|
copyparty/web/browser.css.gz
CHANGED
|
Binary file
|
copyparty/web/browser.html
CHANGED
|
@@ -145,6 +145,9 @@
|
|
|
145
145
|
document.documentElement.className = (STG && STG.cpp_thm) || dtheme;
|
|
146
146
|
</script>
|
|
147
147
|
<script src="{{ r }}/.cpr/util.js?_={{ ts }}"></script>
|
|
148
|
+
{%- if lang != "eng" %}
|
|
149
|
+
<script src="{{ r }}/.cpr/tl/{{ lang }}.js?_={{ ts }}"></script>
|
|
150
|
+
{%- endif %}
|
|
148
151
|
<script src="{{ r }}/.cpr/baguettebox.js?_={{ ts }}"></script>
|
|
149
152
|
<script src="{{ r }}/.cpr/browser.js?_={{ ts }}"></script>
|
|
150
153
|
<script src="{{ r }}/.cpr/up2k.js?_={{ ts }}"></script>
|
copyparty/web/browser.js.gz
CHANGED
|
Binary file
|
copyparty/web/splash.html
CHANGED
|
@@ -211,6 +211,9 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ this.args.theme
|
|
|
211
211
|
|
|
212
212
|
</script>
|
|
213
213
|
<script src="{{ r }}/.cpr/util.js?_={{ ts }}"></script>
|
|
214
|
+
{%- if lang != "eng" %}
|
|
215
|
+
<script src="{{ r }}/.cpr/tl/{{ lang }}.js?_={{ ts }}"></script>
|
|
216
|
+
{%- endif %}
|
|
214
217
|
<script src="{{ r }}/.cpr/splash.js?_={{ ts }}"></script>
|
|
215
218
|
{%- if js %}
|
|
216
219
|
<script src="{{ js }}_={{ ts }}"></script>
|
copyparty/web/splash.js.gz
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
copyparty/web/util.js.gz
CHANGED
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: copyparty
|
|
3
|
-
Version: 1.19.
|
|
3
|
+
Version: 1.19.17
|
|
4
4
|
Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
|
|
5
5
|
Author-email: ed <copyparty@ocv.me>
|
|
6
6
|
License: MIT
|
|
@@ -588,6 +588,9 @@ examples:
|
|
|
588
588
|
|
|
589
589
|
if you want to grant access to all users who are logged in, the group `acct` will always contain all known users, so for example `-v /mnt/music:music:r,@acct`
|
|
590
590
|
|
|
591
|
+
* to do the opposite, granting access to everyone who is NOT logged in. `*,-@acct` does the trick, for example `-v /srv/welcome:welcome:r,*,-@acct`
|
|
592
|
+
* single users can also be subtracted from a group: `@admins,-james`
|
|
593
|
+
|
|
591
594
|
anyone trying to bruteforce a password gets banned according to `--ban-pw`; default is 24h ban for 9 failed attempts in 1 hour
|
|
592
595
|
|
|
593
596
|
and if you want to use config files instead of commandline args (good!) then here's the same examples as a configfile; save it as `foobar.conf` and use it like this: `python copyparty-sfx.py -c foobar.conf`
|
|
@@ -1558,7 +1561,12 @@ tweaking the ui
|
|
|
1558
1561
|
* to sort in music order (album, track, artist, title) with filename as fallback, you could `--sort tags/Circle,tags/.tn,tags/Artist,tags/Title,href`
|
|
1559
1562
|
* to sort by upload date, first enable showing the upload date in the listing with `-e2d -mte +.up_at` and then `--sort tags/.up_at`
|
|
1560
1563
|
|
|
1561
|
-
see [./docs/rice](./docs/rice) for more, including
|
|
1564
|
+
see [./docs/rice](./docs/rice) for more, including:
|
|
1565
|
+
* how to [hide ui-elements](./docs/rice/README.md#hide-ui-elements)
|
|
1566
|
+
* [custom fonts](./docs/rice/README.md#custom-fonts)
|
|
1567
|
+
* [custom loading-spinner](./docs/rice/README.md#boring-loader-spinner)
|
|
1568
|
+
* adding stuff (css/`<meta>`/...) [to the html `<head>` tag](./docs/rice/README.md#head)
|
|
1569
|
+
* [adding your own translation](./docs/rice/README.md#translations)
|
|
1562
1570
|
|
|
1563
1571
|
|
|
1564
1572
|
## opengraph
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
copyparty/__init__.py,sha256=
|
|
2
|
-
copyparty/__main__.py,sha256=
|
|
3
|
-
copyparty/__version__.py,sha256=
|
|
4
|
-
copyparty/authsrv.py,sha256=
|
|
1
|
+
copyparty/__init__.py,sha256=7fjx-1nxaxr6UHo6A7MocA3-UPZTPP6jfgrNNfP38bk,2926
|
|
2
|
+
copyparty/__main__.py,sha256=uzOymQUZzDEFQa9SNZWLtbu7zbCd_6NEID0lmgrLtng,150194
|
|
3
|
+
copyparty/__version__.py,sha256=pQd30Cga5MCctT15TAcN5imWPCkMU0k4XYeP-zt5IGw,253
|
|
4
|
+
copyparty/authsrv.py,sha256=JDUjrEra0e9yUDT_xqWju4wWhuVZjEz3iBlr9sotkR8,135540
|
|
5
5
|
copyparty/broker_mp.py,sha256=QdOXXvV2Xn6J0CysEqyY3GZbqxQMyWnTpnba-a5lMc0,4987
|
|
6
6
|
copyparty/broker_mpw.py,sha256=LXQlmxzOvdpqP1aZoiIvWHAYUV_PoewLORLD1BGRs0g,3449
|
|
7
7
|
copyparty/broker_thr.py,sha256=fjoYtpSscUA7-nMl4r1n2R7UK3J9lrvLS3rUZ-iJzKQ,1721
|
|
8
8
|
copyparty/broker_util.py,sha256=oZ3dGdJXLYvmdV4KSFdUv_PGErkgU-7kgr1SIglkjCU,1663
|
|
9
9
|
copyparty/cert.py,sha256=OGTUBxhqPbseG0Bd4cHD6e5T5T8JdGqp3q0KAYqX0Cc,8031
|
|
10
|
-
copyparty/cfg.py,sha256=
|
|
10
|
+
copyparty/cfg.py,sha256=MPSVOamweuBhz65UdZQ7PVIzMle8BOyWQVBZBtesoZ4,17782
|
|
11
11
|
copyparty/dxml.py,sha256=VZADJS9z18LalENSvVfjk29ddnpaDQ-v8AVm_THwS1c,2607
|
|
12
12
|
copyparty/fsutil.py,sha256=kGvNM9G9YLeqcQjhDGfmT8gV7fn2WU0xye9BulL4h04,6469
|
|
13
|
-
copyparty/ftpd.py,sha256=
|
|
14
|
-
copyparty/httpcli.py,sha256=
|
|
13
|
+
copyparty/ftpd.py,sha256=uw8HOpkBfDPX-MpUvWgzuZhT3VLx3PNdoCAXgGdgGSA,18627
|
|
14
|
+
copyparty/httpcli.py,sha256=XtNzx_aUP2VkXRurOB7GW2RpP2t6G4G53as6zN6pZa4,250071
|
|
15
15
|
copyparty/httpconn.py,sha256=IA9fdCjigawZ4kWhgvVN3nSiy5pb3W2qaE6rFqUYdq0,6943
|
|
16
16
|
copyparty/httpsrv.py,sha256=6Al4seTbEqARBYkPwx_8YLS6qz6-oJQHwFdO1rqEgd4,19094
|
|
17
17
|
copyparty/ico.py,sha256=-7QjF_jIxnPo4Vr0oUPksQ_U_Ef0HRsSPm3s71idOz8,3879
|
|
18
18
|
copyparty/mdns.py,sha256=OfAms3kqolF5KFkorwwKH7ysd6_DRQzi3Ri62vTdCHA,19293
|
|
19
19
|
copyparty/metrics.py,sha256=1dim0ShnsD5cfspRbeN9Mt14wOIxPRtxCZY2IScikKw,8974
|
|
20
|
-
copyparty/mtag.py,sha256=
|
|
20
|
+
copyparty/mtag.py,sha256=xfo6dm769Qq9kCGcYt9vyyS6774v0NPjNSXoUq3A3tw,23184
|
|
21
21
|
copyparty/multicast.py,sha256=aqiY_ufCxcJ_VHn89jmdJFz61UukjEbQmHLGS6L-6JY,12423
|
|
22
22
|
copyparty/pwhash.py,sha256=58txP8GXIHOtWd__Tni8qkilHEGpOFsKIPuzjdFLc6M,4426
|
|
23
23
|
copyparty/qrkode.py,sha256=dkjcHDfEdxozFVwVAY8bFFf5P0cqieYmaMdnFixeiuM,2681
|
|
24
|
-
copyparty/smbd.py,sha256=
|
|
24
|
+
copyparty/smbd.py,sha256=e-IBDEVzFgSHspQjpUm2d5K58koBT109ZOPJup1yBJ0,14892
|
|
25
25
|
copyparty/ssdp.py,sha256=R1Z61GZOxBMF2Sk4RTxKWMOemogmcjEWG-CvLihd45k,7023
|
|
26
26
|
copyparty/star.py,sha256=tV5BbX6AiQ7N4UU8DYtSTckNYeoeey4DBqq4LjfymbY,3818
|
|
27
27
|
copyparty/sutil.py,sha256=E65jAaOzHlJYnqsOKDMPVT8kALPUVexpkSStWBdItkY,3231
|
|
28
|
-
copyparty/svchub.py,sha256=
|
|
28
|
+
copyparty/svchub.py,sha256=Qvcicxab_Xwy3pA22PIGTM2aIqVbmhRM7YwQDJ8aLpI,54964
|
|
29
29
|
copyparty/szip.py,sha256=9srQzjsTBrBadf6QMh4YRAL70rkZLevAOHqXWK5jvr8,8846
|
|
30
30
|
copyparty/tcpsrv.py,sha256=xQEJsDES9cYJnXaxy1GqN_M_8rYeAKM94Fkbg9sZWRI,22305
|
|
31
|
-
copyparty/tftpd.py,sha256=
|
|
31
|
+
copyparty/tftpd.py,sha256=TA5-8b_JAmSWuN9YiHiRVBw_4Wusnr2ENidr06Uyej8,14500
|
|
32
32
|
copyparty/th_cli.py,sha256=n3MMbnN7HTVSBHkTI2qLIjgwVvHkGsfTW7-aPJ-2o4s,5545
|
|
33
33
|
copyparty/th_srv.py,sha256=r4I8PaMfg_eOf7Zo3GZpT22U-DsYnQO_R0fiZjB9R38,38573
|
|
34
34
|
copyparty/u2idx.py,sha256=9Fcm8cDgLU4DdrH_2Q-lHAbMz4VfzLnANS0s4QgWZzE,14890
|
|
35
|
-
copyparty/up2k.py,sha256
|
|
36
|
-
copyparty/util.py,sha256=
|
|
35
|
+
copyparty/up2k.py,sha256=-Cqg7g6iAshI0k-89-1yVOmFhbFNYHnOb83L6z9mFvc,185204
|
|
36
|
+
copyparty/util.py,sha256=b_f1Ff2K4hfjOB6uHyJ3gyr8xX6S2wCA_Vxy4mTaaVE,110639
|
|
37
37
|
copyparty/bos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
-
copyparty/bos/bos.py,sha256=
|
|
38
|
+
copyparty/bos/bos.py,sha256=5Cp0Ob5XnCt8Zmr56QLQmsc9rkdz8Y1UBeB0026TqoE,3388
|
|
39
39
|
copyparty/bos/path.py,sha256=yEjCq2ki9CvxA5sCT8pS0keEXwugs0ZeUyUhdBziOCI,777
|
|
40
40
|
copyparty/res/COPYING.txt,sha256=Zfcbw5KN_KJ7PQeLgoXwyWcAXXb0gc41iQiHcnGSNxg,19902
|
|
41
41
|
copyparty/res/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -55,10 +55,10 @@ copyparty/stolen/ifaddr/__init__.py,sha256=vpREjAyPubr5s1NJi91icXV3q1o4DrKAvHABw
|
|
|
55
55
|
copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUuTOrU,2626
|
|
56
56
|
copyparty/stolen/ifaddr/_shared.py,sha256=uNC4SdEIgdSLKvuUzsf1aM-H1Xrc_9mpLoOT43YukGs,6206
|
|
57
57
|
copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
|
|
58
|
-
copyparty/web/baguettebox.js.gz,sha256=
|
|
59
|
-
copyparty/web/browser.css.gz,sha256=
|
|
60
|
-
copyparty/web/browser.html,sha256=
|
|
61
|
-
copyparty/web/browser.js.gz,sha256=
|
|
58
|
+
copyparty/web/baguettebox.js.gz,sha256=B0gNOVblZWC3dcOektvuqT2jfVK99WY6ThRo9t1iu_A,9499
|
|
59
|
+
copyparty/web/browser.css.gz,sha256=DPIruSmxA-yw7yv6vBiQZoIKOCcDLOrxORm3ae5GNWQ,15878
|
|
60
|
+
copyparty/web/browser.html,sha256=IxHHqvGMlrG8B4hYkoIaH2cX6qCOCCZ6TQbAx9oB8KY,4865
|
|
61
|
+
copyparty/web/browser.js.gz,sha256=vfurFx7CklzzYDs_GDJ_AXkTJHN-O46jO7gx4qr7WfI,72501
|
|
62
62
|
copyparty/web/browser2.html,sha256=NRUZ08GH-e2YcGXcoz0UjYg6JIVF42u4IMX4HHwWTmg,1587
|
|
63
63
|
copyparty/web/cf.html,sha256=lJThtNFNAQT1ClCHHlivAkDGE0LutedwopXD62Z8Nys,589
|
|
64
64
|
copyparty/web/dbg-audio.js.gz,sha256=fNf4wGVGdz5fDtn-97ks3XPIglTKnTKiYo4Dk2m-NoA,688
|
|
@@ -81,13 +81,13 @@ copyparty/web/shares.css.gz,sha256=ChgHt-2dPgvPCpwClNeijX39OWJIbwj7NBIZXLLvaT0,5
|
|
|
81
81
|
copyparty/web/shares.html,sha256=SWgcgiAXEtV6xFqYDUlgg6WmrjedmgP3hCaVksNk1y4,2582
|
|
82
82
|
copyparty/web/shares.js.gz,sha256=LGgFdYhtTwBp96x6CtWZpMWrGaZW7vn5LYvIhPQqm8g,942
|
|
83
83
|
copyparty/web/splash.css.gz,sha256=Ez7MRPtPzYEiSsLsI7S9o8_jGFQxUFvK2j92ow5AoDg,1155
|
|
84
|
-
copyparty/web/splash.html,sha256=
|
|
85
|
-
copyparty/web/splash.js.gz,sha256=
|
|
84
|
+
copyparty/web/splash.html,sha256=NOYmsKmPpzJN0UbavTEq5Pfb9993URrOC9rBl6EJOBY,7578
|
|
85
|
+
copyparty/web/splash.js.gz,sha256=QPvYszEB_HAR98nb1pnEYnuuz23zHjH3wUTJGaa_Myo,1182
|
|
86
86
|
copyparty/web/svcs.html,sha256=eBT6zq130hLHcD7OzYZD4ozFEd_bmU1-hTqDTt09Xs8,17576
|
|
87
87
|
copyparty/web/svcs.js.gz,sha256=DapO-UcJYln4VPyZ6Pwi0Lzhlyx0Hul7y7E2ephu34c,971
|
|
88
88
|
copyparty/web/ui.css.gz,sha256=Txx36dDbFI7_9I2LPUO40nCFnxLFKVpdkBsHFwI7JoE,2848
|
|
89
89
|
copyparty/web/up2k.js.gz,sha256=3-_qOof3UR00_jVDxTGpQFv-DH3gfPS8k1QByHZtd14,25035
|
|
90
|
-
copyparty/web/util.js.gz,sha256=
|
|
90
|
+
copyparty/web/util.js.gz,sha256=YGNczP3-yjio2iU2lUBsMKSiikiji-vgZIljSANu_z0,16387
|
|
91
91
|
copyparty/web/w.hash.js.gz,sha256=rI-78PyXCdVjOpULbD9raBRyxxaPls5OjR7wonzXZPE,1193
|
|
92
92
|
copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
93
93
|
copyparty/web/a/partyfuse.py,sha256=QxBoe0iu4LTedmxWdIsuBUlwdxQ7zQh9LAFtjAFcPpo,28206
|
|
@@ -107,9 +107,28 @@ copyparty/web/deps/prismd.css.gz,sha256=VPKuZhPmVyhTKHo2xN6IBX-C2A8Eo313vIPxQ2Hx
|
|
|
107
107
|
copyparty/web/deps/scp.woff2,sha256=mmjmsoLDBPKa5VHcEdxZiJcDR1S1TOvCjIg5Cf1iL0s,8684
|
|
108
108
|
copyparty/web/deps/sha512.ac.js.gz,sha256=OLk7EjA5e-DtJGlV0IQbvokpmoyE5v7djezx9kZBabE,7046
|
|
109
109
|
copyparty/web/deps/sha512.hw.js.gz,sha256=UAed2_ocklZCnIzcSYz2h4P1ycztlCLj-ewsRTud2lU,7939
|
|
110
|
-
copyparty
|
|
111
|
-
copyparty
|
|
112
|
-
copyparty
|
|
113
|
-
copyparty
|
|
114
|
-
copyparty
|
|
115
|
-
copyparty
|
|
110
|
+
copyparty/web/tl/chi.js.gz,sha256=TMOdOsT5e6g5JkJSNfxMBj8j9Lcgp5CPAPSU_TBrWI4,14686
|
|
111
|
+
copyparty/web/tl/cze.js.gz,sha256=tWbPL2LyQj95z1THu0oIhKZT0xDW3nC3QqqyBUsSmEo,15424
|
|
112
|
+
copyparty/web/tl/deu.js.gz,sha256=Xw-PejKnh8VNEMkS9yh7FUgZYn_pj7G9iqgWlhpLbPM,15567
|
|
113
|
+
copyparty/web/tl/epo.js.gz,sha256=d9b2MLwN6jstK522tZWRcf6j5c4Q6Vm3VrV-C5Z_lu0,14213
|
|
114
|
+
copyparty/web/tl/fin.js.gz,sha256=7SUK-xUwBe8aq49gPxdEX2GbjNCVzN4v_rJC7zZHgac,15168
|
|
115
|
+
copyparty/web/tl/fra.js.gz,sha256=9Jhn3878w-7BiMI9fRqZDJcWjs-8DJuLCza4LTC9bOU,15825
|
|
116
|
+
copyparty/web/tl/grc.js.gz,sha256=Q6vsE2hX8O7hv05AIjRXI46ozgHvsuifcz9S3Pse-e0,17752
|
|
117
|
+
copyparty/web/tl/ita.js.gz,sha256=IYjg4KqMayWSVr_jUaprRHf93Vvmpi64ZgGTaoXbisY,14661
|
|
118
|
+
copyparty/web/tl/kor.js.gz,sha256=XWlZvsX1nDVA_s-9vZXJh5gZpiScu4vcRkudmM0vXvg,15326
|
|
119
|
+
copyparty/web/tl/nld.js.gz,sha256=6d9tDZDK44IpUiEQqU7XLrzv4fKqakOBQzuoh-eyHdI,15430
|
|
120
|
+
copyparty/web/tl/nno.js.gz,sha256=i-bzHEOBfqyRV9fT5UmSZKZfNX_7XkU66E7mkBd-M00,14817
|
|
121
|
+
copyparty/web/tl/nor.js.gz,sha256=RADjEOWqkzm7JSZbGMZhoXhbw21ks8Df1DDPBe_f2Io,14598
|
|
122
|
+
copyparty/web/tl/pol.js.gz,sha256=IIhRwrdmJ29HWCQXO0aLQKT7K4Tql4KJnRw5rOG7Nx4,15694
|
|
123
|
+
copyparty/web/tl/por.js.gz,sha256=rwBCgtgdL24r-oNCPyODhA0ldv0dJnLTg273YHEDI5E,14886
|
|
124
|
+
copyparty/web/tl/rus.js.gz,sha256=SoH7G1VcAUnbv-yhYJB1x-ZSRiHCwwZ-xQ7ImykryaM,16909
|
|
125
|
+
copyparty/web/tl/spa.js.gz,sha256=pEqdC_qfbF1JNJQg5UX7bj6XXVZoLWzWCLkeT_oVNFk,14956
|
|
126
|
+
copyparty/web/tl/swe.js.gz,sha256=JAz_p2ceHLxsu-lBfc3zcukszbnCDkcvE4IU4nzW2Kk,14393
|
|
127
|
+
copyparty/web/tl/tur.js.gz,sha256=yOgKEuZ8zpGJo7E-wPXIKjwVcQMAoDLDiJow_B3yomo,14977
|
|
128
|
+
copyparty/web/tl/ukr.js.gz,sha256=3ZUR27PBTI_QyhEcoX0yo6_KawvehTRzqbJ0q1pc_bo,17243
|
|
129
|
+
copyparty-1.19.17.dist-info/licenses/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
|
|
130
|
+
copyparty-1.19.17.dist-info/METADATA,sha256=-xwwzxdEnbrnryX-iV-Cx1mm0FVXGRqeTusKHmKa_kU,182009
|
|
131
|
+
copyparty-1.19.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
132
|
+
copyparty-1.19.17.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
|
|
133
|
+
copyparty-1.19.17.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
|
|
134
|
+
copyparty-1.19.17.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|