copyparty 1.16.0__tar.gz → 1.16.2__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.0 → copyparty-1.16.2}/PKG-INFO +1 -1
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/__main__.py +7 -5
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/__version__.py +2 -2
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/authsrv.py +98 -14
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/cfg.py +1 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/httpcli.py +12 -47
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/httpsrv.py +2 -2
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/mtag.py +29 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/pwhash.py +10 -8
- copyparty-1.16.2/copyparty/res/COPYING.txt +95 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/u2idx.py +9 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/up2k.py +5 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/util.py +22 -5
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/a/u2c.py +2 -0
- copyparty-1.16.2/copyparty/web/baguettebox.js.gz +0 -0
- copyparty-1.16.2/copyparty/web/browser.css.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/browser.html +2 -3
- copyparty-1.16.2/copyparty/web/browser.js.gz +0 -0
- copyparty-1.16.2/copyparty/web/shares.js.gz +0 -0
- copyparty-1.16.2/copyparty/web/splash.css.gz +0 -0
- copyparty-1.16.2/copyparty/web/ui.css.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/up2k.js.gz +0 -0
- copyparty-1.16.2/copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty.egg-info/PKG-INFO +1 -1
- copyparty-1.16.0/copyparty/res/COPYING.txt +0 -159
- copyparty-1.16.0/copyparty/web/baguettebox.js.gz +0 -0
- copyparty-1.16.0/copyparty/web/browser.css.gz +0 -0
- copyparty-1.16.0/copyparty/web/browser.js.gz +0 -0
- copyparty-1.16.0/copyparty/web/shares.js.gz +0 -0
- copyparty-1.16.0/copyparty/web/splash.css.gz +0 -0
- copyparty-1.16.0/copyparty/web/ui.css.gz +0 -0
- copyparty-1.16.0/copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/LICENSE +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/README.md +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/__init__.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/bos/bos.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/bos/path.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/broker_mp.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/broker_mpw.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/broker_thr.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/broker_util.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/cert.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/dxml.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/fsutil.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/ftpd.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/httpconn.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/ico.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/mdns.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/metrics.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/multicast.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/res/__init__.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/smbd.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/ssdp.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/star.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/dnslib/dns.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/dnslib/label.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/sutil.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/svchub.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/szip.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/tcpsrv.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/tftpd.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/th_cli.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/th_srv.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/a/partyfuse.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/browser2.html +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/cf.html +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/busy.mp3.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/easymde.css.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/easymde.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/fuse.py +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/marked.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/deps/sha512.hw.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/md.html +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/md.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/md2.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/mde.html +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/msg.html +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/shares.css.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/shares.html +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/splash.html +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/svcs.html +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty.egg-info/SOURCES.txt +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/pyproject.toml +0 -0
- {copyparty-1.16.0 → copyparty-1.16.2}/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.2
|
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
|
@@ -870,8 +870,9 @@ def get_sects():
|
|
870
870
|
use argon2id with timecost 3, 256 MiB, 4 threads, version 19 (0x13/v1.3)
|
871
871
|
|
872
872
|
\033[36m--ah-alg scrypt\033[0m # which is the same as:
|
873
|
-
\033[36m--ah-alg scrypt,13,2,8,4\033[0m
|
874
|
-
use scrypt with cost 2**13, 2 iterations, blocksize 8, 4 threads
|
873
|
+
\033[36m--ah-alg scrypt,13,2,8,4,32\033[0m
|
874
|
+
use scrypt with cost 2**13, 2 iterations, blocksize 8, 4 threads,
|
875
|
+
and allow using up to 32 MiB RAM (ram=cost*blksz roughly)
|
875
876
|
|
876
877
|
\033[36m--ah-alg sha2\033[0m # which is the same as:
|
877
878
|
\033[36m--ah-alg sha2,424242\033[0m
|
@@ -1343,12 +1344,12 @@ def add_thumbnail(ap):
|
|
1343
1344
|
# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html
|
1344
1345
|
# https://github.com/libvips/libvips
|
1345
1346
|
# ffmpeg -hide_banner -demuxers | awk '/^ D /{print$2}' | while IFS= read -r x; do ffmpeg -hide_banner -h demuxer=$x; done | grep -E '^Demuxer |extensions:'
|
1346
|
-
ap2.add_argument("--th-r-pil", metavar="T,T", type=u, default="avif,avifs,blp,bmp,dcx,dds,dib,emf,eps,fits,flc,fli,fpx,gif,heic,heics,heif,heifs,icns,ico,im,j2p,j2k,jp2,jpeg,jpg,jpx,pbm,pcx,pgm,png,pnm,ppm,psd,qoi,sgi,spi,tga,tif,tiff,webp,wmf,xbm,xpm", help="image formats to decode using pillow")
|
1347
|
+
ap2.add_argument("--th-r-pil", metavar="T,T", type=u, default="avif,avifs,blp,bmp,cbz,dcx,dds,dib,emf,eps,fits,flc,fli,fpx,gif,heic,heics,heif,heifs,icns,ico,im,j2p,j2k,jp2,jpeg,jpg,jpx,pbm,pcx,pgm,png,pnm,ppm,psd,qoi,sgi,spi,tga,tif,tiff,webp,wmf,xbm,xpm", help="image formats to decode using pillow")
|
1347
1348
|
ap2.add_argument("--th-r-vips", metavar="T,T", type=u, default="avif,exr,fit,fits,fts,gif,hdr,heic,jp2,jpeg,jpg,jpx,jxl,nii,pfm,pgm,png,ppm,svg,tif,tiff,webp", help="image formats to decode using pyvips")
|
1348
|
-
ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,dds,dib,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg")
|
1349
|
+
ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,cbz,dds,dib,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg")
|
1349
1350
|
ap2.add_argument("--th-r-ffv", metavar="T,T", type=u, default="3gp,asf,av1,avc,avi,flv,h264,h265,hevc,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,ts,vob,webm,wmv", help="video formats to decode using ffmpeg")
|
1350
1351
|
ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,mdgz,mdxz,mdz,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg")
|
1351
|
-
ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz", help="audio formats to decompress before passing to ffmpeg")
|
1352
|
+
ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz, cbz=jpg.cbz", help="audio/image formats to decompress before passing to ffmpeg")
|
1352
1353
|
|
1353
1354
|
|
1354
1355
|
def add_transcoding(ap):
|
@@ -1448,6 +1449,7 @@ def add_ui(ap, retry):
|
|
1448
1449
|
ap2.add_argument("--themes", metavar="NUM", type=int, default=8, help="number of themes installed")
|
1449
1450
|
ap2.add_argument("--au-vol", metavar="0-100", type=int, default=50, choices=range(0, 101), help="default audio/video volume percent")
|
1450
1451
|
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)")
|
1452
|
+
ap2.add_argument("--nsort", action="store_true", help="default-enable natural sort of filenames with leading numbers (volflag=nsort)")
|
1451
1453
|
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)")
|
1452
1454
|
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")
|
1453
1455
|
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,18 +360,21 @@ class VFS(object):
|
|
360
360
|
self.ahtml = {}
|
361
361
|
self.aadmin = {}
|
362
362
|
self.adot = {}
|
363
|
-
self.
|
363
|
+
self.js_ls = {}
|
364
|
+
self.js_htm = ""
|
364
365
|
|
365
366
|
if realpath:
|
366
367
|
rp = realpath + ("" if realpath.endswith(os.sep) else os.sep)
|
367
368
|
vp = vpath + ("/" if vpath else "")
|
368
369
|
self.histpath = os.path.join(realpath, ".hist") # db / thumbcache
|
369
370
|
self.all_vols = {vpath: self} # flattened recursive
|
371
|
+
self.all_nodes = {vpath: self} # also jumpvols
|
370
372
|
self.all_aps = [(rp, self)]
|
371
373
|
self.all_vps = [(vp, self)]
|
372
374
|
else:
|
373
375
|
self.histpath = ""
|
374
376
|
self.all_vols = {}
|
377
|
+
self.all_nodes = {}
|
375
378
|
self.all_aps = []
|
376
379
|
self.all_vps = []
|
377
380
|
|
@@ -389,9 +392,11 @@ class VFS(object):
|
|
389
392
|
def get_all_vols(
|
390
393
|
self,
|
391
394
|
vols ,
|
395
|
+
nodes ,
|
392
396
|
aps ,
|
393
397
|
vps ,
|
394
398
|
) :
|
399
|
+
nodes[self.vpath] = self
|
395
400
|
if self.realpath:
|
396
401
|
vols[self.vpath] = self
|
397
402
|
rp = self.realpath
|
@@ -401,7 +406,7 @@ class VFS(object):
|
|
401
406
|
vps.append((vp, self))
|
402
407
|
|
403
408
|
for v in self.nodes.values():
|
404
|
-
v.get_all_vols(vols, aps, vps)
|
409
|
+
v.get_all_vols(vols, nodes, aps, vps)
|
405
410
|
|
406
411
|
def add(self, src , dst ) :
|
407
412
|
"""get existing, or add new path to the vfs"""
|
@@ -1528,10 +1533,11 @@ class AuthSrv(object):
|
|
1528
1533
|
|
1529
1534
|
assert vfs # type: ignore
|
1530
1535
|
vfs.all_vols = {}
|
1536
|
+
vfs.all_nodes = {}
|
1531
1537
|
vfs.all_aps = []
|
1532
1538
|
vfs.all_vps = []
|
1533
|
-
vfs.get_all_vols(vfs.all_vols, vfs.all_aps, vfs.all_vps)
|
1534
|
-
for vol in vfs.
|
1539
|
+
vfs.get_all_vols(vfs.all_vols, vfs.all_nodes, vfs.all_aps, vfs.all_vps)
|
1540
|
+
for vol in vfs.all_nodes.values():
|
1535
1541
|
vol.all_aps.sort(key=lambda x: len(x[0]), reverse=True)
|
1536
1542
|
vol.all_vps.sort(key=lambda x: len(x[0]), reverse=True)
|
1537
1543
|
vol.root = vfs
|
@@ -1582,7 +1588,7 @@ class AuthSrv(object):
|
|
1582
1588
|
|
1583
1589
|
vfs.nodes[shr] = vfs.all_vols[shr] = shv
|
1584
1590
|
for vol in shv.nodes.values():
|
1585
|
-
vfs.all_vols[vol.vpath] = vol
|
1591
|
+
vfs.all_vols[vol.vpath] = vfs.all_nodes[vol.vpath] = vol
|
1586
1592
|
vol.get_dbv = vol._get_share_src
|
1587
1593
|
vol.ls = vol._ls_nope
|
1588
1594
|
|
@@ -1725,7 +1731,19 @@ class AuthSrv(object):
|
|
1725
1731
|
|
1726
1732
|
self.log("\n\n".join(ta) + "\n", c=3)
|
1727
1733
|
|
1728
|
-
|
1734
|
+
rhisttab = {}
|
1735
|
+
vfs.histtab = {}
|
1736
|
+
for zv in vfs.all_vols.values():
|
1737
|
+
histp = zv.histpath
|
1738
|
+
is_shr = shr and zv.vpath.split("/")[0] == shr
|
1739
|
+
if histp and not is_shr and histp in rhisttab:
|
1740
|
+
zv2 = rhisttab[histp]
|
1741
|
+
t = "invalid config; multiple volumes share the same histpath (database location):\n histpath: %s\n volume 1: /%s [%s]\n volume 2: %s [%s]"
|
1742
|
+
t = t % (histp, zv2.vpath, zv2.realpath, zv.vpath, zv.realpath)
|
1743
|
+
self.log(t, 1)
|
1744
|
+
raise Exception(t)
|
1745
|
+
rhisttab[histp] = zv
|
1746
|
+
vfs.histtab[zv.realpath] = histp
|
1729
1747
|
|
1730
1748
|
for vol in vfs.all_vols.values():
|
1731
1749
|
lim = Lim(self.log_func)
|
@@ -1784,12 +1802,12 @@ class AuthSrv(object):
|
|
1784
1802
|
vol.lim = lim
|
1785
1803
|
|
1786
1804
|
if self.args.no_robots:
|
1787
|
-
for vol in vfs.
|
1805
|
+
for vol in vfs.all_nodes.values():
|
1788
1806
|
# volflag "robots" overrides global "norobots", allowing indexing by search engines for this vol
|
1789
1807
|
if not vol.flags.get("robots"):
|
1790
1808
|
vol.flags["norobots"] = True
|
1791
1809
|
|
1792
|
-
for vol in vfs.
|
1810
|
+
for vol in vfs.all_nodes.values():
|
1793
1811
|
if self.args.no_vthumb:
|
1794
1812
|
vol.flags["dvthumb"] = True
|
1795
1813
|
if self.args.no_athumb:
|
@@ -1801,7 +1819,7 @@ class AuthSrv(object):
|
|
1801
1819
|
vol.flags["dithumb"] = True
|
1802
1820
|
|
1803
1821
|
have_fk = False
|
1804
|
-
for vol in vfs.
|
1822
|
+
for vol in vfs.all_nodes.values():
|
1805
1823
|
fk = vol.flags.get("fk")
|
1806
1824
|
fka = vol.flags.get("fka")
|
1807
1825
|
if fka and not fk:
|
@@ -1833,7 +1851,7 @@ class AuthSrv(object):
|
|
1833
1851
|
zs = os.path.join(E.cfg, "fk-salt.txt")
|
1834
1852
|
self.log(t % (fk_len, 16, zs), 3)
|
1835
1853
|
|
1836
|
-
for vol in vfs.
|
1854
|
+
for vol in vfs.all_nodes.values():
|
1837
1855
|
if "pk" in vol.flags and "gz" not in vol.flags and "xz" not in vol.flags:
|
1838
1856
|
vol.flags["gz"] = False # def.pk
|
1839
1857
|
|
@@ -1844,7 +1862,7 @@ class AuthSrv(object):
|
|
1844
1862
|
|
1845
1863
|
all_mte = {}
|
1846
1864
|
errors = False
|
1847
|
-
for vol in vfs.
|
1865
|
+
for vol in vfs.all_nodes.values():
|
1848
1866
|
if (self.args.e2ds and vol.axs.uwrite) or self.args.e2dsa:
|
1849
1867
|
vol.flags["e2ds"] = True
|
1850
1868
|
|
@@ -2062,7 +2080,7 @@ class AuthSrv(object):
|
|
2062
2080
|
errors = True
|
2063
2081
|
|
2064
2082
|
have_daw = False
|
2065
|
-
for vol in vfs.
|
2083
|
+
for vol in vfs.all_nodes.values():
|
2066
2084
|
daw = vol.flags.get("daw") or self.args.daw
|
2067
2085
|
if daw:
|
2068
2086
|
vol.flags["daw"] = True
|
@@ -2077,13 +2095,12 @@ class AuthSrv(object):
|
|
2077
2095
|
self.log("--smb can only be used when --ah-alg is none", 1)
|
2078
2096
|
errors = True
|
2079
2097
|
|
2080
|
-
for vol in vfs.
|
2098
|
+
for vol in vfs.all_nodes.values():
|
2081
2099
|
for k in list(vol.flags.keys()):
|
2082
2100
|
if re.match("^-[^-]+$", k):
|
2083
2101
|
vol.flags.pop(k[1:], None)
|
2084
2102
|
vol.flags.pop(k)
|
2085
2103
|
|
2086
|
-
for vol in vfs.all_vols.values():
|
2087
2104
|
if vol.flags.get("dots"):
|
2088
2105
|
for name in vol.axs.uread:
|
2089
2106
|
vol.axs.udot.add(name)
|
@@ -2225,6 +2242,11 @@ class AuthSrv(object):
|
|
2225
2242
|
for x, y in vfs.all_vols.items()
|
2226
2243
|
if x != shr and not x.startswith(shrs)
|
2227
2244
|
}
|
2245
|
+
vfs.all_nodes = {
|
2246
|
+
x: y
|
2247
|
+
for x, y in vfs.all_nodes.items()
|
2248
|
+
if x != shr and not x.startswith(shrs)
|
2249
|
+
}
|
2228
2250
|
|
2229
2251
|
assert db and cur and cur2 and shv # type: ignore
|
2230
2252
|
for row in cur.execute("select * from sh"):
|
@@ -2277,6 +2299,68 @@ class AuthSrv(object):
|
|
2277
2299
|
cur.close()
|
2278
2300
|
db.close()
|
2279
2301
|
|
2302
|
+
self.js_ls = {}
|
2303
|
+
self.js_htm = {}
|
2304
|
+
for vn in self.vfs.all_nodes.values():
|
2305
|
+
vf = vn.flags
|
2306
|
+
vn.js_ls = {
|
2307
|
+
"idx": "e2d" in vf,
|
2308
|
+
"itag": "e2t" in vf,
|
2309
|
+
"dnsort": "nsort" in vf,
|
2310
|
+
"dsort": vf["sort"],
|
2311
|
+
"dcrop": vf["crop"],
|
2312
|
+
"dth3x": vf["th3x"],
|
2313
|
+
"u2ts": vf["u2ts"],
|
2314
|
+
"frand": bool(vf.get("rand")),
|
2315
|
+
"lifetime": vf.get("lifetime") or 0,
|
2316
|
+
"unlist": vf.get("unlist") or "",
|
2317
|
+
}
|
2318
|
+
js_htm = {
|
2319
|
+
"s_name": self.args.bname,
|
2320
|
+
"have_up2k_idx": "e2d" in vf,
|
2321
|
+
"have_acode": not self.args.no_acode,
|
2322
|
+
"have_shr": self.args.shr,
|
2323
|
+
"have_zip": not self.args.no_zip,
|
2324
|
+
"have_mv": not self.args.no_mv,
|
2325
|
+
"have_del": not self.args.no_del,
|
2326
|
+
"have_unpost": int(self.args.unpost),
|
2327
|
+
"have_emp": self.args.emp,
|
2328
|
+
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
|
2329
|
+
"txt_ext": self.args.textfiles.replace(",", " "),
|
2330
|
+
"def_hcols": list(vf.get("mth") or []),
|
2331
|
+
"unlist0": vf.get("unlist") or "",
|
2332
|
+
"dgrid": "grid" in vf,
|
2333
|
+
"dgsel": "gsel" in vf,
|
2334
|
+
"dnsort": "nsort" in vf,
|
2335
|
+
"dsort": vf["sort"],
|
2336
|
+
"dcrop": vf["crop"],
|
2337
|
+
"dth3x": vf["th3x"],
|
2338
|
+
"dvol": self.args.au_vol,
|
2339
|
+
"idxh": int(self.args.ih),
|
2340
|
+
"themes": self.args.themes,
|
2341
|
+
"turbolvl": self.args.turbo,
|
2342
|
+
"u2j": self.args.u2j,
|
2343
|
+
"u2sz": self.args.u2sz,
|
2344
|
+
"u2ts": vf["u2ts"],
|
2345
|
+
"frand": bool(vf.get("rand")),
|
2346
|
+
"lifetime": vn.js_ls["lifetime"],
|
2347
|
+
"u2sort": self.args.u2sort,
|
2348
|
+
}
|
2349
|
+
vn.js_htm = json.dumps(js_htm)
|
2350
|
+
|
2351
|
+
vols = list(vfs.all_nodes.values())
|
2352
|
+
if enshare:
|
2353
|
+
vols.append(shv)
|
2354
|
+
vols.extend(list(shv.nodes.values()))
|
2355
|
+
|
2356
|
+
for vol in vols:
|
2357
|
+
dbv = vol.get_dbv("")[0]
|
2358
|
+
vol.js_ls = vol.js_ls or dbv.js_ls or {}
|
2359
|
+
vol.js_htm = vol.js_htm or dbv.js_htm or "{}"
|
2360
|
+
|
2361
|
+
zs = str(vol.flags.get("tcolor") or self.args.tcolor)
|
2362
|
+
vol.flags["tcolor"] = zs.lstrip("#")
|
2363
|
+
|
2280
2364
|
def load_sessions(self, quiet=False) :
|
2281
2365
|
# mutex me
|
2282
2366
|
if self.args.no_ses:
|
@@ -243,7 +243,6 @@ class HttpCli(object):
|
|
243
243
|
ka["ts"] = self.conn.hsrv.cachebuster()
|
244
244
|
ka["lang"] = self.args.lang
|
245
245
|
ka["favico"] = self.args.favico
|
246
|
-
ka["s_name"] = self.args.bname
|
247
246
|
ka["s_doctitle"] = self.args.doctitle
|
248
247
|
ka["tcolor"] = self.vn.flags["tcolor"]
|
249
248
|
|
@@ -700,7 +699,7 @@ class HttpCli(object):
|
|
700
699
|
|
701
700
|
if pex.code != 404 or self.do_log:
|
702
701
|
self.log(
|
703
|
-
"%s\033[0m, %s" % (msg, self.vpath),
|
702
|
+
"http%d: %s\033[0m, %s" % (pex.code, msg, self.vpath),
|
704
703
|
6 if em.startswith("client d/c ") else 3,
|
705
704
|
)
|
706
705
|
|
@@ -1409,12 +1408,13 @@ class HttpCli(object):
|
|
1409
1408
|
vst = os.stat_result((16877, -1, -1, 1, 1000, 1000, 8, zi, zi, zi))
|
1410
1409
|
|
1411
1410
|
try:
|
1412
|
-
|
1411
|
+
st = bos.stat(tap)
|
1413
1412
|
except OSError as ex:
|
1414
1413
|
if ex.errno not in (errno.ENOENT, errno.ENOTDIR):
|
1415
1414
|
raise
|
1416
1415
|
raise Pebkac(404)
|
1417
1416
|
|
1417
|
+
topdir = {"vp": "", "st": st}
|
1418
1418
|
fgen = []
|
1419
1419
|
|
1420
1420
|
depth = self.headers.get("depth", "infinity").lower()
|
@@ -1450,6 +1450,12 @@ class HttpCli(object):
|
|
1450
1450
|
wrap=False,
|
1451
1451
|
)
|
1452
1452
|
|
1453
|
+
elif depth == "0" or not stat.S_ISDIR(st.st_mode):
|
1454
|
+
# propfind on a file; return as topdir
|
1455
|
+
if not self.can_read and not self.can_get:
|
1456
|
+
self.log("inaccessible: [%s]" % (self.vpath,))
|
1457
|
+
raise Pebkac(401, "authenticate")
|
1458
|
+
|
1453
1459
|
elif depth == "1":
|
1454
1460
|
_, vfs_ls, vfs_virt = vn.ls(
|
1455
1461
|
rem,
|
@@ -1468,9 +1474,6 @@ class HttpCli(object):
|
|
1468
1474
|
fgen = [{"vp": vp, "st": st} for vp, st in vfs_ls]
|
1469
1475
|
fgen += [{"vp": v, "st": vst} for v in vfs_virt]
|
1470
1476
|
|
1471
|
-
elif depth == "0":
|
1472
|
-
pass
|
1473
|
-
|
1474
1477
|
else:
|
1475
1478
|
t = "invalid depth value '{}' (must be either '0' or '1'{})"
|
1476
1479
|
t2 = " or 'infinity'" if self.args.dav_inf else ""
|
@@ -5474,61 +5477,28 @@ class HttpCli(object):
|
|
5474
5477
|
is_js = False
|
5475
5478
|
|
5476
5479
|
vf = vn.flags
|
5477
|
-
unlist = vf.get("unlist", "")
|
5478
5480
|
ls_ret = {
|
5479
5481
|
"dirs": [],
|
5480
5482
|
"files": [],
|
5481
5483
|
"taglist": [],
|
5482
5484
|
"srvinf": srv_infot,
|
5483
5485
|
"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
5486
|
"perms": perms,
|
5487
|
+
"cfg": vn.js_ls,
|
5494
5488
|
}
|
5495
5489
|
cgv = {
|
5496
5490
|
"ls0": None,
|
5497
5491
|
"acct": self.uname,
|
5498
5492
|
"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
5493
|
}
|
5525
5494
|
j2a = {
|
5495
|
+
"cgv1": vn.js_htm,
|
5526
5496
|
"cgv": cgv,
|
5527
5497
|
"vpnodes": vpnodes,
|
5528
5498
|
"files": [],
|
5529
5499
|
"ls0": None,
|
5530
5500
|
"taglist": [],
|
5531
|
-
"have_tags_idx": e2t,
|
5501
|
+
"have_tags_idx": int(e2t),
|
5532
5502
|
"have_b_u": (self.can_write and self.uparam.get("b") == "u"),
|
5533
5503
|
"sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"),
|
5534
5504
|
"url_suf": url_suf,
|
@@ -5899,17 +5869,12 @@ class HttpCli(object):
|
|
5899
5869
|
"dirs": dirs,
|
5900
5870
|
"files": files,
|
5901
5871
|
"taglist": taglist,
|
5902
|
-
"unlist": unlist,
|
5903
5872
|
}
|
5904
5873
|
j2a["files"] = []
|
5905
5874
|
else:
|
5906
5875
|
j2a["files"] = dirs + files
|
5907
5876
|
|
5908
5877
|
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
5878
|
|
5914
5879
|
if add_og and "raw" not in self.uparam:
|
5915
5880
|
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
|
@@ -607,7 +607,7 @@ class HttpSrv(object):
|
|
607
607
|
"""
|
608
608
|
dli = {}
|
609
609
|
for k, (a, b, c, d, e) in sdli.items():
|
610
|
-
vn = self.asrv.vfs.
|
610
|
+
vn = self.asrv.vfs.all_nodes[c]
|
611
611
|
dli[k] = (a, b, vn, d, e)
|
612
612
|
|
613
613
|
self.tdli = dli
|
@@ -4,6 +4,7 @@ from __future__ import print_function, unicode_literals
|
|
4
4
|
import argparse
|
5
5
|
import json
|
6
6
|
import os
|
7
|
+
import re
|
7
8
|
import shutil
|
8
9
|
import subprocess as sp
|
9
10
|
import sys
|
@@ -56,6 +57,9 @@ def have_ff(scmd ) :
|
|
56
57
|
HAVE_FFMPEG = not os.environ.get("PRTY_NO_FFMPEG") and have_ff("ffmpeg")
|
57
58
|
HAVE_FFPROBE = not os.environ.get("PRTY_NO_FFPROBE") and have_ff("ffprobe")
|
58
59
|
|
60
|
+
CBZ_PICS = set("png jpg jpeg gif bmp tga tif tiff webp avif".split())
|
61
|
+
CBZ_01 = re.compile(r"(^|[^0-9v])0+[01]\b")
|
62
|
+
|
59
63
|
|
60
64
|
class MParser(object):
|
61
65
|
def __init__(self, cmdline ) :
|
@@ -120,6 +124,7 @@ def au_unpk(
|
|
120
124
|
log , fmt_map , abspath , vn = None
|
121
125
|
) :
|
122
126
|
ret = ""
|
127
|
+
maxsz = 1024 * 1024 * 64
|
123
128
|
try:
|
124
129
|
ext = abspath.split(".")[-1].lower()
|
125
130
|
au, pk = fmt_map[ext].split(".")
|
@@ -142,17 +147,41 @@ def au_unpk(
|
|
142
147
|
zf = zipfile.ZipFile(abspath, "r")
|
143
148
|
zil = zf.infolist()
|
144
149
|
zil = [x for x in zil if x.filename.lower().split(".")[-1] == au]
|
150
|
+
if not zil:
|
151
|
+
raise Exception("no audio inside zip")
|
145
152
|
fi = zf.open(zil[0])
|
146
153
|
|
154
|
+
elif pk == "cbz":
|
155
|
+
import zipfile
|
156
|
+
|
157
|
+
zf = zipfile.ZipFile(abspath, "r")
|
158
|
+
znil = [(x.filename.lower(), x) for x in zf.infolist()]
|
159
|
+
nf = len(znil)
|
160
|
+
znil = [x for x in znil if x[0].split(".")[-1] in CBZ_PICS]
|
161
|
+
znil = [x for x in znil if "cover" in x[0]] or znil
|
162
|
+
znil = [x for x in znil if CBZ_01.search(x[0])] or znil
|
163
|
+
t = "cbz: %d files, %d hits" % (nf, len(znil))
|
164
|
+
if znil:
|
165
|
+
t += ", using " + znil[0][1].filename
|
166
|
+
log(t)
|
167
|
+
if not znil:
|
168
|
+
raise Exception("no images inside cbz")
|
169
|
+
fi = zf.open(znil[0][1])
|
170
|
+
|
147
171
|
else:
|
148
172
|
raise Exception("unknown compression %s" % (pk,))
|
149
173
|
|
174
|
+
fsz = 0
|
150
175
|
with os.fdopen(fd, "wb") as fo:
|
151
176
|
while True:
|
152
177
|
buf = fi.read(32768)
|
153
178
|
if not buf:
|
154
179
|
break
|
155
180
|
|
181
|
+
fsz += len(buf)
|
182
|
+
if fsz > maxsz:
|
183
|
+
raise Exception("zipbomb defused")
|
184
|
+
|
156
185
|
fo.write(buf)
|
157
186
|
|
158
187
|
return ret
|
@@ -24,17 +24,13 @@ class PWHash(object):
|
|
24
24
|
def __init__(self, args ):
|
25
25
|
self.args = args
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
except:
|
30
|
-
alg = args.ah_alg
|
31
|
-
ac = {}
|
32
|
-
|
27
|
+
zsl = args.ah_alg.split(",")
|
28
|
+
alg = zsl[0]
|
33
29
|
if alg == "none":
|
34
30
|
alg = ""
|
35
31
|
|
36
32
|
self.alg = alg
|
37
|
-
self.ac =
|
33
|
+
self.ac = zsl[1:]
|
38
34
|
if not alg:
|
39
35
|
self.on = False
|
40
36
|
self.hash = unicode
|
@@ -90,17 +86,23 @@ class PWHash(object):
|
|
90
86
|
its = 2
|
91
87
|
blksz = 8
|
92
88
|
para = 4
|
89
|
+
ramcap = 0 # openssl 1.1 = 32 MiB
|
93
90
|
try:
|
94
91
|
cost = 2 << int(self.ac[0])
|
95
92
|
its = int(self.ac[1])
|
96
93
|
blksz = int(self.ac[2])
|
97
94
|
para = int(self.ac[3])
|
95
|
+
ramcap = int(self.ac[4]) * 1024 * 1024
|
98
96
|
except:
|
99
97
|
pass
|
100
98
|
|
99
|
+
cfg = {"salt": self.salt, "n": cost, "r": blksz, "p": para, "dklen": 24}
|
100
|
+
if ramcap:
|
101
|
+
cfg["maxmem"] = ramcap
|
102
|
+
|
101
103
|
ret = plain.encode("utf-8")
|
102
104
|
for _ in range(its):
|
103
|
-
ret = hashlib.scrypt(ret,
|
105
|
+
ret = hashlib.scrypt(ret, **cfg)
|
104
106
|
|
105
107
|
return "+" + base64.urlsafe_b64encode(ret).decode("utf-8")
|
106
108
|
|
@@ -0,0 +1,95 @@
|
|
1
|
+
[07m--- server-side --- software ---[0m
|
2
|
+
|
3
|
+
https://github.com/9001/copyparty/
|
4
|
+
Copyright (c) 2019 ed
|
5
|
+
License: MIT
|
6
|
+
|
7
|
+
https://github.com/pallets/jinja/
|
8
|
+
Copyright (c) 2007 Pallets
|
9
|
+
License: BSD 3-Clause
|
10
|
+
|
11
|
+
https://github.com/pallets/markupsafe/
|
12
|
+
Copyright (c) 2010 Pallets
|
13
|
+
License: BSD 3-Clause
|
14
|
+
|
15
|
+
https://github.com/paulc/dnslib/
|
16
|
+
Copyright (c) 2010-2017 Paul Chakravarti
|
17
|
+
License: BSD 2-Clause
|
18
|
+
|
19
|
+
https://github.com/pydron/ifaddr/
|
20
|
+
Copyright (c) 2014 Stefan C. Mueller
|
21
|
+
License: BSD-2-Clause
|
22
|
+
|
23
|
+
https://github.com/giampaolo/pyftpdlib/
|
24
|
+
Copyright (c) 2007 Giampaolo Rodola
|
25
|
+
License: MIT
|
26
|
+
|
27
|
+
https://github.com/9001/partftpy
|
28
|
+
Copyright (c) 2010-2021 Michael P. Soulier
|
29
|
+
License: MIT
|
30
|
+
|
31
|
+
https://github.com/nayuki/QR-Code-generator/
|
32
|
+
Copyright (c) Project Nayuki
|
33
|
+
License: MIT
|
34
|
+
|
35
|
+
https://github.com/ahupp/python-magic/
|
36
|
+
Copyright (c) 2001-2014 Adam Hupp
|
37
|
+
License: MIT
|
38
|
+
|
39
|
+
[07m--- client-side --- software ---[0m
|
40
|
+
|
41
|
+
https://github.com/Daninet/hash-wasm/
|
42
|
+
Copyright (c) 2020 Dani Biró
|
43
|
+
License: MIT
|
44
|
+
|
45
|
+
https://github.com/openpgpjs/asmcrypto.js/
|
46
|
+
Copyright (c) 2013 Artem S Vybornov
|
47
|
+
License: MIT
|
48
|
+
|
49
|
+
https://github.com/feimosi/baguetteBox.js/
|
50
|
+
Copyright (c) 2017 Marek Grzybek
|
51
|
+
License: MIT
|
52
|
+
|
53
|
+
https://github.com/markedjs/marked/
|
54
|
+
Copyright (c) 2018+, MarkedJS
|
55
|
+
Copyright (c) 2011-2018, Christopher Jeffrey (https://github.com/chjj/)
|
56
|
+
License: MIT
|
57
|
+
|
58
|
+
https://github.com/codemirror/codemirror5/
|
59
|
+
Copyright (c) 2017 Marijn Haverbeke <marijnh@gmail.com> and others
|
60
|
+
License: MIT
|
61
|
+
|
62
|
+
https://github.com/Ionaru/easy-markdown-editor/
|
63
|
+
Copyright (c) 2015 Sparksuite, Inc.
|
64
|
+
Copyright (c) 2017 Jeroen Akkerman.
|
65
|
+
License: MIT
|
66
|
+
|
67
|
+
[07m--- client-side --- fonts ---[0m
|
68
|
+
|
69
|
+
https://github.com/adobe-fonts/source-code-pro/
|
70
|
+
Copyright (c) 2010-2019 Adobe
|
71
|
+
License: SIL OFL 1.1
|
72
|
+
|
73
|
+
https://github.com/FortAwesome/Font-Awesome/
|
74
|
+
Copyright (c) 2022 Fonticons, Inc.
|
75
|
+
License: SIL OFL 1.1
|
76
|
+
|
77
|
+
|
78
|
+
[07m--- MIT License ---[0m
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
[07m--- ISC License ---[0m
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
[07m--- BSD 2-Clause License ---[0m
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
[07m--- BSD 3-Clause License ---[0m
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
[07m--- SIL Open Font License v1.1 ---[0m
|
95
|
+
|