package org.fnppl.opensdx.file_transfer; /* * Copyright (C) 2010-2015 * fine people e.V. <opensdx@fnppl.org> * Henning ThieƟ <ht@fnppl.org> * * http://fnppl.org */ /* * Software license * * As far as this file or parts of this file is/are software, rather than documentation, this software-license applies / shall be applied. * * This file is part of openSDX * openSDX is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * openSDX is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * and GNU General Public License along with openSDX. * If not, see <http://www.gnu.org/licenses/>. * */ /* * Documentation license * * As far as this file or parts of this file is/are documentation, rather than software, this documentation-license applies / shall be applied. * * This file is part of openSDX. * Permission is granted to copy, distribute and/or modify this document * under the terms of the GNU Free Documentation License, Version 1.3 * or any later version published by the Free Software Foundation; * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. * A copy of the license is included in the section entitled "GNU * Free Documentation License" resp. in the file called "FDL.txt". * */ import java.io.*; import java.net.ConnectException; import java.net.Socket; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Vector; import org.fnppl.opensdx.common.Util; import org.fnppl.opensdx.file_transfer.commands.OSDXFileTransferUserPassLoginCommand; import org.fnppl.opensdx.file_transfer.errors.OSDXErrorCode; import org.fnppl.opensdx.file_transfer.errors.OSDXException; import org.fnppl.opensdx.file_transfer.errors.OSDXException.FileAlreadyExistsException; import org.fnppl.opensdx.file_transfer.errors.OSDXException.FileDoesNotExistException; import org.fnppl.opensdx.file_transfer.errors.OSDXException.FileSizeException; import org.fnppl.opensdx.file_transfer.errors.OSDXException.MakeDirectoryException; import org.fnppl.opensdx.file_transfer.errors.OSDXException.SocketNotConnectedException; import org.fnppl.opensdx.file_transfer.helper.RightsAndDuties; import org.fnppl.opensdx.file_transfer.model.RemoteFile; import org.fnppl.opensdx.helper.Logger; import org.fnppl.opensdx.helper.ProgressListener; import org.fnppl.opensdx.security.AsymmetricKeyPair; import org.fnppl.opensdx.security.MD5; import org.fnppl.opensdx.security.OSDXKey; import org.fnppl.opensdx.security.SecurityHelper; import org.fnppl.opensdx.security.SymmetricKey; import org.fnppl.opensdx.xml.Document; public class OSDXFileTransferAdapter { private static boolean DEBUG = false; private static String OSDX_FILETRANSFERADAPTER_VERSION = "osdx_ftclient_sync v.2013-03-29"; static { System.out.println("OSDXFileTransferAdapter :: starting in version "+OSDX_FILETRANSFERADAPTER_VERSION); } protected int maxPacketSize = 50*1024; //50kB private Logger logger = Logger.getFileTransferLogger(); private String host; private int port; private String prepath; private OSDXKey mySigningKey; private String username = null; private static AsymmetricKeyPair userSessionKey = null; //HT 2012-03-20 really good idea to have it static?! private String password = null; private Socket socket; private BufferedInputStream in; private BufferedOutputStream out; private SecureConnection dataOut = null; private SecureConnection dataIn = null; private String errorMsg = null; //We will keep this solution for now to avoid side effects private boolean secureConnectionEstablished = false; private byte[] client_nonce = null; private byte[] server_nonce = null; protected RightsAndDuties rightsAndDuties = null; private RemoteFile root = new RemoteFile("", "/", 0L, System.currentTimeMillis(), true); public OSDXFileTransferAdapter() { try { dataOut = null; dataIn = null; } catch (Exception e) { e.printStackTrace(); } } public boolean connect(String host, int port, String prepath, String username, String pass) throws Exception { this.host = host; this.port = port; this.username = username; this.password = pass; this.mySigningKey = null; if (prepath==null || prepath.length()==0) { this.prepath = "/"; } else { this.prepath = prepath; } secureConnectionEstablished = false; client_nonce = null; server_nonce = null; try { logger.logMsg("trying to connect to host: "+host+" port: "+port+" version: "+OSDX_FILETRANSFERADAPTER_VERSION); socket = new Socket(host, port); } catch (Exception ex) { logger.logException(ex); throw ex; } logger.logMsg("Socket connected."); if (socket.isConnected()) { in = new BufferedInputStream(socket.getInputStream()); out = new BufferedOutputStream(socket.getOutputStream()); dataOut = new SecureConnection(null, null, out); dataIn = new SecureConnection(null, in, null); if(!initSecureUserPassConnection(host)){ logger.logMsg("ERROR: Couldn't establish secure user connection to host: " + host); throw new OSDXException().new InitSecureUserPassConnectionException(); } } else { logger.logMsg("ERROR: Socket is not connected"); throw new OSDXException().new SocketNotConnectedException(); } return true; } public boolean connect(String host, int port, String prepath, OSDXKey mySigningKey, String username) throws Exception { this.host = host; this.port = port; this.username = username; if (prepath==null || prepath.length()==0) { this.prepath = "/"; } else { this.prepath = prepath; } this.mySigningKey = mySigningKey; secureConnectionEstablished = false; client_nonce = null; server_nonce = null; try { logger.logMsg("trying to connect to host: "+host+" port: "+port+" version: "+OSDX_FILETRANSFERADAPTER_VERSION); socket = new Socket(host, port); } catch (Exception ex) { logger.logException(ex); throw ex; } logger.logMsg("Socket connected."); // System.out.println("inner connect ok: "+socket.isConnected()); if (socket.isConnected()) { in = new BufferedInputStream(socket.getInputStream()); out = new BufferedOutputStream(socket.getOutputStream()); dataOut = new SecureConnection(null, null, out); dataIn = new SecureConnection(null, in, null); //secureConnectionEstablished = initSecureConnection(host, mySigningKey); return true; } else { // System.out.println("ERROR: Connection to server could NOT be established!"); return false; } } public boolean isConnected() { return socket.isConnected() && secureConnectionEstablished; } private void ensureAsymmetricKeyPair() throws Exception { if(userSessionKey == null) { logger.logMsg("Creating asymmetric keyPair for this session..."); long l = System.currentTimeMillis(); userSessionKey = AsymmetricKeyPair.generateAsymmetricKeyPair(); l = System.currentTimeMillis() -l ; logger.logMsg("Creating asymmetric keyPair for this session took "+l+"ms"); } } private boolean initSecureUserPassConnection(String host) { try { logger.logMsg("init secure connection to host: "+host+"..."); ensureAsymmetricKeyPair(); //send request client_nonce = SecurityHelper.getRandomBytes(32); // userSessionKey // sessionKey = SymmetricKey.getKeyFromPass(pass.toCharArray(), client_nonce); // String pass_username // asd String init = OSDX_FILETRANSFERADAPTER_VERSION +"\n"; init += host+"\n"; init += SecurityHelper.HexDecoder.encode(client_nonce,':',-1)+"\n"; init += userSessionKey.getKeyIDHex()+"\n"; init += SecurityHelper.HexDecoder.encode(userSessionKey.getPublicModulus(),':',-1)+"\n"; init += SecurityHelper.HexDecoder.encode(userSessionKey.getPublicExponent(),':',-1)+"\n"; byte[][] checks = SecurityHelper.getMD5SHA1SHA256(client_nonce); init += SecurityHelper.HexDecoder.encode(userSessionKey.sign(checks[1],checks[2],checks[3],0L),':',-1)+"\n"; init += "\n"; dataOut.sendRawBytes(init.getBytes("UTF-8")); byte[] responsePartKeyData = dataIn.receiveRawBytesPackage(); byte[] responsePartEncData = dataIn.receiveRawBytesPackage(); //process response try { String[] lines = new String(responsePartKeyData,"UTF-8").split("\n"); // for (int i=0;i<lines.length;i++) { // System.out.println("("+(i+1)+")"+" "+lines[i]); // } //check signature byte[] server_mod = SecurityHelper.HexDecoder.decode(lines[3]); byte[] server_exp = SecurityHelper.HexDecoder.decode(lines[4]); byte[] server_signature = SecurityHelper.HexDecoder.decode(lines[5]); AsymmetricKeyPair server_pubkey = new AsymmetricKeyPair(server_mod, server_exp, null); byte[] encdata = responsePartEncData; checks = SecurityHelper.getMD5SHA1SHA256(encdata); boolean verifySig = server_pubkey.verify(server_signature, checks[1],checks[2],checks[3],0L); //System.out.println("signature verified: "+verifySig); if (verifySig) { //System.out.println("init msg signature verified!"); //build enc key byte[] decData = userSessionKey.decryptBlocks(encdata); String[] encLines = new String(decData, "UTF-8").split("\n"); // for (int i=0;i<encLines.length;i++) { // System.out.println("ENC "+(i+1)+" :: "+encLines[i]); // } server_nonce = SecurityHelper.HexDecoder.decode(encLines[1]); byte[] concat_nonce = SecurityHelper.concat(client_nonce, server_nonce); // System.out.println("byte len :: concat_nonce = "+concat_nonce.length); byte[] key_bytes = SecurityHelper.getSHA256(concat_nonce); //32 bytes = 256 bit byte[] iv = Arrays.copyOf(SecurityHelper.getMD5(concat_nonce),16); //16 bytes = 128 bit // System.out.println("byte len :: iv = "+iv.length+" b = "+key_bytes.length); // System.out.println(SecurityHelper.HexDecoder.encode(iv, '\0', -1)); // System.out.println(SecurityHelper.HexDecoder.encode(key_bytes, '\0', -1)); dataOut.key = new SymmetricKey(key_bytes, iv); dataIn.key = dataOut.key; secureConnectionEstablished = true; if (loginUserPass()) { System.out.println("Login successful..."); } else { if (errorMsg == null) { System.out.println("ERROR at Login :: unknown error"); } else { System.out.println("ERROR at Login :: "+errorMsg); } } } else { System.out.println("init msg signature NOT verified!"); logger.logError("init msg signature NOT verified!"); } } catch (OSDXException osdxe){ osdxe.printStackTrace(); throw osdxe; //Rethrow } catch (Exception ex) { ex.printStackTrace(); logger.logException(ex); } } catch (Exception ex) { ex.printStackTrace(); logger.logException(ex); } return true; } private void initSecureConnection(String host, OSDXKey key) { try { logger.logMsg("init secure connection to host: "+host+" with keyid: "+key.getKeyID()+" ..."); //send request client_nonce = SecurityHelper.getRandomBytes(32); String init = OSDX_FILETRANSFERADAPTER_VERSION +"\n"; init += host+"\n"; init += SecurityHelper.HexDecoder.encode(client_nonce,':',-1)+"\n"; init += key.getKeyID()+"\n"; init += SecurityHelper.HexDecoder.encode(key.getPublicModulusBytes(),':',-1)+"\n"; init += SecurityHelper.HexDecoder.encode(key.getPublicExponentBytes(),':',-1)+"\n"; byte[][] checks = SecurityHelper.getMD5SHA1SHA256(client_nonce); init += SecurityHelper.HexDecoder.encode(key.sign(checks[1],checks[2],checks[3],0L),':',-1)+"\n"; init += "\n"; dataOut.sendRawBytes(init.getBytes("UTF-8")); byte[] responsePartKeyData = dataIn.receiveRawBytesPackage(); byte[] responsePartEncData = dataIn.receiveRawBytesPackage(); //process response try { String[] lines = new String(responsePartKeyData,"UTF-8").split("\n"); // for (int i=0;i<lines.length;i++) { // System.out.println("("+(i+1)+")"+" "+lines[i]); // } //check signature byte[] server_mod = SecurityHelper.HexDecoder.decode(lines[3]); byte[] server_exp = SecurityHelper.HexDecoder.decode(lines[4]); byte[] server_signature = SecurityHelper.HexDecoder.decode(lines[5]); AsymmetricKeyPair server_pubkey = new AsymmetricKeyPair(server_mod, server_exp, null); byte[] encdata = responsePartEncData; checks = SecurityHelper.getMD5SHA1SHA256(encdata); boolean verifySig = server_pubkey.verify(server_signature, checks[1],checks[2],checks[3],0L); //System.out.println("signature verified: "+verifySig); if (verifySig) { //System.out.println("init msg signature verified!"); //build enc key byte[] decData = mySigningKey.decryptBlocks(encdata); String[] encLines = new String(decData, "UTF-8").split("\n"); // for (int i=0;i<encLines.length;i++) { // System.out.println("ENC "+(i+1)+" :: "+encLines[i]); // } server_nonce = SecurityHelper.HexDecoder.decode(encLines[1]); byte[] concat_nonce = SecurityHelper.concat(client_nonce, server_nonce); // System.out.println("byte len :: concat_nonce = "+concat_nonce.length); byte[] key_bytes = SecurityHelper.getSHA256(concat_nonce); //32 bytes = 256 bit byte[] iv = Arrays.copyOf(SecurityHelper.getMD5(concat_nonce),16); //16 bytes = 128 bit // System.out.println("byte len :: iv = "+iv.length+" b = "+key_bytes.length); // System.out.println(SecurityHelper.HexDecoder.encode(iv, '\0', -1)); // System.out.println(SecurityHelper.HexDecoder.encode(key_bytes, '\0', -1)); dataOut.key = new SymmetricKey(key_bytes, iv); dataIn.key = dataOut.key; secureConnectionEstablished = true; if (login()) { System.out.println("Login successful..."); } else { if (errorMsg == null) { System.out.println("ERROR at Login :: unknown error"); } else { System.out.println("ERROR at Login :: "+errorMsg); } } } else { System.out.println("init msg signature NOT verified!"); logger.logError("init msg signature NOT verified!"); } } catch (Exception ex) { ex.printStackTrace(); logger.logException(ex); } } catch (Exception ex) { ex.printStackTrace(); logger.logException(ex); } } public RemoteFile getRoot() { return root; } private boolean login() throws OSDXException { SimpleCommand cmd = new SimpleCommand(dataIn, dataOut) { public boolean onACK() { try { String msg = new String(dataIn.content,"UTF-8"); String[] param = Util.getParams(msg); try { rightsAndDuties = RightsAndDuties.fromElement(Document.fromString(param[1]).getRootElement(), -1); return true; } catch (Exception ex) { ex.printStackTrace(); rightsAndDuties = null; errorMsg = getMessageFromContent(dataIn.content); return false; } } catch (UnsupportedEncodingException ex) { errorMsg = "unsupported encoding"; return false; } } }; boolean ok = cmd.process("LOGIN "+username); if(dataIn.isError()){ dataIn.getError().throwException(cmd.errorMsg); } errorMsg = cmd.errorMsg; return ok; } private boolean loginUserPass() throws OSDXException { SimpleCommand cmd = new SimpleCommand(dataIn, dataOut) { public boolean onACK() { try { String msg = new String(dataIn.content,"UTF-8"); String[] param = Util.getParams(msg); try { rightsAndDuties = RightsAndDuties.fromElement(Document.fromString(param[1]).getRootElement(), -1); return true; } catch (Exception ex) { ex.printStackTrace(); rightsAndDuties = null; errorMsg = getMessageFromContent(dataIn.content); return false; } } catch (UnsupportedEncodingException ex) { errorMsg = "unsupported encoding"; return false; } } }; boolean ok = cmd.process("USERPASSLOGIN "+username+"\t"+OSDXFileTransferUserPassLoginCommand.getUserPassAuth(username, password)); if(dataIn.isError()){ dataIn.getError().throwException(cmd.errorMsg); } errorMsg = cmd.errorMsg; return ok; } private void handleUnexpectedPackageID() { System.out.println("Unexpected Package Received:"); System.out.println("id = "+dataIn.id); System.out.println("type = "+SecurityHelper.HexDecoder.encode(new byte[]{dataIn.type})); System.out.println("length = "+dataIn.len); } private void handleConnectionClosed() { System.out.println("Connection closed by Server."); } public boolean mkdir(String absoluteDirectoryName) throws OSDXException { SimpleCommand cmd = new SimpleCommand(dataIn, dataOut); boolean ok = cmd.process("MKDIR "+absoluteDirectoryName); if(dataIn.isError()){ dataIn.getError().throwException(cmd.errorMsg); } errorMsg = cmd.errorMsg; return ok; } public String getMostRecentErrorMSG() { return errorMsg; } public boolean delete(String absoluteRemoteFilename) throws OSDXException { SimpleCommand cmd = new SimpleCommand(dataIn, dataOut); boolean ok = cmd.process("DELETE "+absoluteRemoteFilename); if(dataIn.isError()){ dataIn.getError().throwException(cmd.errorMsg); } errorMsg = cmd.errorMsg; return ok; } public boolean rename(String absoluteRemoteFilename, String newfilename) throws OSDXException { String[] params = new String[] {absoluteRemoteFilename,newfilename}; String command = "RENAME "+Util.makeParamsString(params); SimpleCommand cmd = new SimpleCommand(dataIn, dataOut); boolean ok = cmd.process(command); if(dataIn.isError()){ dataIn.getError().throwException(cmd.errorMsg); } errorMsg = cmd.errorMsg; return ok; } public Vector<RemoteFile> list(String absoluteDirectoryName) throws OSDXException { final Vector<RemoteFile> list = new Vector<RemoteFile>(); SimpleCommand cmd = new SimpleCommand(dataIn, dataOut) { public boolean onACK() { //parse list String s = getMessageFromContentNN(dataIn.content); if (DEBUG) System.out.println("RECEIVED LIST: "+s); if (s.length()>0) { String[] files = s.split("\n"); for (int i=0;i<files.length;i++) { RemoteFile rf = RemoteFile.fromParamString(files[i]); if (rf!=null) { list.add(rf); } } } return true; } }; boolean ok = cmd.process("LIST "+absoluteDirectoryName); if(dataIn.isError()){ dataIn.getError().throwException(cmd.errorMsg); } errorMsg = cmd.errorMsg; if (!ok) { return null; } else { return list; } } public RemoteFile fileinfo(String absoluteRemoteFilename) throws OSDXException { final Vector<RemoteFile> list = new Vector<RemoteFile>(); SimpleCommand cmd = new SimpleCommand(dataIn, dataOut) { public boolean onACK() { //parse fileinfo RemoteFile rf = RemoteFile.fromParamString(getMessageFromContentNN(dataIn.content)); if (rf!=null) { list.add(rf); return true; } else { return false; } } }; boolean ok = cmd.process("FILE "+absoluteRemoteFilename); if(dataIn.isError()) { dataIn.getError().throwException(cmd.errorMsg+" REMOTEFILEPATH: "+absoluteRemoteFilename); } errorMsg = cmd.errorMsg; if (!ok) { return null; } else { if (list.size()>0) { return list.get(0); } else { return null; } } } public boolean uploadOldStyle(File localFile, String absoluteRemotePath) { boolean ret = false; try { System.out.println("Upload of file: "+localFile.getCanonicalPath()+" -> "+absoluteRemotePath); boolean ok = uploadOldStyle(localFile, absoluteRemotePath, false, null); if (ok) { System.out.println("Upload finished.\n"); ret = true; } else { if(errorMsg==null) { System.out.println("ERROR\n"); } else { System.out.println("ERROR: "+errorMsg+"\n"); } } } catch (Exception ex) { ex.printStackTrace(); } return ret; } public boolean uploadResume(File localFile, String absoluteRemotePath) throws OSDXException, SocketException { return uploadResume(localFile, absoluteRemotePath, null); } public boolean uploadResume(File localFile, String absoluteRemotePath, ProgressListener pg) throws OSDXException { boolean ret = false; try { System.out.println("Upload/Resume of file: "+localFile.getCanonicalPath()+" -> "+absoluteRemotePath); boolean ok = upload(localFile, absoluteRemotePath, true, pg); if (ok) { System.out.println("Upload/Resume finished.\n"); ret = true; } else { if (errorMsg==null) { System.out.println("ERROR\n"); } else { System.out.println("ERROR: "+errorMsg+"\n"); } } } catch (OSDXException osdxe){ osdxe.printStackTrace(); throw osdxe; //Rethrow } catch (SocketException se){ se.printStackTrace(); errorMsg = "The connection to the serve is lost!"; secureConnectionEstablished = false; //Hier nun die Ƥquivalente OSDX Exception werfen throw new OSDXException().new SocketNotConnectedException(errorMsg); } catch (Exception ex) { ex.printStackTrace(); } return ret; } public boolean uploadResumeOldStyle(File localFile, String absoluteRemotePath) { boolean ret = false; try { System.out.println("Upload/Resume of file: "+localFile.getCanonicalPath()+" -> "+absoluteRemotePath); boolean ok = uploadOldStyle(localFile, absoluteRemotePath, true, null); if (ok) { System.out.println("Upload/Resume finished.\n"); ret = true; } else { if (errorMsg==null) { System.out.println("ERROR\n"); } else { System.out.println("ERROR: "+errorMsg+"\n"); } } } catch (Exception ex) { ex.printStackTrace(); } return ret; } public boolean uploadOldStyle(File localFile, String absoluteRemoteFilename, boolean resume, ProgressListener pg) throws Exception { errorMsg = null; long id = SecureConnection.getID(); int num = 0; long filePos = -1L; long fileLen = localFile.length(); FileInputStream fileIn = null; long maxFilelengthForMD5 = 100*1024*1024L; //100 MB boolean hasNext = true; if (pg!=null) { if (fileLen>0) { pg.setMaxProgress(fileLen); } else { pg.setMaxProgress(1); } pg.setProgress(0); pg.onUpate(); } String command = null; String[] param; if (fileLen>0) { byte[] md5 = null; if (fileLen<maxFilelengthForMD5) { try { md5 = SecurityHelper.getMD5(localFile); } catch (Exception e) { System.out.println("Error calculating md5 hash of "+localFile.getAbsolutePath()); e.printStackTrace(); md5 = null; } } if (md5!=null) { param = new String[] {absoluteRemoteFilename,""+fileLen,SecurityHelper.HexDecoder.encode(md5)}; } else { param = new String[] {absoluteRemoteFilename,""+fileLen}; } } else { fileLen = 0L; param = new String[] {absoluteRemoteFilename,""+fileLen}; } if (resume) { command = "RESUMEPUT "+Util.makeParamsString(param); } else { command = "PUT "+Util.makeParamsString(param); } dataOut.setCommand(id, command); if (DEBUG) { Logger.getFileTransferLogger().logMsg("SEND CMD: "+command); } dataOut.sendPackage(); boolean hasPkg = false; while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } while (hasPkg) { if (!SecureConnection.isError(dataIn.type)) { if (dataIn.type == SecureConnection.TYPE_ACK) { //System.out.println("ACK upload of file: "+remoteName); if (fileLen<=0) { //progress ready for file of length 0 if (pg!=null) { pg.setProgress(pg.getMaxProgress()); pg.onUpate(); } return true; } //open file for transfer fileIn = new FileInputStream(localFile); if (resume) { String msg = getMessageFromContent(dataIn.content); System.out.println("resume msg :: "+msg+" filePos before = "+filePos); if (msg!=null && msg.equals("upload already complete")) { hasNext = false; System.out.println(msg); //notifyUpdate(fileLen-1, fileLen, null); //progress ready if (pg!=null) { pg.setProgress(pg.getMaxProgress()); pg.onUpate(); } return true; } else { try { filePos = Long.parseLong(getMessageFromContent(dataIn.content)); System.out.println("file pos = "+filePos); if (filePos>=fileLen) { errorMsg = "file position > file length"; return false; } fileIn.skip(filePos);//skip forward to filepos if (pg!=null) { pg.setProgress(filePos); pg.onUpate(); } } catch (Exception ex) { //ex.printStackTrace(); errorMsg = "wrong format: file upload resume position not parseable"; return false; } } } //send data byte[] data = new byte[maxPacketSize]; while (hasNext) { //read from file int read = fileIn.read(data); if (read>0) { num++; if (read<maxPacketSize) { dataOut.setData(id, num, Arrays.copyOf(data, read)); } else { dataOut.setData(id, num, data); } dataOut.sendPackage(); filePos += read; if (pg!=null) { pg.setProgress(filePos); pg.onUpate(); } } else if (read==-1) { hasNext = false; } //notifyUpdate(filePos, fileLen, null); if (filePos>=fileLen) { hasNext = false; } } //receive next package while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } if (!hasPkg) { handleConnectionClosed(); return false; } } else if (dataIn.type == SecureConnection.TYPE_ACK_COMPLETE) { //System.out.println("Upload complete"); //progress ready after receiving ACK_COMPLETE if (pg!=null) { pg.setProgress(pg.getMaxProgress()); pg.onUpate(); } try { fileIn.close(); } catch (Exception ex) { ex.printStackTrace(); } return true; } } else { //stop upload hasNext = false; try { fileIn.close(); } catch (Exception ex) { //ex.printStackTrace(); } errorMsg = getMessageFromContent(dataIn.content); return false; } } if (!hasPkg) { handleConnectionClosed(); return false; } else { System.out.println("should never be in this state!!!"); return false; } } public boolean upload(byte[] data, String absoluteRemoteFilename, boolean resume, ProgressListener pg) throws Exception { // -> PUT [absoluteRemoteFilename] // -> PUT_RESUME [filename] // <- ACK // <- ACK [length], [MD5_part] // -> send data packages // -> check length & MD5_part // -> PUT_EOF [length], [MD5] // -> send data package after [length] // <- ACK_COMPLETE // -> PUT_EOF [length], [MD5] // <- ACK_COMPLETE errorMsg = null; long id = SecureConnection.getID(); int num = 0; long dataPos = -1L; long dataLen = data.length; MD5 md5 = new MD5(); if (pg!=null) { if (dataLen>0) { pg.setMaxProgress(dataLen); } else { pg.setMaxProgress(1); } pg.setProgress(0); pg.onUpate(); } String command = null; String[] param = new String[] {absoluteRemoteFilename}; if (resume) { command = "PUT_RESUME "+Util.makeParamsString(param); } else { command = "PUT "+Util.makeParamsString(param); } dataOut.setCommand(id, command); if (DEBUG) { Logger.getFileTransferLogger().logMsg("SEND CMD: "+command); } dataOut.sendPackage(); boolean hasPkg = false; while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } boolean transferData = false; while (hasPkg) { if (!SecureConnection.isError(dataIn.type)) { if (dataIn.type == SecureConnection.TYPE_ACK) { //System.out.println("ACK upload of file: "+remoteName); dataPos = 0; if (resume) { // String msg = getMessageFromContent(dataIn.content); // //System.out.println("resume msg :: "+msg+" filePos before = "+dataPos); // if (msg!=null && msg.equals("upload already complete")) { // hasNext = false; // System.out.println(msg); // //notifyUpdate(fileLen-1, fileLen, null); // //progress ready // if (pg!=null) { // pg.setProgress(pg.getMaxProgress()); // pg.onUpate(); // } // return true; // } else { // try { // dataPos = Long.parseLong(getMessageFromContent(dataIn.content)); // //System.out.println("data pos = "+dataPos); // if (dataPos>=dataLen) { // errorMsg = "data position > data length"; // return false; // } // if (pg!=null) { // pg.setProgress(dataPos); // pg.onUpate(); // } // } catch (Exception ex) { // //ex.printStackTrace(); // errorMsg = "wrong format: data upload resume position not parseable"; // return false; // } // } } //send data transferData = (dataLen>dataPos); while (transferData) { //read from data int nextPackSize = (int)(dataLen-dataPos); if (nextPackSize>maxPacketSize) { nextPackSize = maxPacketSize; } if (nextPackSize>0) { num++; byte[] send = Arrays.copyOfRange(data, (int)dataPos, (int)dataPos+nextPackSize); dataOut.setData(id, num, send); dataOut.sendPackage(); md5.update(send); dataPos += nextPackSize; } //notify update if (pg!=null) { pg.setProgress(dataPos); pg.onUpate(); } if (dataPos>=dataLen) { transferData = false; } } //send length and md5 dataOut.setCommand(id, "PUT_EOF "+Util.makeParamsString(new String[] {""+dataPos, md5.getMD5HexString()})); dataOut.sendPackage(); //receive next package while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } if (!hasPkg) { handleConnectionClosed(); return false; } } else if (dataIn.type == SecureConnection.TYPE_ACK_COMPLETE) { //System.out.println("Upload complete"); //progress ready after receiving ACK_COMPLETE if (pg!=null) { pg.setProgress(pg.getMaxProgress()); pg.onUpate(); } return true; } } else { //stop upload (if running) transferData = false; if(dataIn.isError()){ dataIn.getError().throwException(getMessageFromContent(dataIn.content)); } errorMsg = getMessageFromContent(dataIn.content); return false; } } if (!hasPkg) { handleConnectionClosed(); return false; } else { System.out.println("should never be in this state!!!"); return false; } } public boolean upload(File localFile, String absoluteRemoteFilename) throws Exception { boolean ret = false; try { System.out.println("Upload of file: "+localFile.getCanonicalPath()+" -> "+absoluteRemoteFilename); boolean ok = upload(localFile, absoluteRemoteFilename, false, null); if (ok) { System.out.println("Upload finished.\n"); ret = true; } else { if(errorMsg==null) { System.out.println("ERROR\n"); } else { System.out.println("ERROR: "+errorMsg+"\n"); } } } catch (OSDXException osdxe){ osdxe.printStackTrace(); throw osdxe; //Rethrow } catch (Exception ex) { ex.printStackTrace(); } return ret; } public boolean upload(File localFile, String absoluteRemoteFilename, boolean resume, ProgressListener pg) throws Exception { // -> PUT [absoluteRemoteFilename] // -> PUT_RESUME [filename] // <- ACK // <- ACK [length], [MD5_part] // -> send data packages // -> check length & MD5_part // -> PUT_EOF [length], [MD5] // -> send data package after [length] // <- ACK_COMPLETE // -> PUT_EOF [length], [MD5] // <- ACK_COMPLETE errorMsg = null; long id = SecureConnection.getID(); int num = 0; long dataPos = -1L; long dataLen = localFile.length(); MD5 md5 = new MD5(); if (pg!=null) { if (dataLen>0) { pg.setMaxProgress(dataLen); } else { pg.setMaxProgress(1); } pg.setProgress(0); pg.onUpate(); } String command = null; String[] param = new String[] {absoluteRemoteFilename}; if (resume) { command = "PUT_RESUME "+Util.makeParamsString(param); } else { command = "PUT "+Util.makeParamsString(param); } dataOut.setCommand(id, command); if (DEBUG) { Logger.getFileTransferLogger().logMsg("SEND CMD: "+command); } dataOut.sendPackage(); boolean hasPkg = false; while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } boolean transferData = false; while (hasPkg) { if (!SecureConnection.isError(dataIn.type)) { if (dataIn.type == SecureConnection.TYPE_ACK) { //System.out.println("ACK upload of file: "+remoteName); dataPos = 0; FileInputStream fileIn = new FileInputStream(localFile); byte[] buffer = new byte[maxPacketSize]; if (resume) { String[] resumeParam = Util.getParams(getMessageFromContentNN(dataIn.content)); if (resumeParam.length>=2) { long transferred = Long.parseLong(resumeParam[0]); String md5String = resumeParam[1]; MD5 md5Local = new MD5(); //System.out.println("Resuming upload at pos "+transferred+" md5 given = "+md5String); //get md5String byte[] buf = new byte[maxPacketSize]; int nextPackSize = (int)(transferred-dataPos); if (nextPackSize>maxPacketSize) { nextPackSize = maxPacketSize; } int read = 0; while (nextPackSize>0 && read != -1) { //CON-5 infinite loop solved if (nextPackSize<maxPacketSize) { buf = new byte[nextPackSize]; } read = fileIn.read(buf); if (read>0) { md5.update(buf,read); md5Local.update(buf,read); dataPos += read; } nextPackSize = (int)(transferred-dataPos); if (nextPackSize>maxPacketSize) { nextPackSize = maxPacketSize; } } //compare md5 byte[] my_md5 = md5Local.getMD5bytes(); //can only read the md5 bytes one time !!! byte[] your_md5 = SecurityHelper.HexDecoder.decode(md5String); if (!Arrays.equals(my_md5,your_md5)) { OSDXErrorCode.ERROR_MD5_CHECK.throwException("MD5 check failed for resuming upload"); } } else if (resumeParam.length==1 && resumeParam[0].equals("0")) { //normal put } else { OSDXErrorCode.ERROR_WITH_MESSAGE.throwException("wrong format: data upload resume position not parseable"); errorMsg = "wrong format: data upload resume position not parseable"; return false; } } //send data transferData = (dataLen>dataPos); while (transferData) { //read from file int read = fileIn.read(buffer); if (read<0) { //end of file transferData = false; } else if (read>0) { if (read<maxPacketSize) { dataOut.setData(id, num, Arrays.copyOf(buffer, read)); dataOut.sendPackage(); md5.update(buffer, read); dataPos += read; } else { dataOut.setData(id, num, buffer); dataOut.sendPackage(); md5.update(buffer); dataPos += read; } //System.out.println("data pos = "+dataPos+ " of "+dataLen); //notify update if (pg!=null) { pg.setProgress(dataPos); pg.onUpate(); } } } if (fileIn !=null) { fileIn.close(); } //send length and md5 dataOut.setCommand(id, "PUT_EOF "+Util.makeParamsString(new String[] {""+dataPos, md5.getMD5HexString()})); dataOut.sendPackage(); //receive next package while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } if (!hasPkg) { handleConnectionClosed(); return false; } } else if (dataIn.type == SecureConnection.TYPE_ACK_COMPLETE) { //System.out.println("Upload complete"); //progress ready after receiving ACK_COMPLETE if (pg!=null) { pg.setProgress(pg.getMaxProgress()); pg.onUpate(); } return true; } } else { //stop upload (if running) transferData = false; if(dataIn.isError()){ dataIn.getError().throwException(getMessageFromContent(dataIn.content)); } errorMsg = getMessageFromContent(dataIn.content); return false; } } if (!hasPkg) { handleConnectionClosed(); return false; } else { System.out.println("should never be in this state!!!"); return false; } } public boolean uploadOldStyle(byte[] data, String absoluteRemoteFilename, boolean resume, ProgressListener pg) throws Exception { errorMsg = null; long id = SecureConnection.getID(); int num = 0; long dataPos = -1L; long dataLen = data.length; long maxFilelengthForMD5 = 100*1024*1024L; //100 MB boolean hasNext = true; if (pg!=null) { if (dataLen>0) { pg.setMaxProgress(dataLen); } else { pg.setMaxProgress(1); } pg.setProgress(0); pg.onUpate(); } String command = null; String[] param; if (dataLen>0) { byte[] md5 = null; if (dataLen<maxFilelengthForMD5) { try { md5 = SecurityHelper.getMD5(data); } catch (Exception e) { System.out.println("Error calculating md5 hash of data"); e.printStackTrace(); md5 = null; } } if (md5!=null) { param = new String[] {absoluteRemoteFilename,""+dataLen,SecurityHelper.HexDecoder.encode(md5)}; } else { param = new String[] {absoluteRemoteFilename,""+dataLen}; } } else { dataLen = 0L; param = new String[] {absoluteRemoteFilename,""+dataLen}; } if (resume) { command = "RESUMEPUT "+Util.makeParamsString(param); } else { command = "PUT "+Util.makeParamsString(param); } dataOut.setCommand(id, command); if (DEBUG) { Logger.getFileTransferLogger().logMsg("SEND CMD: "+command); } dataOut.sendPackage(); boolean hasPkg = false; while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } while (hasPkg) { if (!SecureConnection.isError(dataIn.type)) { if (dataIn.type == SecureConnection.TYPE_ACK) { //System.out.println("ACK upload of file: "+remoteName); if (dataLen<=0) { //progress ready for file of length 0 if (pg!=null) { pg.setProgress(pg.getMaxProgress()); pg.onUpate(); } return true; } dataPos = 0; if (resume) { String msg = getMessageFromContent(dataIn.content); //System.out.println("resume msg :: "+msg+" filePos before = "+dataPos); if (msg!=null && msg.equals("upload already complete")) { hasNext = false; System.out.println(msg); //notifyUpdate(fileLen-1, fileLen, null); //progress ready if (pg!=null) { pg.setProgress(pg.getMaxProgress()); pg.onUpate(); } return true; } else { try { dataPos = Long.parseLong(getMessageFromContent(dataIn.content)); //System.out.println("data pos = "+dataPos); if (dataPos>=dataLen) { errorMsg = "data position > data length"; return false; } if (pg!=null) { pg.setProgress(dataPos); pg.onUpate(); } } catch (Exception ex) { //ex.printStackTrace(); errorMsg = "wrong format: data upload resume position not parseable"; return false; } } } //send data while (hasNext) { //read from data int nextPackSize = (int)(dataLen-dataPos); if (nextPackSize>maxPacketSize) { nextPackSize = maxPacketSize; } if (nextPackSize>0) { num++; dataOut.setData(id, num, Arrays.copyOfRange(data, (int)dataPos, (int)dataPos+nextPackSize)); dataOut.sendPackage(); dataPos += nextPackSize; } //notify update if (pg!=null) { pg.setProgress(dataPos); pg.onUpate(); } if (dataPos>=dataLen) { hasNext = false; } } //receive next package while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } if (!hasPkg) { handleConnectionClosed(); return false; } } else if (dataIn.type == SecureConnection.TYPE_ACK_COMPLETE) { //System.out.println("Upload complete"); //progress ready after receiving ACK_COMPLETE if (pg!=null) { pg.setProgress(pg.getMaxProgress()); pg.onUpate(); } return true; } } else { //stop upload hasNext = false; errorMsg = getMessageFromContent(dataIn.content); return false; } } if (!hasPkg) { handleConnectionClosed(); return false; } else { System.out.println("should never be in this state!!!"); return false; } } public void download(String absoluteRemoteFilename, File localFile, boolean showProgress) throws OSDXException { try { System.out.println("Download of file: "+absoluteRemoteFilename+" -> "+localFile.getCanonicalPath()); ProgressListener pg = null; if (showProgress) { pg = new ProgressListener() { int lastProg = -1; public void onUpate() { if (getMaxProgress()>0) { int prog = (int) (getProgress()*10L / getMaxProgress()); if (prog > lastProg) { System.out.println(" progress: "+prog*10+"%"); lastProg = prog; } } } }; } boolean ok = download(absoluteRemoteFilename, localFile, false, pg); if (ok) { System.out.println("Download finished.\n"); } else { if (errorMsg==null) { System.out.println("ERROR\n"); } else { System.out.println("ERROR: "+errorMsg+"\n"); } } } catch (OSDXException osdxe){ throw osdxe; //Rethrow } catch (Exception ex) { ex.printStackTrace(); } } public boolean download(String absoluteRemoteFilename, File localFile, boolean resume, ProgressListener pg) throws Exception { errorMsg = null; long id = SecureConnection.getID(); int num = 0; long fileLen = -1L; long filePos = -1L; byte[] md5 = null; FileOutputStream fileOut = null; String command; if (resume && localFile.exists()) { long length = localFile.length(); String param = Util.makeParamsString(new String[]{absoluteRemoteFilename,""+length}); command = "RESUMEGET "+param; filePos = length; } else { resume = false; command = "GET "+absoluteRemoteFilename; filePos = 0L; } dataOut.setCommand(id, command); if (DEBUG) { Logger.getFileTransferLogger().logMsg("SEND CMD: "+command); } dataOut.sendPackage(); boolean hasPkg = false; while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } while (hasPkg) { if (!SecureConnection.isError(dataIn.type)) { if (dataIn.type == SecureConnection.TYPE_ACK) { String[] p = Util.getParams(getMessageFromContentNN(dataIn.content)); fileLen = Long.parseLong(p[0]); //System.out.println("filelength = "+fileLen); if (p.length==2) { try { md5 = SecurityHelper.HexDecoder.decode(p[1]); System.out.println("md5 = "+p[1]); } catch (Exception ex) { System.out.println("Warning: could not parse md5 hash: "+p[1]); md5 = null; } } if (fileLen==0) { localFile.createNewFile(); if (pg!=null) { pg.setMaxProgress(1); pg.setProgress(1); pg.onUpate(); } return true; } else { //open file for output localFile.getParentFile().mkdirs(); if (resume) { fileOut = new FileOutputStream(localFile,true); //append if resume } else { fileOut = new FileOutputStream(localFile); //new if not resume } } if (resume) { //already finished download if (filePos>fileLen) { //System.out.println("ERROR wrong filesize."); //close file try { fileOut.close(); } catch (IOException e) { e.printStackTrace(); } OSDXErrorCode.ERROR_WRONG_FILESIZE.throwException("Error downloading \""+absoluteRemoteFilename+"\" :: wrong filesize"); errorMsg = "Error downloading \""+absoluteRemoteFilename+"\" :: wrong filesize"; return false; } else if (fileLen==filePos) { if (pg!=null) { pg.setMaxProgress(fileLen); pg.setProgress(filePos); pg.onUpate(); } if (md5!=null){ //check md5 byte[] myMd5 = SecurityHelper.getMD5(localFile); if (Arrays.equals(md5, myMd5)) { System.out.println("MD5 check ok"); return true; } else { System.out.println("MD5 check FAILD!"); OSDXErrorCode.ERROR_MD5_CHECK.throwException("Error downloading \""+absoluteRemoteFilename+"\" :: MD5 check FAILD!"); errorMsg = "Error downloading \""+absoluteRemoteFilename+"\" :: MD5 check FAILD!"; return false; } } else { return true; } } } if (pg!=null) { pg.setMaxProgress(fileLen); pg.setProgress(filePos); pg.onUpate(); } //receive next package while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } if (!hasPkg) { handleConnectionClosed(); return false; } } else if (dataIn.type == SecureConnection.TYPE_DATA) { //write content fileOut.write(dataIn.content); filePos += dataIn.content.length; //update progress if (pg!=null) { pg.setMaxProgress(fileLen); pg.setProgress(filePos); pg.onUpate(); } //finish if filePos at end if (filePos>=fileLen) { //finished //System.out.println("Download finished: "+localFile.getAbsolutePath()); //close file try { fileOut.flush(); fileOut.close(); } catch (IOException e) { e.printStackTrace(); } if (filePos>fileLen) { OSDXErrorCode.ERROR_WRONG_FILESIZE.throwException("Error downloading \""+absoluteRemoteFilename+"\" :: wrong filesize"); errorMsg = "Error downloading \""+absoluteRemoteFilename+"\" :: wrong filesize"; //System.out.println("ERROR wrong filesize."); return false; } else { //successfully finished download if (md5!=null){ //check md5 byte[] myMd5 = SecurityHelper.getMD5(localFile); if (Arrays.equals(md5, myMd5)) { System.out.println("MD5 check ok"); return true; } else { System.out.println("MD5 check FAILD!"); OSDXErrorCode.ERROR_MD5_CHECK.throwException("Error downloading \""+absoluteRemoteFilename+"\" :: MD5 check FAILD!"); errorMsg = "Error downloading \""+absoluteRemoteFilename+"\" :: MD5 check FAILD!"; return false; } } else { //notifyUpdate(filePos, fileLen, null); return true; } } } else { //not finished yet //receive next package while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } if (!hasPkg) { handleConnectionClosed(); return false; } } } } //end of if !error else { //stop download try { if (fileOut!=null) { fileOut.close(); } } catch (Exception ex) { //ex.printStackTrace(); } if(dataIn.isError()){ dataIn.getError().throwException(getMessageFromContent(dataIn.content)); } errorMsg = getMessageFromContent(dataIn.content); return false; } } if (!hasPkg) { handleConnectionClosed(); return false; } else { System.out.println("should never be in this state!!!"); return false; } } public boolean download(String absoluteRemoteFilename, OutputStream out, ProgressListener pg) throws Exception { errorMsg = null; long id = SecureConnection.getID(); int num = 0; long fileLen = -1L; long filePos = -1L; byte[] md5 = null; String command; command = "GET "+absoluteRemoteFilename; filePos = 0L; dataOut.setCommand(id, command); if (DEBUG) { Logger.getFileTransferLogger().logMsg("SEND CMD: "+command); } dataOut.sendPackage(); boolean hasPkg = false; while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } while (hasPkg) { if (!SecureConnection.isError(dataIn.type)) { if (dataIn.type == SecureConnection.TYPE_ACK) { String[] p = Util.getParams(getMessageFromContentNN(dataIn.content)); fileLen = Long.parseLong(p[0]); //System.out.println("filelength = "+fileLen); if (p.length==2) { try { md5 = SecurityHelper.HexDecoder.decode(p[1]); System.out.println("md5 = "+p[1]); } catch (Exception ex) { System.out.println("Warning: could not parse md5 hash: "+p[1]); md5 = null; } } if (fileLen==0) { // localFile.createNewFile(); if (pg!=null) { pg.setMaxProgress(1); pg.setProgress(1); pg.onUpate(); } return true; } else { //open file for output } if (pg!=null) { pg.setMaxProgress(fileLen); pg.setProgress(filePos); pg.onUpate(); } //receive next package while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } if (!hasPkg) { handleConnectionClosed(); return false; } } else if (dataIn.type == SecureConnection.TYPE_DATA) { //write content out.write(dataIn.content); filePos += dataIn.content.length; //update progress if (pg!=null) { pg.setMaxProgress(fileLen); pg.setProgress(filePos); pg.onUpate(); } //finish if filePos at end if (filePos>=fileLen) { //finished //System.out.println("Download finished: "+localFile.getAbsolutePath()); try { out.flush(); // fileOut.close(); } catch (IOException e) { e.printStackTrace(); } if (filePos>fileLen) { OSDXErrorCode.ERROR_WRONG_FILESIZE.throwException("Error downloading \""+absoluteRemoteFilename+"\" :: wrong filesize"); errorMsg = "Error downloading \""+absoluteRemoteFilename+"\" :: wrong filesize"; //System.out.println("ERROR wrong filesize."); return false; } else { //successfully finished download // if (md5 != null) { // //check md5 // byte[] myMd5 = SecurityHelper.getMD5(localFile); // if (Arrays.equals(md5, myMd5)) { // System.out.println("MD5 check ok"); // return true; // } else { // System.out.println("MD5 check FAILD!"); // errorMsg = "Error downloading \""+absoluteRemoteFilename+"\" :: MD5 check FAILD!"; // return false; // } // } else { //notifyUpdate(filePos, fileLen, null); return true; // } } } else { //not finished yet //receive next package while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } if (!hasPkg) { handleConnectionClosed(); return false; } } } } //end of if !error else { //stop download try { // if (fileOut!=null) { // fileOut.close(); // } } catch (Exception ex) { //ex.printStackTrace(); } OSDXErrorCode.ERROR_WITH_MESSAGE.throwException(getMessageFromContent(dataIn.content)); errorMsg = getMessageFromContent(dataIn.content); return false; } } if (!hasPkg) { handleConnectionClosed(); return false; } else { System.out.println("should never be in this state!!!"); return false; } } public void closeConnection() { System.out.println("Closing connection."); errorMsg = null; long id = SecureConnection.getID(); String command = "QUIT "; dataOut.setCommand(id, command); if (DEBUG) { Logger.getFileTransferLogger().logMsg("SEND CMD: "+command); } try { dataOut.sendPackage(); } catch (Exception e) { e.printStackTrace(); } try { socket.close(); } catch (Exception e) { e.printStackTrace(); } } private boolean isAllowed(int rightType) { if (rightsAndDuties==null) { return false; } return rightsAndDuties.hasRight(rightType); } private String getMessageFromContent(byte[] content) { if (content==null) return null; try { return new String(content,"UTF-8"); } catch (UnsupportedEncodingException e) { } return null; } private String getMessageFromContentNN(byte[] content) { if (content==null) return ""; try { return new String(content,"UTF-8"); } catch (UnsupportedEncodingException e) { } return ""; } // //file.getParent() does NOT work for Files from args[] // private static String getParentDir(File f) throws Exception { // String d = f.getCanonicalPath(); // d = d.substring(0,d.length()-f.getName().length()-1); // return d; // } public static void main(String[] args) throws Exception { exceptionTest(); //test(); //testPlain(); } public static void testPlain() throws Exception { OSDXFileTransferAdapter client = new OSDXFileTransferAdapter(); String username = "testuser"; String pass = "testpass"; client.connect("localhost", 4221,"/", username, pass); Vector<RemoteFile> rfs = client.list("/"); for(int i=0;i<rfs.size();i++) { RemoteFile r = rfs.elementAt(i); System.out.println(r.toString()); } } public static void exceptionTest() { try { OSDXFileTransferAdapter client = new OSDXFileTransferAdapter(); OSDXKey mysigning = OSDXKey.fromElement(Document.fromString("<?xml version=\"1.0\" encoding=\"UTF-8\"?> <keypair><identities><identity><identnum>0001</identnum><email>test</email><mnemonic restricted=\"true\">test</mnemonic><sha256>2D:83:44:CA:3A:4C:85:3A:FB:E9:A3:15:D1:B4:70:BA:CC:7C:16:C7:DC:80:D9:AF:4F:E5:3D:74:4A:58:47:CE</sha256></identity></identities><sha1fingerprint>27:61:62:78:C1:29:F3:C6:A9:03:44:D2:18:36:37:22:E2:9F:63:BF</sha1fingerprint><authoritativekeyserver>localhost</authoritativekeyserver><datapath><step1><datasource>LOCAL</datasource><datainsertdatetime>2011-06-08 04:42:04 GMT+00:00</datainsertdatetime></step1></datapath><valid_from>2011-06-08 04:42:04 GMT+00:00</valid_from><valid_until>2036-06-07 10:42:04 GMT+00:00</valid_until><usage>ONLYSIGN</usage><level>MASTER</level><parentkeyid /><algo>RSA</algo><bits>3072</bits><modulus>00:88:FA:94:53:C5:EC:A9:31:63:FD:20:E3:38:A6:C8:B7:7F:32:41:4B:84:07:A1:AF:81:48:21:6F:D8:87:58:40:BF:DC:1A:E5:BD:A9:8E:ED:90:84:ED:84:BB:2E:04:FB:4F:33:F9:46:8B:0D:D0:58:F5:85:5C:F7:43:93:60:3A:BF:10:4B:92:65:DF:86:13:11:C0:6A:46:6F:4B:68:C3:5B:C3:48:BF:8E:16:00:36:68:A5:0E:C6:03:3B:87:7C:49:0C:18:FE:34:DA:78:03:F8:4B:B3:22:B9:D5:63:D8:74:B8:88:4C:E9:4D:A4:CE:A5:7C:09:B2:19:55:77:55:81:4C:FF:76:CD:87:69:B9:D4:B8:53:BE:9C:07:52:ED:53:09:D7:66:82:FC:A5:0A:79:2B:0D:06:5A:A7:76:77:F9:C4:27:B3:FD:BB:4A:80:44:8F:83:0F:DA:7E:A1:E7:22:24:D0:CC:EA:B2:F0:7F:03:BF:FC:FA:BB:B5:2D:17:63:40:1F:78:41:34:E4:ED:5A:F7:A2:1A:C5:75:FC:0F:93:44:95:AD:09:0D:10:90:D1:77:6B:D4:02:3C:8B:43:0B:91:3C:F5:F9:4A:94:0C:D4:EC:DD:2B:56:D4:AB:B9:C1:A4:74:AC:85:2E:6C:7C:AE:21:17:11:41:CB:9D:1C:16:98:1A:4F:03:8A:34:80:C5:2E:F6:E8:29:DB:3F:1C:EA:B1:B7:21:A9:5F:FA:93:D3:47:FA:DD:28:8F:4F:AA:53:1B:16:32:61:3B:B2:41:0E:37:DB:16:5B:14:AA:A9:D4:6C:C3:3E:0E:8D:90:B9:C4:83:C1:A6:6A:BF:E0:7F:56:AF:7D:7F:47:E5:4E:9C:8E:E9:E4:27:06:F9:0A:8A:22:7A:85:2D:FE:B2:AF:10:EC:5B:36:E7:96:60:E2:77:C5:9F:78:B9:51:A4:CE:7C:1D:D3:43:BF:4F:B1:2C:3F:DF:30:04:B6:7E:40:7E:F3:0E:F1:12:42:78:C6:4A:07</modulus><pubkey><exponent>01:00:01</exponent></pubkey><privkey><exponent><locked><mantraname>mantra: password</mantraname><algo>AES@256</algo><initvector>6F:67:A3:5C:C0:5A:67:F6:30:32:9A:0E:1E:3A:8B:1B</initvector><padding>CBC/PKCS#5</padding><bytes>12:9A:B4:1C:1F:8D:8B:88:39:CD:CD:C4:C9:4D:BE:65:56:2C:48:40:E8:3A:ED:09:F3:BF:0D:A7:A8:09:77:B7:C1:15:FB:8C:93:57:B6:38:F3:31:9B:A8:1E:21:27:40:9E:93:E9:4A:1F:B1:41:02:CF:40:96:2C:A6:17:2B:48:68:58:70:AD:B7:E1:52:6F:09:19:11:67:59:BC:1F:FD:BE:88:C0:B2:FF:76:34:EF:1B:26:DA:9F:4C:47:66:0E:87:BB:1C:09:CB:F2:77:BC:CB:AE:89:CA:C4:65:98:DA:D1:6E:ED:22:08:70:FC:BB:E2:CC:41:7F:5C:12:7B:A6:D3:32:73:FA:BB:E2:95:A6:1C:34:3E:FD:A8:90:D0:9A:0B:4E:96:06:89:DD:6F:35:02:E5:FB:CA:0A:E7:0D:2E:A1:B3:81:17:DE:8D:7F:96:F4:36:AA:02:4E:EF:C0:EF:56:37:C0:53:FB:B9:E3:C0:5B:69:9E:7C:EC:1F:A3:0B:C5:99:B7:5D:54:52:28:17:4A:B1:3D:C8:36:54:2A:94:0C:32:F7:1B:6A:11:37:91:B5:43:5D:BF:DB:6F:D3:B4:37:18:32:81:81:C1:72:80:B6:95:0E:B0:61:FF:05:CE:FC:98:E5:F1:E4:D1:33:B7:EF:B8:EB:EF:6B:A7:FE:C6:37:77:CF:43:12:C3:5F:2B:2A:51:19:E8:C4:6D:F6:0E:15:C4:C3:AD:BE:4C:FE:D6:D5:3A:00:D8:E0:0B:00:78:A9:5F:D8:21:28:06:B8:74:F2:06:23:63:81:B8:CC:03:EC:2C:ED:6B:74:23:E4:31:C1:4E:9C:B2:24:F0:93:A4:7D:6C:6A:E2:C1:95:EC:EA:DF:DC:85:2B:60:15:24:DE:FD:DD:94:BF:CF:C9:8D:74:DE:8A:D8:89:DC:16:FA:9D:28:37:EE:65:44:AD:61:FB:33:D4:E8:66:D3:BA:D8:38:E1:16:F1:EF:97:FF:01:D7:C3:7D:76:CE:A2:12:1C:24:AC:EC:AE:AC:2B:08:99:7A:D8:A4:41:49:A4:0E:AF:83</bytes></locked></exponent></privkey><gpgkeyserverid /></keypair> ").getRootElement()); mysigning.unlockPrivateKey("password"); String username = "testuser"; try { //Connection Test client.connect("lalala", 4221,"/", mysigning, username); } catch (UnknownHostException uhe){ System.out.println("Connection exception test successfull!"); }catch ( ConnectException ce){ System.out.println("Connection exception test successfull!"); } client.connect("127.0.0.1", 4221,"/", mysigning, username); try{ client.upload(new File("FDL.txt"), "/FDL.txt"); //client.uploadResume(new File("/data/tvtv/BigBang_S05/The_Big_Bang_Theory_S05x01_12.03.13.HQ.avi"), "/test.avi"); } catch (FileSizeException fse){ System.out.println("Filesize Exception test successfull!"); } try { client.download("/FDL.txt", new File("/tmp/FDL.txt"),true); } catch (FileDoesNotExistException fdne){ System.out.println("File Does Not Exists Exception test successfull!"); } try{ client.mkdir("/blub"); } catch (MakeDirectoryException mde){ System.out.println("Make Directory Exception test successfull!"); } try{ RemoteFile rf = client.fileinfo("/blub"); if (rf != null) { System.out.println("FileInfo:: "+rf.toString()); } } catch (OSDXException oex){ System.out.println(""); } client.rename("/blub", "blablub"); Vector<RemoteFile> list = client.list("/"); if (list!=null) { System.out.println("LIST"); for (RemoteFile f : list) { System.out.println(f.toString()); } System.out.println(); } client.delete("/blablub"); client.delete("/FDL.txt"); list = client.list("/"); if (list!=null) { System.out.println("LIST"); for (RemoteFile f : list) { System.out.println(f.toString()); } System.out.println(); } client.closeConnection(); } catch (Exception ex) { ex.printStackTrace(); } } public static void test() { try { OSDXFileTransferAdapter client = new OSDXFileTransferAdapter(); OSDXKey mysigning = OSDXKey.fromElement(Document.fromString("<?xml version=\"1.0\" encoding=\"UTF-8\"?> <keypair><identities><identity><identnum>0001</identnum><email>test</email><mnemonic restricted=\"true\">test</mnemonic><sha256>2D:83:44:CA:3A:4C:85:3A:FB:E9:A3:15:D1:B4:70:BA:CC:7C:16:C7:DC:80:D9:AF:4F:E5:3D:74:4A:58:47:CE</sha256></identity></identities><sha1fingerprint>27:61:62:78:C1:29:F3:C6:A9:03:44:D2:18:36:37:22:E2:9F:63:BF</sha1fingerprint><authoritativekeyserver>localhost</authoritativekeyserver><datapath><step1><datasource>LOCAL</datasource><datainsertdatetime>2011-06-08 04:42:04 GMT+00:00</datainsertdatetime></step1></datapath><valid_from>2011-06-08 04:42:04 GMT+00:00</valid_from><valid_until>2036-06-07 10:42:04 GMT+00:00</valid_until><usage>ONLYSIGN</usage><level>MASTER</level><parentkeyid /><algo>RSA</algo><bits>3072</bits><modulus>00:88:FA:94:53:C5:EC:A9:31:63:FD:20:E3:38:A6:C8:B7:7F:32:41:4B:84:07:A1:AF:81:48:21:6F:D8:87:58:40:BF:DC:1A:E5:BD:A9:8E:ED:90:84:ED:84:BB:2E:04:FB:4F:33:F9:46:8B:0D:D0:58:F5:85:5C:F7:43:93:60:3A:BF:10:4B:92:65:DF:86:13:11:C0:6A:46:6F:4B:68:C3:5B:C3:48:BF:8E:16:00:36:68:A5:0E:C6:03:3B:87:7C:49:0C:18:FE:34:DA:78:03:F8:4B:B3:22:B9:D5:63:D8:74:B8:88:4C:E9:4D:A4:CE:A5:7C:09:B2:19:55:77:55:81:4C:FF:76:CD:87:69:B9:D4:B8:53:BE:9C:07:52:ED:53:09:D7:66:82:FC:A5:0A:79:2B:0D:06:5A:A7:76:77:F9:C4:27:B3:FD:BB:4A:80:44:8F:83:0F:DA:7E:A1:E7:22:24:D0:CC:EA:B2:F0:7F:03:BF:FC:FA:BB:B5:2D:17:63:40:1F:78:41:34:E4:ED:5A:F7:A2:1A:C5:75:FC:0F:93:44:95:AD:09:0D:10:90:D1:77:6B:D4:02:3C:8B:43:0B:91:3C:F5:F9:4A:94:0C:D4:EC:DD:2B:56:D4:AB:B9:C1:A4:74:AC:85:2E:6C:7C:AE:21:17:11:41:CB:9D:1C:16:98:1A:4F:03:8A:34:80:C5:2E:F6:E8:29:DB:3F:1C:EA:B1:B7:21:A9:5F:FA:93:D3:47:FA:DD:28:8F:4F:AA:53:1B:16:32:61:3B:B2:41:0E:37:DB:16:5B:14:AA:A9:D4:6C:C3:3E:0E:8D:90:B9:C4:83:C1:A6:6A:BF:E0:7F:56:AF:7D:7F:47:E5:4E:9C:8E:E9:E4:27:06:F9:0A:8A:22:7A:85:2D:FE:B2:AF:10:EC:5B:36:E7:96:60:E2:77:C5:9F:78:B9:51:A4:CE:7C:1D:D3:43:BF:4F:B1:2C:3F:DF:30:04:B6:7E:40:7E:F3:0E:F1:12:42:78:C6:4A:07</modulus><pubkey><exponent>01:00:01</exponent></pubkey><privkey><exponent><locked><mantraname>mantra: password</mantraname><algo>AES@256</algo><initvector>6F:67:A3:5C:C0:5A:67:F6:30:32:9A:0E:1E:3A:8B:1B</initvector><padding>CBC/PKCS#5</padding><bytes>12:9A:B4:1C:1F:8D:8B:88:39:CD:CD:C4:C9:4D:BE:65:56:2C:48:40:E8:3A:ED:09:F3:BF:0D:A7:A8:09:77:B7:C1:15:FB:8C:93:57:B6:38:F3:31:9B:A8:1E:21:27:40:9E:93:E9:4A:1F:B1:41:02:CF:40:96:2C:A6:17:2B:48:68:58:70:AD:B7:E1:52:6F:09:19:11:67:59:BC:1F:FD:BE:88:C0:B2:FF:76:34:EF:1B:26:DA:9F:4C:47:66:0E:87:BB:1C:09:CB:F2:77:BC:CB:AE:89:CA:C4:65:98:DA:D1:6E:ED:22:08:70:FC:BB:E2:CC:41:7F:5C:12:7B:A6:D3:32:73:FA:BB:E2:95:A6:1C:34:3E:FD:A8:90:D0:9A:0B:4E:96:06:89:DD:6F:35:02:E5:FB:CA:0A:E7:0D:2E:A1:B3:81:17:DE:8D:7F:96:F4:36:AA:02:4E:EF:C0:EF:56:37:C0:53:FB:B9:E3:C0:5B:69:9E:7C:EC:1F:A3:0B:C5:99:B7:5D:54:52:28:17:4A:B1:3D:C8:36:54:2A:94:0C:32:F7:1B:6A:11:37:91:B5:43:5D:BF:DB:6F:D3:B4:37:18:32:81:81:C1:72:80:B6:95:0E:B0:61:FF:05:CE:FC:98:E5:F1:E4:D1:33:B7:EF:B8:EB:EF:6B:A7:FE:C6:37:77:CF:43:12:C3:5F:2B:2A:51:19:E8:C4:6D:F6:0E:15:C4:C3:AD:BE:4C:FE:D6:D5:3A:00:D8:E0:0B:00:78:A9:5F:D8:21:28:06:B8:74:F2:06:23:63:81:B8:CC:03:EC:2C:ED:6B:74:23:E4:31:C1:4E:9C:B2:24:F0:93:A4:7D:6C:6A:E2:C1:95:EC:EA:DF:DC:85:2B:60:15:24:DE:FD:DD:94:BF:CF:C9:8D:74:DE:8A:D8:89:DC:16:FA:9D:28:37:EE:65:44:AD:61:FB:33:D4:E8:66:D3:BA:D8:38:E1:16:F1:EF:97:FF:01:D7:C3:7D:76:CE:A2:12:1C:24:AC:EC:AE:AC:2B:08:99:7A:D8:A4:41:49:A4:0E:AF:83</bytes></locked></exponent></privkey><gpgkeyserverid /></keypair> ").getRootElement()); mysigning.unlockPrivateKey("password"); String username = "testuser"; client.connect("localhost", 4221,"/", mysigning, username); client.upload(new File("FDL.txt"), "/FDL.txt"); //client.uploadResume(new File("/data/tvtv/BigBang_S05/The_Big_Bang_Theory_S05x01_12.03.13.HQ.avi"), "/test.avi"); client.download("/FDL.txt", new File("/tmp/FDL.txt"),true); client.mkdir("/blub"); RemoteFile rf = client.fileinfo("/blub"); if (rf != null) { System.out.println("FileInfo:: "+rf.toString()); } client.rename("/blub", "blablub"); Vector<RemoteFile> list = client.list("/"); if (list!=null) { System.out.println("LIST"); for (RemoteFile f : list) { System.out.println(f.toString()); } System.out.println(); } client.delete("/blablub"); client.delete("/FDL.txt"); list = client.list("/"); if (list!=null) { System.out.println("LIST"); for (RemoteFile f : list) { System.out.println(f.toString()); } System.out.println(); } client.closeConnection(); } catch (Exception ex) { ex.printStackTrace(); } } private class SimpleCommand { public String errorMsg = null; //hook in here public boolean onACK() { return true; } private SecureConnection dataIn; private SecureConnection dataOut; public SimpleCommand(SecureConnection dataIn, SecureConnection dataOut) { this.dataIn = dataIn; this.dataOut = dataOut; } public boolean process(String command) { long id = SecureConnection.getID(); errorMsg = null; dataOut.setCommand(id, command); if (DEBUG) { Logger.getFileTransferLogger().logMsg("SEND CMD: "+command); } try { dataOut.sendPackage(); boolean hasPkg = false; while ((hasPkg = dataIn.receiveNextPackage()) && dataIn.id != id) { handleUnexpectedPackageID(); } if (hasPkg) { if (dataIn.type == SecureConnection.TYPE_ACK) { return onACK(); } else if (SecureConnection.isError(dataIn.type)) { errorMsg = getMessageFromContent(dataIn.content); return false; } return false; } else { handleConnectionClosed(); return false; } } catch (Exception ex) { ex.printStackTrace(); errorMsg = ex.getMessage(); return false; } } } }