From b072ed5807459d6659a563403fe4d1fcc01da3d7 Mon Sep 17 00:00:00 2001 From: Anno van Vliet Date: Fri, 9 Aug 2024 16:55:14 +0200 Subject: [PATCH] Adding Admin setting page --- plugin.xml | 14 + pom.xml | 5 + src/i18n/httpfileupload_i18n.properties | 27 ++ .../httpfileupload/HttpFileUploadPlugin.java | 83 ++++-- src/web/WEB-INF/web.xml | 6 + src/web/httpfileupload-settings.jsp | 268 ++++++++++++++++++ 6 files changed, 382 insertions(+), 21 deletions(-) create mode 100644 src/web/WEB-INF/web.xml create mode 100644 src/web/httpfileupload-settings.jsp diff --git a/plugin.xml b/plugin.xml index 911eef6..47807e2 100644 --- a/plugin.xml +++ b/plugin.xml @@ -8,4 +8,18 @@ 2024-01-19 4.7.0 1.8 + true + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 8cf1b31..281c02e 100644 --- a/pom.xml +++ b/pom.xml @@ -54,6 +54,11 @@ maven-assembly-plugin + + + org.eclipse.jetty + jetty-jspc-maven-plugin + diff --git a/src/i18n/httpfileupload_i18n.properties b/src/i18n/httpfileupload_i18n.properties index 7d98945..de3a991 100644 --- a/src/i18n/httpfileupload_i18n.properties +++ b/src/i18n/httpfileupload_i18n.properties @@ -8,3 +8,30 @@ system_property.plugin.httpfileupload.clamavPort=Controls the port that is used system_property.plugin.httpfileupload.clamavConnectionTimeout=Controls the connection timeout that is used when integrating with an external (third-party) ClamAV malware scanner daemon. system_property.plugin.httpfileupload.fileRepo=Defines the file system path (directory) in which data is stored on the server. If the path is absent, or invalid, a temporary directory will be used. system_property.plugin.httpfileupload.maxFileSize=Defines the maximum size (in bytes) of files that can be uploaded. + +# admin page setting +httpfileupload.settings.title = Http File Upload Settings +httpfileupload.settings.success = Http File Upload Settings have been saved. +httpfileupload.settings.message.metadata.title = Upload Settings +httpfileupload.settings.message.metadata.description = +httpfileupload.settings.description = Use the form below to manage the Http File Upload settings. +httpfileupload.settings.cancel = Cancel +httpfileupload.settings.update.settings = Save +httpfileupload.settings.announcedProtocol.title=Announced Protocol +httpfileupload.settings.announcedWebHost.title=Announced Web Host +httpfileupload.settings.announcedPort.title=Announced TCP Port +httpfileupload.settings.announcedContextRoot.title=Announced Context root +httpfileupload.settings.fileRepo.title=File Directory +httpfileupload.settings.maxFileSize.title=Maximum File size + +httpfileupload.settings.logs.title=Web Binding Settings. +httpfileupload.settings.logs.description=File Uploads are shared through a web interface. +httpfileupload.settings.logs.redirect=The {0}HTTP Binding service{1} has to be used to change the actual port on which the Http File Upload service is hosted. If the external address is different for the external users, the values below should be adjusted. +httpfileupload.settings.logs.link.announced=File Uploads are shared through a external web interface at the following announced address: {0}. +httpfileupload.settings.logs.link.unsecure=The announced address is not the same as the internal address: {0}. This can be corrected by setting the proper values below. However, These values are ignored if XML properties ''plugin.httpfileupload.serverspecific'' are defined. +httpfileupload.settings.logs.link.secure=The announced address is not the same as the internal secure Web address: {0}. This can be corrected by setting the proper values below. However, These values are ignored if XML properties ''plugin.httpfileupload.serverspecific'' are defined. + +httpfileupload.sidebar.settings=Http File Upload Settings +httpfileupload.sidebar.settings.desc=Manage Http File Upload Settings. + +warning.httpbinding.disabled=The HTTP Binding service appears to be disabled! File Uploads will not be accessible without this service. {0}Please enable the HTTP Binding service here!{1} diff --git a/src/java/org/igniterealtime/openfire/plugins/httpfileupload/HttpFileUploadPlugin.java b/src/java/org/igniterealtime/openfire/plugins/httpfileupload/HttpFileUploadPlugin.java index 5187f24..36b3d74 100644 --- a/src/java/org/igniterealtime/openfire/plugins/httpfileupload/HttpFileUploadPlugin.java +++ b/src/java/org/igniterealtime/openfire/plugins/httpfileupload/HttpFileUploadPlugin.java @@ -15,10 +15,20 @@ */ package org.igniterealtime.openfire.plugins.httpfileupload; -import nl.goodbytes.xmpp.xep0363.*; -import nl.goodbytes.xmpp.xep0363.clamav.ClamavMalwareScanner; -import nl.goodbytes.xmpp.xep0363.repository.DirectoryRepository; -import nl.goodbytes.xmpp.xep0363.repository.TempDirectoryRepository; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + import org.apache.tomcat.InstanceManager; import org.apache.tomcat.SimpleInstanceManager; import org.eclipse.jetty.apache.jsp.JettyJasperInitializer; @@ -36,17 +46,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.IOException; -import java.nio.file.InvalidPathException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Duration; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import nl.goodbytes.xmpp.xep0363.Component; +import nl.goodbytes.xmpp.xep0363.MalwareScanner; +import nl.goodbytes.xmpp.xep0363.MalwareScannerManager; +import nl.goodbytes.xmpp.xep0363.Repository; +import nl.goodbytes.xmpp.xep0363.RepositoryManager; +import nl.goodbytes.xmpp.xep0363.SlotManager; +import nl.goodbytes.xmpp.xep0363.clamav.ClamavMalwareScanner; +import nl.goodbytes.xmpp.xep0363.repository.DirectoryRepository; +import nl.goodbytes.xmpp.xep0363.repository.TempDirectoryRepository; /** * Created by guus on 18-11-17. @@ -62,7 +70,7 @@ public class HttpFileUploadPlugin implements Plugin, PropertyEventListener * Unlike this (database-based) property, the XML property can be assigned different values on each server, which * can come in handy in an Openfire cluster. */ - private static final SystemProperty ANNOUNCED_WEB_PROTOCOL = SystemProperty.Builder.ofType(String.class) + public static final SystemProperty ANNOUNCED_WEB_PROTOCOL = SystemProperty.Builder.ofType(String.class) .setKey("plugin.httpfileupload.announcedWebProtocol") .setDefaultValue("https") .setDynamic(true) @@ -77,7 +85,7 @@ public class HttpFileUploadPlugin implements Plugin, PropertyEventListener * Unlike this (database-based) property, the XML property can be assigned different values on each server, which * can come in handy in an Openfire cluster. */ - private static final SystemProperty ANNOUNCED_WEB_HOST = SystemProperty.Builder.ofType(String.class) + public static final SystemProperty ANNOUNCED_WEB_HOST = SystemProperty.Builder.ofType(String.class) .setKey("plugin.httpfileupload.announcedWebHost") .setDefaultValue(XMPPServer.getInstance().getServerInfo().getHostname()) .setDynamic(true) @@ -92,7 +100,7 @@ public class HttpFileUploadPlugin implements Plugin, PropertyEventListener * Unlike this (database-based) property, the XML property can be assigned different values on each server, which * can come in handy in an Openfire cluster. */ - private static final SystemProperty ANNOUNCED_WEB_PORT = SystemProperty.Builder.ofType(Integer.class) + public static final SystemProperty ANNOUNCED_WEB_PORT = SystemProperty.Builder.ofType(Integer.class) .setKey("plugin.httpfileupload.announcedWebPort") .setDefaultValue(HttpBindManager.HTTP_BIND_SECURE_PORT.getValue()) .setDynamic(true) @@ -107,7 +115,7 @@ public class HttpFileUploadPlugin implements Plugin, PropertyEventListener * Unlike this (database-based) property, the XML property can be assigned different values on each server, which * can come in handy in an Openfire cluster. */ - private static final SystemProperty ANNOUNCED_WEB_CONTEXT_ROOT = SystemProperty.Builder.ofType(String.class) + public static final SystemProperty ANNOUNCED_WEB_CONTEXT_ROOT = SystemProperty.Builder.ofType(String.class) .setKey("plugin.httpfileupload.announcedWebContextRoot") .setDefaultValue("/httpfileupload") .setDynamic(false) @@ -121,7 +129,7 @@ public class HttpFileUploadPlugin implements Plugin, PropertyEventListener * Unlike this (database-based) property, the XML property can be assigned different values on each server, which * can come in handy in an Openfire cluster. */ - private static final SystemProperty MAX_FILE_SIZE = SystemProperty.Builder.ofType(Long.class) + public static final SystemProperty MAX_FILE_SIZE = SystemProperty.Builder.ofType(Long.class) .setKey("plugin.httpfileupload.maxFileSize") .setDefaultValue(SlotManager.DEFAULT_MAX_FILE_SIZE) .setDynamic(true) @@ -137,7 +145,7 @@ public class HttpFileUploadPlugin implements Plugin, PropertyEventListener * Unlike this (database-based) property, the XML property can be assigned different values on each server, which * can come in handy in an Openfire cluster. */ - private static final SystemProperty FILE_REPO = SystemProperty.Builder.ofType(String.class) + public static final SystemProperty FILE_REPO = SystemProperty.Builder.ofType(String.class) .setKey("plugin.httpfileupload.fileRepo") .setDynamic(false) .setPlugin("HTTP File Upload") @@ -478,6 +486,39 @@ public void destroyPlugin() PropertyEventDispatcher.removeListener(this); } + + public void check(String fileRepo ) throws IOException { + try { + final Path path = Paths.get( fileRepo ); + + if ( !path.toFile().exists() ) { + throw new IOException("Path '" + path + "' does not exists"); + } + if ( !path.toFile().isDirectory() ) { + throw new IOException("Path '" + path + "' not a directory"); + } + if ( !path.toFile().canWrite() ) { + throw new IOException("Path '" + path + "' not writable"); + } + + } catch ( InvalidPathException e ) { + throw new IOException( "Invalid value '" + fileRepo + "': " + e.getMessage() ); + } + } + + public String getAnnouncedAddress() throws URISyntaxException { + + final URI uri = new URI( + getWebProtocolFromProperties(), + null, // userinfo + getWebHostFromProperties(), + getWebPortFromProperties(), + getWebContextRootFromProperties(), + null, // query + null // fragment + ); + return uri.toASCIIString(); + } @Override public void propertySet(String property, Map params) { diff --git a/src/web/WEB-INF/web.xml b/src/web/WEB-INF/web.xml new file mode 100644 index 0000000..5fae1f0 --- /dev/null +++ b/src/web/WEB-INF/web.xml @@ -0,0 +1,6 @@ + + + diff --git a/src/web/httpfileupload-settings.jsp b/src/web/httpfileupload-settings.jsp new file mode 100644 index 0000000..2f65335 --- /dev/null +++ b/src/web/httpfileupload-settings.jsp @@ -0,0 +1,268 @@ +<%@page import="java.net.URI"%> +<%@page import="java.net.URISyntaxException"%> +<%@page import="java.io.IOException"%> +<%@ page contentType="text/html; charset=UTF-8" %> +<%@ page errorPage="/error.jsp" %> +<%@ page import="org.igniterealtime.openfire.plugins.httpfileupload.HttpFileUploadPlugin"%> +<%@ page import="org.jivesoftware.openfire.http.HttpBindManager" %> +<%@ page import="org.jivesoftware.util.ParamUtils" %> +<%@ page import="org.jivesoftware.openfire.XMPPServer" %> +<%@ page import="org.jivesoftware.util.StringUtils" %> +<%@ page import="org.jivesoftware.util.CookieUtils" %> +<%@ page import="org.jivesoftware.util.ParamUtils" %> +<%@ page import="java.time.Duration" %> +<%@ page import="java.util.HashMap" %> +<%@ page import="java.util.Map" %> +<%@ page import="java.util.Optional" %> + +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> + +<% webManager.init(request, response, session, application, out ); %> +<% + // Get handle on the HttpFileUpload plugin + HttpFileUploadPlugin plugin = (HttpFileUploadPlugin) XMPPServer.getInstance().getPluginManager().getPluginByName("HTTP File Upload").get(); + +%> + + + + <fmt:message key="httpfileupload.settings.title"/> + + + + + + +<% // Get parameters + boolean update = request.getParameter("update") != null; + + Map errors = new HashMap<>(); + String errorMessage = ""; + + if (request.getParameter("cancel") != null) { + response.sendRedirect("httpfileupload-settings.jsp"); + return; + } + + String fileRepo = Optional.ofNullable( HttpFileUploadPlugin.FILE_REPO.getValue()).orElse(""); + + String announcedAddress = "unknown"; + try { + announcedAddress = plugin.getAnnouncedAddress(); + } catch (URISyntaxException e) { + errors.put("announcedAddress" , e.getMessage() ); + errorMessage = "Announced Address is not correct: " + e.getMessage(); + } + + // Update the session kick policy if requested + if (request.getMethod().equals("POST") && update) { + // New settings for message archiving. + String announcedProtocol = request.getParameter("announcedProtocol"); + String announcedWebHost = request.getParameter("announcedWebHost"); + Integer announcedPort = ParamUtils.getIntParameter(request, "announcedPort", HttpFileUploadPlugin.ANNOUNCED_WEB_PORT.getValue()); + String announcedContextRoot = request.getParameter("announcedContextRoot"); + long maxFileSize = ParamUtils.getLongParameter(request, "maxFileSize", HttpFileUploadPlugin.MAX_FILE_SIZE.getValue()); + fileRepo = request.getParameter("fileRepo"); + + if ( fileRepo != null && !fileRepo.equals("") ) { + try { + plugin.check(fileRepo); + } catch ( IOException e ) { + errors.put("fileRepo" , e.getMessage() ); + errorMessage = "File Directory not correct: " + e.getMessage(); + } + } + + try { + final URI uri = new URI( + announcedProtocol, + null, // userinfo + announcedWebHost, + announcedPort, + announcedContextRoot, + null, // query + null // fragment + ); + announcedAddress = uri.toASCIIString(); + errors.remove("announcedAddress"); + } catch (URISyntaxException e) { + errors.put("announcedAddress" , e.getMessage() ); + errorMessage = "Announced Address is not correct: " + e.getMessage(); + } + + // If no errors, continue: + if (errors.size() == 0) { + HttpFileUploadPlugin.ANNOUNCED_WEB_PROTOCOL.setValue(announcedProtocol); + HttpFileUploadPlugin.ANNOUNCED_WEB_HOST.setValue(announcedWebHost); + HttpFileUploadPlugin.ANNOUNCED_WEB_PORT.setValue(announcedPort); + HttpFileUploadPlugin.ANNOUNCED_WEB_CONTEXT_ROOT.setValue(announcedContextRoot); + HttpFileUploadPlugin.FILE_REPO.setValue(fileRepo); + HttpFileUploadPlugin.MAX_FILE_SIZE.setValue(maxFileSize); + + webManager.logEvent("Changed HTTP File Upload settings (httpfileupload plugin)", + "announced Protocol: " + announcedProtocol + + ", announced Web Host: " + announcedWebHost + + ", announced Port: " + announcedPort + + ", announced Context Root: " + announcedContextRoot + + ", File Directory: " + fileRepo + + ", maxFileSize: " + maxFileSize ); + +%> +
+ +

+<% + } + } +%> + +<% if (errors.size() > 0) { %> +
+ <%= errorMessage%> +
+
+<% } %> + +

+ +

+ + <% if ( ! HttpBindManager.getInstance().isHttpBindEnabled() ) { %> + +
+ + + + + +
+ + "/> + + +
+

+ <% } %> +
+
+

+ + + +

+ + <% + if ( HttpFileUploadPlugin.ANNOUNCED_WEB_PROTOCOL.getValue().equals("https") ) { + + final String securedAddress = "https://" + XMPPServer.getInstance().getServerInfo().getHostname() + ":" + HttpBindManager.HTTP_BIND_SECURE_PORT.getValue() + "/httpfileupload"; + + if ( !announcedAddress.equals(securedAddress)) { %> +
+ + + +
+ <% } + } else { + + final String unsecuredAddress = "http://" + XMPPServer.getInstance().getServerInfo().getHostname() + ":" + HttpBindManager.HTTP_BIND_PORT.getValue() + "/httpfileupload"; + + if ( !announcedAddress.equals(unsecuredAddress) ) { %> +
+ + + +
+ <% } + } + %> + +

+ "/> + +

+
+ +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+ + "> + "> + +
+ + +