Skip to main content

Secure file transfer with Java and Versile

Just made an example of how to transfer a file over a secure and authenticated connection in pure Java - without having to use additional technology like ssh/scp. Versile has all you need for creating a secure and authenticated connection, and you'll decide what files you want to expose - nothing more - nothing less.

This is the file server (include versile.jar in your classpath - and create a file called "personregister.txt" in the working directory):

 package versileexample;  
 import java.io.File;  
 import java.io.FileNotFoundException;  
 import java.io.RandomAccessFile;  
 import java.security.interfaces.RSAPublicKey;  
 import java.util.logging.Level;  
 import java.util.logging.Logger;  
 import org.versile.Versile;  
 import org.versile.common.auth.VAuth;  
 import org.versile.common.auth.VCredentials;  
 import org.versile.common.auth.VPrivateCredentials;  
 import org.versile.common.peer.VInetSocketPeer;  
 import org.versile.common.peer.VPeer;  
 import org.versile.crypto.VDecentralIdentity;  
 import org.versile.crypto.VRSAKeyPair;  
 import org.versile.orb.entity.VObject;  
 import org.versile.orb.external.Publish;  
 import org.versile.orb.external.VExternal;  
 import org.versile.orb.link.VLinkAuth;  
 import org.versile.orb.service.VGatewayFactory;  
 import org.versile.reactor.service.VOPService;  
 import org.versile.vse.stream.VByteStreamer;  
 import org.versile.vse.stream.VSimpleFileStreamerData;  
 import org.versile.vse.stream.VStreamError;  
 /**  
  * A simple file server  
  */  
 public class VersileFileServerExample extends VExternal {  
   /**  
    * Remotely callable method returning stream to a shared file. We'll only share one file in this example.  
    * @return  
    * @throws VStreamError  
    * @throws FileNotFoundException   
    */  
   @Publish(show=true, ctx=false)    
   public VByteStreamer getSharedFile() throws VStreamError, FileNotFoundException {         
     VSimpleFileStreamerData.Config cfg = new VSimpleFileStreamerData.Config();  
     cfg.setReadable(true);  
     System.out.println("Returning stream to shared file");  
     // Return streamer to the textfile "personregister.txt"  
     return new VByteStreamer(  
         new VSimpleFileStreamerData(  
         new RandomAccessFile(new File("personregister.txt"), "r"),  
         cfg));  
   }  
   /**  
    * Factory class for remotely accessible service object  
    */  
   public static class Factory implements VGatewayFactory {  
     @Override  
     public VObject build() {        
       return new VersileFileServerExample();  
     }  
   }  
   public static void main(String[] args) throws Exception {  
     // Accept AGPL license  
     Versile.setInternalUseAGPL();  
     // Public key authorized for login  
     final RSAPublicKey authorizedKey = VRSAKeyPair.importPublicArmored(("-----BEGIN RSA PUBLIC KEY-----\n" +  
                     "MIGJAoGBAL80uZMXR6vclBMLL9OZS/bpIO6AIitZpEyTZ96qMbpkgoqP6Wi9ev1Isag3jsZORpPf\n" +  
                     "6OJfMEHAWcF5YxzzLKDd13fAswRzbF2VA+QRikJkT8OED1wseX5rZbo7CenStVd6JMecOUr7wsb9\n" +  
                     "MTY/fgcQyYY8u/yBaBUSLeoJfQPdAgMBAAE=\n" +  
                     "-----END RSA PUBLIC KEY-----").getBytes());  
     // Create server identity  
     VPrivateCredentials serverCredentials = new VPrivateCredentials(VDecentralIdentity.dia(1024, "VersileExample", "Versile", "Versile2014"));  
     // Create service  
     VOPService service = new VOPService(new Factory(), serverCredentials,   
         new VLinkAuth(new VAuth(true,false) {  
       /**  
        * Logic for which public keys to accept - this example only accepts the key above  
        * @param credentials  
        * @return   
        */  
       @Override  
       public synchronized boolean acceptCredentials(VCredentials credentials) {  
         if(authorizedKey.equals(credentials.getPublicKey())){  
           Logger.getLogger(getClass().getName()).info("Authorized link");  
           return true;  
         } else {  
           Logger.getLogger(getClass().getName()).info("Unknown public key");  
           return false;  
         }  
       }  
       /**  
        * We can also accept only specified peers - but in this example we'll just log the ip address of the client  
        * @param peer  
        * @return   
        */  
       @Override  
       public synchronized boolean acceptPeer(VPeer peer) {  
         VInetSocketPeer ipeer = (VInetSocketPeer)peer;  
         Logger.getLogger(getClass().getName()).  
             log(Level.INFO,   
             "Link auth request from {0}",   
             ipeer.getInetAddress().getHostString());        
         return super.acceptPeer(peer);  
       }            
     }));  
     // Start file server  
     service.start();  
   }  
 }  

And now a simple client for downloading the shared file (include versile.jar in your classpath):

 package versileexample;  
 import java.io.FileOutputStream;  
 import org.versile.Versile;  
 import org.versile.common.auth.VPrivateCredentials;  
 import org.versile.crypto.VDecentralIdentity;  
 import org.versile.crypto.VRSAKeyPair;  
 import org.versile.orb.entity.VProxy;  
 import org.versile.orb.link.VLinkReference;  
 import org.versile.reactor.url.VUrl;  
 import org.versile.vse.VSEResolver;  
 import org.versile.vse.stream.VByteStream;  
 import org.versile.vse.stream.VByteStreamerProxy;  
 public class VersileFileServerClientExample {  
   public static void main(String[] args) throws Exception {  
     // Versile license   
     Versile.setInternalUseAGPL();  
     // Enable streaming data types  
     VSEResolver.addToGlobalModules();  
     // Create credentials for logging into the server  
     VRSAKeyPair key = VDecentralIdentity.dia(1024, "test", "peter", "dfw/23hcFDawqaDreq");  
     VPrivateCredentials credentials = new VPrivateCredentials(key);  
     // Export public key (can be inserted into authorized key variable in server example)  
     System.out.println(new String(key.exportPublicArmoredPkcs()));  
     // Get proxy to server and connect  
     VProxy proxy = (VProxy) VUrl.resolve("vop://localhost/",credentials);  
     // Call method returning stream to shared file and connect to stream  
     VByteStreamerProxy streamer = (VByteStreamerProxy) proxy.call("getSharedFile", new Object[] {});  
     VByteStream stream = streamer.connect();  
     stream.waitActive();  
     // Read from stream and write to local file  
     FileOutputStream fos = new FileOutputStream("downloadedfile.txt");  
     byte[] filedata;  
     do {  
       filedata = stream.read(65536);        
       fos.write(filedata);  
     } while(filedata.length>0);  
     fos.close();  
     stream.close();      
     System.out.println("File downloaded and saved");  
     // Disconnect from server  
     ((VLinkReference)proxy.get())._v_link().shutdown(false);  
   }  
 }  

Comments

Popular posts from this blog

Angular components not reloading on route change

Spent a long time wondering why route changes caused strange effects on my component, and found out that it was because my component wasn't reloading at all. I had this assumption that when a route parameter changed (e.g. /projects/1 changed to /projects/2 ) the component for the route would be reloaded. But this is not the default behaviour of the Angular router. The default behaviour of the Angular router is to reuse the route if the configuration is the same (and not reload the component). But we can override this by providing a RouteReuseStrategy to our @NgModule: providers: [ { provide: RouteReuseStrategy, useClass: AARouteReuseStrategy } ] The full custom implementation of the RouteReuseStrategy will then be like this (and it's the shouldReuseRoute method that changes the behaviour so that the component is reloaded on route parameter change): export class AARouteReuseStrategy extends RouteReuseStrategy { shouldDetach(route: ActivatedRou...

Using Angular i18n translation strings outside templates

As of today in Angular 6 i18n is only available in the templates. So what if we want to use translated messages programatically and outside templates? I still use the component template html file to declare the message to be translated, but by obtaining the TemplateRef ViewChild in the component typescript file I can get the translated messages from typescript. <ng-template #boardInvitationEmailBody let-organization="organization" let-url="url"> <ng-container i18n>You have been invited to join the board portal for</ng-container> {{organization}}. <ng-container i18n> Please follow the link to: </ng-container> {{url}} </ng-template> So in the typescript code i can now call the createEmailBodyTranlated text method to get the translated text for use outside the template. @ViewChild('boardInvitationEmailBody') boardInvitationEmailBody: TemplateRef ; createEmailBodyTranslatedText(org...

Using GIT for offline web app syncing and storage

Offline web applications, progressive web apps (PWA) using service workers for being available offline also needs a way to sync changes with the server. Mostly we store data in JSON documents, and we could identify changes per line - which is something GIT is excellent at. So how could we make the browser a GIT client? I've been working on this for some months now, and compiled libgit2 to webassembly using emscripten - and it turns out to work very well. Some video demos: Cloning a repository: https://youtu.be/rcBluzpUWE4 Merging of file changes: https://youtu.be/xfGrMwLy_tw The project is here: https://github.com/fintechneo/angular-git-filebrowser