mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 00:52:16 -06:00
add cursed TLS to enable crypto.subtle, thx webkit
This commit is contained in:
parent
fe83994dc6
commit
9fcd4823b5
|
@ -25,5 +25,11 @@ class EnvParams(object):
|
||||||
+ "/copyparty"
|
+ "/copyparty"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.mkdir(self.cfg)
|
||||||
|
except:
|
||||||
|
if not os.path.isdir(self.cfg):
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
E = EnvParams()
|
E = EnvParams()
|
||||||
|
|
|
@ -8,10 +8,14 @@ __copyright__ = 2019
|
||||||
__license__ = "MIT"
|
__license__ = "MIT"
|
||||||
__url__ = "https://github.com/9001/copyparty/"
|
__url__ = "https://github.com/9001/copyparty/"
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import filecmp
|
||||||
import locale
|
import locale
|
||||||
import argparse
|
import argparse
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
|
from .__init__ import E
|
||||||
from .__version__ import S_VERSION, S_BUILD_DT
|
from .__version__ import S_VERSION, S_BUILD_DT
|
||||||
from .svchub import SvcHub
|
from .svchub import SvcHub
|
||||||
|
|
||||||
|
@ -35,7 +39,7 @@ class RiceFormatter(argparse.HelpFormatter):
|
||||||
return "".join(indent + line + "\n" for line in text.splitlines())
|
return "".join(indent + line + "\n" for line in text.splitlines())
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def ensure_locale():
|
||||||
for x in [
|
for x in [
|
||||||
"en_US.UTF-8",
|
"en_US.UTF-8",
|
||||||
"English_United States.UTF8",
|
"English_United States.UTF8",
|
||||||
|
@ -48,6 +52,37 @@ def main():
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_cert():
|
||||||
|
"""
|
||||||
|
the default cert (and the entire TLS support) is only here to enable the
|
||||||
|
crypto.subtle javascript API, which is necessary due to the webkit guys
|
||||||
|
being massive memers (https://www.chromium.org/blink/webcrypto)
|
||||||
|
|
||||||
|
i feel awful about this and so should they
|
||||||
|
"""
|
||||||
|
cert_insec = os.path.join(E.mod, "res/insecure.pem")
|
||||||
|
cert_cfg = os.path.join(E.cfg, "cert.pem")
|
||||||
|
if not os.path.exists(cert_cfg):
|
||||||
|
shutil.copy2(cert_insec, cert_cfg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if filecmp.cmp(cert_cfg, cert_insec):
|
||||||
|
print(
|
||||||
|
"\033[33m\n using default TLS certificate; https will be insecure."
|
||||||
|
+ "\033[36m\n certificate location: {}\033[0m\n".format(cert_cfg)
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# speaking of the default cert,
|
||||||
|
# printf 'NO\n.\n.\n.\n.\ncopyparty-insecure\n.\n' | faketime '2000-01-01 00:00:00' openssl req -x509 -sha256 -newkey rsa:2048 -keyout insecure.pem -out insecure.pem -days $((($(printf %d 0x7fffffff)-$(date +%s --date=2000-01-01T00:00:00Z))/(60*60*24))) -nodes && ls -al insecure.pem && openssl x509 -in insecure.pem -text -noout
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ensure_locale()
|
||||||
|
ensure_cert()
|
||||||
|
|
||||||
ap = argparse.ArgumentParser(
|
ap = argparse.ArgumentParser(
|
||||||
formatter_class=RiceFormatter,
|
formatter_class=RiceFormatter,
|
||||||
prog="copyparty",
|
prog="copyparty",
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
from __future__ import print_function, unicode_literals
|
from __future__ import print_function, unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import ssl
|
||||||
|
import socket
|
||||||
import jinja2
|
import jinja2
|
||||||
|
|
||||||
from .__init__ import E
|
from .__init__ import E
|
||||||
|
@ -16,15 +18,14 @@ class HttpConn(object):
|
||||||
creates an HttpCli for each request (Connection: Keep-Alive)
|
creates an HttpCli for each request (Connection: Keep-Alive)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, sck, addr, args, auth, log_func):
|
def __init__(self, sck, addr, args, auth, log_func, cert_path):
|
||||||
self.s = sck
|
self.s = sck
|
||||||
self.addr = addr
|
self.addr = addr
|
||||||
self.args = args
|
self.args = args
|
||||||
self.auth = auth
|
self.auth = auth
|
||||||
|
self.cert_path = cert_path
|
||||||
|
|
||||||
self.sr = Unrecv(sck)
|
|
||||||
self.workload = 0
|
self.workload = 0
|
||||||
|
|
||||||
self.log_func = log_func
|
self.log_func = log_func
|
||||||
self.log_src = "{} \033[36m{}".format(addr[0], addr[1]).ljust(26)
|
self.log_src = "{} \033[36m{}".format(addr[0], addr[1]).ljust(26)
|
||||||
|
|
||||||
|
@ -37,9 +38,38 @@ class HttpConn(object):
|
||||||
def respath(self, res_name):
|
def respath(self, res_name):
|
||||||
return os.path.join(E.mod, "web", res_name)
|
return os.path.join(E.mod, "web", res_name)
|
||||||
|
|
||||||
|
def log(self, msg):
|
||||||
|
self.log_func(self.log_src, msg)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
method = None
|
||||||
|
if self.cert_path:
|
||||||
|
method = self.s.recv(4, socket.MSG_PEEK)
|
||||||
|
if len(method) != 4:
|
||||||
|
err = b"need at least 4 bytes in the first packet; got {}".format(
|
||||||
|
len(method)
|
||||||
|
)
|
||||||
|
self.log(err)
|
||||||
|
self.s.send(b"HTTP/1.1 400 Bad Request\r\n\r\n" + err)
|
||||||
|
return
|
||||||
|
|
||||||
|
if method not in [None, b"GET ", b"HEAD", b"POST"]:
|
||||||
|
self.log_src = self.log_src.replace("[36m", "[35m")
|
||||||
|
try:
|
||||||
|
self.s = ssl.wrap_socket(
|
||||||
|
self.s, server_side=True, certfile=self.cert_path
|
||||||
|
)
|
||||||
|
except OSError as ex:
|
||||||
|
if "ALERT_BAD_CERTIFICATE" in ex.strerror:
|
||||||
|
self.log("client rejected our certificate (nice)")
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
self.sr = Unrecv(self.s)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
cli = HttpCli(self)
|
cli = HttpCli(self)
|
||||||
if not cli.run():
|
if not cli.run():
|
||||||
self.s.close()
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from __future__ import print_function, unicode_literals
|
from __future__ import print_function, unicode_literals
|
||||||
|
|
||||||
|
import os
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
from .__init__ import E
|
||||||
from .httpconn import HttpConn
|
from .httpconn import HttpConn
|
||||||
from .authsrv import AuthSrv
|
from .authsrv import AuthSrv
|
||||||
|
|
||||||
|
@ -27,6 +29,12 @@ class HttpSrv(object):
|
||||||
self.workload_thr_alive = False
|
self.workload_thr_alive = False
|
||||||
self.auth = AuthSrv(args, log_func)
|
self.auth = AuthSrv(args, log_func)
|
||||||
|
|
||||||
|
cert_path = os.path.join(E.cfg, "cert.pem")
|
||||||
|
if os.path.exists(cert_path):
|
||||||
|
self.cert_path = cert_path
|
||||||
|
else:
|
||||||
|
self.cert_path = None
|
||||||
|
|
||||||
def accept(self, sck, addr):
|
def accept(self, sck, addr):
|
||||||
"""takes an incoming tcp connection and creates a thread to handle it"""
|
"""takes an incoming tcp connection and creates a thread to handle it"""
|
||||||
thr = threading.Thread(target=self.thr_client, args=(sck, addr, self.log))
|
thr = threading.Thread(target=self.thr_client, args=(sck, addr, self.log))
|
||||||
|
@ -42,7 +50,7 @@ class HttpSrv(object):
|
||||||
|
|
||||||
def thr_client(self, sck, addr, log):
|
def thr_client(self, sck, addr, log):
|
||||||
"""thread managing one tcp client"""
|
"""thread managing one tcp client"""
|
||||||
cli = HttpConn(sck, addr, self.args, self.auth, log)
|
cli = HttpConn(sck, addr, self.args, self.auth, log, self.cert_path)
|
||||||
with self.mutex:
|
with self.mutex:
|
||||||
self.clients[cli] = 0
|
self.clients[cli] = 0
|
||||||
self.workload += 50
|
self.workload += 50
|
||||||
|
@ -57,6 +65,7 @@ class HttpSrv(object):
|
||||||
cli.run()
|
cli.run()
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
sck.close()
|
||||||
with self.mutex:
|
with self.mutex:
|
||||||
del self.clients[cli]
|
del self.clients[cli]
|
||||||
|
|
||||||
|
|
48
copyparty/res/insecure.pem
Normal file
48
copyparty/res/insecure.pem
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDD84b31Brvmfcc
|
||||||
|
GTwXuf5n5NW6KxIhLWVZgsCJq+lwGTGl1Cqm9vnzZqD7MDLNzztWk51FDXxeJy9Z
|
||||||
|
Vos1F+n3qfDi4zdd8zWIJxLTsIEkqZjSWiQqqmFijXoaEPBsQ32qRZprh/FfNw3P
|
||||||
|
TagroIgpgzd196eoWdDdggenYBG8/PbktaBKgOo6jz6Q5/UzNTmvcbtlxlsxPos8
|
||||||
|
aTqzezCgA/cArg8mxmfvRPrw8umC8ATiVLvGrXeMiSvcr8Els5air/idhYC8u5zO
|
||||||
|
zGZCePxoKUptQvh/06jsye1S3JOf+RsfAWvu7DgWvSJU2dHfVmtb4ZMSa6cjqTPP
|
||||||
|
cW7S1WyLAgMBAAECggEAAwabqvAHinOiMTjiiKtClnAeLMXFfeWpjvxJ5NZWwHhj
|
||||||
|
H+Bq2DEwIuYOzlIsNqlgjTGyWAKhTQLl5EdF1wgLgNuK8LX5gOXkibmwvLwZAmvs
|
||||||
|
BDOII3CGGHN+0zA3xjQ0mJCCle5/d6zt9amJU0MjVyDDlnrAiAT7CLCdVaRSIczv
|
||||||
|
SETM90NBVHNMraB+Tz9kR1FhyDDlzqpRn/19Hm4BG6/iSmPYpL3jgCRWNweXSXdd
|
||||||
|
x9EitJCz6Yo9+0qPD8DayrH5sKviZw0QDXUezWCcQvgXMsv5MJa7+UaawLk6bq5B
|
||||||
|
Ou1TFGuFdNeNmWofAwPE8UOSIXoKhBK84z5lpTs44QKBgQDg9bRrn3a2u8vpx3r7
|
||||||
|
B+v4dlVq5I3lbVwLwEo6vnw2UiIOtQaQMiWX8HoHR3rmzCVMZq8xNNhEYSboFgtB
|
||||||
|
bbQaxoApdqVTF700c5Le82tj3rBXN0vBIUm6Nzpz0IKQw8HWGz1q/sHd8uZdmtAO
|
||||||
|
m4JrZIJqMItcLhyjYCp8hRUkvwKBgQDe/SZVCBMocHASyB4RgeAkNKSjFEYe2yAl
|
||||||
|
23W9Me3koJqTvHEZnv3Xk5O3HF0dxElktJW5slyrA2BcrzuusO+pge/29OV4ypFa
|
||||||
|
kI51ebMgO3hm2BKKMwxR3mT4KVAbKveLi7hdlnbHVCcZelygkw+11tzIfaikeswR
|
||||||
|
c4FoyPpvNQKBgDEA1OBsyCteFTlDnuJ4A0sIW+sBBnfnrplQtdq+C8i5c3nIrTlT
|
||||||
|
8yR52dskEv2bkrRl2dvaKxIaJ6N+yczi3MzIWLqvgavsC+cVFfVDCS2kIL2e6f2U
|
||||||
|
Br9tsGnyDb8DJYJCRMq92/VBKDVTt+a2sV47cr02/eSClvJvzFF7m/N5AoGAJYzD
|
||||||
|
k7YUY87rUH5aceBI+k/TGZMka7XCqB1Yqk9qHAHfhdlJwmK/pDm5ujAQjh6rrUWr
|
||||||
|
oOWkLTgYVgM8LaKl+Qlke1Wp/rk92N5W3vlrbJYXJFpmZNdLz81/ezqZvrlxjhIt
|
||||||
|
LbVUsyQ8oVG1n2SkVJ6l9y0R5QC4tIea1yZg5bECgYEAhF2EOtBCJ3EDEpHvnlK7
|
||||||
|
OuLRVjce4Vy+Mj3nFbHQMJf+A1B7+B43Ce1fn94OfGJldLDjvaZb8O91JAkHAwJQ
|
||||||
|
GCpOVj9go0ffg/2hurtXW3bMLXIXqcn1538MB5NdlcL22+T0CCprAeuRQm4saMhz
|
||||||
|
mkt5VszEuF/c88usk0ZMm4Y=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDNTCCAh2gAwIBAgIUWWDVQNmrPPo2HlyhYuSYY2uKPbEwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwKjELMAkGA1UEBhMCTk8xGzAZBgNVBAMMEmNvcHlwYXJ0eS1pbnNlY3VyZTAe
|
||||||
|
Fw0wMDAxMDEwMDAwMDBaFw0zODAxMTkwMDAwMDBaMCoxCzAJBgNVBAYTAk5PMRsw
|
||||||
|
GQYDVQQDDBJjb3B5cGFydHktaW5zZWN1cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
||||||
|
DwAwggEKAoIBAQDD84b31BrvmfccGTwXuf5n5NW6KxIhLWVZgsCJq+lwGTGl1Cqm
|
||||||
|
9vnzZqD7MDLNzztWk51FDXxeJy9ZVos1F+n3qfDi4zdd8zWIJxLTsIEkqZjSWiQq
|
||||||
|
qmFijXoaEPBsQ32qRZprh/FfNw3PTagroIgpgzd196eoWdDdggenYBG8/PbktaBK
|
||||||
|
gOo6jz6Q5/UzNTmvcbtlxlsxPos8aTqzezCgA/cArg8mxmfvRPrw8umC8ATiVLvG
|
||||||
|
rXeMiSvcr8Els5air/idhYC8u5zOzGZCePxoKUptQvh/06jsye1S3JOf+RsfAWvu
|
||||||
|
7DgWvSJU2dHfVmtb4ZMSa6cjqTPPcW7S1WyLAgMBAAGjUzBRMB0GA1UdDgQWBBQC
|
||||||
|
uhBjOit55cEz7jMIiJq2BljqxDAfBgNVHSMEGDAWgBQCuhBjOit55cEz7jMIiJq2
|
||||||
|
BljqxDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCu7VE/Pt4H
|
||||||
|
IOHAacQFJN9rdUtI1lcvbJEMdpPglHgFa546pgzDjS8QGvULmppb4mkMbezZ2u+v
|
||||||
|
ZsWMfLxATYgfqEPO/fnT/UqFX2TI2pmmZhqSV+eW8AGRPD5LYyfXpvU4ciSz4Fyl
|
||||||
|
FlrcCOStbeOjHwpeF+n92sF6/LL3n4yy1jmLnTaZDdd59PcWpQkX8omBWlXPdCPR
|
||||||
|
ot0ZI2OpK5mDUG2FglCXl29k1q/zLsKPyfmG7T6VOMB8HO7EylzgSTke4WH9QLR/
|
||||||
|
bkn7AZU+JEIdC6SgR0WSQAntqM+b/OuYSBzXDX0XLwnyY2Dx8SshKNF9v6GwTq7j
|
||||||
|
yQev95xStUTw
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -6,9 +6,9 @@
|
||||||
<title>copyparty</title>
|
<title>copyparty</title>
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=0.8">
|
<meta name="viewport" content="width=device-width, initial-scale=0.8">
|
||||||
<link rel="stylesheet" type="text/css" media="screen" href="/.cpr/browser.css">
|
<link rel="stylesheet" type="text/css" media="screen" href="/.cpr/browser.css{{ ts }}">
|
||||||
{%- if can_upload %}
|
{%- if can_upload %}
|
||||||
<link rel="stylesheet" type="text/css" media="screen" href="/.cpr/upload.css">
|
<link rel="stylesheet" type="text/css" media="screen" href="/.cpr/upload.css{{ ts }}">
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
margin: 1em auto;
|
margin: 1em auto;
|
||||||
padding: 1em 0;
|
padding: 1em 0;
|
||||||
width: 15em;
|
width: 12em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: .4em .4em 0 #111;
|
box-shadow: .4em .4em 0 #111;
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
}
|
}
|
||||||
#u2conf {
|
#u2conf {
|
||||||
margin: 1em auto;
|
margin: 1em auto;
|
||||||
width: 30em;
|
width: 26em;
|
||||||
}
|
}
|
||||||
#u2conf * {
|
#u2conf * {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -39,6 +39,10 @@ combines parts into final file if all-ok
|
||||||
|
|
||||||
use sha512 instead of sha256 everywhere
|
use sha512 instead of sha256 everywhere
|
||||||
write directly to .$wark.tmp instead of parts, then move to destination
|
write directly to .$wark.tmp instead of parts, then move to destination
|
||||||
|
may have to forego the predictable wark and instead use random key:
|
||||||
|
webkit is doing the https-only meme for crypto.subtle.*
|
||||||
|
so native sha512 is unavailable on LAN (oh no)
|
||||||
|
so having the client hash everything before first byte is NG
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,6 +56,20 @@ registry moves file into place when all chunks are verified
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## in case we can't rely on sha512 of entire file
|
||||||
|
|
||||||
|
handshake
|
||||||
|
client gets wark (random session-key)
|
||||||
|
localstorage[filename+size] = wark
|
||||||
|
thread 1: sha512 chunks
|
||||||
|
thread 2: upload chunks
|
||||||
|
server renames wark to filename on last chunk finished
|
||||||
|
if conflict with another wark during upload: all files are renamed
|
||||||
|
if conflict with existing filename: new file is renamed
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## required capabilities
|
## required capabilities
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue