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