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