Search in sources :

Example 1 with RequestWrapper

use of net.i2p.servlet.RequestWrapper in project i2p.i2p by i2p.

the class WebMail method processRequest.

// // Start request handling here ////
/**
 * The entry point for all web page loads
 *
 * @param httpRequest
 * @param response
 * @param isPOST disallow button pushes if false
 * @throws IOException
 * @throws ServletException
 */
private void processRequest(HttpServletRequest httpRequest, HttpServletResponse response, boolean isPOST) throws IOException, ServletException {
    I2PAppContext ctx = I2PAppContext.getGlobalContext();
    // Fetch routerconsole theme (or use our default if it doesn't exist)
    String theme = ctx.getProperty(RC_PROP_THEME, DEFAULT_THEME);
    // Apply any override
    theme = Config.getProperty(CONFIG_THEME, theme);
    boolean universalTheming = ctx.getBooleanProperty(RC_PROP_UNIVERSAL_THEMING);
    if (universalTheming) {
        // Fetch routerconsole theme (or use our default if it doesn't exist)
        theme = ctx.getProperty(RC_PROP_THEME, DEFAULT_THEME);
        // Ensure that theme exists
        String[] themes = getThemes();
        boolean themeExists = false;
        for (int i = 0; i < themes.length; i++) {
            if (themes[i].equals(theme))
                themeExists = true;
        }
        if (!themeExists) {
            theme = DEFAULT_THEME;
        }
    }
    boolean forceMobileConsole = ctx.getBooleanProperty(RC_PROP_FORCE_MOBILE_CONSOLE);
    boolean isMobile = (forceMobileConsole || isMobile(httpRequest.getHeader("User-Agent")));
    httpRequest.setCharacterEncoding("UTF-8");
    response.setCharacterEncoding("UTF-8");
    response.setHeader("X-Frame-Options", "SAMEORIGIN");
    response.setHeader("Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'");
    response.setHeader("X-XSS-Protection", "1; mode=block");
    response.setHeader("X-Content-Type-Options", "nosniff");
    response.setHeader("Referrer-Policy", "no-referrer");
    response.setHeader("Accept-Ranges", "none");
    RequestWrapper request = new RequestWrapper(httpRequest);
    SessionObject sessionObject = null;
    String subtitle = "";
    HttpSession httpSession = request.getSession(true);
    sessionObject = getSessionObject(httpSession);
    synchronized (sessionObject) {
        sessionObject.error = "";
        sessionObject.info = "";
        sessionObject.pageChanged = false;
        sessionObject.themePath = "/themes/susimail/" + theme + '/';
        sessionObject.imgPath = sessionObject.themePath + "images/";
        sessionObject.isMobile = isMobile;
        if (isPOST) {
            try {
                String nonce = request.getParameter(SUSI_NONCE);
                if (nonce == null || !sessionObject.isValidNonce(nonce)) {
                    // These two strings are already in the router console FormHandler,
                    // so translate with that bundle.
                    sessionObject.error += consoleGetString("Invalid form submission, probably because you used the 'back' or 'reload' button on your browser. Please resubmit.", ctx) + '\n' + consoleGetString("If the problem persists, verify that you have cookies enabled in your browser.", ctx) + '\n';
                    isPOST = false;
                }
            } catch (IllegalStateException ise) {
                // too big, can't get any parameters
                sessionObject.error += ise.getMessage() + '\n';
                isPOST = false;
            }
        }
        // // Start state determination and button processing
        State state = null;
        if (sessionObject.mailbox == null) {
            state = State.AUTH;
        } else if (isPOST) {
            // This must be called to add the attachment before
            // processStateChangeButtons() sends the message
            state = processComposeButtons(sessionObject, request);
        }
        state = processStateChangeButtons(sessionObject, request, isPOST, state);
        state = processConfigButtons(sessionObject, request, isPOST, state);
        Debug.debug(Debug.DEBUG, "Prelim. state is " + state);
        if (state == State.CONFIG) {
            if (isPOST) {
                // P-R-G
                String q = '?' + CONFIGURE;
                sendRedirect(httpRequest, response, q);
                return;
            }
        }
        if (state == State.LOADING) {
            if (isPOST) {
                sendRedirect(httpRequest, response, null);
                return;
            }
        }
        if (state != State.AUTH) {
            if (isPOST)
                state = processGenericButtons(sessionObject, request, state);
        }
        if (state == State.LIST) {
            if (isPOST) {
                int page = 1;
                String sp = request.getParameter(CUR_PAGE);
                if (sp != null) {
                    try {
                        page = Integer.parseInt(sp);
                    } catch (NumberFormatException nfe) {
                    }
                }
                int newPage = processFolderButtons(sessionObject, page, request);
                // REFRESH on list page
                if (newPage != page || buttonPressed(request, LIST) || buttonPressed(request, SEND) || buttonPressed(request, CANCEL) || buttonPressed(request, REFRESH) || buttonPressed(request, LOGIN) || buttonPressed(request, OFFLINE)) {
                    // P-R-G
                    String q = '?' + CUR_PAGE + '=' + newPage;
                    // CURRENT_SORT is only in page POSTs
                    String str = request.getParameter(CURRENT_SORT);
                    if (str != null && !str.equals(SORT_DEFAULT) && VALID_SORTS.contains(str))
                        q += "&sort=" + str;
                    sendRedirect(httpRequest, response, q);
                    return;
                }
            }
        }
        // ?show= links - this forces State.SHOW
        String b64UIDL = request.getParameter(SHOW);
        // attachment links, images, next/prev/delete on show form
        if (b64UIDL == null)
            b64UIDL = request.getParameter(B64UIDL);
        String showUIDL = Base64.decodeToString(b64UIDL);
        if (state == State.SHOW) {
            if (isPOST) {
                String newShowUIDL = processMessageButtons(sessionObject, showUIDL, request);
                if (newShowUIDL == null) {
                    state = State.LIST;
                    showUIDL = null;
                } else if (!newShowUIDL.equals(showUIDL) || buttonPressed(request, SEND) || buttonPressed(request, CANCEL)) {
                    // SEND and CANCEL are from NEW page
                    // P-R-G
                    String q;
                    if (newShowUIDL.equals(DELETE))
                        q = '?' + DELETE + "=1&" + SHOW + '=' + Base64.encode(showUIDL);
                    else
                        q = '?' + SHOW + '=' + Base64.encode(newShowUIDL);
                    sendRedirect(httpRequest, response, q);
                    return;
                }
            }
            // ?download=nnn&amp;b64uidl link (same for ?att) should be valid in any state
            if (showUIDL != null && processDownloadLink(sessionObject, showUIDL, request, response)) {
                // download or raw view sent, or 404
                return;
            }
            if (isPOST && showUIDL != null && processSaveAsLink(sessionObject, showUIDL, request, response)) {
                // download sent, or 404
                return;
            }
            // sessionObject.showUIDL = null
            if (showUIDL != null) {
                Mail mail = sessionObject.mailCache.getMail(showUIDL, MailCache.FetchMode.ALL);
                if (mail != null && mail.error.length() > 0) {
                    sessionObject.error += mail.error;
                    mail.error = "";
                }
            } else {
                // can't SHOW without a UIDL
                state = State.LIST;
            }
        }
        /*
			 * update folder content
			 * We need a valid and sorted folder for SHOW also, for the previous/next buttons
			 */
        Folder<String> folder = sessionObject.folder;
        // folder could be null after an error, we can't proceed if it is
        if (folder == null && (state == State.LIST || state == State.SHOW)) {
            sessionObject.error += "Internal error, no folder\n";
            state = State.AUTH;
        }
        // // End state determination, state will not change after here
        Debug.debug(Debug.DEBUG, "Final state is " + state);
        if (state == State.LIST || state == State.SHOW) {
            // sort buttons are GETs
            String oldSort = folder.getCurrentSortBy();
            SortOrder oldOrder = folder.getCurrentSortingDirection();
            processSortingButtons(sessionObject, request);
            if (state == State.LIST) {
                for (Iterator<String> it = sessionObject.folder.currentPageIterator(); it != null && it.hasNext(); ) {
                    String uidl = it.next();
                    Mail mail = sessionObject.mailCache.getMail(uidl, MailCache.FetchMode.HEADER);
                    if (mail != null && mail.error.length() > 0) {
                        sessionObject.error += mail.error;
                        mail.error = "";
                    }
                }
            }
            // get through cache so we have the disk-only ones too
            String[] uidls = sessionObject.mailCache.getUIDLs();
            if (folder.addElements(Arrays.asList(uidls)) > 0) {
            // we added elements, so it got sorted
            } else {
                // check for changed sort
                String curSort = folder.getCurrentSortBy();
                SortOrder curOrder = folder.getCurrentSortingDirection();
                if (oldOrder != curOrder || !oldSort.equals(curSort))
                    folder.sort();
            }
        }
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        // // Begin output
        PrintWriter out = response.getWriter();
        /*
				 * build subtitle
				 */
        if (state == State.AUTH) {
            subtitle = _t("Login");
        } else if (state == State.LOADING) {
            subtitle = _t("Loading emails, please wait...");
        } else if (state == State.LIST) {
            // mailbox.getNumMails() forces a connection, don't use it
            // Not only does it slow things down, but a failure causes all our messages to "vanish"
            // subtitle = ngettext("1 Message", "{0} Messages", sessionObject.mailbox.getNumMails());
            subtitle = ngettext("1 Message", "{0} Messages", folder.getSize());
        } else if (state == State.SHOW) {
            Mail mail = showUIDL != null ? sessionObject.mailCache.getMail(showUIDL, MailCache.FetchMode.HEADER) : null;
            if (mail != null && mail.hasHeader()) {
                if (mail.shortSubject != null)
                    // already HTML encoded
                    subtitle = mail.shortSubject;
                else
                    subtitle = _t("Show Message");
            } else {
                subtitle = _t("Message not found.");
            }
        } else if (state == State.NEW) {
            subtitle = _t("New Message");
        } else if (state == State.CONFIG) {
            subtitle = _t("Configuration");
        }
        response.setContentType("text/html");
        /*
				 * write header
				 */
        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n" + "<head>\n" + "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n" + "<title>" + _t("SusiMail") + " - " + subtitle + "</title>\n" + "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + sessionObject.themePath + "susimail.css?" + CoreVersion.VERSION + "\">");
        if (sessionObject.isMobile) {
            out.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=2.0, user-scalable=yes\" />\n" + "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + sessionObject.themePath + "mobile.css?" + CoreVersion.VERSION + "\" />");
        }
        if (state != State.AUTH)
            out.println("<link rel=\"stylesheet\" href=\"/susimail/css/print.css?" + CoreVersion.VERSION + "\" type=\"text/css\" media=\"print\" />");
        if (state == State.NEW || state == State.CONFIG) {
            // TODO cancel if to and body are empty
            out.println("<script src=\"/susimail/js/compose.js?" + CoreVersion.VERSION + "\" type=\"text/javascript\"></script>");
        } else if (state == State.LIST) {
            out.println("<script src=\"/susimail/js/folder.js?" + CoreVersion.VERSION + "\" type=\"text/javascript\"></script>");
        } else if (state == State.LOADING) {
            // TODO JS?
            out.println("<meta http-equiv=\"refresh\" content=\"5;url=" + myself + "\">");
        // TODO we don't need the form below
        }
        out.print("</head>\n<body" + (state == State.LIST ? " onload=\"deleteboxclicked()\">" : ">"));
        String nonce = state == State.AUTH ? LOGIN_NONCE : Long.toString(ctx.random().nextLong());
        sessionObject.addNonce(nonce);
        out.println("<div class=\"page\"><div class=\"header\"><img class=\"header\" src=\"" + sessionObject.imgPath + "susimail.png\" alt=\"Susimail\"></div>\n" + "<form method=\"POST\" enctype=\"multipart/form-data\" action=\"" + myself + "\" accept-charset=\"UTF-8\">\n" + "<input type=\"hidden\" name=\"" + SUSI_NONCE + "\" value=\"" + nonce + "\">\n" + // we use this to know if the user thought he was logged in at the time
        "<input type=\"hidden\" name=\"" + DEBUG_STATE + "\" value=\"" + state + "\">");
        if (state == State.SHOW || state == State.NEW) {
            // Store the reference UIDL on the compose form also
            if (showUIDL != null) {
                // reencode, as showUIDL may have changed, and also for XSS
                b64UIDL = Base64.encode(showUIDL);
                out.println("<input type=\"hidden\" name=\"" + B64UIDL + "\" value=\"" + b64UIDL + "\">");
            } else if (state == State.NEW) {
                // for NEW, try to get back to the current page if we weren't replying
                int page = 1;
                String sp = request.getParameter(CUR_PAGE);
                if (sp != null) {
                    try {
                        page = Integer.parseInt(sp);
                    } catch (NumberFormatException nfe) {
                    }
                }
                out.println("<input type=\"hidden\" name=\"" + CUR_PAGE + "\" value=\"" + page + "\">");
            }
        }
        if (state == State.SHOW || state == State.NEW || state == State.LIST) {
            // Save sort order in case it changes later
            String curSort = folder.getCurrentSortBy();
            SortOrder curOrder = folder.getCurrentSortingDirection();
            // UP is reverse sort. DOWN is normal sort.
            String fullSort = curOrder == SortOrder.UP ? '-' + curSort : curSort;
            out.println("<input type=\"hidden\" name=\"" + CURRENT_SORT + "\" value=\"" + fullSort + "\">");
            out.println("<input type=\"hidden\" name=\"" + CURRENT_FOLDER + "\" value=\"" + PersistentMailCache.DIR_FOLDER + "\">");
        }
        boolean showRefresh = false;
        if (sessionObject.isLoading) {
            sessionObject.info += _t("Loading emails, please wait...") + '\n';
            showRefresh = true;
        }
        if (sessionObject.isFetching) {
            sessionObject.info += _t("Checking for new emails on server") + '\n';
            showRefresh = true;
        } else if (state != State.LOADING && state != State.AUTH && state != State.CONFIG) {
            String error = sessionObject.connectError;
            if (error != null && error.length() > 0) {
                sessionObject.error += error + '\n';
                sessionObject.connectError = null;
            }
            int added = sessionObject.newMails;
            if (added > 0) {
                sessionObject.info += ngettext("{0} new message", "{0} new messages", added) + '\n';
                sessionObject.newMails = -1;
            } else if (added == 0) {
                sessionObject.info += _t("No new messages") + '\n';
                sessionObject.newMails = -1;
            }
        }
        if (showRefresh) {
            sessionObject.info += _t("Refresh the page for updates") + '\n';
        }
        if (sessionObject.error.length() > 0 || sessionObject.info.length() > 0) {
            out.println("<div class=\"notifications\" onclick=\"this.remove()\">");
            if (sessionObject.error.length() > 0)
                out.println("<p class=\"error\">" + quoteHTML(sessionObject.error).replace("\n", "<br>") + "</p>");
            if (sessionObject.info.length() > 0)
                out.println("<p class=\"info\"><b>" + quoteHTML(sessionObject.info).replace("\n", "<br>") + "</b></p>");
            out.println("</div>");
        }
        /*
				 * now write body
				 */
        if (state == State.AUTH)
            showLogin(out);
        else if (state == State.LOADING)
            showLoading(out, sessionObject, request);
        else if (state == State.LIST)
            showFolder(out, sessionObject, request);
        else if (state == State.SHOW)
            showMessage(out, sessionObject, showUIDL, buttonPressed(request, DELETE));
        else if (state == State.NEW)
            showCompose(out, sessionObject, request);
        else if (state == State.CONFIG)
            showConfig(out, sessionObject);
        // out.println( "</form><div id=\"footer\"><hr><p class=\"footer\">susimail v0." + version +" " + ( RELEASE ? "release" : "development" ) + " &copy; 2004-2005 <a href=\"mailto:susi23@mail.i2p\">susi</a></div></div></body>\n</html>");
        out.println("</form><div class=\"footer\"><p class=\"footer\">susimail &copy; 2004-2005 susi</p></div></div></body>\n</html>");
        out.flush();
    }
// synch sessionObject
}
Also used : I2PAppContext(net.i2p.I2PAppContext) HttpSession(javax.servlet.http.HttpSession) SortOrder(i2p.susi.util.Folder.SortOrder) RequestWrapper(net.i2p.servlet.RequestWrapper) PrintWriter(java.io.PrintWriter)

Aggregations

SortOrder (i2p.susi.util.Folder.SortOrder)1 PrintWriter (java.io.PrintWriter)1 HttpSession (javax.servlet.http.HttpSession)1 I2PAppContext (net.i2p.I2PAppContext)1 RequestWrapper (net.i2p.servlet.RequestWrapper)1