package org.openslx.taskmanager.tasks; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.net.URLConnection; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.openslx.satserver.util.Exec; import org.openslx.satserver.util.Util; import org.openslx.taskmanager.api.AbstractTask; import com.google.gson.annotations.Expose; public class DownloadFile extends AbstractTask { @Expose private String url = null; @Expose private String destination = null; @Expose private String gpg = null; private Output status = new Output(); private static final String[] ALLOWED_DIRS = { "/srv/openslx/www/boot/", "/tmp/" }; @Override protected boolean initTask() { this.setStatusObject( status ); if ( this.url == null ) { status.error = "No URL given."; return false; } this.destination = FilenameUtils.normalize( this.destination ); if ( this.destination == null || !Util.startsWith( this.destination, ALLOWED_DIRS ) || this.destination.endsWith( "/" ) ) { status.error = "File not in allowed directory"; return false; } return true; } @Override protected boolean execute() { URLConnection connection = null; BufferedInputStream in = null; FileOutputStream fout = null; try { File tmpFile = File.createTempFile( "bwlp-", ".tmp", null ); connection = new URL( this.url ).openConnection(); in = new BufferedInputStream( connection.getInputStream() ); fout = new FileOutputStream( tmpFile ); status.size = connection.getContentLengthLong(); if ( status.size <= 0 ) // If size is unknown, fake progress... status.progress = 10; final byte data[] = new byte[ 90000 ]; int count; while ( ( count = in.read( data, 0, data.length ) ) != -1 ) { fout.write( data, 0, count ); status.complete += count; if ( status.size > 0 ) status.progress = (int) ( 100l * status.complete / status.size ); else if ( status.progress < 99 && System.currentTimeMillis() % 20 == 0 ) status.progress++; } fout.close(); in.close(); // If we have a gpg sig, validate if ( this.gpg != null && !this.gpg.isEmpty() ) { File gpgTempFile = null; try { gpgTempFile = File.createTempFile( "bwlp-", ".gpg", null ); Util.writeStringToFile( gpgTempFile, this.gpg ); } catch ( Exception e ) { status.error = "Could not create temporary file for gpg signature"; return false; } if ( 0 != Exec.sync( 10, "gpg", "--verify", gpgTempFile.getAbsolutePath(), tmpFile.getAbsolutePath() ) ) { status.error = "GPG signature of downloaded file not valid!\n\n" + this.gpg; return false; } gpgTempFile.delete(); } // Move file to destination File dest = new File( this.destination ); FileUtils.forceMkdir( new File( dest.getParent() ) ); if ( dest.exists() ) dest.delete(); if ( !tmpFile.renameTo( dest ) ) { status.error = "Could not move downloaded file to destination directory!"; return false; } return true; } catch ( IOException e ) { status.error = "Download error: " + e.toString(); return false; } finally { Util.multiClose( in, fout ); } } /** * Output - contains additional status data of this task */ @SuppressWarnings( "unused" ) private static class Output { protected String error = null; protected long size = -1; protected long complete = 0; protected int progress = 0; } }