Coverage Report - org.apache.maven.plugin.gpg.GpgSigner
 
Classes in this File Line Coverage Branch Coverage Complexity
GpgSigner
0%
0/93
0%
0/48
2,929
GpgSigner$MaskingThread
0%
0/15
0%
0/2
2,929
 
 1  
 package org.apache.maven.plugin.gpg;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.BufferedReader;
 23  
 import java.io.ByteArrayInputStream;
 24  
 import java.io.File;
 25  
 import java.io.IOException;
 26  
 import java.io.InputStream;
 27  
 import java.io.InputStreamReader;
 28  
 
 29  
 import org.apache.maven.plugin.MojoExecutionException;
 30  
 import org.apache.maven.project.MavenProject;
 31  
 import org.codehaus.plexus.util.Os;
 32  
 import org.codehaus.plexus.util.StringUtils;
 33  
 import org.codehaus.plexus.util.cli.CommandLineException;
 34  
 import org.codehaus.plexus.util.cli.CommandLineUtils;
 35  
 import org.codehaus.plexus.util.cli.Commandline;
 36  
 import org.codehaus.plexus.util.cli.DefaultConsumer;
 37  
 
 38  0
 public class GpgSigner
 39  
 {
 40  
 
 41  
     public static final String SIGNATURE_EXTENSION = ".asc";
 42  
 
 43  
     private String executable;
 44  
  
 45  
     private boolean useAgent;
 46  
 
 47  0
     private boolean isInteractive = true;
 48  
 
 49  
     private String keyname;
 50  
 
 51  
     private String passphrase;
 52  
 
 53  
     private File outputDir;
 54  
 
 55  
     private File buildDir;
 56  
 
 57  
     private File baseDir;
 58  
 
 59  
     private File homeDir;
 60  
 
 61  
     public void setExecutable( String executable )
 62  
     {
 63  0
         this.executable = executable;
 64  0
     }
 65  
 
 66  
     public void setInteractive( boolean b )
 67  
     {
 68  0
         isInteractive = b;
 69  0
     }
 70  
 
 71  
     public void setUseAgent( boolean b )
 72  
     {
 73  0
         useAgent = b;
 74  0
     }
 75  
 
 76  
     public void setKeyName( String s )
 77  
     {
 78  0
         keyname = s;
 79  0
     }
 80  
 
 81  
     public void setPassPhrase( String s )
 82  
     {
 83  0
         passphrase = s;
 84  0
     }
 85  
 
 86  
     public void setOutputDirectory( File out )
 87  
     {
 88  0
         outputDir = out;
 89  0
     }
 90  
 
 91  
     public void setBuildDirectory( File out )
 92  
     {
 93  0
         buildDir = out;
 94  0
     }
 95  
 
 96  
     public void setBaseDirectory( File out )
 97  
     {
 98  0
         baseDir = out;
 99  0
     }
 100  
 
 101  
     public void setHomeDirectory( File homeDirectory )
 102  
     {
 103  0
         homeDir = homeDirectory;
 104  0
     }
 105  
 
 106  
     public File generateSignatureForArtifact( File file )
 107  
         throws MojoExecutionException
 108  
     {
 109  0
         File signature = new File( file + SIGNATURE_EXTENSION );
 110  
 
 111  0
         boolean isInBuildDir = false;
 112  0
         if ( buildDir != null )
 113  
         {
 114  0
             File parent = signature.getParentFile();
 115  0
             if ( buildDir.equals( parent ) )
 116  
             {
 117  0
                 isInBuildDir = true;
 118  
             }
 119  
         }
 120  0
         if ( !isInBuildDir && outputDir != null )
 121  
         {
 122  0
             String fileDirectory = "";
 123  0
             File signatureDirectory = signature;
 124  
 
 125  0
             while ( ( signatureDirectory = signatureDirectory.getParentFile() ) != null )
 126  
             {
 127  0
                 if ( !signatureDirectory.equals( baseDir ) )
 128  
                 {
 129  0
                     fileDirectory = signatureDirectory.getName() + File.separatorChar + fileDirectory;
 130  
                 }
 131  
                 else
 132  
                 {
 133  
                     break;
 134  
                 }
 135  
             }
 136  0
             signatureDirectory = new File( outputDir, fileDirectory );
 137  0
             if ( !signatureDirectory.exists() )
 138  
             {
 139  0
                 signatureDirectory.mkdirs();
 140  
             }
 141  0
             signature = new File( signatureDirectory, file.getName() + SIGNATURE_EXTENSION );
 142  
         }
 143  
 
 144  0
         if ( signature.exists() )
 145  
         {
 146  0
             signature.delete();
 147  
         }
 148  
 
 149  0
         Commandline cmd = new Commandline();
 150  
 
 151  0
         if ( StringUtils.isNotEmpty( executable ) )
 152  
         {
 153  0
             cmd.setExecutable( executable );
 154  
         }
 155  
         else
 156  
         {
 157  0
             cmd.setExecutable( "gpg" + ( Os.isFamily( Os.FAMILY_WINDOWS ) ? ".exe" : "" ) );
 158  
         }
 159  
 
 160  0
         if ( homeDir != null )
 161  
         {
 162  0
             cmd.createArg().setValue( "--homedir" );
 163  0
             cmd.createArg().setFile( homeDir );
 164  
         }
 165  
 
 166  0
         if ( useAgent )
 167  
         {
 168  0
             cmd.createArg().setValue( "--use-agent" );
 169  
         }
 170  
         else
 171  
         {
 172  0
             cmd.createArg().setValue( "--no-use-agent" );
 173  
         }
 174  
 
 175  0
         InputStream in = null;
 176  0
         if ( null != passphrase )
 177  
         {
 178  
             // make --passphrase-fd effective in gpg2
 179  0
             cmd.createArg().setValue( "--batch" );
 180  
 
 181  0
             cmd.createArg().setValue( "--passphrase-fd" );
 182  
 
 183  0
             cmd.createArg().setValue( "0" );
 184  
 
 185  
             // Prepare the input stream which will be used to pass the passphrase to the executable
 186  0
             in = new ByteArrayInputStream( passphrase.getBytes() );
 187  
         }
 188  
 
 189  0
         if ( null != keyname )
 190  
         {
 191  0
             cmd.createArg().setValue( "--local-user" );
 192  
 
 193  0
             cmd.createArg().setValue( keyname );
 194  
         }
 195  
 
 196  0
         cmd.createArg().setValue( "--armor" );
 197  
 
 198  0
         cmd.createArg().setValue( "--detach-sign" );
 199  
 
 200  0
         if ( !isInteractive )
 201  
         {
 202  0
             cmd.createArg().setValue( "--no-tty" );
 203  
         }
 204  
 
 205  0
         cmd.createArg().setValue( "--output" );
 206  0
         cmd.createArg().setFile( signature );
 207  
 
 208  0
         cmd.createArg().setFile( file );
 209  
 
 210  
         try
 211  
         {
 212  0
             int exitCode = CommandLineUtils.executeCommandLine( cmd, in, new DefaultConsumer(), new DefaultConsumer() );
 213  
 
 214  0
             if ( exitCode != 0 )
 215  
             {
 216  0
                 throw new MojoExecutionException( "Exit code: " + exitCode );
 217  
             }
 218  
         }
 219  0
         catch ( CommandLineException e )
 220  
         {
 221  0
             throw new MojoExecutionException( "Unable to execute gpg command", e );
 222  0
         }
 223  
 
 224  0
         return signature;
 225  
     }
 226  
 
 227  
     private MavenProject findReactorProject( MavenProject prj )
 228  
     {
 229  0
         if ( prj.getParent() != null && prj.getParent().getBasedir() != null && prj.getParent().getBasedir().exists() )
 230  
         {
 231  0
             return findReactorProject( prj.getParent() );
 232  
         }
 233  0
         return prj;
 234  
     }
 235  
 
 236  
     public String getPassphrase( MavenProject project )
 237  
         throws IOException
 238  
     {
 239  0
         String pass = null;
 240  
 
 241  0
         if ( project != null )
 242  
         {
 243  0
             pass = project.getProperties().getProperty( "gpg.passphrase" );
 244  0
             if ( pass == null )
 245  
             {
 246  0
                 MavenProject prj2 = findReactorProject( project );
 247  0
                 pass = prj2.getProperties().getProperty( "gpg.passphrase" );
 248  
             }
 249  
         }
 250  0
         if ( pass == null )
 251  
         {
 252  
             // TODO: with JDK 1.6, we could call System.console().readPassword("GPG Passphrase: ", null);
 253  
 
 254  0
             BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) );
 255  0
             while ( System.in.available() != 0 )
 256  
             {
 257  
                 // there's some junk already on the input stream, consume it
 258  
                 // so we can get the real passphrase
 259  0
                 System.in.read();
 260  
             }
 261  
 
 262  0
             System.out.print( "GPG Passphrase:  " );
 263  0
             MaskingThread thread = new MaskingThread();
 264  0
             thread.start();
 265  
 
 266  0
             pass = in.readLine();
 267  
 
 268  
             // stop masking
 269  0
             thread.stopMasking();
 270  
         }
 271  0
         if ( project != null )
 272  
         {
 273  0
             findReactorProject( project ).getProperties().setProperty( "gpg.passphrase", pass );
 274  
         }
 275  0
         return pass;
 276  
     }
 277  
 
 278  
     // based on ideas from http://java.sun.com/developer/technicalArticles/Security/pwordmask/
 279  0
     class MaskingThread
 280  
         extends Thread
 281  
     {
 282  
         private volatile boolean stop;
 283  
 
 284  
         /**
 285  
          * Begin masking until asked to stop.
 286  
          */
 287  
         public void run()
 288  
         {
 289  
             // this needs to be high priority to make sure the characters don't
 290  
             // really get to the screen.
 291  
 
 292  0
             int priority = Thread.currentThread().getPriority();
 293  0
             Thread.currentThread().setPriority( Thread.MAX_PRIORITY );
 294  
 
 295  
             try
 296  
             {
 297  0
                 stop = false;
 298  0
                 while ( !stop )
 299  
                 {
 300  
                     // print a backspace + * to overwrite anything they type
 301  0
                     System.out.print( "\010*" );
 302  
                     try
 303  
                     {
 304  
                         // attempt masking at this rate
 305  0
                         Thread.sleep( 1 );
 306  
                     }
 307  0
                     catch ( InterruptedException iex )
 308  
                     {
 309  0
                         Thread.currentThread().interrupt();
 310  
                         return;
 311  0
                     }
 312  
                 }
 313  
             }
 314  
             finally
 315  
             {
 316  
                 // restore the original priority
 317  0
                 Thread.currentThread().setPriority( priority );
 318  0
             }
 319  0
         }
 320  
 
 321  
         /**
 322  
          * Instruct the thread to stop masking.
 323  
          */
 324  
         public void stopMasking()
 325  
         {
 326  0
             this.stop = true;
 327  0
         }
 328  
     }
 329  
 
 330  
 }