Now we're there

Use randomly salted hash of username as access_token and authenticate
with it.
This commit is contained in:
Brandon Doornbos 2026-06-04 04:43:11 +02:00
parent d0a8583efa
commit 0afd6dc137
2 changed files with 40 additions and 13 deletions

View file

@ -801,6 +801,12 @@ class HttpCli(object):
else: else:
self.log("unknown username: %r" % (idp_usr,), 1) self.log("unknown username: %r" % (idp_usr,), 1)
try:
if self.args.wopi:
self.uname = self.conn.hsrv.wopi_files.get(self.uparam.get("access_token")).get("uname")
except:
pass
if self.args.have_ipu_or_ipr: if self.args.have_ipu_or_ipr:
if self.args.ipu and (self.uname == "*" or self.args.ao_ipu_wins): if self.args.ipu and (self.uname == "*" or self.args.ao_ipu_wins):
self.uname = self.conn.ipu_iu[self.conn.ipu_nm.map(self.ip)] self.uname = self.conn.ipu_iu[self.conn.ipu_nm.map(self.ip)]
@ -1540,8 +1546,8 @@ class HttpCli(object):
def tx_wopi_api(self) -> bool: def tx_wopi_api(self) -> bool:
path = self.vpath.split('/') path = self.vpath.split('/')
if "files" in path: if "files" in path and self.conn.hsrv.wopi_files[self.uparam["access_token"]]["file_key"] in path:
real_path = self.conn.hsrv.wopi_files[path[2]] real_path = self.conn.hsrv.wopi_files[self.uparam["access_token"]]["path"]
vfs, _ = self.asrv.vfs.get(real_path, self.uname, False, True) vfs, _ = self.asrv.vfs.get(real_path, self.uname, False, True)
full_path = vfs.realpath + "/" + real_path full_path = vfs.realpath + "/" + real_path
@ -1589,23 +1595,29 @@ class HttpCli(object):
def tx_wopi(self) -> bool: def tx_wopi(self) -> bool:
path = self.vpath + "/" + str(self.uparam["wopi"]) path = self.vpath + "/" + str(self.uparam["wopi"])
session_salt = ub64enc(os.urandom(64)).decode("utf-8")
session_key = self.gen_fk(2, session_salt, self.uname, 0, 0)
file_key = self.gen_fk(2, self.args.fk_salt, path, 0, 0) file_key = self.gen_fk(2, self.args.fk_salt, path, 0, 0)
self.conn.hsrv.wopi_files[file_key] = path self.conn.hsrv.wopi_files[session_key] = {
"uname": self.uname,
"file_key": file_key,
"path": path,
}
try: try:
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) ctx = ssl.create_default_context()
ctx.check_hostname = False if self.args.wopi_self_signed else True
ctx.verify_mode = ssl.CERT_NONE if self.args.wopi_self_signed else ssl.CERT_REQUIRED ctx.verify_mode = ssl.CERT_NONE if self.args.wopi_self_signed else ssl.CERT_REQUIRED
discovery = urllib.request.urlopen(self.args.wopi_client + "/hosting/discovery", context=ctx) discovery = urllib.request.urlopen(self.args.wopi_client + "/hosting/discovery", context=ctx)
response = ET.fromstring(discovery.read()) response = ET.fromstring(discovery.read())
ext = path.split('.')[-1] ext = path.split('.')[-1]
wopi_url = response.find(".//action[@ext='%s'][@urlsrc]" % ext).get("urlsrc") wopi_url = response.find(".//action[@ext='%s'][@urlsrc]" % ext).get("urlsrc")
favicon_url = response.find(".//action[@ext='%s'].." % ext).get("favIconUrl") favicon_url = response.find(".//action[@ext='%s'].." % ext).get("favIconUrl")
url = wopi_url + "WOPISrc=https://" + self.host + "/wopi/files/" + file_key url = wopi_url + urllib.parse.quote("WOPISrc=https://" + self.host + "/wopi/files/" + file_key, safe="=")
except Exception as error: except Exception as error:
self.log("Couldn't get urls from WOPI client: %s" % error) self.log("Couldn't get urls from WOPI client: %s" % error)
return False return False
ret = [ ret = [
"""\ """\
<!DOCTYPE html> <!DOCTYPE html>
@ -1614,7 +1626,7 @@ class HttpCli(object):
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="icon" href="%s" /> <link rel="icon" href="%s" />
<title>Load Collabora Online</title> <title>Loading...</title>
<style> <style>
body { body {
margin: 0; margin: 0;
@ -1622,7 +1634,7 @@ class HttpCli(object):
height: 100vh; height: 100vh;
overflow: hidden; overflow: hidden;
} }
iframe { #viewer {
width: 100%%; width: 100%%;
height: 100%%; height: 100%%;
border: 0; border: 0;
@ -1630,11 +1642,22 @@ class HttpCli(object):
</style> </style>
</head> </head>
<body> <body>
<iframe src="%s" /> <div style="display: none">
<form action="%s" enctype="multipart/form-data" method="post" target="viewer" id="submit-form">
<input name="access_token" value="%s" type="hidden" id="access-token"/>
<input type="submit" value="" />
</form>
</div>
<iframe id="viewer" name="viewer" allow="clipboard-read *; clipboard-write *; fullscreen *"></iframe>
<script>
document.getElementById("submit-form").submit();
</script>
</body> </body>
</html> </html>
""" """
% (favicon_url, url) % (favicon_url, url, session_key)
] ]
bret = "".join(ret).encode("utf-8", "replace") bret = "".join(ret).encode("utf-8", "replace")
@ -3480,8 +3503,12 @@ class HttpCli(object):
def rx_wopi(self) -> bool: def rx_wopi(self) -> bool:
path = self.vpath.split('/') path = self.vpath.split('/')
if "files" in path and "contents" in path: if (
real_path = self.conn.hsrv.wopi_files[path[2]] "files" in path and
"contents" in path and
self.conn.hsrv.wopi_files[self.uparam["access_token"]]["file_key"] in path
):
real_path = self.conn.hsrv.wopi_files[self.uparam["access_token"]]["path"]
vfs, _ = self.asrv.vfs.get(real_path, self.uname, False, True) vfs, _ = self.asrv.vfs.get(real_path, self.uname, False, True)
full_path = vfs.realpath + "/" + real_path full_path = vfs.realpath + "/" + real_path

View file

@ -243,7 +243,7 @@ class HttpSrv(object):
Daemon(self.post_init, "hsrv-init2") Daemon(self.post_init, "hsrv-init2")
if self.args.wopi: if self.args.wopi:
self.wopi_files: dict[str, str] = {} self.wopi_files: dict[str, dict[str, str]] = {}
def post_init(self) -> None: def post_init(self) -> None:
try: try: