All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.console.AnnotatedLargeText Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *
 * Copyright (c) 2004-2010, Oracle Corporation.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *
 *
 *
 *
 *******************************************************************************/ 

package hudson.console;

import hudson.model.Hudson;
import hudson.remoting.ObjectInputStreamEx;
import hudson.util.IOException2;
import hudson.util.IOUtils;
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;
import org.apache.commons.codec.binary.Base64;

/**
 * Extension to {@link LargeText} that handles annotations by
 * {@link ConsoleAnnotator}.
 *
 * 

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. * *

The serialized {@link ConsoleAnnotator} is encrypted to avoid malicious * clients from instantiating arbitrary {@link ConsoleAnnotator}s. * * @param Context type. * @author Kohsuke Kawaguchi * @since 1.349 */ public class AnnotatedLargeText 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 { ObjectInputStream ois = null; try { String base64 = req != null ? req.getHeader("X-ConsoleAnnotator") : null; if (base64 != null) { Cipher sym = Secret.getCipher("AES"); sym.init(Cipher.DECRYPT_MODE, Hudson.getInstance().getSecretKeyAsAES128()); ois = new ObjectInputStreamEx(new GZIPInputStream( new CipherInputStream(new ByteArrayInputStream(Base64.decodeBase64(base64)), sym)), Hudson.getInstance().pluginManager.uberClassLoader); 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(); } } } catch (GeneralSecurityException e) { throw new IOException2(e); } catch (ClassNotFoundException e) { throw new IOException2(e); } finally { IOUtils.closeQuietly(ois); } // 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); ObjectOutputStream oos = null; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); Cipher sym = Secret.getCipher("AES"); sym.init(Cipher.ENCRYPT_MODE, Hudson.getInstance().getSecretKeyAsAES128()); try { oos = new ObjectOutputStream(new GZIPOutputStream(new CipherOutputStream(baos, sym))); oos.writeLong(System.currentTimeMillis()); // send timestamp to prevent a replay attack oos.writeObject(caw.getConsoleAnnotator()); } finally { IOUtils.closeQuietly(oos); } StaplerResponse rsp = Stapler.getCurrentResponse(); if (rsp != null) { rsp.setHeader("X-ConsoleAnnotator", new String(Base64.encodeBase64(baos.toByteArray()))); } } catch (GeneralSecurityException e) { throw new IOException2(e); } return r; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy