package com.mendhak.gpslogger.senders.sftp; import android.util.Base64; import com.jcraft.jsch.*; import com.mendhak.gpslogger.common.Strings; import com.mendhak.gpslogger.common.events.UploadEvents; import com.mendhak.gpslogger.common.slf4j.Logs; import com.path.android.jobqueue.Job; import com.path.android.jobqueue.Params; import de.greenrobot.event.EventBus; import org.slf4j.Logger; import java.io.*; import java.util.Properties; public class SFTPJob extends Job { private static final Logger LOG = Logs.of(SFTPJob.class); private final File localFile; private final String host; private final int port; private final String pathToPrivateKey; private final String privateKeyPassphrase; private final String username; private final String password; private final String hostKey; private final String remoteDir; public SFTPJob(File localFile, String remoteDir, String host, int port, String pathToPrivateKey, String privateKeyPassphrase, String username, String password, String hostKey) { super(new Params(1).requireNetwork().persist().addTags(getJobTag(localFile))); this.localFile = localFile; this.remoteDir = remoteDir; this.host = host; this.port = port; this.pathToPrivateKey = pathToPrivateKey; this.privateKeyPassphrase = privateKeyPassphrase; this.username = username; this.password = password; this.hostKey = hostKey; } @Override public void onAdded() { LOG.debug("SFTP Job added"); } @Override public void onRun() throws Throwable { LOG.debug("SFTP Job onRun"); com.jcraft.jsch.Session session = null; final JSch jsch = new JSch(); FileInputStream fis = null; try { String keystring = this.hostKey; if (!Strings.isNullOrEmpty(keystring)) { byte[] key = Base64.decode(keystring, Base64.DEFAULT); jsch.getHostKeyRepository().add(new HostKey(host, key), null); } jsch.addIdentity(this.pathToPrivateKey, this.privateKeyPassphrase); session = jsch.getSession(this.username, this.host, this.port); session.setPassword(this.password); Properties prop = new Properties(); prop.put("StrictHostKeyChecking", "yes"); session.setConfig(prop); LOG.debug("Connecting..."); session.connect(); if (session.isConnected()) { LOG.debug("Connected, opening SFTP channel"); Channel channel = session.openChannel("sftp"); channel.connect(); ChannelSftp channelSftp = (ChannelSftp) channel; LOG.debug("Changing directory to " + this.remoteDir); channelSftp.cd(this.remoteDir); LOG.debug("Uploading " + this.localFile.getName() + " to remote server"); channelSftp.put(new FileInputStream(this.localFile), this.localFile.getName(), ChannelSftp.OVERWRITE); LOG.debug("Disconnecting"); channelSftp.disconnect(); channel.disconnect(); session.disconnect(); EventBus.getDefault().post(new UploadEvents.SFTP().succeeded()); } else { EventBus.getDefault().post(new UploadEvents.SFTP().failed("Could not connect, unknown reasons", null)); } } catch (SftpException sftpex) { LOG.error(sftpex.getMessage(), sftpex); EventBus.getDefault().post(new UploadEvents.SFTP().failed(sftpex.getMessage(), sftpex)); } catch (final JSchException jex) { LOG.error(jex.getMessage(), jex); if (jex.getMessage().contains("reject HostKey") || jex.getMessage().contains("HostKey has been changed")) { LOG.debug(session.getHostKey().getKey()); UploadEvents.SFTP sftpException = new UploadEvents.SFTP(); sftpException.hostKey = session.getHostKey().getKey(); sftpException.fingerprint = session.getHostKey().getFingerPrint(jsch); EventBus.getDefault().post(sftpException.failed(jex.getMessage(), jex)); } else { throw jex; } } catch (Exception ex) { LOG.error(ex.getMessage(), ex); EventBus.getDefault().post(new UploadEvents.SFTP().failed(ex.getMessage(), ex)); } finally { try { fis.close(); } catch (Exception ee) { } } } @Override protected void onCancel() { LOG.debug("SFTP Job Cancelled"); } @Override protected boolean shouldReRunOnThrowable(Throwable throwable) { LOG.error("Could not upload to SFTP server", throwable); EventBus.getDefault().post(new UploadEvents.SFTP().failed(throwable.getMessage(), throwable)); return false; } public static String getJobTag(File gpxFile) { return "SFTP" + gpxFile.getName(); } }