mirror of
https://github.com/9001/copyparty.git
synced 2025-08-16 08:32:13 -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"
|
||||
)
|
||||
|
||||
try:
|
||||
os.mkdir(self.cfg)
|
||||
except:
|
||||
if not os.path.isdir(self.cfg):
|
||||
raise
|
||||
|
||||
|
||||
E = EnvParams()
|
||||
|
|
|
@ -8,10 +8,14 @@ __copyright__ = 2019
|
|||
__license__ = "MIT"
|
||||
__url__ = "https://github.com/9001/copyparty/"
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import filecmp
|
||||
import locale
|
||||
import argparse
|
||||
from textwrap import dedent
|
||||
|
||||
from .__init__ import E
|
||||
from .__version__ import S_VERSION, S_BUILD_DT
|
||||
from .svchub import SvcHub
|
||||
|
||||
|
@ -35,7 +39,7 @@ class RiceFormatter(argparse.HelpFormatter):
|
|||
return "".join(indent + line + "\n" for line in text.splitlines())
|
||||
|
||||
|
||||
def main():
|
||||
def ensure_locale():
|
||||
for x in [
|
||||
"en_US.UTF-8",
|
||||
"English_United States.UTF8",
|
||||
|
@ -48,6 +52,37 @@ def main():
|
|||
except:
|
||||
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(
|
||||
formatter_class=RiceFormatter,
|
||||
prog="copyparty",
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import os
|
||||
import ssl
|
||||
import socket
|
||||
import jinja2
|
||||
|
||||
from .__init__ import E
|
||||
|
@ -16,15 +18,14 @@ class HttpConn(object):
|
|||
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.addr = addr
|
||||
self.args = args
|
||||
self.auth = auth
|
||||
self.cert_path = cert_path
|
||||
|
||||
self.sr = Unrecv(sck)
|
||||
self.workload = 0
|
||||
|
||||
self.log_func = log_func
|
||||
self.log_src = "{} \033[36m{}".format(addr[0], addr[1]).ljust(26)
|
||||
|
||||
|
@ -37,9 +38,38 @@ class HttpConn(object):
|
|||
def respath(self, 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):
|
||||
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:
|
||||
cli = HttpCli(self)
|
||||
if not cli.run():
|
||||
self.s.close()
|
||||
return
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
# coding: utf-8
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
|
||||
from .__init__ import E
|
||||
from .httpconn import HttpConn
|
||||
from .authsrv import AuthSrv
|
||||
|
||||
|
@ -27,6 +29,12 @@ class HttpSrv(object):
|
|||
self.workload_thr_alive = False
|
||||
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):
|
||||
"""takes an incoming tcp connection and creates a thread to handle it"""
|
||||
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):
|
||||
"""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:
|
||||
self.clients[cli] = 0
|
||||
self.workload += 50
|
||||
|
@ -57,6 +65,7 @@ class HttpSrv(object):
|
|||
cli.run()
|
||||
|
||||
finally:
|
||||
sck.close()
|
||||
with self.mutex:
|
||||
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>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<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 %}
|
||||
<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 %}
|
||||
</head>
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
font-size: 2em;
|
||||
margin: 1em auto;
|
||||
padding: 1em 0;
|
||||
width: 15em;
|
||||
width: 12em;
|
||||
cursor: pointer;
|
||||
box-shadow: .4em .4em 0 #111;
|
||||
}
|
||||
|
@ -71,7 +71,7 @@
|
|||
}
|
||||
#u2conf {
|
||||
margin: 1em auto;
|
||||
width: 30em;
|
||||
width: 26em;
|
||||
}
|
||||
#u2conf * {
|
||||
text-align: center;
|
||||
|
|
|
@ -39,6 +39,10 @@ combines parts into final file if all-ok
|
|||
|
||||
use sha512 instead of sha256 everywhere
|
||||
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
|
||||
|
||||
|
|
Loading…
Reference in a new issue