mirror of
https://github.com/suitenumerique/drive.git
synced 2026-09-11 12:17:59 +02:00
✨(wopi) save woopi client proof key in the configuration
The proof-key feature is not yet implemented. The first step is to save the proof-key given by the client in its discovery document.
This commit is contained in:
@@ -1788,7 +1788,7 @@ class ItemViewSet(
|
||||
if request.user.is_authenticated and request.user.language
|
||||
else settings.LANGUAGE_CODE
|
||||
)
|
||||
launch_url = compute_wopi_launch_url(wopi_client["url"], get_file_info, language)
|
||||
launch_url = compute_wopi_launch_url(wopi_client.get("launch_url"), get_file_info, language)
|
||||
|
||||
return drf.response.Response(
|
||||
{
|
||||
|
||||
@@ -40,11 +40,14 @@ def configure_wopi_settings(valid_mimetype, valid_wopi_launch_url):
|
||||
{
|
||||
"mimetypes": {
|
||||
valid_mimetype: {
|
||||
"url": valid_wopi_launch_url,
|
||||
"launch_url": valid_wopi_launch_url,
|
||||
"client": "vendorA",
|
||||
},
|
||||
},
|
||||
"extensions": {},
|
||||
"vendorA": {
|
||||
"proof_keys": {},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
"""Task configuring WOPI using discovery url."""
|
||||
|
||||
from base64 import b64decode
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
|
||||
import requests
|
||||
from celery import Celery
|
||||
from celery.schedules import crontab
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
|
||||
from defusedxml.ElementTree import fromstring
|
||||
|
||||
from drive.celery_app import app as celery_app
|
||||
@@ -44,6 +48,19 @@ def configure_wopi_clients():
|
||||
)
|
||||
|
||||
|
||||
def build_rsa_public_key(modulus, exponent):
|
||||
"""Build RSA public key from modulus and exponent."""
|
||||
mod = int(b64decode(modulus).hex(), 16)
|
||||
exp = int(b64decode(exponent).hex(), 16)
|
||||
|
||||
rsa_public_key = RSAPublicNumbers(exp, mod).public_key()
|
||||
|
||||
return rsa_public_key.public_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
||||
)
|
||||
|
||||
|
||||
def _configure_wopi_client_from_discovery(client, discovery_url):
|
||||
"""Configure wopi client from discovery url."""
|
||||
|
||||
@@ -67,6 +84,27 @@ def _configure_wopi_client_from_discovery(client, discovery_url):
|
||||
if net_zone is None:
|
||||
raise RuntimeError(f"net-zone element not found in discovery url for wopi client {client}")
|
||||
|
||||
proof_key_node = root.find(".//proof-key")
|
||||
proof_keys = {}
|
||||
|
||||
if proof_key_node is not None:
|
||||
# build current and old public key
|
||||
current_public_key = build_rsa_public_key(
|
||||
proof_key_node.get("modulus"), proof_key_node.get("exponent")
|
||||
)
|
||||
old_public_key = build_rsa_public_key(
|
||||
proof_key_node.get("oldmodulus"), proof_key_node.get("oldexponent")
|
||||
)
|
||||
|
||||
proof_keys = {
|
||||
"public_key": current_public_key,
|
||||
"old_public_key": old_public_key,
|
||||
}
|
||||
|
||||
wopi_configuration[client] = {
|
||||
"proof_keys": proof_keys,
|
||||
}
|
||||
|
||||
# Iterate through all app elements
|
||||
for app in net_zone.findall(".//app"):
|
||||
app_name = app.get("name")
|
||||
@@ -85,7 +123,7 @@ def _configure_wopi_client_from_discovery(client, discovery_url):
|
||||
continue
|
||||
|
||||
wopi_configuration["mimetypes"][mimetype] = {
|
||||
"url": action.get("urlsrc"),
|
||||
"launch_url": action.get("urlsrc"),
|
||||
"client": client,
|
||||
}
|
||||
|
||||
@@ -96,7 +134,7 @@ def _configure_wopi_client_from_discovery(client, discovery_url):
|
||||
continue
|
||||
|
||||
wopi_configuration["extensions"][extension] = {
|
||||
"url": action.get("urlsrc"),
|
||||
"launch_url": action.get("urlsrc"),
|
||||
"client": client,
|
||||
}
|
||||
|
||||
|
||||
@@ -49,16 +49,83 @@ def test_configure_wopi_clients(settings):
|
||||
assert cache.get(WOPI_CONFIGURATION_CACHE_KEY) == {
|
||||
"mimetypes": {
|
||||
"application/vnd.oasis.opendocument.text": {
|
||||
"url": "http://localhost:9980/browser/0968141f2c/cool.html?",
|
||||
"launch_url": "http://localhost:9980/browser/0968141f2c/cool.html?",
|
||||
"client": "vendorA",
|
||||
},
|
||||
},
|
||||
"extensions": {
|
||||
"odt": {
|
||||
"url": "http://localhost:9980/browser/0968141f2c/cool.html?",
|
||||
"launch_url": "http://localhost:9980/browser/0968141f2c/cool.html?",
|
||||
"client": "vendorA",
|
||||
},
|
||||
},
|
||||
"vendorA": {
|
||||
"proof_keys": {},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_configure_wopi_clients_with_proof_keys(settings):
|
||||
"""Test the configure_wopi celery task with client using proof key."""
|
||||
|
||||
settings.WOPI_CLIENTS = ["vendorA"]
|
||||
settings.WOPI_CLIENTS_CONFIGURATION = {
|
||||
"vendorA": {
|
||||
"discovery_url": "https://vendorA.com/hosting/discovery",
|
||||
}
|
||||
}
|
||||
|
||||
# pylint: disable=line-too-long
|
||||
responses.add(
|
||||
responses.GET,
|
||||
"https://vendorA.com/hosting/discovery",
|
||||
body="""
|
||||
<wopi-discovery>
|
||||
<net-zone name="external-http">
|
||||
<app favIconUrl="http://localhost:9980/browser/0968141f2c/images/x-office-document.svg" name="writer">
|
||||
<action default="true" ext="sxw" name="view" urlsrc="http://localhost:9980/browser/0968141f2c/cool.html?"/>
|
||||
<action default="true" ext="odt" name="edit" urlsrc="http://localhost:9980/browser/0968141f2c/cool.html?"/>
|
||||
</app>
|
||||
<app name="application/vnd.oasis.opendocument.text">
|
||||
<action default="true" ext="" name="edit" urlsrc="http://localhost:9980/browser/0968141f2c/cool.html?"/>
|
||||
</app>
|
||||
</net-zone>
|
||||
<proof-key
|
||||
oldvalue="BgIAAACkAABSU0ExAAgAAAEAAQD75uIhulOrvFWdgiI3BUqZWj3Zxlii/oCz4CQpH72jYZgbPkKpFC0D0zXznEvn8jgkekLjTD4Q3Dj5UoqN7atjGqhcCuLyiKqkjbklrOS/PS/nhKNJjMWgEUksRKu2vHXJmUhO1FECEgwHM7TOQtDnVJuMV0TK5MsjuhV7cU4uLe42gnzrrLbmpLM6UroNkwOTw723AwrzUSlNVecwMOEijfZj9hhvPzsTuMkIf48OfCQZk5VUJh4/D4lLlvqwFd8Lu48KXvEstWgRF+13pieinmEmQXSgBLzqMi//I9BbpPQQAl1AIy5o0HayDthDDYx5mis3sVEBwEs8dIQJgoTT"
|
||||
oldmodulus="04SCCYR0PEvAAVGxNyuaeYwNQ9gOsnbQaC4jQF0CEPSkW9Aj/y8y6rwEoHRBJmGeoiemd+0XEWi1LPFeCo+7C98VsPqWS4kPPx4mVJWTGSR8Do9/CMm4Ezs/bxj2Y/aNIuEwMOdVTSlR8woDt73DkwOTDbpSOrOk5ras63yCNu4tLk5xexW6I8vkykRXjJtU59BCzrQzBwwSAlHUTkiZyXW8tqtELEkRoMWMSaOE5y89v+SsJbmNpKqI8uIKXKgaY6vtjYpS+TjcED5M40J6JDjy50uc8zXTAy0UqUI+G5hho70fKSTgs4D+oljG2T1amUoFNyKCnVW8q1O6IeLm+w=="
|
||||
oldexponent="AQAB"
|
||||
value="BgIAAACkAABSU0ExAAgAAAEAAQD75uIhulOrvFWdgiI3BUqZWj3Zxlii/oCz4CQpH72jYZgbPkKpFC0D0zXznEvn8jgkekLjTD4Q3Dj5UoqN7atjGqhcCuLyiKqkjbklrOS/PS/nhKNJjMWgEUksRKu2vHXJmUhO1FECEgwHM7TOQtDnVJuMV0TK5MsjuhV7cU4uLe42gnzrrLbmpLM6UroNkwOTw723AwrzUSlNVecwMOEijfZj9hhvPzsTuMkIf48OfCQZk5VUJh4/D4lLlvqwFd8Lu48KXvEstWgRF+13pieinmEmQXSgBLzqMi//I9BbpPQQAl1AIy5o0HayDthDDYx5mis3sVEBwEs8dIQJgoTT"
|
||||
modulus="04SCCYR0PEvAAVGxNyuaeYwNQ9gOsnbQaC4jQF0CEPSkW9Aj/y8y6rwEoHRBJmGeoiemd+0XEWi1LPFeCo+7C98VsPqWS4kPPx4mVJWTGSR8Do9/CMm4Ezs/bxj2Y/aNIuEwMOdVTSlR8woDt73DkwOTDbpSOrOk5ras63yCNu4tLk5xexW6I8vkykRXjJtU59BCzrQzBwwSAlHUTkiZyXW8tqtELEkRoMWMSaOE5y89v+SsJbmNpKqI8uIKXKgaY6vtjYpS+TjcED5M40J6JDjy50uc8zXTAy0UqUI+G5hho70fKSTgs4D+oljG2T1amUoFNyKCnVW8q1O6IeLm+w=="
|
||||
exponent="AQAB"/>
|
||||
</wopi-discovery>
|
||||
""",
|
||||
)
|
||||
|
||||
assert cache.get(WOPI_CONFIGURATION_CACHE_KEY) is None
|
||||
|
||||
configure_wopi_clients()
|
||||
|
||||
# pylint: disable=line-too-long
|
||||
assert cache.get(WOPI_CONFIGURATION_CACHE_KEY) == {
|
||||
"mimetypes": {
|
||||
"application/vnd.oasis.opendocument.text": {
|
||||
"launch_url": "http://localhost:9980/browser/0968141f2c/cool.html?",
|
||||
"client": "vendorA",
|
||||
},
|
||||
},
|
||||
"extensions": {
|
||||
"odt": {
|
||||
"launch_url": "http://localhost:9980/browser/0968141f2c/cool.html?",
|
||||
"client": "vendorA",
|
||||
},
|
||||
},
|
||||
"vendorA": {
|
||||
"proof_keys": {
|
||||
"old_public_key": b"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA04SCCYR0PEvAAVGxNyua\neYwNQ9gOsnbQaC4jQF0CEPSkW9Aj/y8y6rwEoHRBJmGeoiemd+0XEWi1LPFeCo+7\nC98VsPqWS4kPPx4mVJWTGSR8Do9/CMm4Ezs/bxj2Y/aNIuEwMOdVTSlR8woDt73D\nkwOTDbpSOrOk5ras63yCNu4tLk5xexW6I8vkykRXjJtU59BCzrQzBwwSAlHUTkiZ\nyXW8tqtELEkRoMWMSaOE5y89v+SsJbmNpKqI8uIKXKgaY6vtjYpS+TjcED5M40J6\nJDjy50uc8zXTAy0UqUI+G5hho70fKSTgs4D+oljG2T1amUoFNyKCnVW8q1O6IeLm\n+wIDAQAB\n-----END PUBLIC KEY-----\n",
|
||||
"public_key": b"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA04SCCYR0PEvAAVGxNyua\neYwNQ9gOsnbQaC4jQF0CEPSkW9Aj/y8y6rwEoHRBJmGeoiemd+0XEWi1LPFeCo+7\nC98VsPqWS4kPPx4mVJWTGSR8Do9/CMm4Ezs/bxj2Y/aNIuEwMOdVTSlR8woDt73D\nkwOTDbpSOrOk5ras63yCNu4tLk5xexW6I8vkykRXjJtU59BCzrQzBwwSAlHUTkiZ\nyXW8tqtELEkRoMWMSaOE5y89v+SsJbmNpKqI8uIKXKgaY6vtjYpS+TjcED5M40J6\nJDjy50uc8zXTAy0UqUI+G5hho70fKSTgs4D+oljG2T1amUoFNyKCnVW8q1O6IeLm\n+wIDAQAB\n-----END PUBLIC KEY-----\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ def is_item_wopi_supported(item, user):
|
||||
|
||||
|
||||
def get_wopi_client_config(item, user):
|
||||
"""make
|
||||
"""
|
||||
Get the WOPI client configuration for an item.
|
||||
"""
|
||||
if (
|
||||
@@ -33,7 +33,7 @@ def get_wopi_client_config(item, user):
|
||||
):
|
||||
return None
|
||||
|
||||
wopi_configuration = cache.get(WOPI_CONFIGURATION_CACHE_KEY, default=WOPI_DEFAULT_CONFIGURATION)
|
||||
wopi_configuration = get_wopi_configuration()
|
||||
|
||||
if not wopi_configuration:
|
||||
return None
|
||||
@@ -50,6 +50,23 @@ def get_wopi_client_config(item, user):
|
||||
return result
|
||||
|
||||
|
||||
def get_wopi_client_proof_keys(item, user):
|
||||
"""get the wopi proof keys for an item"""
|
||||
wopi_client_config = get_wopi_client_config(item, user)
|
||||
|
||||
if not wopi_client_config:
|
||||
return None
|
||||
|
||||
wopi_configuration = get_wopi_configuration()
|
||||
|
||||
return wopi_configuration[wopi_client_config["client"]]["proof_keys"]
|
||||
|
||||
|
||||
def get_wopi_configuration():
|
||||
"""get the wopi configuration"""
|
||||
return cache.get(WOPI_CONFIGURATION_CACHE_KEY, default=WOPI_DEFAULT_CONFIGURATION)
|
||||
|
||||
|
||||
def compute_wopi_launch_url(launch_url, get_file_info_path, lang=None):
|
||||
"""
|
||||
Compute the WOPI launch URL for an item.
|
||||
|
||||
Reference in New Issue
Block a user