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
         
     |