Package hudson.console

Source Code of hudson.console.AnnotatedLargeText

/*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.console;

import com.trilead.ssh2.crypto.Base64;
import jenkins.model.Jenkins;
import hudson.remoting.ObjectInputStreamEx;
import hudson.util.IOException2;
import hudson.util.Secret;
import hudson.util.TimeUnit2;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.framework.io.ByteBuffer;
import org.kohsuke.stapler.framework.io.LargeText;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import static java.lang.Math.abs;

/**
* Extension to {@link LargeText} that handles annotations by {@link ConsoleAnnotator}.
*
* <p>
* In addition to run each line through {@link ConsoleAnnotationOutputStream} for adding markup,
* this class persists {@link ConsoleAnnotator} into a byte sequence and send it to the client
* as an HTTP header. The client JavaScript sends it back next time it fetches the following output.
*
* <p>
* The serialized {@link ConsoleAnnotator} is encrypted to avoid malicious clients from instantiating
* arbitrary {@link ConsoleAnnotator}s.
*
* @param <T>
*      Context type.
* @author Kohsuke Kawaguchi
* @since 1.349
*/
public class AnnotatedLargeText<T> extends LargeText {
    /**
     * Can be null.
     */
    private T context;

    public AnnotatedLargeText(File file, Charset charset, boolean completed, T context) {
        super(file, charset, completed);
        this.context = context;
    }

    public AnnotatedLargeText(ByteBuffer memory, Charset charset, boolean completed, T context) {
        super(memory, charset, completed);
        this.context = context;
    }

    public void doProgressiveHtml(StaplerRequest req, StaplerResponse rsp) throws IOException {
        req.setAttribute("html",true);
        doProgressText(req,rsp);
    }

    /**
     * Aliasing what I think was a wrong name in {@link LargeText}
     */
    public void doProgressiveText(StaplerRequest req, StaplerResponse rsp) throws IOException {
        doProgressText(req,rsp);
    }

    /**
     * For reusing code between text/html and text/plain, we run them both through the same code path
     * and use this request attribute to differentiate.
     */
    private boolean isHtml() {
        return Stapler.getCurrentRequest().getAttribute("html")!=null;
    }

    @Override
    protected void setContentType(StaplerResponse rsp) {
        rsp.setContentType(isHtml() ? "text/html;charset=UTF-8" : "text/plain;charset=UTF-8");
    }

    private ConsoleAnnotator createAnnotator(StaplerRequest req) throws IOException {
        try {
            String base64 = req!=null ? req.getHeader("X-ConsoleAnnotator") : null;
            if (base64!=null) {
                Cipher sym = Secret.getCipher("AES");
                sym.init(Cipher.DECRYPT_MODE, Jenkins.getInstance().getSecretKeyAsAES128());

                ObjectInputStream ois = new ObjectInputStreamEx(new GZIPInputStream(
                        new CipherInputStream(new ByteArrayInputStream(Base64.decode(base64.toCharArray())),sym)),
                        Jenkins.getInstance().pluginManager.uberClassLoader);
                try {
                    long timestamp = ois.readLong();
                    if (TimeUnit2.HOURS.toMillis(1) > abs(System.currentTimeMillis()-timestamp))
                        // don't deserialize something too old to prevent a replay attack
                        return (ConsoleAnnotator)ois.readObject();
                } finally {
                    ois.close();
                }
            }
        } catch (GeneralSecurityException e) {
            throw new IOException2(e);
        } catch (ClassNotFoundException e) {
            throw new IOException2(e);
        }
        // start from scratch
        return ConsoleAnnotator.initial(context==null ? null : context.getClass());
    }

    @Override
    public long writeLogTo(long start, Writer w) throws IOException {
        if (isHtml())
            return writeHtmlTo(start, w);
        else
            return super.writeLogTo(start,w);
    }

    @Override
    public long writeLogTo(long start, OutputStream out) throws IOException {
        return super.writeLogTo(start, new PlainTextConsoleOutputStream(out));
    }

    public long writeHtmlTo(long start, Writer w) throws IOException {
        ConsoleAnnotationOutputStream caw = new ConsoleAnnotationOutputStream(
                w, createAnnotator(Stapler.getCurrentRequest()), context, charset);
        long r = super.writeLogTo(start,caw);

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            Cipher sym = Secret.getCipher("AES");
            sym.init(Cipher.ENCRYPT_MODE, Jenkins.getInstance().getSecretKeyAsAES128());
            ObjectOutputStream oos = new ObjectOutputStream(new GZIPOutputStream(new CipherOutputStream(baos,sym)));
            oos.writeLong(System.currentTimeMillis()); // send timestamp to prevent a replay attack
            oos.writeObject(caw.getConsoleAnnotator());
            oos.close();
            StaplerResponse rsp = Stapler.getCurrentResponse();
            if (rsp!=null)
                rsp.setHeader("X-ConsoleAnnotator", new String(Base64.encode(baos.toByteArray())));
        } catch (GeneralSecurityException e) {
            throw new IOException2(e);
        }
        return r;
    }

}
TOP

Related Classes of hudson.console.AnnotatedLargeText

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.