1 package org.apache.maven.plugin.gpg;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 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 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 this.executable = executable;
64 }
65
66 public void setInteractive( boolean b )
67 {
68 isInteractive = b;
69 }
70
71 public void setUseAgent( boolean b )
72 {
73 useAgent = b;
74 }
75
76 public void setKeyName( String s )
77 {
78 keyname = s;
79 }
80
81 public void setPassPhrase( String s )
82 {
83 passphrase = s;
84 }
85
86 public void setOutputDirectory( File out )
87 {
88 outputDir = out;
89 }
90
91 public void setBuildDirectory( File out )
92 {
93 buildDir = out;
94 }
95
96 public void setBaseDirectory( File out )
97 {
98 baseDir = out;
99 }
100
101 public void setHomeDirectory( File homeDirectory )
102 {
103 homeDir = homeDirectory;
104 }
105
106 public File generateSignatureForArtifact( File file )
107 throws MojoExecutionException
108 {
109 File signature = new File( file + SIGNATURE_EXTENSION );
110
111 boolean isInBuildDir = false;
112 if ( buildDir != null )
113 {
114 File parent = signature.getParentFile();
115 if ( buildDir.equals( parent ) )
116 {
117 isInBuildDir = true;
118 }
119 }
120 if ( !isInBuildDir && outputDir != null )
121 {
122 String fileDirectory = "";
123 File signatureDirectory = signature;
124
125 while ( ( signatureDirectory = signatureDirectory.getParentFile() ) != null )
126 {
127 if ( !signatureDirectory.equals( baseDir ) )
128 {
129 fileDirectory = signatureDirectory.getName() + File.separatorChar + fileDirectory;
130 }
131 else
132 {
133 break;
134 }
135 }
136 signatureDirectory = new File( outputDir, fileDirectory );
137 if ( !signatureDirectory.exists() )
138 {
139 signatureDirectory.mkdirs();
140 }
141 signature = new File( signatureDirectory, file.getName() + SIGNATURE_EXTENSION );
142 }
143
144 if ( signature.exists() )
145 {
146 signature.delete();
147 }
148
149 Commandline cmd = new Commandline();
150
151 if ( StringUtils.isNotEmpty( executable ) )
152 {
153 cmd.setExecutable( executable );
154 }
155 else
156 {
157 cmd.setExecutable( "gpg" + ( Os.isFamily( Os.FAMILY_WINDOWS ) ? ".exe" : "" ) );
158 }
159
160 if ( homeDir != null )
161 {
162 cmd.createArg().setValue( "--homedir" );
163 cmd.createArg().setFile( homeDir );
164 }
165
166 if ( useAgent )
167 {
168 cmd.createArg().setValue( "--use-agent" );
169 }
170 else
171 {
172 cmd.createArg().setValue( "--no-use-agent" );
173 }
174
175 InputStream in = null;
176 if ( null != passphrase )
177 {
178
179 cmd.createArg().setValue( "--batch" );
180
181 cmd.createArg().setValue( "--passphrase-fd" );
182
183 cmd.createArg().setValue( "0" );
184
185
186 in = new ByteArrayInputStream( passphrase.getBytes() );
187 }
188
189 if ( null != keyname )
190 {
191 cmd.createArg().setValue( "--local-user" );
192
193 cmd.createArg().setValue( keyname );
194 }
195
196 cmd.createArg().setValue( "--armor" );
197
198 cmd.createArg().setValue( "--detach-sign" );
199
200 if ( !isInteractive )
201 {
202 cmd.createArg().setValue( "--no-tty" );
203 }
204
205 cmd.createArg().setValue( "--output" );
206 cmd.createArg().setFile( signature );
207
208 cmd.createArg().setFile( file );
209
210 try
211 {
212 int exitCode = CommandLineUtils.executeCommandLine( cmd, in, new DefaultConsumer(), new DefaultConsumer() );
213
214 if ( exitCode != 0 )
215 {
216 throw new MojoExecutionException( "Exit code: " + exitCode );
217 }
218 }
219 catch ( CommandLineException e )
220 {
221 throw new MojoExecutionException( "Unable to execute gpg command", e );
222 }
223
224 return signature;
225 }
226
227 private MavenProject findReactorProject( MavenProject prj )
228 {
229 if ( prj.getParent() != null && prj.getParent().getBasedir() != null && prj.getParent().getBasedir().exists() )
230 {
231 return findReactorProject( prj.getParent() );
232 }
233 return prj;
234 }
235
236 public String getPassphrase( MavenProject project )
237 throws IOException
238 {
239 String pass = null;
240
241 if ( project != null )
242 {
243 pass = project.getProperties().getProperty( "gpg.passphrase" );
244 if ( pass == null )
245 {
246 MavenProject prj2 = findReactorProject( project );
247 pass = prj2.getProperties().getProperty( "gpg.passphrase" );
248 }
249 }
250 if ( pass == null )
251 {
252
253
254 BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) );
255 while ( System.in.available() != 0 )
256 {
257
258
259 System.in.read();
260 }
261
262 System.out.print( "GPG Passphrase: " );
263 MaskingThread thread = new MaskingThread();
264 thread.start();
265
266 pass = in.readLine();
267
268
269 thread.stopMasking();
270 }
271 if ( project != null )
272 {
273 findReactorProject( project ).getProperties().setProperty( "gpg.passphrase", pass );
274 }
275 return pass;
276 }
277
278
279 class MaskingThread
280 extends Thread
281 {
282 private volatile boolean stop;
283
284
285
286
287 public void run()
288 {
289
290
291
292 int priority = Thread.currentThread().getPriority();
293 Thread.currentThread().setPriority( Thread.MAX_PRIORITY );
294
295 try
296 {
297 stop = false;
298 while ( !stop )
299 {
300
301 System.out.print( "\010*" );
302 try
303 {
304
305 Thread.sleep( 1 );
306 }
307 catch ( InterruptedException iex )
308 {
309 Thread.currentThread().interrupt();
310 return;
311 }
312 }
313 }
314 finally
315 {
316
317 Thread.currentThread().setPriority( priority );
318 }
319 }
320
321
322
323
324 public void stopMasking()
325 {
326 this.stop = true;
327 }
328 }
329
330 }