copyparty 1.16.1__tar.gz → 1.16.3__tar.gz
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-1.16.1 → copyparty-1.16.3}/PKG-INFO +6 -3
- {copyparty-1.16.1 → copyparty-1.16.3}/README.md +5 -2
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/__main__.py +6 -1
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/__version__.py +2 -2
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/authsrv.py +83 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/cfg.py +3 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/httpcli.py +108 -66
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/httpsrv.py +1 -1
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/mdns.py +7 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/res/COPYING.txt +23 -30
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/dnslib/dns.py +2 -2
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/dnslib/label.py +21 -1
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/svchub.py +1 -1
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/u2idx.py +32 -20
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/up2k.py +34 -13
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/util.py +42 -6
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/a/u2c.py +7 -3
- copyparty-1.16.3/copyparty/web/baguettebox.js.gz +0 -0
- copyparty-1.16.3/copyparty/web/browser.css.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/browser.html +2 -3
- copyparty-1.16.3/copyparty/web/browser.js.gz +0 -0
- copyparty-1.16.3/copyparty/web/deps/easymde.js.gz +0 -0
- copyparty-1.16.3/copyparty/web/deps/marked.js.gz +0 -0
- copyparty-1.16.3/copyparty/web/deps/sha512.hw.js.gz +0 -0
- copyparty-1.16.3/copyparty/web/md.js.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/md2.js.gz +0 -0
- copyparty-1.16.3/copyparty/web/shares.js.gz +0 -0
- copyparty-1.16.3/copyparty/web/splash.css.gz +0 -0
- copyparty-1.16.3/copyparty/web/ui.css.gz +0 -0
- copyparty-1.16.3/copyparty/web/up2k.js.gz +0 -0
- copyparty-1.16.3/copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty.egg-info/PKG-INFO +6 -3
- copyparty-1.16.1/copyparty/web/baguettebox.js.gz +0 -0
- copyparty-1.16.1/copyparty/web/browser.css.gz +0 -0
- copyparty-1.16.1/copyparty/web/browser.js.gz +0 -0
- copyparty-1.16.1/copyparty/web/deps/easymde.js.gz +0 -0
- copyparty-1.16.1/copyparty/web/deps/marked.js.gz +0 -0
- copyparty-1.16.1/copyparty/web/deps/sha512.hw.js.gz +0 -0
- copyparty-1.16.1/copyparty/web/md.js.gz +0 -0
- copyparty-1.16.1/copyparty/web/shares.js.gz +0 -0
- copyparty-1.16.1/copyparty/web/splash.css.gz +0 -0
- copyparty-1.16.1/copyparty/web/ui.css.gz +0 -0
- copyparty-1.16.1/copyparty/web/up2k.js.gz +0 -0
- copyparty-1.16.1/copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/LICENSE +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/__init__.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/bos/bos.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/bos/path.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/broker_mp.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/broker_mpw.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/broker_thr.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/broker_util.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/cert.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/dxml.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/fsutil.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/ftpd.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/httpconn.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/ico.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/metrics.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/mtag.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/multicast.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/pwhash.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/res/__init__.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/smbd.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/ssdp.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/star.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/sutil.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/szip.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/tcpsrv.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/tftpd.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/th_cli.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/th_srv.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/a/partyfuse.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/browser2.html +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/cf.html +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/deps/busy.mp3.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/deps/easymde.css.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/deps/fuse.py +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/md.html +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/mde.html +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/msg.html +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/shares.css.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/shares.html +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/splash.html +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/svcs.html +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty.egg-info/SOURCES.txt +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/pyproject.toml +0 -0
- {copyparty-1.16.1 → copyparty-1.16.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.16.
|
3
|
+
Version: 1.16.3
|
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
|
@@ -1152,11 +1152,12 @@ using the GUI (winXP or later):
|
|
1152
1152
|
* on winXP only, click the `Sign up for online storage` hyperlink instead and put the URL there
|
1153
1153
|
* providing your password as the username is recommended; the password field can be anything or empty
|
1154
1154
|
|
1155
|
-
|
1155
|
+
the webdav client that's built into windows has the following list of bugs; you can avoid all of these by connecting with rclone instead:
|
1156
1156
|
* win7+ doesn't actually send the password to the server when reauthenticating after a reboot unless you first try to login with an incorrect password and then switch to the correct password
|
1157
1157
|
* or just type your password into the username field instead to get around it entirely
|
1158
1158
|
* connecting to a folder which allows anonymous read will make writing impossible, as windows has decided it doesn't need to login
|
1159
1159
|
* workaround: connect twice; first to a folder which requires auth, then to the folder you actually want, and leave both of those mounted
|
1160
|
+
* or set the server-option `--dav-auth` to force password-auth for all webdav clients
|
1160
1161
|
* win7+ may open a new tcp connection for every file and sometimes forgets to close them, eventually needing a reboot
|
1161
1162
|
* maybe NIC-related (??), happens with win10-ltsc on e1000e but not virtio
|
1162
1163
|
* windows cannot access folders which contain filenames with invalid unicode or forbidden characters (`<>:"/\|?*`), or names ending with `.`
|
@@ -1323,7 +1324,7 @@ note:
|
|
1323
1324
|
|
1324
1325
|
### exclude-patterns
|
1325
1326
|
|
1326
|
-
to save some time, you can provide a regex pattern for filepaths to only index by filename/path/size/last-modified (and not the hash of the file contents) by setting `--no-hash \.iso
|
1327
|
+
to save some time, you can provide a regex pattern for filepaths to only index by filename/path/size/last-modified (and not the hash of the file contents) by setting `--no-hash '\.iso$'` or the volflag `:c,nohash=\.iso$`, this has the following consequences:
|
1327
1328
|
* initial indexing is way faster, especially when the volume is on a network disk
|
1328
1329
|
* makes it impossible to [file-search](#file-search)
|
1329
1330
|
* if someone uploads the same file contents, the upload will not be detected as a dupe, so it will not get symlinked or rejected
|
@@ -1334,6 +1335,8 @@ similarly, you can fully ignore files/folders using `--no-idx [...]` and `:c,noi
|
|
1334
1335
|
|
1335
1336
|
if you set `--no-hash [...]` globally, you can enable hashing for specific volumes using flag `:c,nohash=`
|
1336
1337
|
|
1338
|
+
to exclude certain filepaths from search-results, use `--srch-excl` or volflag `srch_excl` instead of `--no-idx`, for example `--srch-excl 'password|logs/[0-9]'`
|
1339
|
+
|
1337
1340
|
### filesystem guards
|
1338
1341
|
|
1339
1342
|
avoid traversing into other filesystems using `--xdev` / volflag `:c,xdev`, skipping any symlinks or bind-mounts to another HDD for example
|
@@ -1097,11 +1097,12 @@ using the GUI (winXP or later):
|
|
1097
1097
|
* on winXP only, click the `Sign up for online storage` hyperlink instead and put the URL there
|
1098
1098
|
* providing your password as the username is recommended; the password field can be anything or empty
|
1099
1099
|
|
1100
|
-
|
1100
|
+
the webdav client that's built into windows has the following list of bugs; you can avoid all of these by connecting with rclone instead:
|
1101
1101
|
* win7+ doesn't actually send the password to the server when reauthenticating after a reboot unless you first try to login with an incorrect password and then switch to the correct password
|
1102
1102
|
* or just type your password into the username field instead to get around it entirely
|
1103
1103
|
* connecting to a folder which allows anonymous read will make writing impossible, as windows has decided it doesn't need to login
|
1104
1104
|
* workaround: connect twice; first to a folder which requires auth, then to the folder you actually want, and leave both of those mounted
|
1105
|
+
* or set the server-option `--dav-auth` to force password-auth for all webdav clients
|
1105
1106
|
* win7+ may open a new tcp connection for every file and sometimes forgets to close them, eventually needing a reboot
|
1106
1107
|
* maybe NIC-related (??), happens with win10-ltsc on e1000e but not virtio
|
1107
1108
|
* windows cannot access folders which contain filenames with invalid unicode or forbidden characters (`<>:"/\|?*`), or names ending with `.`
|
@@ -1268,7 +1269,7 @@ note:
|
|
1268
1269
|
|
1269
1270
|
### exclude-patterns
|
1270
1271
|
|
1271
|
-
to save some time, you can provide a regex pattern for filepaths to only index by filename/path/size/last-modified (and not the hash of the file contents) by setting `--no-hash \.iso
|
1272
|
+
to save some time, you can provide a regex pattern for filepaths to only index by filename/path/size/last-modified (and not the hash of the file contents) by setting `--no-hash '\.iso$'` or the volflag `:c,nohash=\.iso$`, this has the following consequences:
|
1272
1273
|
* initial indexing is way faster, especially when the volume is on a network disk
|
1273
1274
|
* makes it impossible to [file-search](#file-search)
|
1274
1275
|
* if someone uploads the same file contents, the upload will not be detected as a dupe, so it will not get symlinked or rejected
|
@@ -1279,6 +1280,8 @@ similarly, you can fully ignore files/folders using `--no-idx [...]` and `:c,noi
|
|
1279
1280
|
|
1280
1281
|
if you set `--no-hash [...]` globally, you can enable hashing for specific volumes using flag `:c,nohash=`
|
1281
1282
|
|
1283
|
+
to exclude certain filepaths from search-results, use `--srch-excl` or volflag `srch_excl` instead of `--no-idx`, for example `--srch-excl 'password|logs/[0-9]'`
|
1284
|
+
|
1282
1285
|
### filesystem guards
|
1283
1286
|
|
1284
1287
|
avoid traversing into other filesystems using `--xdev` / volflag `:c,xdev`, skipping any symlinks or bind-mounts to another HDD for example
|
@@ -1116,6 +1116,8 @@ def add_zc_mdns(ap):
|
|
1116
1116
|
ap2.add_argument("--zm6", action="store_true", help="IPv6 only")
|
1117
1117
|
ap2.add_argument("--zmv", action="store_true", help="verbose mdns")
|
1118
1118
|
ap2.add_argument("--zmvv", action="store_true", help="verboser mdns")
|
1119
|
+
ap2.add_argument("--zm-no-pe", action="store_true", help="mute parser errors (invalid incoming MDNS packets)")
|
1120
|
+
ap2.add_argument("--zm-nwa-1", action="store_true", help="disable workaround for avahi-bug #379 (corruption in Avahi's mDNS reflection feature)")
|
1119
1121
|
ap2.add_argument("--zms", metavar="dhf", type=u, default="", help="list of services to announce -- d=webdav h=http f=ftp s=smb -- lowercase=plaintext uppercase=TLS -- default: all enabled services except http/https (\033[32mDdfs\033[0m if \033[33m--ftp\033[0m and \033[33m--smb\033[0m is set, \033[32mDd\033[0m otherwise)")
|
1120
1122
|
ap2.add_argument("--zm-ld", metavar="PATH", type=u, default="", help="link a specific folder for webdav shares")
|
1121
1123
|
ap2.add_argument("--zm-lh", metavar="PATH", type=u, default="", help="link a specific folder for http shares")
|
@@ -1308,7 +1310,7 @@ def add_logging(ap):
|
|
1308
1310
|
ap2.add_argument("--log-htp", action="store_true", help="debug: print http-server threadpool scaling")
|
1309
1311
|
ap2.add_argument("--ihead", metavar="HEADER", type=u, action='append', help="print request \033[33mHEADER\033[0m; [\033[32m*\033[0m]=all")
|
1310
1312
|
ap2.add_argument("--ohead", metavar="HEADER", type=u, action='append', help="print response \033[33mHEADER\033[0m; [\033[32m*\033[0m]=all")
|
1311
|
-
ap2.add_argument("--lf-url", metavar="RE", type=u, default=r"^/\.cpr
|
1313
|
+
ap2.add_argument("--lf-url", metavar="RE", type=u, default=r"^/\.cpr/|[?&]th=[wjp]|/\.(_|ql_|DS_Store$|localized$)", help="dont log URLs matching regex \033[33mRE\033[0m")
|
1312
1314
|
|
1313
1315
|
|
1314
1316
|
def add_admin(ap):
|
@@ -1393,6 +1395,7 @@ def add_db_general(ap, hcores):
|
|
1393
1395
|
ap2.add_argument("--db-act", metavar="SEC", type=float, default=10.0, help="defer any scheduled volume reindexing until \033[33mSEC\033[0m seconds after last db write (uploads, renames, ...)")
|
1394
1396
|
ap2.add_argument("--srch-time", metavar="SEC", type=int, default=45, help="search deadline -- terminate searches running for more than \033[33mSEC\033[0m seconds")
|
1395
1397
|
ap2.add_argument("--srch-hits", metavar="N", type=int, default=7999, help="max search results to allow clients to fetch; 125 results will be shown initially")
|
1398
|
+
ap2.add_argument("--srch-excl", metavar="PTN", type=u, default="", help="regex: exclude files from search results if the file-URL matches \033[33mPTN\033[0m (case-sensitive). Example: [\033[32mpassword|logs/[0-9]\033[0m] any URL containing 'password' or 'logs/DIGIT' (volflag=srch_excl)")
|
1396
1399
|
ap2.add_argument("--dotsrch", action="store_true", help="show dotfiles in search results (volflags: dotsrch | nodotsrch)")
|
1397
1400
|
|
1398
1401
|
|
@@ -1449,6 +1452,8 @@ def add_ui(ap, retry):
|
|
1449
1452
|
ap2.add_argument("--themes", metavar="NUM", type=int, default=8, help="number of themes installed")
|
1450
1453
|
ap2.add_argument("--au-vol", metavar="0-100", type=int, default=50, choices=range(0, 101), help="default audio/video volume percent")
|
1451
1454
|
ap2.add_argument("--sort", metavar="C,C,C", type=u, default="href", help="default sort order, comma-separated column IDs (see header tooltips), prefix with '-' for descending. Examples: \033[32mhref -href ext sz ts tags/Album tags/.tn\033[0m (volflag=sort)")
|
1455
|
+
ap2.add_argument("--nsort", action="store_true", help="default-enable natural sort of filenames with leading numbers (volflag=nsort)")
|
1456
|
+
ap2.add_argument("--hsortn", metavar="N", type=int, default=2, help="number of sorting rules to include in media URLs by default (volflag=hsortn)")
|
1452
1457
|
ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files matching \033[33mREGEX\033[0m in file list. Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)")
|
1453
1458
|
ap2.add_argument("--favico", metavar="TXT", type=u, default="c 000 none" if retry else "🎉 000 none", help="\033[33mfavicon-text\033[0m [ \033[33mforeground\033[0m [ \033[33mbackground\033[0m ] ], set blank to disable")
|
1454
1459
|
ap2.add_argument("--mpmc", metavar="URL", type=u, default="", help="change the mediaplayer-toggle mouse cursor; URL to a folder with {2..5}.png inside (or disable with [\033[32m.\033[0m])")
|
@@ -360,6 +360,8 @@ class VFS(object):
|
|
360
360
|
self.ahtml = {}
|
361
361
|
self.aadmin = {}
|
362
362
|
self.adot = {}
|
363
|
+
self.js_ls = {}
|
364
|
+
self.js_htm = ""
|
363
365
|
|
364
366
|
if realpath:
|
365
367
|
rp = realpath + ("" if realpath.endswith(os.sep) else os.sep)
|
@@ -1871,6 +1873,7 @@ class AuthSrv(object):
|
|
1871
1873
|
["no_hash", "nohash"],
|
1872
1874
|
["no_idx", "noidx"],
|
1873
1875
|
["og_ua", "og_ua"],
|
1876
|
+
["srch_excl", "srch_excl"],
|
1874
1877
|
]:
|
1875
1878
|
if vf in vol.flags:
|
1876
1879
|
ptn = re.compile(vol.flags.pop(vf))
|
@@ -2077,6 +2080,22 @@ class AuthSrv(object):
|
|
2077
2080
|
self.log(t.format(mtp), 1)
|
2078
2081
|
errors = True
|
2079
2082
|
|
2083
|
+
for vol in vfs.all_vols.values():
|
2084
|
+
re1 = vol.flags.get("srch_excl")
|
2085
|
+
excl = [re1.pattern] if re1 else []
|
2086
|
+
|
2087
|
+
vpaths = []
|
2088
|
+
vtop = vol.vpath
|
2089
|
+
for vp2 in vfs.all_vols.keys():
|
2090
|
+
if vp2.startswith((vtop + "/").lstrip("/")) and vtop != vp2:
|
2091
|
+
vpaths.append(re.escape(vp2[len(vtop) :].lstrip("/")))
|
2092
|
+
if vpaths:
|
2093
|
+
excl.append("^(%s)/" % ("|".join(vpaths),))
|
2094
|
+
|
2095
|
+
vol.flags["srch_re_dots"] = re.compile("|".join(excl or ["^$"]))
|
2096
|
+
excl.extend([r"^\.", r"/\."])
|
2097
|
+
vol.flags["srch_re_nodot"] = re.compile("|".join(excl))
|
2098
|
+
|
2080
2099
|
have_daw = False
|
2081
2100
|
for vol in vfs.all_nodes.values():
|
2082
2101
|
daw = vol.flags.get("daw") or self.args.daw
|
@@ -2297,6 +2316,70 @@ class AuthSrv(object):
|
|
2297
2316
|
cur.close()
|
2298
2317
|
db.close()
|
2299
2318
|
|
2319
|
+
self.js_ls = {}
|
2320
|
+
self.js_htm = {}
|
2321
|
+
for vn in self.vfs.all_nodes.values():
|
2322
|
+
vf = vn.flags
|
2323
|
+
vn.js_ls = {
|
2324
|
+
"idx": "e2d" in vf,
|
2325
|
+
"itag": "e2t" in vf,
|
2326
|
+
"dnsort": "nsort" in vf,
|
2327
|
+
"dhsortn": vf["hsortn"],
|
2328
|
+
"dsort": vf["sort"],
|
2329
|
+
"dcrop": vf["crop"],
|
2330
|
+
"dth3x": vf["th3x"],
|
2331
|
+
"u2ts": vf["u2ts"],
|
2332
|
+
"frand": bool(vf.get("rand")),
|
2333
|
+
"lifetime": vf.get("lifetime") or 0,
|
2334
|
+
"unlist": vf.get("unlist") or "",
|
2335
|
+
}
|
2336
|
+
js_htm = {
|
2337
|
+
"s_name": self.args.bname,
|
2338
|
+
"have_up2k_idx": "e2d" in vf,
|
2339
|
+
"have_acode": not self.args.no_acode,
|
2340
|
+
"have_shr": self.args.shr,
|
2341
|
+
"have_zip": not self.args.no_zip,
|
2342
|
+
"have_mv": not self.args.no_mv,
|
2343
|
+
"have_del": not self.args.no_del,
|
2344
|
+
"have_unpost": int(self.args.unpost),
|
2345
|
+
"have_emp": self.args.emp,
|
2346
|
+
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
|
2347
|
+
"txt_ext": self.args.textfiles.replace(",", " "),
|
2348
|
+
"def_hcols": list(vf.get("mth") or []),
|
2349
|
+
"unlist0": vf.get("unlist") or "",
|
2350
|
+
"dgrid": "grid" in vf,
|
2351
|
+
"dgsel": "gsel" in vf,
|
2352
|
+
"dnsort": "nsort" in vf,
|
2353
|
+
"dhsortn": vf["hsortn"],
|
2354
|
+
"dsort": vf["sort"],
|
2355
|
+
"dcrop": vf["crop"],
|
2356
|
+
"dth3x": vf["th3x"],
|
2357
|
+
"dvol": self.args.au_vol,
|
2358
|
+
"idxh": int(self.args.ih),
|
2359
|
+
"themes": self.args.themes,
|
2360
|
+
"turbolvl": self.args.turbo,
|
2361
|
+
"u2j": self.args.u2j,
|
2362
|
+
"u2sz": self.args.u2sz,
|
2363
|
+
"u2ts": vf["u2ts"],
|
2364
|
+
"frand": bool(vf.get("rand")),
|
2365
|
+
"lifetime": vn.js_ls["lifetime"],
|
2366
|
+
"u2sort": self.args.u2sort,
|
2367
|
+
}
|
2368
|
+
vn.js_htm = json.dumps(js_htm)
|
2369
|
+
|
2370
|
+
vols = list(vfs.all_nodes.values())
|
2371
|
+
if enshare:
|
2372
|
+
vols.append(shv)
|
2373
|
+
vols.extend(list(shv.nodes.values()))
|
2374
|
+
|
2375
|
+
for vol in vols:
|
2376
|
+
dbv = vol.get_dbv("")[0]
|
2377
|
+
vol.js_ls = vol.js_ls or dbv.js_ls or {}
|
2378
|
+
vol.js_htm = vol.js_htm or dbv.js_htm or "{}"
|
2379
|
+
|
2380
|
+
zs = str(vol.flags.get("tcolor") or self.args.tcolor)
|
2381
|
+
vol.flags["tcolor"] = zs.lstrip("#")
|
2382
|
+
|
2300
2383
|
def load_sessions(self, quiet=False) :
|
2301
2384
|
# mutex me
|
2302
2385
|
if self.args.no_ses:
|
@@ -42,6 +42,7 @@ def vf_bmap() :
|
|
42
42
|
"magic",
|
43
43
|
"no_sb_md",
|
44
44
|
"no_sb_lg",
|
45
|
+
"nsort",
|
45
46
|
"og",
|
46
47
|
"og_no_head",
|
47
48
|
"og_s_title",
|
@@ -69,6 +70,7 @@ def vf_vmap() :
|
|
69
70
|
}
|
70
71
|
for k in (
|
71
72
|
"dbd",
|
73
|
+
"hsortn",
|
72
74
|
"html_head",
|
73
75
|
"lg_sbf",
|
74
76
|
"md_sbf",
|
@@ -190,6 +192,7 @@ flagcats = {
|
|
190
192
|
"xvol": "do not follow symlinks leaving the volume root",
|
191
193
|
"dotsrch": "show dotfiles in search results",
|
192
194
|
"nodotsrch": "hide dotfiles in search results (default)",
|
195
|
+
"srch_excl": "exclude search results with URL matching this regex",
|
193
196
|
},
|
194
197
|
'database, audio tags\n"mte", "mth", "mtp", "mtm" all work the same as -mte, -mth, ...': {
|
195
198
|
"mtp=.bpm=f,audio-bpm.py": 'uses the "audio-bpm.py" program to\ngenerate ".bpm" tags from uploads (f = overwrite tags)',
|
@@ -14,6 +14,7 @@ import re
|
|
14
14
|
import socket
|
15
15
|
import stat
|
16
16
|
import string
|
17
|
+
import sys
|
17
18
|
import threading # typechk
|
18
19
|
import time
|
19
20
|
import uuid
|
@@ -76,6 +77,7 @@ from .util import (
|
|
76
77
|
html_escape,
|
77
78
|
humansize,
|
78
79
|
ipnorm,
|
80
|
+
justcopy,
|
79
81
|
load_resource,
|
80
82
|
loadpy,
|
81
83
|
log_reloc,
|
@@ -120,6 +122,8 @@ if not hasattr(socket, "AF_UNIX"):
|
|
120
122
|
|
121
123
|
_ = (argparse, threading)
|
122
124
|
|
125
|
+
USED4SEC = {"usedforsecurity": False} if sys.version_info > (3, 9) else {}
|
126
|
+
|
123
127
|
NO_CACHE = {"Cache-Control": "no-cache"}
|
124
128
|
|
125
129
|
ALL_COOKIES = "k304 no304 js idxh dots cppwd cppws".split()
|
@@ -133,6 +137,10 @@ READMES = [[0, ["preadme.md", "PREADME.md"]], [1, ["readme.md", "README.md"]]]
|
|
133
137
|
|
134
138
|
RSS_SORT = {"m": "mt", "u": "at", "n": "fn", "s": "sz"}
|
135
139
|
|
140
|
+
A_FILE = os.stat_result(
|
141
|
+
(0o644, -1, -1, 1, 1000, 1000, 8, 0x39230101, 0x39230101, 0x39230101)
|
142
|
+
)
|
143
|
+
|
136
144
|
|
137
145
|
class HttpCli(object):
|
138
146
|
"""
|
@@ -243,7 +251,6 @@ class HttpCli(object):
|
|
243
251
|
ka["ts"] = self.conn.hsrv.cachebuster()
|
244
252
|
ka["lang"] = self.args.lang
|
245
253
|
ka["favico"] = self.args.favico
|
246
|
-
ka["s_name"] = self.args.bname
|
247
254
|
ka["s_doctitle"] = self.args.doctitle
|
248
255
|
ka["tcolor"] = self.vn.flags["tcolor"]
|
249
256
|
|
@@ -700,7 +707,7 @@ class HttpCli(object):
|
|
700
707
|
|
701
708
|
if pex.code != 404 or self.do_log:
|
702
709
|
self.log(
|
703
|
-
"%s\033[0m, %s" % (msg, self.vpath),
|
710
|
+
"http%d: %s\033[0m, %s" % (pex.code, msg, self.vpath),
|
704
711
|
6 if em.startswith("client d/c ") else 3,
|
705
712
|
)
|
706
713
|
|
@@ -1239,7 +1246,7 @@ class HttpCli(object):
|
|
1239
1246
|
self.log("RSS %s @%s" % (self.req, self.uname))
|
1240
1247
|
|
1241
1248
|
if not self.can_read:
|
1242
|
-
return self.tx_404()
|
1249
|
+
return self.tx_404(True)
|
1243
1250
|
|
1244
1251
|
vn = self.vn
|
1245
1252
|
if not vn.flags.get("rss"):
|
@@ -1409,17 +1416,19 @@ class HttpCli(object):
|
|
1409
1416
|
vst = os.stat_result((16877, -1, -1, 1, 1000, 1000, 8, zi, zi, zi))
|
1410
1417
|
|
1411
1418
|
try:
|
1412
|
-
|
1419
|
+
st = bos.stat(tap)
|
1413
1420
|
except OSError as ex:
|
1414
1421
|
if ex.errno not in (errno.ENOENT, errno.ENOTDIR):
|
1415
1422
|
raise
|
1416
1423
|
raise Pebkac(404)
|
1417
1424
|
|
1425
|
+
topdir = {"vp": "", "st": st}
|
1418
1426
|
fgen = []
|
1419
1427
|
|
1420
1428
|
depth = self.headers.get("depth", "infinity").lower()
|
1421
1429
|
if depth == "infinity":
|
1422
|
-
|
1430
|
+
# allow depth:0 from unmapped root, but require read-axs otherwise
|
1431
|
+
if not self.can_read and (self.vpath or self.asrv.vfs.realpath):
|
1423
1432
|
t = "depth:infinity requires read-access in /%s"
|
1424
1433
|
t = t % (self.vpath,)
|
1425
1434
|
self.log(t, 3)
|
@@ -1450,6 +1459,12 @@ class HttpCli(object):
|
|
1450
1459
|
wrap=False,
|
1451
1460
|
)
|
1452
1461
|
|
1462
|
+
elif depth == "0" or not stat.S_ISDIR(st.st_mode):
|
1463
|
+
# propfind on a file; return as topdir
|
1464
|
+
if not self.can_read and not self.can_get:
|
1465
|
+
self.log("inaccessible: [%s]" % (self.vpath,))
|
1466
|
+
raise Pebkac(401, "authenticate")
|
1467
|
+
|
1453
1468
|
elif depth == "1":
|
1454
1469
|
_, vfs_ls, vfs_virt = vn.ls(
|
1455
1470
|
rem,
|
@@ -1468,15 +1483,12 @@ class HttpCli(object):
|
|
1468
1483
|
fgen = [{"vp": vp, "st": st} for vp, st in vfs_ls]
|
1469
1484
|
fgen += [{"vp": v, "st": vst} for v in vfs_virt]
|
1470
1485
|
|
1471
|
-
elif depth == "0":
|
1472
|
-
pass
|
1473
|
-
|
1474
1486
|
else:
|
1475
1487
|
t = "invalid depth value '{}' (must be either '0' or '1'{})"
|
1476
1488
|
t2 = " or 'infinity'" if self.args.dav_inf else ""
|
1477
1489
|
raise Pebkac(412, t.format(depth, t2))
|
1478
1490
|
|
1479
|
-
if not self.can_read and not self.can_write and not
|
1491
|
+
if not self.can_read and not self.can_write and not fgen:
|
1480
1492
|
self.log("inaccessible: [%s]" % (self.vpath,))
|
1481
1493
|
raise Pebkac(401, "authenticate")
|
1482
1494
|
|
@@ -1755,7 +1767,7 @@ class HttpCli(object):
|
|
1755
1767
|
|
1756
1768
|
if not self.can_write:
|
1757
1769
|
t = "user %s does not have write-access under /%s"
|
1758
|
-
raise Pebkac(403, t % (self.uname, self.vn.vpath))
|
1770
|
+
raise Pebkac(403 if self.pw else 401, t % (self.uname, self.vn.vpath))
|
1759
1771
|
|
1760
1772
|
if not self.args.no_dav and self._applesan():
|
1761
1773
|
return self.headers.get("content-length") == "0"
|
@@ -2046,10 +2058,31 @@ class HttpCli(object):
|
|
2046
2058
|
# small toctou, but better than clobbering a hardlink
|
2047
2059
|
wunlink(self.log, path, vfs.flags)
|
2048
2060
|
|
2061
|
+
hasher = None
|
2062
|
+
copier = hashcopy
|
2063
|
+
if "ck" in self.ouparam or "ck" in self.headers:
|
2064
|
+
zs = self.ouparam.get("ck") or self.headers.get("ck") or ""
|
2065
|
+
if not zs or zs == "no":
|
2066
|
+
copier = justcopy
|
2067
|
+
elif zs == "md5":
|
2068
|
+
hasher = hashlib.md5(**USED4SEC)
|
2069
|
+
elif zs == "sha1":
|
2070
|
+
hasher = hashlib.sha1(**USED4SEC)
|
2071
|
+
elif zs == "sha256":
|
2072
|
+
hasher = hashlib.sha256(**USED4SEC)
|
2073
|
+
elif zs in ("blake2", "b2"):
|
2074
|
+
hasher = hashlib.blake2b(**USED4SEC)
|
2075
|
+
elif zs in ("blake2s", "b2s"):
|
2076
|
+
hasher = hashlib.blake2s(**USED4SEC)
|
2077
|
+
elif zs == "sha512":
|
2078
|
+
pass
|
2079
|
+
else:
|
2080
|
+
raise Pebkac(500, "unknown hash alg")
|
2081
|
+
|
2049
2082
|
f, fn = ren_open(fn, *open_a, **params)
|
2050
2083
|
try:
|
2051
2084
|
path = os.path.join(fdir, fn)
|
2052
|
-
post_sz, sha_hex, sha_b64 =
|
2085
|
+
post_sz, sha_hex, sha_b64 = copier(reader, f, hasher, 0, self.args.s_wr_slp)
|
2053
2086
|
finally:
|
2054
2087
|
f.close()
|
2055
2088
|
|
@@ -2286,8 +2319,8 @@ class HttpCli(object):
|
|
2286
2319
|
# kinda silly but has the least side effects
|
2287
2320
|
return self.handle_new_md()
|
2288
2321
|
|
2289
|
-
if act
|
2290
|
-
return self.handle_plain_upload(file0)
|
2322
|
+
if act in ("bput", "uput"):
|
2323
|
+
return self.handle_plain_upload(file0, act == "uput")
|
2291
2324
|
|
2292
2325
|
if act == "tput":
|
2293
2326
|
return self.handle_text_upload()
|
@@ -2898,13 +2931,41 @@ class HttpCli(object):
|
|
2898
2931
|
)
|
2899
2932
|
|
2900
2933
|
def handle_plain_upload(
|
2901
|
-
self,
|
2934
|
+
self,
|
2935
|
+
file0 ,
|
2936
|
+
nohash ,
|
2902
2937
|
) :
|
2903
2938
|
assert self.parser
|
2904
2939
|
nullwrite = self.args.nw
|
2905
2940
|
vfs, rem = self.asrv.vfs.get(self.vpath, self.uname, False, True)
|
2906
2941
|
self._assert_safe_rem(rem)
|
2907
2942
|
|
2943
|
+
halg = "sha512"
|
2944
|
+
hasher = None
|
2945
|
+
copier = hashcopy
|
2946
|
+
if nohash:
|
2947
|
+
halg = ""
|
2948
|
+
copier = justcopy
|
2949
|
+
elif "ck" in self.ouparam or "ck" in self.headers:
|
2950
|
+
halg = self.ouparam.get("ck") or self.headers.get("ck") or ""
|
2951
|
+
if not halg or halg == "no":
|
2952
|
+
copier = justcopy
|
2953
|
+
halg = ""
|
2954
|
+
elif halg == "md5":
|
2955
|
+
hasher = hashlib.md5(**USED4SEC)
|
2956
|
+
elif halg == "sha1":
|
2957
|
+
hasher = hashlib.sha1(**USED4SEC)
|
2958
|
+
elif halg == "sha256":
|
2959
|
+
hasher = hashlib.sha256(**USED4SEC)
|
2960
|
+
elif halg in ("blake2", "b2"):
|
2961
|
+
hasher = hashlib.blake2b(**USED4SEC)
|
2962
|
+
elif halg in ("blake2s", "b2s"):
|
2963
|
+
hasher = hashlib.blake2s(**USED4SEC)
|
2964
|
+
elif halg == "sha512":
|
2965
|
+
pass
|
2966
|
+
else:
|
2967
|
+
raise Pebkac(500, "unknown hash alg")
|
2968
|
+
|
2908
2969
|
upload_vpath = self.vpath
|
2909
2970
|
lim = vfs.get_dbv(rem)[0].lim
|
2910
2971
|
fdir_base = vfs.canonical(rem)
|
@@ -3034,8 +3095,8 @@ class HttpCli(object):
|
|
3034
3095
|
try:
|
3035
3096
|
tabspath = os.path.join(fdir, tnam)
|
3036
3097
|
self.log("writing to {}".format(tabspath))
|
3037
|
-
sz, sha_hex, sha_b64 =
|
3038
|
-
p_data, f,
|
3098
|
+
sz, sha_hex, sha_b64 = copier(
|
3099
|
+
p_data, f, hasher, max_sz, self.args.s_wr_slp
|
3039
3100
|
)
|
3040
3101
|
if sz == 0:
|
3041
3102
|
raise Pebkac(400, "empty files in post")
|
@@ -3167,10 +3228,15 @@ class HttpCli(object):
|
|
3167
3228
|
jmsg["error"] = errmsg
|
3168
3229
|
errmsg = "ERROR: " + errmsg
|
3169
3230
|
|
3231
|
+
if halg:
|
3232
|
+
file_fmt = '{0}: {1} // {2} // {3} bytes // <a href="/{4}">{5}</a> {6}\n'
|
3233
|
+
else:
|
3234
|
+
file_fmt = '{3} bytes // <a href="/{4}">{5}</a> {6}\n'
|
3235
|
+
|
3170
3236
|
for sz, sha_hex, sha_b64, ofn, lfn, ap in files:
|
3171
3237
|
vsuf = ""
|
3172
3238
|
if (self.can_read or self.can_upget) and "fk" in vfs.flags:
|
3173
|
-
st = bos.stat(ap)
|
3239
|
+
st = A_FILE if nullwrite else bos.stat(ap)
|
3174
3240
|
alg = 2 if "fka" in vfs.flags else 1
|
3175
3241
|
vsuf = "?k=" + self.gen_fk(
|
3176
3242
|
alg,
|
@@ -3185,7 +3251,8 @@ class HttpCli(object):
|
|
3185
3251
|
|
3186
3252
|
vpath = "{}/{}".format(upload_vpath, lfn).strip("/")
|
3187
3253
|
rel_url = quotep(self.args.RS + vpath) + vsuf
|
3188
|
-
msg +=
|
3254
|
+
msg += file_fmt.format(
|
3255
|
+
halg,
|
3189
3256
|
sha_hex[:56],
|
3190
3257
|
sha_b64,
|
3191
3258
|
sz,
|
@@ -3201,13 +3268,14 @@ class HttpCli(object):
|
|
3201
3268
|
self.host,
|
3202
3269
|
rel_url,
|
3203
3270
|
),
|
3204
|
-
"sha512": sha_hex[:56],
|
3205
|
-
"sha_b64": sha_b64,
|
3206
3271
|
"sz": sz,
|
3207
3272
|
"fn": lfn,
|
3208
3273
|
"fn_orig": ofn,
|
3209
3274
|
"path": rel_url,
|
3210
3275
|
}
|
3276
|
+
if halg:
|
3277
|
+
jpart[halg] = sha_hex[:56]
|
3278
|
+
jpart["sha_b64"] = sha_b64
|
3211
3279
|
jmsg["files"].append(jpart)
|
3212
3280
|
|
3213
3281
|
vspd = self._spd(sz_total, False)
|
@@ -4600,6 +4668,18 @@ class HttpCli(object):
|
|
4600
4668
|
if "th" in self.ouparam:
|
4601
4669
|
return self.tx_svg("e" + pt[:3])
|
4602
4670
|
|
4671
|
+
# most webdav clients will not send credentials until they
|
4672
|
+
# get 401'd, so send a challenge if we're Absolutely Sure
|
4673
|
+
# that the client is not a graphical browser
|
4674
|
+
if (
|
4675
|
+
rc == 403
|
4676
|
+
and not self.pw
|
4677
|
+
and not self.ua.startswith("Mozilla/")
|
4678
|
+
and "sec-fetch-site" not in self.headers
|
4679
|
+
):
|
4680
|
+
rc = 401
|
4681
|
+
self.out_headers["WWW-Authenticate"] = 'Basic realm="a"'
|
4682
|
+
|
4603
4683
|
t = t.format(self.args.SR)
|
4604
4684
|
qv = quotep(self.vpaths) + self.ourlq()
|
4605
4685
|
html = self.j2s(
|
@@ -5240,7 +5320,7 @@ class HttpCli(object):
|
|
5240
5320
|
st = bos.stat(abspath)
|
5241
5321
|
except:
|
5242
5322
|
if "on404" not in vn.flags:
|
5243
|
-
return self.tx_404()
|
5323
|
+
return self.tx_404(not self.can_read)
|
5244
5324
|
|
5245
5325
|
ret = self.on40x(vn.flags["on404"], vn, rem)
|
5246
5326
|
if ret == "true":
|
@@ -5251,9 +5331,9 @@ class HttpCli(object):
|
|
5251
5331
|
try:
|
5252
5332
|
st = bos.stat(abspath)
|
5253
5333
|
except:
|
5254
|
-
return self.tx_404()
|
5334
|
+
return self.tx_404(not self.can_read)
|
5255
5335
|
else:
|
5256
|
-
return self.tx_404()
|
5336
|
+
return self.tx_404(not self.can_read)
|
5257
5337
|
|
5258
5338
|
if rem.startswith(".hist/up2k.") or (
|
5259
5339
|
rem.endswith("/dir.txt") and rem.startswith(".hist/th/")
|
@@ -5380,13 +5460,13 @@ class HttpCli(object):
|
|
5380
5460
|
vrem = vjoin(vrem, fn)
|
5381
5461
|
abspath = ap2
|
5382
5462
|
break
|
5383
|
-
elif self.vpath.rsplit("/", 1)[1] in ("index.htm", "index.html"):
|
5463
|
+
elif self.vpath.rsplit("/", 1)[-1] in ("index.htm", "index.html"):
|
5384
5464
|
fk_pass = True
|
5385
5465
|
|
5386
5466
|
if not is_dir and (self.can_read or self.can_get):
|
5387
5467
|
if not self.can_read and not fk_pass and "fk" in vn.flags:
|
5388
5468
|
if not use_filekey:
|
5389
|
-
return self.tx_404()
|
5469
|
+
return self.tx_404(True)
|
5390
5470
|
|
5391
5471
|
if add_og and not abspath.lower().endswith(".md"):
|
5392
5472
|
if og_ua or self.host not in self.headers.get("referer", ""):
|
@@ -5474,61 +5554,28 @@ class HttpCli(object):
|
|
5474
5554
|
is_js = False
|
5475
5555
|
|
5476
5556
|
vf = vn.flags
|
5477
|
-
unlist = vf.get("unlist", "")
|
5478
5557
|
ls_ret = {
|
5479
5558
|
"dirs": [],
|
5480
5559
|
"files": [],
|
5481
5560
|
"taglist": [],
|
5482
5561
|
"srvinf": srv_infot,
|
5483
5562
|
"acct": self.uname,
|
5484
|
-
"idx": e2d,
|
5485
|
-
"itag": e2t,
|
5486
|
-
"dsort": vf["sort"],
|
5487
|
-
"dcrop": vf["crop"],
|
5488
|
-
"dth3x": vf["th3x"],
|
5489
|
-
"u2ts": vf["u2ts"],
|
5490
|
-
"lifetime": vn.flags.get("lifetime") or 0,
|
5491
|
-
"frand": bool(vn.flags.get("rand")),
|
5492
|
-
"unlist": unlist,
|
5493
5563
|
"perms": perms,
|
5564
|
+
"cfg": vn.js_ls,
|
5494
5565
|
}
|
5495
5566
|
cgv = {
|
5496
5567
|
"ls0": None,
|
5497
5568
|
"acct": self.uname,
|
5498
5569
|
"perms": perms,
|
5499
|
-
"u2ts": vf["u2ts"],
|
5500
|
-
"lifetime": ls_ret["lifetime"],
|
5501
|
-
"frand": bool(vn.flags.get("rand")),
|
5502
|
-
"def_hcols": [],
|
5503
|
-
"have_emp": self.args.emp,
|
5504
|
-
"have_up2k_idx": e2d,
|
5505
|
-
"have_acode": (not self.args.no_acode),
|
5506
|
-
"have_mv": (not self.args.no_mv),
|
5507
|
-
"have_del": (not self.args.no_del),
|
5508
|
-
"have_zip": (not self.args.no_zip),
|
5509
|
-
"have_shr": self.args.shr,
|
5510
|
-
"have_unpost": int(self.args.unpost),
|
5511
|
-
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
|
5512
|
-
"dgrid": "grid" in vf,
|
5513
|
-
"dgsel": "gsel" in vf,
|
5514
|
-
"dsort": vf["sort"],
|
5515
|
-
"dcrop": vf["crop"],
|
5516
|
-
"dth3x": vf["th3x"],
|
5517
|
-
"dvol": self.args.au_vol,
|
5518
|
-
"themes": self.args.themes,
|
5519
|
-
"turbolvl": self.args.turbo,
|
5520
|
-
"u2j": self.args.u2j,
|
5521
|
-
"u2sz": self.args.u2sz,
|
5522
|
-
"idxh": int(self.args.ih),
|
5523
|
-
"u2sort": self.args.u2sort,
|
5524
5570
|
}
|
5525
5571
|
j2a = {
|
5572
|
+
"cgv1": vn.js_htm,
|
5526
5573
|
"cgv": cgv,
|
5527
5574
|
"vpnodes": vpnodes,
|
5528
5575
|
"files": [],
|
5529
5576
|
"ls0": None,
|
5530
5577
|
"taglist": [],
|
5531
|
-
"have_tags_idx": e2t,
|
5578
|
+
"have_tags_idx": int(e2t),
|
5532
5579
|
"have_b_u": (self.can_write and self.uparam.get("b") == "u"),
|
5533
5580
|
"sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"),
|
5534
5581
|
"url_suf": url_suf,
|
@@ -5899,17 +5946,12 @@ class HttpCli(object):
|
|
5899
5946
|
"dirs": dirs,
|
5900
5947
|
"files": files,
|
5901
5948
|
"taglist": taglist,
|
5902
|
-
"unlist": unlist,
|
5903
5949
|
}
|
5904
5950
|
j2a["files"] = []
|
5905
5951
|
else:
|
5906
5952
|
j2a["files"] = dirs + files
|
5907
5953
|
|
5908
5954
|
j2a["taglist"] = taglist
|
5909
|
-
j2a["txt_ext"] = self.args.textfiles.replace(",", " ")
|
5910
|
-
|
5911
|
-
if "mth" in vn.flags:
|
5912
|
-
j2a["def_hcols"] = list(vn.flags["mth"])
|
5913
5955
|
|
5914
5956
|
if add_og and "raw" not in self.uparam:
|
5915
5957
|
j2a["this"] = self
|
@@ -132,7 +132,7 @@ class HttpSrv(object):
|
|
132
132
|
dls = {} # state
|
133
133
|
self.dli = self.tdli = dli
|
134
134
|
self.dls = self.tdls = dls
|
135
|
-
self.iiam = '<img src="%s.cpr/iiam.gif" />' % (self.args.SRS,)
|
135
|
+
self.iiam = '<img src="%s.cpr/iiam.gif?cache=i" />' % (self.args.SRS,)
|
136
136
|
|
137
137
|
self.bound = set()
|
138
138
|
self.name = "hsrv" + nsuf
|