copyparty 1.15.0__py3-none-any.whl → 1.15.1__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/__main__.py +5 -0
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +74 -3
- copyparty/broker_mp.py +4 -0
- copyparty/broker_mpw.py +4 -0
- copyparty/broker_thr.py +1 -0
- copyparty/httpcli.py +41 -11
- copyparty/svchub.py +67 -1
- copyparty/up2k.py +17 -2
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- {copyparty-1.15.0.dist-info → copyparty-1.15.1.dist-info}/METADATA +1 -1
- {copyparty-1.15.0.dist-info → copyparty-1.15.1.dist-info}/RECORD +17 -17
- {copyparty-1.15.0.dist-info → copyparty-1.15.1.dist-info}/LICENSE +0 -0
- {copyparty-1.15.0.dist-info → copyparty-1.15.1.dist-info}/WHEEL +0 -0
- {copyparty-1.15.0.dist-info → copyparty-1.15.1.dist-info}/entry_points.txt +0 -0
- {copyparty-1.15.0.dist-info → copyparty-1.15.1.dist-info}/top_level.txt +0 -0
copyparty/__main__.py
CHANGED
@@ -1061,6 +1061,7 @@ def add_cert(ap, cert_path):
|
|
1061
1061
|
|
1062
1062
|
|
1063
1063
|
def add_auth(ap):
|
1064
|
+
ses_db = os.path.join(E.cfg, "sessions.db")
|
1064
1065
|
ap2 = ap.add_argument_group('IdP / identity provider / user authentication options')
|
1065
1066
|
ap2.add_argument("--idp-h-usr", metavar="HN", type=u, default="", help="bypass the copyparty authentication checks and assume the request-header \033[33mHN\033[0m contains the username of the requesting user (for use with authentik/oauth/...)\n\033[1;31mWARNING:\033[0m if you enable this, make sure clients are unable to specify this header themselves; must be washed away and replaced by a reverse-proxy")
|
1066
1067
|
ap2.add_argument("--idp-h-grp", metavar="HN", type=u, default="", help="assume the request-header \033[33mHN\033[0m contains the groupname of the requesting user; can be referenced in config files for group-based access control")
|
@@ -1068,6 +1069,9 @@ def add_auth(ap):
|
|
1068
1069
|
ap2.add_argument("--idp-gsep", metavar="RE", type=u, default="|:;+,", help="if there are multiple groups in \033[33m--idp-h-grp\033[0m, they are separated by one of the characters in \033[33mRE\033[0m")
|
1069
1070
|
ap2.add_argument("--no-bauth", action="store_true", help="disable basic-authentication support; do not accept passwords from the 'Authenticate' header at all. NOTE: This breaks support for the android app")
|
1070
1071
|
ap2.add_argument("--bauth-last", action="store_true", help="keeps basic-authentication enabled, but only as a last-resort; if a cookie is also provided then the cookie wins")
|
1072
|
+
ap2.add_argument("--ses-db", metavar="PATH", type=u, default=ses_db, help="where to store the sessions database (if you run multiple copyparty instances, make sure they use different DBs)")
|
1073
|
+
ap2.add_argument("--ses-len", metavar="CHARS", type=int, default=20, help="session key length; default is 120 bits ((20//4)*4*6)")
|
1074
|
+
ap2.add_argument("--no-ses", action="store_true", help="disable sessions; use plaintext passwords in cookies")
|
1071
1075
|
|
1072
1076
|
|
1073
1077
|
def add_chpw(ap):
|
@@ -1465,6 +1469,7 @@ def run_argparse(
|
|
1465
1469
|
) :
|
1466
1470
|
ap = argparse.ArgumentParser(
|
1467
1471
|
formatter_class=formatter,
|
1472
|
+
usage=argparse.SUPPRESS,
|
1468
1473
|
prog="copyparty",
|
1469
1474
|
description="http file sharing hub v{} ({})".format(S_VERSION, S_BUILD_DT),
|
1470
1475
|
)
|
copyparty/__version__.py
CHANGED
copyparty/authsrv.py
CHANGED
@@ -833,8 +833,10 @@ class AuthSrv(object):
|
|
833
833
|
|
834
834
|
# fwd-decl
|
835
835
|
self.vfs = VFS(log_func, "", "", AXS(), {})
|
836
|
-
self.acct = {}
|
837
|
-
self.iacct = {}
|
836
|
+
self.acct = {} # uname->pw
|
837
|
+
self.iacct = {} # pw->uname
|
838
|
+
self.ases = {} # uname->session
|
839
|
+
self.sesa = {} # session->uname
|
838
840
|
self.defpw = {}
|
839
841
|
self.grps = {}
|
840
842
|
self.re_pwd = None
|
@@ -2174,8 +2176,11 @@ class AuthSrv(object):
|
|
2174
2176
|
self.grps = grps
|
2175
2177
|
self.iacct = {v: k for k, v in acct.items()}
|
2176
2178
|
|
2179
|
+
self.load_sessions()
|
2180
|
+
|
2177
2181
|
self.re_pwd = None
|
2178
2182
|
pwds = [re.escape(x) for x in self.iacct.keys()]
|
2183
|
+
pwds.extend(list(self.sesa))
|
2179
2184
|
if pwds:
|
2180
2185
|
if self.ah.on:
|
2181
2186
|
zs = r"(\[H\] pw:.*|[?&]pw=)([^&]+)"
|
@@ -2250,6 +2255,72 @@ class AuthSrv(object):
|
|
2250
2255
|
cur.close()
|
2251
2256
|
db.close()
|
2252
2257
|
|
2258
|
+
def load_sessions(self, quiet=False) :
|
2259
|
+
# mutex me
|
2260
|
+
if self.args.no_ses:
|
2261
|
+
self.ases = {}
|
2262
|
+
self.sesa = {}
|
2263
|
+
return
|
2264
|
+
|
2265
|
+
import sqlite3
|
2266
|
+
|
2267
|
+
ases = {}
|
2268
|
+
blen = (self.args.ses_len // 4) * 4 # 3 bytes in 4 chars
|
2269
|
+
blen = (blen * 3) // 4 # bytes needed for ses_len chars
|
2270
|
+
|
2271
|
+
db = sqlite3.connect(self.args.ses_db)
|
2272
|
+
cur = db.cursor()
|
2273
|
+
|
2274
|
+
for uname, sid in cur.execute("select un, si from us"):
|
2275
|
+
if uname in self.acct:
|
2276
|
+
ases[uname] = sid
|
2277
|
+
|
2278
|
+
n = []
|
2279
|
+
q = "insert into us values (?,?,?)"
|
2280
|
+
for uname in self.acct:
|
2281
|
+
if uname not in ases:
|
2282
|
+
sid = ub64enc(os.urandom(blen)).decode("utf-8")
|
2283
|
+
cur.execute(q, (uname, sid, int(time.time())))
|
2284
|
+
ases[uname] = sid
|
2285
|
+
n.append(uname)
|
2286
|
+
|
2287
|
+
if n:
|
2288
|
+
db.commit()
|
2289
|
+
|
2290
|
+
cur.close()
|
2291
|
+
db.close()
|
2292
|
+
|
2293
|
+
self.ases = ases
|
2294
|
+
self.sesa = {v: k for k, v in ases.items()}
|
2295
|
+
if n and not quiet:
|
2296
|
+
t = ", ".join(n[:3])
|
2297
|
+
if len(n) > 3:
|
2298
|
+
t += "..."
|
2299
|
+
self.log("added %d new sessions (%s)" % (len(n), t))
|
2300
|
+
|
2301
|
+
def forget_session(self, broker , uname ) :
|
2302
|
+
with self.mutex:
|
2303
|
+
self._forget_session(uname)
|
2304
|
+
|
2305
|
+
if broker:
|
2306
|
+
broker.ask("_reload_sessions").get()
|
2307
|
+
|
2308
|
+
def _forget_session(self, uname ) :
|
2309
|
+
if self.args.no_ses:
|
2310
|
+
return
|
2311
|
+
|
2312
|
+
import sqlite3
|
2313
|
+
|
2314
|
+
db = sqlite3.connect(self.args.ses_db)
|
2315
|
+
cur = db.cursor()
|
2316
|
+
cur.execute("delete from us where un = ?", (uname,))
|
2317
|
+
db.commit()
|
2318
|
+
cur.close()
|
2319
|
+
db.close()
|
2320
|
+
|
2321
|
+
self.sesa.pop(self.ases.get(uname, ""), "")
|
2322
|
+
self.ases.pop(uname, "")
|
2323
|
+
|
2253
2324
|
def chpw(self, broker , uname, pw) :
|
2254
2325
|
if not self.args.chpw:
|
2255
2326
|
return False, "feature disabled in server config"
|
@@ -2269,7 +2340,7 @@ class AuthSrv(object):
|
|
2269
2340
|
if hpw == self.acct[uname]:
|
2270
2341
|
return False, "that's already your password my dude"
|
2271
2342
|
|
2272
|
-
if hpw in self.iacct:
|
2343
|
+
if hpw in self.iacct or hpw in self.sesa:
|
2273
2344
|
return False, "password is taken"
|
2274
2345
|
|
2275
2346
|
with self.mutex:
|
copyparty/broker_mp.py
CHANGED
@@ -72,6 +72,10 @@ class BrokerMp(object):
|
|
72
72
|
for _, proc in enumerate(self.procs):
|
73
73
|
proc.q_pend.put((0, "reload", []))
|
74
74
|
|
75
|
+
def reload_sessions(self) :
|
76
|
+
for _, proc in enumerate(self.procs):
|
77
|
+
proc.q_pend.put((0, "reload_sessions", []))
|
78
|
+
|
75
79
|
def collector(self, proc ) :
|
76
80
|
"""receive message from hub in other process"""
|
77
81
|
while True:
|
copyparty/broker_mpw.py
CHANGED
copyparty/broker_thr.py
CHANGED
@@ -30,6 +30,7 @@ class BrokerThr(BrokerCli):
|
|
30
30
|
self.iphash = HMaccas(os.path.join(self.args.E.cfg, "iphash"), 8)
|
31
31
|
self.httpsrv = HttpSrv(self, None)
|
32
32
|
self.reload = self.noop
|
33
|
+
self.reload_sessions = self.noop
|
33
34
|
|
34
35
|
def shutdown(self) :
|
35
36
|
# self.log("broker", "shutting down")
|
copyparty/httpcli.py
CHANGED
@@ -201,7 +201,8 @@ class HttpCli(object):
|
|
201
201
|
|
202
202
|
def unpwd(self, m ) :
|
203
203
|
a, b, c = m.groups()
|
204
|
-
|
204
|
+
uname = self.asrv.iacct.get(b) or self.asrv.sesa.get(b)
|
205
|
+
return "%s\033[7m %s \033[27m%s" % (a, uname, c)
|
205
206
|
|
206
207
|
def _check_nonfatal(self, ex , post ) :
|
207
208
|
if post:
|
@@ -500,6 +501,8 @@ class HttpCli(object):
|
|
500
501
|
zs = base64.b64decode(zb).decode("utf-8")
|
501
502
|
# try "pwd", "x:pwd", "pwd:x"
|
502
503
|
for bauth in [zs] + zs.split(":", 1)[::-1]:
|
504
|
+
if bauth in self.asrv.sesa:
|
505
|
+
break
|
503
506
|
hpw = self.asrv.ah.hash(bauth)
|
504
507
|
if self.asrv.iacct.get(hpw):
|
505
508
|
break
|
@@ -561,7 +564,11 @@ class HttpCli(object):
|
|
561
564
|
self.uname = "*"
|
562
565
|
else:
|
563
566
|
self.pw = uparam.get("pw") or self.headers.get("pw") or bauth or cookie_pw
|
564
|
-
self.uname =
|
567
|
+
self.uname = (
|
568
|
+
self.asrv.sesa.get(self.pw)
|
569
|
+
or self.asrv.iacct.get(self.asrv.ah.hash(self.pw))
|
570
|
+
or "*"
|
571
|
+
)
|
565
572
|
|
566
573
|
self.rvol = self.asrv.vfs.aread[self.uname]
|
567
574
|
self.wvol = self.asrv.vfs.awrite[self.uname]
|
@@ -2084,6 +2091,9 @@ class HttpCli(object):
|
|
2084
2091
|
if act == "chpw":
|
2085
2092
|
return self.handle_chpw()
|
2086
2093
|
|
2094
|
+
if act == "logout":
|
2095
|
+
return self.handle_logout()
|
2096
|
+
|
2087
2097
|
raise Pebkac(422, 'invalid action "{}"'.format(act))
|
2088
2098
|
|
2089
2099
|
def handle_zip_post(self) :
|
@@ -2405,7 +2415,8 @@ class HttpCli(object):
|
|
2405
2415
|
msg = "new password OK"
|
2406
2416
|
|
2407
2417
|
redir = (self.args.SRS + "?h") if ok else ""
|
2408
|
-
|
2418
|
+
h2 = '<a href="' + self.args.SRS + '?h">ack</a>'
|
2419
|
+
html = self.j2s("msg", h1=msg, h2=h2, redir=redir)
|
2409
2420
|
self.reply(html.encode("utf-8"))
|
2410
2421
|
return True
|
2411
2422
|
|
@@ -2418,9 +2429,8 @@ class HttpCli(object):
|
|
2418
2429
|
uhash = ""
|
2419
2430
|
self.parser.drop()
|
2420
2431
|
|
2421
|
-
|
2422
|
-
|
2423
|
-
]
|
2432
|
+
if not pwd:
|
2433
|
+
raise Pebkac(422, "password cannot be blank")
|
2424
2434
|
|
2425
2435
|
dst = self.args.SRS
|
2426
2436
|
if self.vpath:
|
@@ -2438,9 +2448,27 @@ class HttpCli(object):
|
|
2438
2448
|
self.reply(html.encode("utf-8"))
|
2439
2449
|
return True
|
2440
2450
|
|
2451
|
+
def handle_logout(self) :
|
2452
|
+
assert self.parser
|
2453
|
+
self.parser.drop()
|
2454
|
+
|
2455
|
+
self.log("logout " + self.uname)
|
2456
|
+
self.asrv.forget_session(self.conn.hsrv.broker, self.uname)
|
2457
|
+
self.get_pwd_cookie("x")
|
2458
|
+
|
2459
|
+
dst = self.args.SRS + "?h"
|
2460
|
+
h2 = '<a href="' + dst + '">ack</a>'
|
2461
|
+
html = self.j2s("msg", h1="ok bye", h2=h2, redir=dst)
|
2462
|
+
self.reply(html.encode("utf-8"))
|
2463
|
+
return True
|
2464
|
+
|
2441
2465
|
def get_pwd_cookie(self, pwd ) :
|
2442
|
-
|
2443
|
-
|
2466
|
+
uname = self.asrv.sesa.get(pwd)
|
2467
|
+
if not uname:
|
2468
|
+
hpwd = self.asrv.ah.hash(pwd)
|
2469
|
+
uname = self.asrv.iacct.get(hpwd)
|
2470
|
+
if uname:
|
2471
|
+
pwd = self.asrv.ases.get(uname) or pwd
|
2444
2472
|
if uname:
|
2445
2473
|
msg = "hi " + uname
|
2446
2474
|
dur = int(60 * 60 * self.args.logout)
|
@@ -2452,8 +2480,9 @@ class HttpCli(object):
|
|
2452
2480
|
zb = hashlib.sha512(pwd.encode("utf-8", "replace")).digest()
|
2453
2481
|
logpwd = "%" + base64.b64encode(zb[:12]).decode("utf-8")
|
2454
2482
|
|
2455
|
-
|
2456
|
-
|
2483
|
+
if pwd != "x":
|
2484
|
+
self.log("invalid password: {}".format(logpwd), 3)
|
2485
|
+
self.cbonk(self.conn.hsrv.gpwd, pwd, "pw", "invalid passwords")
|
2457
2486
|
|
2458
2487
|
msg = "naw dude"
|
2459
2488
|
pwd = "x" # nosec
|
@@ -2465,10 +2494,11 @@ class HttpCli(object):
|
|
2465
2494
|
for k in ("cppwd", "cppws") if self.is_https else ("cppwd",):
|
2466
2495
|
ck = gencookie(k, pwd, self.args.R, False)
|
2467
2496
|
self.out_headerlist.append(("Set-Cookie", ck))
|
2497
|
+
self.out_headers.pop("Set-Cookie", None) # drop keepalive
|
2468
2498
|
else:
|
2469
2499
|
k = "cppws" if self.is_https else "cppwd"
|
2470
2500
|
ck = gencookie(k, pwd, self.args.R, self.is_https, dur, "; HttpOnly")
|
2471
|
-
self.
|
2501
|
+
self.out_headers["Set-Cookie"] = ck
|
2472
2502
|
|
2473
2503
|
return dur > 0, msg
|
2474
2504
|
|
copyparty/svchub.py
CHANGED
@@ -215,6 +215,9 @@ class SvcHub(object):
|
|
215
215
|
noch.update([x for x in zsl if x])
|
216
216
|
args.chpw_no = noch
|
217
217
|
|
218
|
+
if not self.args.no_ses:
|
219
|
+
self.setup_session_db()
|
220
|
+
|
218
221
|
if args.shr:
|
219
222
|
self.setup_share_db()
|
220
223
|
|
@@ -363,6 +366,64 @@ class SvcHub(object):
|
|
363
366
|
|
364
367
|
self.broker = Broker(self)
|
365
368
|
|
369
|
+
def setup_session_db(self) :
|
370
|
+
if not HAVE_SQLITE3:
|
371
|
+
self.args.no_ses = True
|
372
|
+
t = "WARNING: sqlite3 not available; disabling sessions, will use plaintext passwords in cookies"
|
373
|
+
self.log("root", t, 3)
|
374
|
+
return
|
375
|
+
|
376
|
+
import sqlite3
|
377
|
+
|
378
|
+
create = True
|
379
|
+
db_path = self.args.ses_db
|
380
|
+
self.log("root", "opening sessions-db %s" % (db_path,))
|
381
|
+
for n in range(2):
|
382
|
+
try:
|
383
|
+
db = sqlite3.connect(db_path)
|
384
|
+
cur = db.cursor()
|
385
|
+
try:
|
386
|
+
cur.execute("select count(*) from us").fetchone()
|
387
|
+
create = False
|
388
|
+
break
|
389
|
+
except:
|
390
|
+
pass
|
391
|
+
except Exception as ex:
|
392
|
+
if n:
|
393
|
+
raise
|
394
|
+
t = "sessions-db corrupt; deleting and recreating: %r"
|
395
|
+
self.log("root", t % (ex,), 3)
|
396
|
+
try:
|
397
|
+
cur.close() # type: ignore
|
398
|
+
except:
|
399
|
+
pass
|
400
|
+
try:
|
401
|
+
db.close() # type: ignore
|
402
|
+
except:
|
403
|
+
pass
|
404
|
+
os.unlink(db_path)
|
405
|
+
|
406
|
+
sch = [
|
407
|
+
r"create table kv (k text, v int)",
|
408
|
+
r"create table us (un text, si text, t0 int)",
|
409
|
+
# username, session-id, creation-time
|
410
|
+
r"create index us_un on us(un)",
|
411
|
+
r"create index us_si on us(si)",
|
412
|
+
r"create index us_t0 on us(t0)",
|
413
|
+
r"insert into kv values ('sver', 1)",
|
414
|
+
]
|
415
|
+
|
416
|
+
assert db # type: ignore
|
417
|
+
assert cur # type: ignore
|
418
|
+
if create:
|
419
|
+
for cmd in sch:
|
420
|
+
cur.execute(cmd)
|
421
|
+
self.log("root", "created new sessions-db")
|
422
|
+
db.commit()
|
423
|
+
|
424
|
+
cur.close()
|
425
|
+
db.close()
|
426
|
+
|
366
427
|
def setup_share_db(self) :
|
367
428
|
al = self.args
|
368
429
|
if not HAVE_SQLITE3:
|
@@ -539,7 +600,7 @@ class SvcHub(object):
|
|
539
600
|
fng = []
|
540
601
|
t_ff = "transcode audio, create spectrograms, video thumbnails"
|
541
602
|
to_check = [
|
542
|
-
(HAVE_SQLITE3, "sqlite", "
|
603
|
+
(HAVE_SQLITE3, "sqlite", "sessions and file/media indexing"),
|
543
604
|
(HAVE_PIL, "pillow", "image thumbnails (plenty fast)"),
|
544
605
|
(HAVE_VIPS, "vips", "image thumbnails (faster, eats more ram)"),
|
545
606
|
(HAVE_WEBP, "pillow-webp", "create thumbnails as webp files"),
|
@@ -939,6 +1000,11 @@ class SvcHub(object):
|
|
939
1000
|
|
940
1001
|
self._reload(rescan_all_vols=rescan_all_vols, up2k=up2k)
|
941
1002
|
|
1003
|
+
def _reload_sessions(self) :
|
1004
|
+
with self.asrv.mutex:
|
1005
|
+
self.asrv.load_sessions(True)
|
1006
|
+
self.broker.reload_sessions()
|
1007
|
+
|
942
1008
|
def stop_thr(self) :
|
943
1009
|
while not self.stop_req:
|
944
1010
|
with self.stop_cond:
|
copyparty/up2k.py
CHANGED
@@ -2843,7 +2843,7 @@ class Up2k(object):
|
|
2843
2843
|
self.log(t)
|
2844
2844
|
del reg[wark]
|
2845
2845
|
|
2846
|
-
elif inc_ap != orig_ap and not data_ok:
|
2846
|
+
elif inc_ap != orig_ap and not data_ok and "done" in reg[wark]:
|
2847
2847
|
self.log("asserting contents of %s" % (orig_ap,))
|
2848
2848
|
dhashes, _ = self._hashlist_from_file(orig_ap)
|
2849
2849
|
dwark = up2k_wark_from_hashlist(self.salt, st.st_size, dhashes)
|
@@ -3104,7 +3104,22 @@ class Up2k(object):
|
|
3104
3104
|
fp = djoin(fdir, fname)
|
3105
3105
|
if job.get("replace") and bos.path.exists(fp):
|
3106
3106
|
self.log("replacing existing file at {}".format(fp))
|
3107
|
-
|
3107
|
+
cur = None
|
3108
|
+
ptop = job["ptop"]
|
3109
|
+
vf = self.flags.get(ptop) or {}
|
3110
|
+
st = bos.stat(fp)
|
3111
|
+
try:
|
3112
|
+
vrel = vjoin(job["prel"], fname)
|
3113
|
+
xlink = bool(vf.get("xlink"))
|
3114
|
+
cur, wark, _, _, _, _ = self._find_from_vpath(ptop, vrel)
|
3115
|
+
self._forget_file(ptop, vrel, cur, wark, True, st.st_size, xlink)
|
3116
|
+
except Exception as ex:
|
3117
|
+
self.log("skipping replace-relink: %r" % (ex,))
|
3118
|
+
finally:
|
3119
|
+
if cur:
|
3120
|
+
cur.connection.commit()
|
3121
|
+
|
3122
|
+
wunlink(self.log, fp, vf)
|
3108
3123
|
|
3109
3124
|
if self.args.plain_ip:
|
3110
3125
|
dip = ip.replace(":", ".")
|
copyparty/web/browser.css.gz
CHANGED
Binary file
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.15.
|
3
|
+
Version: 1.15.1
|
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
|
@@ -1,17 +1,17 @@
|
|
1
1
|
copyparty/__init__.py,sha256=fUINM1abqDGzCCH_JcXdOnLdKOV-SrTI2Xo2QgQW2P4,1703
|
2
|
-
copyparty/__main__.py,sha256=
|
3
|
-
copyparty/__version__.py,sha256=
|
4
|
-
copyparty/authsrv.py,sha256=
|
5
|
-
copyparty/broker_mp.py,sha256=
|
6
|
-
copyparty/broker_mpw.py,sha256=
|
7
|
-
copyparty/broker_thr.py,sha256=
|
2
|
+
copyparty/__main__.py,sha256=M8o_4CGNuteh7j_3iiFN_FTu0IIHKrjRScZOBFKqXis,109083
|
3
|
+
copyparty/__version__.py,sha256=BCJou8sLX4iTHVA4RubRxWxlC8xKh9t-i3XAUnB-aq8,256
|
4
|
+
copyparty/authsrv.py,sha256=pX-Dax35ClxftNnN50UslvZZbPTFI73v-EFLGSqtAA4,98516
|
5
|
+
copyparty/broker_mp.py,sha256=krsUWduBULlZ1LnroHhWLGnUBWYtWc_kohZXgHsE458,4004
|
6
|
+
copyparty/broker_mpw.py,sha256=9kb_3BYUduwtmluuqdm0OhY6T4DwpUSX2xW7jo6veQ8,3326
|
7
|
+
copyparty/broker_thr.py,sha256=BErWJkpd1bnRCcUHowAPNHCfo3CSqVmD-5yVRKjIIhU,1800
|
8
8
|
copyparty/broker_util.py,sha256=w0E-GhoOgq8ow7mEWi3GOyqraux6VG9yk1tif1yo0jc,1474
|
9
9
|
copyparty/cert.py,sha256=kRFkMwBUCV_Vo7BYweD-yJ7Hpp5BCpaXneyBWxlu1PM,7759
|
10
10
|
copyparty/cfg.py,sha256=6cj2xJnBa9vRubM5U_mkA87zG2Ug11vnyk2hYz0XfxI,9965
|
11
11
|
copyparty/dxml.py,sha256=lZpg-kn-kQsXRtNY1n6fRaS-b7uXzMCyv8ovKnhZcZc,1548
|
12
12
|
copyparty/fsutil.py,sha256=hnEHgySI43-XJJKbI8n6t1A6oVHzR_nYdsBcAwtreBk,4610
|
13
13
|
copyparty/ftpd.py,sha256=1vD-KTy07xfEEEk1dx37pUYModpNO2gIhVXvFUr205M,17497
|
14
|
-
copyparty/httpcli.py,sha256=
|
14
|
+
copyparty/httpcli.py,sha256=T-bISKn73-zt-q3C4dbRDgfB1tspze7dhM3gUY0ztX0,183570
|
15
15
|
copyparty/httpconn.py,sha256=mwIDup85cBowIfJOse8rla5bqTz7nf-ChgfR-5-V0JM,6938
|
16
16
|
copyparty/httpsrv.py,sha256=8_1Ivg3eco7HJDjqL_rUB58IOUaUnoXGhO62bOMXLBk,17242
|
17
17
|
copyparty/ico.py,sha256=eWSxEae4wOCfheHl-m-wchYvFRAR_97kJDb4NGaB-Z8,3561
|
@@ -24,14 +24,14 @@ copyparty/smbd.py,sha256=8zkC9BjVtGiKXMLajbdakxoKeFzACdM75SW0_SvqXJA,14490
|
|
24
24
|
copyparty/ssdp.py,sha256=8iyF5sqIjATJLWcAtnJa8eadHosOn0CP4ywltzJ7bVY,7023
|
25
25
|
copyparty/star.py,sha256=tV5BbX6AiQ7N4UU8DYtSTckNYeoeey4DBqq4LjfymbY,3818
|
26
26
|
copyparty/sutil.py,sha256=JTMrQwcWH85hXB_cKG206eDZ967WZDGaP00AWvl_gB0,3214
|
27
|
-
copyparty/svchub.py,sha256=
|
27
|
+
copyparty/svchub.py,sha256=mhELkl2XCvaTrxLcXbfGSPbRtXA1wE66ap73wEWcvFI,40087
|
28
28
|
copyparty/szip.py,sha256=tor4yjdHhEL4Ox-Xg7-cuUFrMO0IwQD29aRX5Cp8MYs,8605
|
29
29
|
copyparty/tcpsrv.py,sha256=jM_Za64O8LEMfMrU4irJluIJZrU494e2b759r_KhaUQ,19881
|
30
30
|
copyparty/tftpd.py,sha256=jZbf2JpeJmkuQWJErmAPG-dKhtYNvIUHbkAgodSXw9Y,13582
|
31
31
|
copyparty/th_cli.py,sha256=o6FMkerYvAXS455z3DUossVztu_nzFlYSQhs6qN6Jt8,4636
|
32
32
|
copyparty/th_srv.py,sha256=27IftjIXUQzRRiUytt-CgXkybEoP3HHHoXaDAvxEmLo,29217
|
33
33
|
copyparty/u2idx.py,sha256=t4mzjj2GDrkjIHt0RM68y1EgT5qOBoz6mkYgjMbqA38,13526
|
34
|
-
copyparty/up2k.py,sha256=
|
34
|
+
copyparty/up2k.py,sha256=USxHI5IN-9DQp_P7Yl4683yxlvaWTslZT90h6sfqpuk,159853
|
35
35
|
copyparty/util.py,sha256=qkwrCRqDI7iCiO3X2RQ1LdGVblnkIQe1YTuJPlF27u4,88666
|
36
36
|
copyparty/bos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
37
|
copyparty/bos/bos.py,sha256=Wb7eWsXJgR5AFlBR9ZOyKrLTwy-Kct9RrGiOu4Jo37Y,1622
|
@@ -55,9 +55,9 @@ copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUu
|
|
55
55
|
copyparty/stolen/ifaddr/_shared.py,sha256=uNC4SdEIgdSLKvuUzsf1aM-H1Xrc_9mpLoOT43YukGs,6206
|
56
56
|
copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
|
57
57
|
copyparty/web/baguettebox.js.gz,sha256=4dS8-r4si84ca71l98672ahnRI86Aq95MU-bc5knykk,7962
|
58
|
-
copyparty/web/browser.css.gz,sha256
|
58
|
+
copyparty/web/browser.css.gz,sha256=TM9gYp-MFSjj_2kV-mKrLFit0Ayz2e7AxI4L0LJmrBE,11608
|
59
59
|
copyparty/web/browser.html,sha256=vvfWiu_aOFRar8u5lridMRKQSPF4R0YkA41zrsh82Qs,4878
|
60
|
-
copyparty/web/browser.js.gz,sha256=
|
60
|
+
copyparty/web/browser.js.gz,sha256=EZhEAuKeZH9qO1gfRzyARG-PFmP7rFtQfHRr0ZnUEYs,84762
|
61
61
|
copyparty/web/browser2.html,sha256=NRUZ08GH-e2YcGXcoz0UjYg6JIVF42u4IMX4HHwWTmg,1587
|
62
62
|
copyparty/web/cf.html,sha256=lJThtNFNAQT1ClCHHlivAkDGE0LutedwopXD62Z8Nys,589
|
63
63
|
copyparty/web/dbg-audio.js.gz,sha256=Ma-KZtK8LnmiwNvNKFKXMPYl_Nn_3U7GsJ6-DRWC2HE,688
|
@@ -105,9 +105,9 @@ copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cV
|
|
105
105
|
copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
|
106
106
|
copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
|
107
107
|
copyparty/web/deps/sha512.hw.js.gz,sha256=vqoXeracj-99Z5MfY3jK2N4WiSzYQdfjy0RnUlQDhSU,8110
|
108
|
-
copyparty-1.15.
|
109
|
-
copyparty-1.15.
|
110
|
-
copyparty-1.15.
|
111
|
-
copyparty-1.15.
|
112
|
-
copyparty-1.15.
|
113
|
-
copyparty-1.15.
|
108
|
+
copyparty-1.15.1.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
|
109
|
+
copyparty-1.15.1.dist-info/METADATA,sha256=sfkSpMV_LX0ITSPAYWbMeaYs8Zz1LC0ZSuv5GSpTjLw,134165
|
110
|
+
copyparty-1.15.1.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
|
111
|
+
copyparty-1.15.1.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
|
112
|
+
copyparty-1.15.1.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
|
113
|
+
copyparty-1.15.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|