<%@ page errorPage="error.jsp"%>
<%@ page import="java.util.Map" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="org.jivesoftware.openfire.spi.ConnectionType" %>
<%@ page import="org.jivesoftware.openfire.XMPPServer" %>
<%@ page import="org.jivesoftware.openfire.keystore.CertificateStoreManager" %>
<%@ page import="org.jivesoftware.openfire.keystore.CertificateStoreConfiguration" %>
<%@ page import="java.io.File" %>
<%@ page import="org.jivesoftware.util.Log" %>
<%@ page import="org.jivesoftware.util.CookieUtils" %>
<%@ page import="org.jivesoftware.util.ParamUtils" %>
<%@ page import="org.jivesoftware.util.StringUtils" %>
<%@ taglib uri="admin" prefix="admin" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

<jsp:useBean id="webManager" class="org.jivesoftware.util.WebManager" />
<jsp:useBean id="now" class="java.util.Date"/>
<%  webManager.init(request, response, session, application, out );

    final CertificateStoreManager certificateStoreManager = XMPPServer.getInstance().getCertificateStoreManager();

    final Map<String, String> errors = new HashMap<>();
    pageContext.setAttribute( "errors", errors );

    // OF-1415: Show distinct boxes for all connection types, but only when their configuration differs!
    boolean showAll = false;
    CertificateStoreConfiguration identityStoreConfiguration = null;
    CertificateStoreConfiguration trustStoreConfiguration = null;
    for ( ConnectionType connectionType : ConnectionType.values() )
    {
        if ( identityStoreConfiguration == null )
        {
            identityStoreConfiguration = certificateStoreManager.getIdentityStoreConfiguration( connectionType );
        }
        if ( !identityStoreConfiguration.equals( certificateStoreManager.getIdentityStoreConfiguration( connectionType ) ) )
        {
            showAll = true;
            break;
        }
        if ( trustStoreConfiguration == null )
        {
            trustStoreConfiguration = certificateStoreManager.getTrustStoreConfiguration( connectionType );
        }
        if ( !trustStoreConfiguration.equals( certificateStoreManager.getTrustStoreConfiguration( connectionType ) ) )
        {
            showAll = true;
            break;
        }
    }

    pageContext.setAttribute( "connectionTypes", showAll ? ConnectionType.values() : "COMBINED" );
    pageContext.setAttribute( "certificateStoreManager", certificateStoreManager );

    boolean update = request.getParameter("update") != null;
    Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
    String csrfParam = ParamUtils.getParameter(request, "csrf");

    if (update) {
        if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
            update = false;
            errors.put("csrf", "CSRF Failure!");
        }
    }
    csrfParam = StringUtils.randomString(15);
    CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
    pageContext.setAttribute("csrf", csrfParam);
    if ( update ) {
        ConnectionType connectionType = null;
        try {
            connectionType = ConnectionType.valueOf( request.getParameter( "connectionType" ) );
        } catch ( IllegalArgumentException ex ) {
            Log.warn( ex );
            errors.put( "connectionType", ex.getMessage() );
        }

        final String locKey = request.getParameter( "loc-key" );
        final String pwdKey = request.getParameter( "pwd-key" );
        final String locTrust = request.getParameter( "loc-trust" );
        final String pwdTrust = request.getParameter( "pwd-trust" );

        if ( locKey == null || locKey.isEmpty() ) {
            errors.put( "locKey", "Identity Store location must be defined." );
        }
        if ( pwdKey == null || pwdKey.isEmpty() ) {
            errors.put( "pwdKey", "Identity Store password must be defined." );
        }
        if ( locTrust == null || locTrust.isEmpty() ) {
            errors.put( "locTrust", "Trust Store location must be defined." );
        }
        if ( pwdTrust == null || pwdTrust.isEmpty() ) {
            errors.put( "pwdTrust", "Trust Store password must be defined." );
        }

        if ( errors.isEmpty() ) {
            try
            {
                final CertificateStoreConfiguration configKey = new CertificateStoreConfiguration( "jks", new File( locKey ), pwdKey.toCharArray() );
                final CertificateStoreConfiguration configTrust = new CertificateStoreConfiguration( "jks", new File( locTrust ), pwdTrust.toCharArray() );
                certificateStoreManager.replaceIdentityStore( connectionType, configKey, false );
                certificateStoreManager.replaceTrustStore( connectionType, configTrust, false );
                pageContext.setAttribute( "updated", true );
            } catch ( Exception ex ) {
                Log.warn( ex );
                errors.put( "update", ex.getMessage() );
            }
        }
    }
%>
<html>
<head>
    <title><fmt:message key="ssl.certificates.store-management.title"/></title>
    <meta name="pageID" content="security-certificate-store-management"/>
</head>
<body>

<c:forEach var="err" items="${errors}">
    <admin:infobox type="error">
        <c:choose>
            <c:when test="${err.key eq 'template'}">
                <fmt:message key="admin.error"/>
            </c:when>
            <c:otherwise>
                <c:if test="${not empty err.value}">
                    <fmt:message key="admin.error"/>: <c:out value="${err.value}"/>
                </c:if>
                (<c:out value="${err.key}"/>)
            </c:otherwise>
        </c:choose>
    </admin:infobox>
</c:forEach>

<!-- Display success report, but only if there were no errors. -->
<c:if test="${updated and empty errors}">
    <admin:infoBox type="success">
        <fmt:message key="ssl.certificates.store-management.saved_successfully"/>
    </admin:infoBox>
</c:if>

<p>
    <fmt:message key="ssl.certificates.store-management.info-1"/>
</p>
<p>
    <fmt:message key="ssl.certificates.store-management.info-2"/>
</p>
<p>
<fmt:message key="ssl.certificates.store-management.info-3"/></p>

<c:forEach items="${connectionTypes}" var="connectionType">

    <c:set var="title">
        <c:choose>
            <c:when test="${connectionType eq 'COMBINED'}"><fmt:message key="ssl.certificates.store-management.combined-stores.title"/></c:when>
            <c:when test="${connectionType eq 'SOCKET_C2S'}"><fmt:message key="ssl.certificates.store-management.socket-c2s-stores.title"/></c:when>
            <c:when test="${connectionType eq 'SOCKET_S2S'}"><fmt:message key="ssl.certificates.store-management.socket-s2s-stores.title"/></c:when>
            <c:when test="${connectionType eq 'BOSH_C2S'}"><fmt:message key="ssl.certificates.store-management.bosh-c2s-stores.title"/></c:when>
            <c:when test="${connectionType eq 'WEBADMIN'}"><fmt:message key="ssl.certificates.store-management.admin-console-stores.title"/></c:when>
            <c:when test="${connectionType eq 'COMPONENT'}"><fmt:message key="ssl.certificates.store-management.component-stores.title"/></c:when>
            <c:when test="${connectionType eq 'CONNECTION_MANAGER'}"><fmt:message key="ssl.certificates.store-management.connection-manager-stores.title"/></c:when>
        </c:choose>
    </c:set>

    <c:set var="description">
        <c:choose>
            <c:when test="${connectionType eq 'COMBINED'}"><fmt:message key="ssl.certificates.store-management.combined-stores.info"/></c:when>
            <c:when test="${connectionType eq 'SOCKET_C2S'}"><fmt:message key="ssl.certificates.store-management.socket-c2s-stores.info"/></c:when>
            <c:when test="${connectionType eq 'SOCKET_S2S'}"><fmt:message key="ssl.certificates.store-management.socket-s2s-stores.info"/></c:when>
            <c:when test="${connectionType eq 'BOSH_C2S'}"><fmt:message key="ssl.certificates.store-management.bosh-c2s-stores.info"/></c:when>
            <c:when test="${connectionType eq 'WEBADMIN'}"><fmt:message key="ssl.certificates.store-management.admin-console-stores.info"/></c:when>
            <c:when test="${connectionType eq 'COMPONENT'}"><fmt:message key="ssl.certificates.store-management.component-stores.info"/></c:when>
            <c:when test="${connectionType eq 'CONNECTION_MANAGER'}"><fmt:message key="ssl.certificates.store-management.connection-manager-stores.info"/></c:when>
        </c:choose>
    </c:set>

    <!-- All connection types share the same config. Pick an arbitrary one to work with. -->
    <c:if test="${connectionType eq 'COMBINED'}">
        <c:set var="connectionType">SOCKET_C2S</c:set>
    </c:if>

    <form action="security-certificate-store-management.jsp" method="post">
        <input type="hidden" name="csrf" value="${csrf}">
        <input type="hidden" name="connectionType" value="${connectionType}"/>

        <admin:contentBox title="${title}">
            <p>
                <c:out value="${description}"/>
            </p>

            <h4><fmt:message key="ssl.certificates.identity-store"/></h4>

            <c:if test="${empty certificateStoreManager.getIdentityStore(connectionType)}">
                <admin:infobox type="warning"><fmt:message key="ssl.certificates.store-management.error.cannot-access"/></admin:infobox>
            </c:if>

            <c:set var="pwdKey" value=""/>
            <c:forEach items="${certificateStoreManager.getIdentityStoreConfiguration(connectionType).password}" var="c">
                <c:set var="pwdKey" value="${pwdKey}${c}"/>
            </c:forEach>

            <table cellpadding="0" cellspacing="0" border="0">
                <tbody>
                <tr>
                    <td><label for="loc-key"><fmt:message key="ssl.certificates.store-management.file_label"/>:</label></td>
                    <td><input id="loc-key" name="loc-key" type="text" size="80" value="${certificateStoreManager.getIdentityStoreConfiguration(connectionType).file}"/></td>
                </tr>
                <tr>
                    <td><label for="pwd-key"><fmt:message key="ssl.certificates.store-management.password_label"/>:</label></td>
                    <td><input id="pwd-key" name="pwd-key" type="password" size="30" value="${pwdKey}"/></td>
                </tr>
                <tr>
                    <td>&nbsp;</td>
                    <td><a href="security-keystore.jsp?connectionType=${connectionType}"><fmt:message key="ssl.certificates.store-management.manage"/></a></td>
                </tr>
                </tbody>
            </table>

            <br/>
            <h4><fmt:message key="ssl.certificates.trust-store"/></h4>

            <c:if test="${empty certificateStoreManager.getTrustStore(connectionType)}">
                <admin:infobox type="warning"><fmt:message key="ssl.certificates.store-management.error.cannot-access"/></admin:infobox>
            </c:if>

            <c:set var="pwdTrust" value=""/>
            <c:forEach items="${certificateStoreManager.getTrustStoreConfiguration(connectionType).password}" var="c">
                <c:set var="pwdTrust" value="${pwdTrust}${c}"/>
            </c:forEach>

            <table cellpadding="0" cellspacing="0" border="0">
                <tbody>
                <tr>
                    <td><label for="loc-trust"><fmt:message key="ssl.certificates.store-management.file_label"/>:</label></td>
                    <td><input id="loc-trust" name="loc-trust" type="text" size="80" value="${certificateStoreManager.getTrustStoreConfiguration(connectionType).file}"/></td>
                </tr>
                <tr>
                    <td><label for="pwd-trust"><fmt:message key="ssl.certificates.store-management.password_label"/>:</label></td>
                    <td><input id="pwd-trust" name="pwd-trust" type="password" size="30" value="${pwdTrust}"/></td>
                </tr>
                <tr>
                    <td>&nbsp;</td>
                    <td><a href="security-truststore.jsp?connectionType=${connectionType}"><fmt:message key="ssl.certificates.store-management.manage"/></a></td>
                </tr>
                </tbody>
            </table>

            <br/>
            <input type="submit" name="update" value="<fmt:message key="global.save_settings" />">

        </admin:contentBox>

    </form>

</c:forEach>

</body>
</html>
