copyparty 1.19.15__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 +47 -11
 - copyparty/__version__.py +2 -2
 - copyparty/authsrv.py +45 -9
 - copyparty/bos/bos.py +5 -1
 - copyparty/cfg.py +20 -0
 - copyparty/ftpd.py +5 -3
 - copyparty/httpcli.py +114 -27
 - copyparty/mdns.py +53 -18
 - copyparty/mtag.py +18 -4
 - copyparty/qrkode.py +107 -0
 - copyparty/res/COPYING.txt +76 -5
 - copyparty/smbd.py +1 -1
 - copyparty/stolen/qrcodegen.py +1 -64
 - copyparty/svchub.py +13 -2
 - copyparty/tcpsrv.py +6 -7
 - copyparty/tftpd.py +1 -1
 - copyparty/th_srv.py +11 -5
 - copyparty/up2k.py +40 -16
 - copyparty/util.py +63 -16
 - copyparty/web/baguettebox.js.gz +0 -0
 - copyparty/web/browser.css.gz +0 -0
 - copyparty/web/browser.html +3 -1
 - 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.15.dist-info → copyparty-1.19.17.dist-info}/METADATA +47 -2
 - {copyparty-1.19.15.dist-info → copyparty-1.19.17.dist-info}/RECORD +52 -32
 - {copyparty-1.19.15.dist-info → copyparty-1.19.17.dist-info}/WHEEL +0 -0
 - {copyparty-1.19.15.dist-info → copyparty-1.19.17.dist-info}/entry_points.txt +0 -0
 - {copyparty-1.19.15.dist-info → copyparty-1.19.17.dist-info}/licenses/LICENSE +0 -0
 - {copyparty-1.19.15.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:
         
     | 
| 
         @@ -805,9 +808,11 @@ def get_sects(): 
     | 
|
| 
       805 
808 
     | 
    
         
             
                         \033[36mf\033[35m forks the process, doesn't wait for completion
         
     | 
| 
       806 
809 
     | 
    
         
             
                         \033[36mc\033[35m checks return code, blocks the action if non-zero
         
     | 
| 
       807 
810 
     | 
    
         
             
                         \033[36mj\033[35m provides json with info as 1st arg instead of filepath
         
     | 
| 
      
 811 
     | 
    
         
            +
                         \033[36ms\033[35m provides input data on stdin (instead of 1st arg)
         
     | 
| 
       808 
812 
     | 
    
         
             
                         \033[36mwN\033[35m waits N sec after command has been started before continuing
         
     | 
| 
       809 
813 
     | 
    
         
             
                         \033[36mtN\033[35m sets an N sec timeout before the command is abandoned
         
     | 
| 
       810 
814 
     | 
    
         
             
                         \033[36miN\033[35m xiu only: volume must be idle for N sec (default = 5)
         
     | 
| 
      
 815 
     | 
    
         
            +
                         \033[36mI\033[35m import and run as module, not as subprocess
         
     | 
| 
       811 
816 
     | 
    
         | 
| 
       812 
817 
     | 
    
         
             
                         \033[36mar\033[35m only run hook if user has read-access
         
     | 
| 
       813 
818 
     | 
    
         
             
                         \033[36marw\033[35m only run hook if user has read-write-access
         
     | 
| 
         @@ -837,6 +842,9 @@ def get_sects(): 
     | 
|
| 
       837 
842 
     | 
    
         
             
                          the \033[33m--\033[35m stops notify-send from reading the message as args
         
     | 
| 
       838 
843 
     | 
    
         
             
                          and the alert will be "hey" followed by the messagetext
         
     | 
| 
       839 
844 
     | 
    
         | 
| 
      
 845 
     | 
    
         
            +
                         \033[36m--xm s,,tee,-a,log.txt\033[35m appends each msg to log.txt;
         
     | 
| 
      
 846 
     | 
    
         
            +
                         \033[36m--xm s,j,,tee,-a,log.txt\033[35m writes it as json instead
         
     | 
| 
      
 847 
     | 
    
         
            +
             
     | 
| 
       840 
848 
     | 
    
         
             
                         \033[36m--xau zmq:pub:tcp://*:5556\033[35m announces uploads on zeromq;
         
     | 
| 
       841 
849 
     | 
    
         
             
                         \033[36m--xau t3,zmq:push:tcp://*:5557\033[35m also works, and you can
         
     | 
| 
       842 
850 
     | 
    
         
             
                         \033[36m--xau t3,j,zmq:req:tcp://localhost:5555\033[35m too for example
         
     | 
| 
         @@ -846,7 +854,8 @@ def get_sects(): 
     | 
|
| 
       846 
854 
     | 
    
         
             
                        as soon as the volume has been idle for iN seconds (5 by default)
         
     | 
| 
       847 
855 
     | 
    
         | 
| 
       848 
856 
     | 
    
         
             
                        \033[36mxiu\033[0m is also unique in that it will pass the metadata to the
         
     | 
| 
       849 
     | 
    
         
            -
                        executed program on STDIN instead of as argv arguments 
     | 
| 
      
 857 
     | 
    
         
            +
                        executed program on STDIN instead of as argv arguments (so
         
     | 
| 
      
 858 
     | 
    
         
            +
                        just like the \033[36ms\033[0m option does for the other hook types), and
         
     | 
| 
       850 
859 
     | 
    
         
             
                        it also includes the wark (file-id/hash) as a json property
         
     | 
| 
       851 
860 
     | 
    
         | 
| 
       852 
861 
     | 
    
         
             
                        \033[36mxban\033[0m can be used to overrule / cancel a user ban event;
         
     | 
| 
         @@ -857,6 +866,12 @@ def get_sects(): 
     | 
|
| 
       857 
866 
     | 
    
         
             
                        on new uploads, but with certain limitations. See
         
     | 
| 
       858 
867 
     | 
    
         
             
                        bin/hooks/reloc* and docs/devnotes.md#hook-effects
         
     | 
| 
       859 
868 
     | 
    
         | 
| 
      
 869 
     | 
    
         
            +
                        the \033[36mI\033[0m option will override most other options, because
         
     | 
| 
      
 870 
     | 
    
         
            +
                        it entirely hands over control to the hook, which is
         
     | 
| 
      
 871 
     | 
    
         
            +
                        then able to tamper with copyparty's internal memory
         
     | 
| 
      
 872 
     | 
    
         
            +
                        and wreck havoc if it wants to -- but this is worh it
         
     | 
| 
      
 873 
     | 
    
         
            +
                        because it makes the hook 140x faster
         
     | 
| 
      
 874 
     | 
    
         
            +
             
     | 
| 
       860 
875 
     | 
    
         
             
                        except for \033[36mxm\033[0m, only one hook / one action can run at a time,
         
     | 
| 
       861 
876 
     | 
    
         
             
                        so it's recommended to use the \033[36mf\033[0m flag unless you really need
         
     | 
| 
       862 
877 
     | 
    
         
             
                        to wait for the hook to finish before continuing (without \033[36mf\033[0m
         
     | 
| 
         @@ -1147,11 +1162,14 @@ def add_general(ap, nc, srvname): 
     | 
|
| 
       1147 
1162 
     | 
    
         
             
                ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,xm", help="how to handle url-form POSTs; see \033[33m--help-urlform\033[0m")
         
     | 
| 
       1148 
1163 
     | 
    
         
             
                ap2.add_argument("--wintitle", metavar="TXT", type=u, default="cpp @ $pub", help="server terminal title, for example [\033[32m$ip-10.1.2.\033[0m] or [\033[32m$ip-]")
         
     | 
| 
       1149 
1164 
     | 
    
         
             
                ap2.add_argument("--name", metavar="TXT", type=u, default=srvname, help="server name (displayed topleft in browser and in mDNS)")
         
     | 
| 
      
 1165 
     | 
    
         
            +
                ap2.add_argument("--name-url", metavar="TXT", type=u, help="URL for server name hyperlink (displayed topleft in browser)")
         
     | 
| 
      
 1166 
     | 
    
         
            +
                ap2.add_argument("--name-html", type=u, help=argparse.SUPPRESS)
         
     | 
| 
       1150 
1167 
     | 
    
         
             
                ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="\033[34mREPEATABLE:\033[0m map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]")
         
     | 
| 
       1151 
1168 
     | 
    
         
             
                ap2.add_argument("--mimes", action="store_true", help="list default mimetype mapping and exit")
         
     | 
| 
       1152 
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)")
         
     | 
| 
       1153 
1170 
     | 
    
         
             
                ap2.add_argument("--license", action="store_true", help="show licenses and exit")
         
     | 
| 
       1154 
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")
         
     | 
| 
       1155 
1173 
     | 
    
         | 
| 
       1156 
1174 
     | 
    
         | 
| 
       1157 
1175 
     | 
    
         
             
            def add_qr(ap, tty):
         
     | 
| 
         @@ -1219,6 +1237,7 @@ def add_upload(ap): 
     | 
|
| 
       1219 
1237 
     | 
    
         
             
                ap2.add_argument("--hardlink-only", action="store_true", help="do not fallback to symlinks when a hardlink cannot be made (volflag=hardlinkonly)")
         
     | 
| 
       1220 
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)")
         
     | 
| 
       1221 
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)")
         
     | 
| 
       1222 
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)")
         
     | 
| 
       1223 
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")
         
     | 
| 
       1224 
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")
         
     | 
| 
         @@ -1506,6 +1525,7 @@ def add_optouts(ap): 
     | 
|
| 
       1506 
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)")
         
     | 
| 
       1507 
1526 
     | 
    
         
             
                ap2.add_argument("--no-tail", action="store_true", help="disable streaming a growing files with ?tail (volflag=notail)")
         
     | 
| 
       1508 
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")
         
     | 
| 
       1509 
1529 
     | 
    
         | 
| 
       1510 
1530 
     | 
    
         | 
| 
       1511 
1531 
     | 
    
         
             
            def add_safety(ap):
         
     | 
| 
         @@ -1524,6 +1544,7 @@ def add_safety(ap): 
     | 
|
| 
       1524 
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")
         
     | 
| 
       1525 
1545 
     | 
    
         
             
                ap2.add_argument("--no-robots", action="store_true", help="adds http and html headers asking search engines to not index anything (volflag=norobots)")
         
     | 
| 
       1526 
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")
         
     | 
| 
       1527 
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]")
         
     | 
| 
       1528 
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]")
         
     | 
| 
       1529 
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")
         
     | 
| 
         @@ -1531,7 +1552,7 @@ def add_safety(ap): 
     | 
|
| 
       1531 
1552 
     | 
    
         
             
                ap2.add_argument("--ban-422", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m 422's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes (invalid requests, attempted exploits ++)")
         
     | 
| 
       1532 
1553 
     | 
    
         
             
                ap2.add_argument("--ban-url", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m sus URL's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; applies only to permissions g/G/h (decent replacement for \033[33m--ban-404\033[0m if that can't be used)")
         
     | 
| 
       1533 
1554 
     | 
    
         
             
                ap2.add_argument("--sus-urls", metavar="R", type=u, default=r"\.php$|(^|/)wp-(admin|content|includes)/", help="URLs which are considered sus / eligible for banning; disable with blank or [\033[32mno\033[0m]")
         
     | 
| 
       1534 
     | 
    
         
            -
                ap2.add_argument("--nonsus-urls", metavar="R", type=u, default=r"^(favicon 
     | 
| 
      
 1555 
     | 
    
         
            +
                ap2.add_argument("--nonsus-urls", metavar="R", type=u, default=r"^(favicon\..{3}|robots\.txt)$|^apple-touch-icon|^\.well-known", help="harmless URLs ignored from 403/404-bans; disable with blank or [\033[32mno\033[0m]")
         
     | 
| 
       1535 
1556 
     | 
    
         
             
                ap2.add_argument("--early-ban", action="store_true", help="if a client is banned, reject its connection as soon as possible; not a good idea to enable when proxied behind cloudflare since it could ban your reverse-proxy")
         
     | 
| 
       1536 
1557 
     | 
    
         
             
                ap2.add_argument("--cookie-nmax", metavar="N", type=int, default=50, help="reject HTTP-request from client if they send more than N cookies")
         
     | 
| 
       1537 
1558 
     | 
    
         
             
                ap2.add_argument("--cookie-cmax", metavar="N", type=int, default=8192, help="reject HTTP-request from client if more than N characters in Cookie header")
         
     | 
| 
         @@ -1588,12 +1609,14 @@ def add_admin(ap): 
     | 
|
| 
       1588 
1609 
     | 
    
         
             
                ap2 = ap.add_argument_group("admin panel options")
         
     | 
| 
       1589 
1610 
     | 
    
         
             
                ap2.add_argument("--no-reload", action="store_true", help="disable ?reload=cfg (reload users/volumes/volflags from config file)")
         
     | 
| 
       1590 
1611 
     | 
    
         
             
                ap2.add_argument("--no-rescan", action="store_true", help="disable ?scan (volume reindexing)")
         
     | 
| 
       1591 
     | 
    
         
            -
                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")
         
     | 
| 
       1592 
1613 
     | 
    
         
             
                ap2.add_argument("--no-ups-page", action="store_true", help="disable ?ru (list of recent uploads)")
         
     | 
| 
       1593 
1614 
     | 
    
         
             
                ap2.add_argument("--no-up-list", action="store_true", help="don't show list of incoming files in controlpanel")
         
     | 
| 
       1594 
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")
         
     | 
| 
       1595 
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)")
         
     | 
| 
       1596 
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")
         
     | 
| 
       1597 
1620 
     | 
    
         | 
| 
       1598 
1621 
     | 
    
         | 
| 
       1599 
1622 
     | 
    
         
             
            def add_thumbnail(ap):
         
     | 
| 
         @@ -1791,6 +1814,15 @@ def add_ui(ap, retry ): 
     | 
|
| 
       1791 
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")
         
     | 
| 
       1792 
1815 
     | 
    
         
             
                ap2.add_argument("--no-sb-md", action="store_true", help="don't sandbox README/PREADME.md documents (volflags: no_sb_md | sb_md)")
         
     | 
| 
       1793 
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)")
         
     | 
| 
       1794 
1826 
     | 
    
         
             
                ap2.add_argument("--have-unlistc", action="store_true", help=argparse.SUPPRESS)
         
     | 
| 
       1795 
1827 
     | 
    
         | 
| 
       1796 
1828 
     | 
    
         | 
| 
         @@ -1918,15 +1950,19 @@ def run_argparse( 
     | 
|
| 
       1918 
1950 
     | 
    
         | 
| 
       1919 
1951 
     | 
    
         | 
| 
       1920 
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 
     | 
    
         
            +
             
     | 
| 
       1921 
1960 
     | 
    
         
             
                time.strptime("19970815", "%Y%m%d")  # python#7980
         
     | 
| 
       1922 
1961 
     | 
    
         
             
                if WINDOWS:
         
     | 
| 
       1923 
1962 
     | 
    
         
             
                    os.system("rem")  # enables colors
         
     | 
| 
       1924 
1963 
     | 
    
         | 
| 
       1925 
1964 
     | 
    
         
             
                init_E(E)
         
     | 
| 
       1926 
1965 
     | 
    
         | 
| 
       1927 
     | 
    
         
            -
                if argv is None:
         
     | 
| 
       1928 
     | 
    
         
            -
                    argv = sys.argv
         
     | 
| 
       1929 
     | 
    
         
            -
             
     | 
| 
       1930 
1966 
     | 
    
         
             
                f = '\033[36mcopyparty v{} "\033[35m{}\033[36m" ({})\n{}\033[0;36m\n   sqlite {} | jinja {} | pyftpd {} | tftp {}\n\033[0m'
         
     | 
| 
       1931 
1967 
     | 
    
         
             
                f = f.format(
         
     | 
| 
       1932 
1968 
     | 
    
         
             
                    S_VERSION,
         
     | 
| 
         @@ -2053,7 +2089,7 @@ def main(argv  = None)  : 
     | 
|
| 
       2053 
2089 
     | 
    
         | 
| 
       2054 
2090 
     | 
    
         
             
                # propagate implications
         
     | 
| 
       2055 
2091 
     | 
    
         
             
                for k1, k2 in IMPLICATIONS:
         
     | 
| 
       2056 
     | 
    
         
            -
                    if getattr(al, k1):
         
     | 
| 
      
 2092 
     | 
    
         
            +
                    if getattr(al, k1, None):
         
     | 
| 
       2057 
2093 
     | 
    
         
             
                        setattr(al, k2, True)
         
     | 
| 
       2058 
2094 
     | 
    
         | 
| 
       2059 
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}
         
     | 
| 
         @@ -2503,13 +2512,17 @@ class AuthSrv(object): 
     | 
|
| 
       2503 
2512 
     | 
    
         | 
| 
       2504 
2513 
     | 
    
         
             
                        ico_url = vol.flags.get("ufavico")
         
     | 
| 
       2505 
2514 
     | 
    
         
             
                        if ico_url:
         
     | 
| 
      
 2515 
     | 
    
         
            +
                            ico_h = ""
         
     | 
| 
       2506 
2516 
     | 
    
         
             
                            ico_ext = ico_url.split("?")[0].split(".")[-1].lower()
         
     | 
| 
       2507 
2517 
     | 
    
         
             
                            if ico_ext in FAVICON_MIMES:
         
     | 
| 
       2508 
2518 
     | 
    
         
             
                                zs = '<link rel="icon" type="%s" href="%s">\n'
         
     | 
| 
       2509 
     | 
    
         
            -
                                 
     | 
| 
      
 2519 
     | 
    
         
            +
                                ico_h = zs % (FAVICON_MIMES[ico_ext], ico_url)
         
     | 
| 
       2510 
2520 
     | 
    
         
             
                            elif ico_ext == "ico":
         
     | 
| 
       2511 
2521 
     | 
    
         
             
                                zs = '<link rel="shortcut icon" href="%s">\n'
         
     | 
| 
       2512 
     | 
    
         
            -
                                 
     | 
| 
      
 2522 
     | 
    
         
            +
                                ico_h = zs % (ico_url,)
         
     | 
| 
      
 2523 
     | 
    
         
            +
                            if ico_h:
         
     | 
| 
      
 2524 
     | 
    
         
            +
                                vol.flags["ufavico_h"] = ico_h
         
     | 
| 
      
 2525 
     | 
    
         
            +
                                head_s += ico_h
         
     | 
| 
       2513 
2526 
     | 
    
         | 
| 
       2514 
2527 
     | 
    
         
             
                        if head_s:
         
     | 
| 
       2515 
2528 
     | 
    
         
             
                            vol.flags["html_head_s"] = head_s
         
     | 
| 
         @@ -2573,6 +2586,15 @@ class AuthSrv(object): 
     | 
|
| 
       2573 
2586 
     | 
    
         
             
                                for x in drop:
         
     | 
| 
       2574 
2587 
     | 
    
         
             
                                    vol.flags.pop(x)
         
     | 
| 
       2575 
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 
     | 
    
         
            +
             
     | 
| 
       2576 
2598 
     | 
    
         
             
                        # verify tags mentioned by -mt[mp] are used by -mte
         
     | 
| 
       2577 
2599 
     | 
    
         
             
                        local_mtp = {}
         
     | 
| 
       2578 
2600 
     | 
    
         
             
                        local_only_mtp = {}
         
     | 
| 
         @@ -2739,9 +2761,13 @@ class AuthSrv(object): 
     | 
|
| 
       2739 
2761 
     | 
    
         
             
                            ["uadmin", "uadmin"],
         
     | 
| 
       2740 
2762 
     | 
    
         
             
                        ]:
         
     | 
| 
       2741 
2763 
     | 
    
         
             
                            u = list(sorted(getattr(zv.axs, attr)))
         
     | 
| 
       2742 
     | 
    
         
            -
                            u  
     | 
| 
       2743 
     | 
    
         
            -
             
     | 
| 
       2744 
     | 
    
         
            -
                             
     | 
| 
      
 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)
         
     | 
| 
       2745 
2771 
     | 
    
         
             
                            t += "\n|  {}:  {}".format(txt, u)
         
     | 
| 
       2746 
2772 
     | 
    
         | 
| 
       2747 
2773 
     | 
    
         
             
                        if "e2d" in zv.flags:
         
     | 
| 
         @@ -2853,8 +2879,6 @@ class AuthSrv(object): 
     | 
|
| 
       2853 
2879 
     | 
    
         | 
| 
       2854 
2880 
     | 
    
         
             
                    if have_reflink:
         
     | 
| 
       2855 
2881 
     | 
    
         
             
                        t = "WARNING: Reflink-based dedup was requested, but %s. This will not work; files will be full copies instead."
         
     | 
| 
       2856 
     | 
    
         
            -
                        if sys.version_info < (3, 14):
         
     | 
| 
       2857 
     | 
    
         
            -
                            self.log(t % "your python version is not new enough", 1)
         
     | 
| 
       2858 
2882 
     | 
    
         
             
                        if not sys.platform.startswith("linux"):
         
     | 
| 
       2859 
2883 
     | 
    
         
             
                            self.log(t % "your OS is not Linux", 1)
         
     | 
| 
       2860 
2884 
     | 
    
         | 
| 
         @@ -2931,6 +2955,11 @@ class AuthSrv(object): 
     | 
|
| 
       2931 
2955 
     | 
    
         
             
                            shn.shr_src = (s_vfs, s_rem)
         
     | 
| 
       2932 
2956 
     | 
    
         
             
                            shn.realpath = s_vfs.canonical(s_rem)
         
     | 
| 
       2933 
2957 
     | 
    
         | 
| 
      
 2958 
     | 
    
         
            +
                            o_vn, _ = shn._get_share_src("")
         
     | 
| 
      
 2959 
     | 
    
         
            +
                            shn.flags = o_vn.flags.copy()
         
     | 
| 
      
 2960 
     | 
    
         
            +
                            shn.dbpath = o_vn.dbpath
         
     | 
| 
      
 2961 
     | 
    
         
            +
                            shn.histpath = o_vn.histpath
         
     | 
| 
      
 2962 
     | 
    
         
            +
             
     | 
| 
       2934 
2963 
     | 
    
         
             
                            # root.all_aps doesn't include any shares, so make a copy where the
         
     | 
| 
       2935 
2964 
     | 
    
         
             
                            # share appears in all abspaths it can provide (for example for chk_ap)
         
     | 
| 
       2936 
2965 
     | 
    
         
             
                            ap = shn.realpath
         
     | 
| 
         @@ -2994,6 +3023,8 @@ class AuthSrv(object): 
     | 
|
| 
       2994 
3023 
     | 
    
         
             
                            "unlist": vf.get("unlist") or "",
         
     | 
| 
       2995 
3024 
     | 
    
         
             
                            "sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"),
         
     | 
| 
       2996 
3025 
     | 
    
         
             
                        }
         
     | 
| 
      
 3026 
     | 
    
         
            +
                        if "ufavico_h" in vf:
         
     | 
| 
      
 3027 
     | 
    
         
            +
                            vn.js_ls["ufavico"] = vf["ufavico_h"]
         
     | 
| 
       2997 
3028 
     | 
    
         
             
                        js_htm = {
         
     | 
| 
       2998 
3029 
     | 
    
         
             
                            "SPINNER": self.args.spinner,
         
     | 
| 
       2999 
3030 
     | 
    
         
             
                            "s_name": self.args.bname,
         
     | 
| 
         @@ -3005,6 +3036,7 @@ class AuthSrv(object): 
     | 
|
| 
       3005 
3036 
     | 
    
         
             
                            "have_shr": self.args.shr,
         
     | 
| 
       3006 
3037 
     | 
    
         
             
                            "shr_who": vf["shr_who"],
         
     | 
| 
       3007 
3038 
     | 
    
         
             
                            "have_zip": not self.args.no_zip,
         
     | 
| 
      
 3039 
     | 
    
         
            +
                            "have_zls": not self.args.no_zls,
         
     | 
| 
       3008 
3040 
     | 
    
         
             
                            "have_mv": not self.args.no_mv,
         
     | 
| 
       3009 
3041 
     | 
    
         
             
                            "have_del": not self.args.no_del,
         
     | 
| 
       3010 
3042 
     | 
    
         
             
                            "have_unpost": int(self.args.unpost),
         
     | 
| 
         @@ -3029,7 +3061,7 @@ class AuthSrv(object): 
     | 
|
| 
       3029 
3061 
     | 
    
         
             
                            "dvol": self.args.au_vol,
         
     | 
| 
       3030 
3062 
     | 
    
         
             
                            "idxh": int(self.args.ih),
         
     | 
| 
       3031 
3063 
     | 
    
         
             
                            "dutc": not self.args.localtime,
         
     | 
| 
       3032 
     | 
    
         
            -
                            "dfszf": self.args.ui_filesz,
         
     | 
| 
      
 3064 
     | 
    
         
            +
                            "dfszf": self.args.ui_filesz.strip("-"),
         
     | 
| 
       3033 
3065 
     | 
    
         
             
                            "themes": self.args.themes,
         
     | 
| 
       3034 
3066 
     | 
    
         
             
                            "turbolvl": self.args.turbo,
         
     | 
| 
       3035 
3067 
     | 
    
         
             
                            "nosubtle": self.args.nosubtle,
         
     | 
| 
         @@ -3041,6 +3073,10 @@ class AuthSrv(object): 
     | 
|
| 
       3041 
3073 
     | 
    
         
             
                            "lifetime": vn.js_ls["lifetime"],
         
     | 
| 
       3042 
3074 
     | 
    
         
             
                            "u2sort": self.args.u2sort,
         
     | 
| 
       3043 
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
         
     | 
| 
       3044 
3080 
     | 
    
         
             
                        vn.js_htm = json_hesc(json.dumps(js_htm))
         
     | 
| 
       3045 
3081 
     | 
    
         | 
| 
       3046 
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:
         
     |