Mercurial > 510Connectbot
annotate src/com/five_ten_sg/connectbot/PubkeyListActivity.java @ 379:aaf1599a8656
document eula key in deployment.connections
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Mon, 04 Aug 2014 15:08:42 -0700 |
parents | 349847b2e318 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 * ConnectBot: simple, powerful, open-source SSH client for Android | |
3 * Copyright 2007 Kenny Root, Jeffrey Sharkey | |
4 * | |
5 * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 * you may not use this file except in compliance with the License. | |
7 * You may obtain a copy of the License at | |
8 * | |
9 * http://www.apache.org/licenses/LICENSE-2.0 | |
10 * | |
11 * Unless required by applicable law or agreed to in writing, software | |
12 * distributed under the License is distributed on an "AS IS" BASIS, | |
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 * See the License for the specific language governing permissions and | |
15 * limitations under the License. | |
16 */ | |
17 | |
18 package com.five_ten_sg.connectbot; | |
19 | |
20 import java.io.ByteArrayOutputStream; | |
21 import java.io.File; | |
22 import java.io.FileInputStream; | |
23 import java.io.FileOutputStream; | |
24 import java.io.IOException; | |
25 import java.io.InputStream; | |
26 import java.security.KeyPair; | |
27 import java.security.PrivateKey; | |
28 import java.security.PublicKey; | |
29 import java.util.EventListener; | |
30 import java.util.List; | |
31 | |
32 import com.five_ten_sg.connectbot.bean.PubkeyBean; | |
33 import com.five_ten_sg.connectbot.service.TerminalManager; | |
34 import com.five_ten_sg.connectbot.util.FileChooser; | |
35 import com.five_ten_sg.connectbot.util.FileChooserCallback; | |
36 import com.five_ten_sg.connectbot.util.PubkeyDatabase; | |
37 import com.five_ten_sg.connectbot.util.PubkeyUtils; | |
38 import android.app.AlertDialog; | |
39 import android.app.ListActivity; | |
40 import android.content.ComponentName; | |
41 import android.content.Context; | |
42 import android.content.DialogInterface; | |
43 import android.content.Intent; | |
44 import android.content.ServiceConnection; | |
45 import android.os.Bundle; | |
46 import android.os.Environment; | |
47 import android.os.IBinder; | |
48 import android.text.ClipboardManager; | |
49 import android.util.Log; | |
50 import android.view.ContextMenu; | |
51 import android.view.LayoutInflater; | |
52 import android.view.Menu; | |
53 import android.view.MenuItem; | |
54 import android.view.MenuItem.OnMenuItemClickListener; | |
55 import android.view.View; | |
56 import android.view.ViewGroup; | |
57 import android.widget.AdapterView; | |
58 import android.widget.AdapterView.OnItemClickListener; | |
59 import android.widget.ArrayAdapter; | |
60 import android.widget.EditText; | |
61 import android.widget.ImageView; | |
62 import android.widget.TableRow; | |
63 import android.widget.TextView; | |
64 import android.widget.Toast; | |
65 | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
132
diff
changeset
|
66 import ch.ethz.ssh2.crypto.Base64; |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
132
diff
changeset
|
67 import ch.ethz.ssh2.crypto.PEMDecoder; |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
132
diff
changeset
|
68 import ch.ethz.ssh2.crypto.PEMStructure; |
0 | 69 |
70 /** | |
71 * List public keys in database by nickname and describe their properties. Allow users to import, | |
72 * generate, rename, and delete key pairs. | |
73 * | |
74 * @author Kenny Root | |
75 */ | |
76 public class PubkeyListActivity extends ListActivity implements EventListener, FileChooserCallback { | |
77 | |
78 public final static String TAG = "ConnectBot.PubkeyListActivity"; | |
79 | |
80 private static final int MAX_KEYFILE_SIZE = 8192; | |
81 private static final int KEYTYPE_PUBLIC = 0; | |
82 private static final int KEYTYPE_PRIVATE = 1; | |
83 | |
84 protected PubkeyDatabase pubkeydb; | |
85 private List<PubkeyBean> pubkeys; | |
86 | |
87 protected ClipboardManager clipboard; | |
88 | |
89 protected LayoutInflater inflater = null; | |
90 | |
91 protected TerminalManager bound = null; | |
92 | |
93 private MenuItem onstartToggle = null; | |
94 private MenuItem confirmUse = null; | |
95 | |
96 private ServiceConnection connection = new ServiceConnection() { | |
97 public void onServiceConnected(ComponentName className, IBinder service) { | |
98 bound = ((TerminalManager.TerminalBinder) service).getService(); | |
99 // update our listview binder to find the service | |
100 updateList(); | |
101 } | |
102 public void onServiceDisconnected(ComponentName className) { | |
103 bound = null; | |
104 updateList(); | |
105 } | |
106 }; | |
107 | |
108 @Override | |
109 public void onStart() { | |
110 super.onStart(); | |
111 bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE); | |
112 | |
113 if (pubkeydb == null) | |
114 pubkeydb = new PubkeyDatabase(this); | |
115 } | |
116 | |
117 @Override | |
118 public void onStop() { | |
119 super.onStop(); | |
120 unbindService(connection); | |
121 | |
122 if (pubkeydb != null) { | |
123 pubkeydb.close(); | |
124 pubkeydb = null; | |
125 } | |
126 } | |
127 | |
128 @Override | |
129 public void onCreate(Bundle icicle) { | |
130 super.onCreate(icicle); | |
131 setContentView(R.layout.act_pubkeylist); | |
132 this.setTitle(String.format("%s: %s", | |
133 getResources().getText(R.string.app_name), | |
134 getResources().getText(R.string.title_pubkey_list))); | |
135 // connect with hosts database and populate list | |
136 pubkeydb = new PubkeyDatabase(this); | |
137 updateList(); | |
138 registerForContextMenu(getListView()); | |
139 getListView().setOnItemClickListener(new OnItemClickListener() { | |
140 public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { | |
141 PubkeyBean pubkey = (PubkeyBean) getListView().getItemAtPosition(position); | |
142 boolean loaded = bound.isKeyLoaded(pubkey.getNickname()); | |
143 | |
144 // handle toggling key in-memory on/off | |
145 if (loaded) { | |
146 bound.removeKey(pubkey.getNickname()); | |
147 updateList(); | |
148 } | |
149 else { | |
150 handleAddKey(pubkey); | |
151 } | |
152 } | |
153 }); | |
154 clipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE); | |
155 inflater = LayoutInflater.from(this); | |
156 } | |
157 | |
158 /** | |
159 * Read given file into memory as <code>byte[]</code>. | |
160 */ | |
161 protected static byte[] readRaw(File file) throws Exception { | |
162 InputStream is = new FileInputStream(file); | |
163 ByteArrayOutputStream os = new ByteArrayOutputStream(); | |
164 int bytesRead; | |
165 byte[] buffer = new byte[1024]; | |
166 | |
167 while ((bytesRead = is.read(buffer)) != -1) { | |
168 os.write(buffer, 0, bytesRead); | |
169 } | |
170 | |
171 os.flush(); | |
172 os.close(); | |
173 is.close(); | |
174 return os.toByteArray(); | |
175 } | |
176 | |
177 @Override | |
178 public boolean onCreateOptionsMenu(Menu menu) { | |
179 super.onCreateOptionsMenu(menu); | |
180 MenuItem generatekey = menu.add(R.string.pubkey_generate); | |
181 generatekey.setIcon(android.R.drawable.ic_menu_manage); | |
182 generatekey.setIntent(new Intent(PubkeyListActivity.this, GeneratePubkeyActivity.class)); | |
183 MenuItem importkey = menu.add(R.string.pubkey_import); | |
184 importkey.setIcon(android.R.drawable.ic_menu_upload); | |
185 importkey.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
186 public boolean onMenuItemClick(MenuItem item) { | |
187 FileChooser.selectFile(PubkeyListActivity.this, PubkeyListActivity.this, | |
188 FileChooser.REQUEST_CODE_SELECT_FILE, | |
189 getString(R.string.file_chooser_select_file, getString(R.string.select_for_key_import))); | |
190 return true; | |
191 } | |
192 }); | |
193 return true; | |
194 } | |
195 | |
196 protected void handleAddKey(final PubkeyBean pubkey) { | |
197 if (pubkey.isEncrypted()) { | |
198 final View view = inflater.inflate(R.layout.dia_password, null); | |
199 final EditText passwordField = (EditText)view.findViewById(android.R.id.text1); | |
200 new AlertDialog.Builder(PubkeyListActivity.this) | |
201 .setView(view) | |
202 .setPositiveButton(R.string.pubkey_unlock, new DialogInterface.OnClickListener() { | |
203 public void onClick(DialogInterface dialog, int which) { | |
204 handleAddKey(pubkey, passwordField.getText().toString()); | |
205 } | |
206 }) | |
207 .setNegativeButton(android.R.string.cancel, null).create().show(); | |
208 } | |
209 else { | |
210 handleAddKey(pubkey, null); | |
211 } | |
212 } | |
213 | |
214 protected void handleAddKey(PubkeyBean keybean, String password) { | |
215 KeyPair pair = null; | |
216 | |
217 if (PubkeyDatabase.KEY_TYPE_IMPORTED.equals(keybean.getType())) { | |
218 // load specific key using pem format | |
219 try { | |
220 pair = PEMDecoder.decode(new String(keybean.getPrivateKey()).toCharArray(), password); | |
221 } | |
222 catch (Exception e) { | |
223 String message = getResources().getString(R.string.pubkey_failed_add, keybean.getNickname()); | |
224 Log.e(TAG, message, e); | |
225 Toast.makeText(PubkeyListActivity.this, message, Toast.LENGTH_LONG).show(); | |
226 } | |
227 } | |
228 else { | |
229 // load using internal generated format | |
230 try { | |
231 PrivateKey privKey = PubkeyUtils.decodePrivate(keybean.getPrivateKey(), keybean.getType(), password); | |
232 PublicKey pubKey = PubkeyUtils.decodePublic(keybean.getPublicKey(), keybean.getType()); | |
233 Log.d(TAG, "Unlocked key " + PubkeyUtils.formatKey(pubKey)); | |
234 pair = new KeyPair(pubKey, privKey); | |
235 } | |
236 catch (Exception e) { | |
237 String message = getResources().getString(R.string.pubkey_failed_add, keybean.getNickname()); | |
238 Log.e(TAG, message, e); | |
239 Toast.makeText(PubkeyListActivity.this, message, Toast.LENGTH_LONG).show(); | |
240 return; | |
241 } | |
242 } | |
243 | |
244 if (pair == null) return; | |
245 | |
246 Log.d(TAG, String.format("Unlocked key '%s'", keybean.getNickname())); | |
247 // save this key in memory | |
248 bound.addKey(keybean, pair, true); | |
249 updateList(); | |
250 } | |
251 | |
252 @Override | |
253 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { | |
254 // Create menu to handle deleting and editing pubkey | |
255 AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; | |
256 final PubkeyBean pubkey = (PubkeyBean) getListView().getItemAtPosition(info.position); | |
257 menu.setHeaderTitle(pubkey.getNickname()); | |
258 // TODO: option load/unload key from in-memory list | |
259 // prompt for password as needed for passworded keys | |
260 // cant change password or clipboard imported keys | |
261 final boolean imported = PubkeyDatabase.KEY_TYPE_IMPORTED.equals(pubkey.getType()); | |
262 final boolean loaded = bound.isKeyLoaded(pubkey.getNickname()); | |
263 MenuItem load = menu.add(loaded ? R.string.pubkey_memory_unload : R.string.pubkey_memory_load); | |
264 load.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
265 public boolean onMenuItemClick(MenuItem item) { | |
266 if (loaded) { | |
267 bound.removeKey(pubkey.getNickname()); | |
268 updateList(); | |
269 } | |
270 else { | |
271 handleAddKey(pubkey); | |
272 //bound.addKey(nickname, trileadKey); | |
273 } | |
274 | |
275 return true; | |
276 } | |
277 }); | |
278 onstartToggle = menu.add(R.string.pubkey_load_on_start); | |
279 onstartToggle.setVisible(!pubkey.isEncrypted()); | |
280 onstartToggle.setCheckable(true); | |
281 onstartToggle.setChecked(pubkey.isStartup()); | |
282 onstartToggle.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
283 public boolean onMenuItemClick(MenuItem item) { | |
284 // toggle onstart status | |
285 pubkey.setStartup(!pubkey.isStartup()); | |
286 pubkeydb.savePubkey(pubkey); | |
287 updateList(); | |
288 return true; | |
289 } | |
290 }); | |
291 MenuItem changePassword = menu.add(R.string.pubkey_change_password); | |
292 changePassword.setVisible(!imported); | |
293 changePassword.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
294 public boolean onMenuItemClick(MenuItem item) { | |
295 final View changePasswordView = inflater.inflate(R.layout.dia_changepassword, null, false); | |
296 ((TableRow)changePasswordView.findViewById(R.id.old_password_prompt)) | |
297 .setVisibility(pubkey.isEncrypted() ? View.VISIBLE : View.GONE); | |
298 new AlertDialog.Builder(PubkeyListActivity.this) | |
299 .setView(changePasswordView) | |
300 .setPositiveButton(R.string.button_change, new DialogInterface.OnClickListener() { | |
301 public void onClick(DialogInterface dialog, int which) { | |
302 String oldPassword = ((EditText)changePasswordView.findViewById(R.id.old_password)).getText().toString(); | |
303 String password1 = ((EditText)changePasswordView.findViewById(R.id.password1)).getText().toString(); | |
304 String password2 = ((EditText)changePasswordView.findViewById(R.id.password2)).getText().toString(); | |
305 | |
306 if (!password1.equals(password2)) { | |
307 new AlertDialog.Builder(PubkeyListActivity.this) | |
308 .setMessage(R.string.alert_passwords_do_not_match_msg) | |
309 .setPositiveButton(android.R.string.ok, null) | |
310 .create().show(); | |
311 return; | |
312 } | |
313 | |
314 try { | |
315 if (!pubkey.changePassword(oldPassword, password1)) | |
316 new AlertDialog.Builder(PubkeyListActivity.this) | |
317 .setMessage(R.string.alert_wrong_password_msg) | |
318 .setPositiveButton(android.R.string.ok, null) | |
319 .create().show(); | |
320 else { | |
321 pubkeydb.savePubkey(pubkey); | |
322 updateList(); | |
323 } | |
324 } | |
325 catch (Exception e) { | |
326 Log.e(TAG, "Could not change private key password", e); | |
327 new AlertDialog.Builder(PubkeyListActivity.this) | |
328 .setMessage(R.string.alert_key_corrupted_msg) | |
329 .setPositiveButton(android.R.string.ok, null) | |
330 .create().show(); | |
331 } | |
332 } | |
333 }) | |
334 .setNegativeButton(android.R.string.cancel, null).create().show(); | |
335 return true; | |
336 } | |
337 }); | |
338 confirmUse = menu.add(R.string.pubkey_confirm_use); | |
339 confirmUse.setCheckable(true); | |
340 confirmUse.setChecked(pubkey.isConfirmUse()); | |
341 confirmUse.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
342 public boolean onMenuItemClick(MenuItem item) { | |
343 // toggle confirm use | |
344 pubkey.setConfirmUse(!pubkey.isConfirmUse()); | |
345 pubkeydb.savePubkey(pubkey); | |
346 updateList(); | |
347 return true; | |
348 } | |
349 }); | |
350 MenuItem copyPublicToClipboard = menu.add(R.string.pubkey_copy_public); | |
351 copyPublicToClipboard.setVisible(!imported); | |
352 copyPublicToClipboard.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
353 public boolean onMenuItemClick(MenuItem item) { | |
354 try { | |
355 PublicKey pk = PubkeyUtils.decodePublic(pubkey.getPublicKey(), pubkey.getType()); | |
356 String openSSHPubkey = PubkeyUtils.convertToOpenSSHFormat(pk, pubkey.getNickname()); | |
357 clipboard.setText(openSSHPubkey); | |
358 } | |
359 catch (Exception e) { | |
360 e.printStackTrace(); | |
361 } | |
362 | |
363 return true; | |
364 } | |
365 }); | |
366 MenuItem exportPublic = menu.add(R.string.pubkey_export_public); | |
367 exportPublic.setVisible(!imported); | |
368 exportPublic.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
369 public boolean onMenuItemClick(MenuItem item) { | |
370 String keyString = PubkeyUtils.getPubkeyString(pubkey); | |
371 | |
372 if (keyString != null) | |
373 saveKeyToFile(keyString, pubkey.getNickname(), KEYTYPE_PUBLIC); | |
374 | |
375 return true; | |
376 } | |
377 }); | |
378 MenuItem copyPrivateToClipboard = menu.add(R.string.pubkey_copy_private); | |
379 copyPrivateToClipboard.setVisible(!pubkey.isEncrypted() || imported); | |
380 copyPrivateToClipboard.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
381 public boolean onMenuItemClick(MenuItem item) { | |
382 String keyString = PubkeyUtils.getPrivkeyString(pubkey, null); | |
383 | |
384 if (keyString != null) | |
385 clipboard.setText(keyString); | |
386 | |
387 return true; | |
388 } | |
389 }); | |
390 MenuItem exportPrivate = menu.add(R.string.pubkey_export_private); | |
391 exportPrivate.setVisible(!pubkey.isEncrypted() || imported); | |
392 exportPrivate.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
393 public boolean onMenuItemClick(MenuItem item) { | |
394 /* if (pubkey.isEncrypted()) { | |
395 final View view = inflater.inflate(R.layout.dia_password, null); | |
396 final EditText passwordField = (EditText)view.findViewById(android.R.id.text1); | |
397 | |
398 new AlertDialog.Builder(PubkeyListActivity.this) | |
399 .setView(view) | |
400 .setPositiveButton(R.string.pubkey_unlock, new DialogInterface.OnClickListener() { | |
401 public void onClick(DialogInterface dialog, int which) { | |
402 String keyString = PubkeyUtils.getPrivkeyString(pubkey, passwordField.getText().toString()); | |
403 if (keyString != null) | |
404 saveKeyToFile(keyString, pubkey.getNickname(), KEYTYPE_PRIVATE); | |
405 } | |
406 }) | |
407 .setNegativeButton(android.R.string.cancel, null).create().show(); | |
408 } else { */ | |
409 String keyString = PubkeyUtils.getPrivkeyString(pubkey, null); | |
410 | |
411 if (keyString != null) | |
412 saveKeyToFile(keyString, pubkey.getNickname(), KEYTYPE_PRIVATE); | |
413 | |
414 // } | |
415 return true; | |
416 } | |
417 }); | |
418 MenuItem delete = menu.add(R.string.pubkey_delete); | |
419 delete.setOnMenuItemClickListener(new OnMenuItemClickListener() { | |
420 public boolean onMenuItemClick(MenuItem item) { | |
421 // prompt user to make sure they really want this | |
422 new AlertDialog.Builder(PubkeyListActivity.this) | |
423 .setMessage(getString(R.string.delete_message, pubkey.getNickname())) | |
424 .setPositiveButton(R.string.delete_pos, new DialogInterface.OnClickListener() { | |
425 public void onClick(DialogInterface dialog, int which) { | |
426 // dont forget to remove from in-memory | |
427 if (loaded) | |
428 bound.removeKey(pubkey.getNickname()); | |
429 | |
430 // delete from backend database and update gui | |
431 pubkeydb.deletePubkey(pubkey); | |
432 updateList(); | |
433 } | |
434 }) | |
435 .setNegativeButton(R.string.delete_neg, null).create().show(); | |
436 return true; | |
437 } | |
438 }); | |
439 } | |
440 | |
441 protected void updateList() { | |
442 if (pubkeydb == null) return; | |
443 | |
444 pubkeys = pubkeydb.allPubkeys(); | |
445 PubkeyAdapter adapter = new PubkeyAdapter(this, pubkeys); | |
446 this.setListAdapter(adapter); | |
447 } | |
448 | |
449 @Override | |
450 protected void onActivityResult(int requestCode, int resultCode, Intent intent) { | |
451 super.onActivityResult(requestCode, resultCode, intent); | |
452 | |
453 switch (requestCode) { | |
454 case FileChooser.REQUEST_CODE_SELECT_FILE: | |
455 if (resultCode == RESULT_OK && intent != null) { | |
456 File file = FileChooser.getSelectedFile(intent); | |
457 | |
458 if (file != null) | |
459 readKeyFromFile(file); | |
460 } | |
461 | |
462 break; | |
463 } | |
464 } | |
465 | |
466 /** | |
467 * @param name | |
468 */ | |
469 private void readKeyFromFile(File file) { | |
470 PubkeyBean pubkey = new PubkeyBean(); | |
471 // find the exact file selected | |
472 pubkey.setNickname(file.getName()); | |
473 | |
474 if (file.length() > MAX_KEYFILE_SIZE) { | |
475 Toast.makeText(PubkeyListActivity.this, | |
476 R.string.pubkey_import_parse_problem, | |
477 Toast.LENGTH_LONG).show(); | |
478 return; | |
479 } | |
480 | |
481 // parse the actual key once to check if its encrypted | |
482 // then save original file contents into our database | |
483 try { | |
484 byte[] raw = readRaw(file); | |
485 String data = new String(raw); | |
486 | |
487 if (data.startsWith(PubkeyUtils.PKCS8_START)) { | |
488 int start = data.indexOf(PubkeyUtils.PKCS8_START) + PubkeyUtils.PKCS8_START.length(); | |
489 int end = data.indexOf(PubkeyUtils.PKCS8_END); | |
490 | |
491 if (end > start) { | |
492 char[] encoded = data.substring(start, end - 1).toCharArray(); | |
493 Log.d(TAG, "encoded: " + new String(encoded)); | |
494 byte[] decoded = Base64.decode(encoded); | |
495 KeyPair kp = PubkeyUtils.recoverKeyPair(decoded); | |
496 pubkey.setType(kp.getPrivate().getAlgorithm()); | |
497 pubkey.setPrivateKey(kp.getPrivate().getEncoded()); | |
498 pubkey.setPublicKey(kp.getPublic().getEncoded()); | |
499 } | |
500 else { | |
501 Log.e(TAG, "Problem parsing PKCS#8 file; corrupt?"); | |
502 Toast.makeText(PubkeyListActivity.this, | |
503 R.string.pubkey_import_parse_problem, | |
504 Toast.LENGTH_LONG).show(); | |
505 } | |
506 } | |
507 else { | |
508 PEMStructure struct = PEMDecoder.parsePEM(new String(raw).toCharArray()); | |
509 pubkey.setEncrypted(PEMDecoder.isPEMEncrypted(struct)); | |
510 pubkey.setType(PubkeyDatabase.KEY_TYPE_IMPORTED); | |
511 pubkey.setPrivateKey(raw); | |
512 } | |
513 | |
514 // write new value into database | |
515 if (pubkeydb == null) | |
516 pubkeydb = new PubkeyDatabase(this); | |
517 | |
518 pubkeydb.savePubkey(pubkey); | |
519 updateList(); | |
520 } | |
521 catch (Exception e) { | |
522 Log.e(TAG, "Problem parsing imported private key", e); | |
523 Toast.makeText(PubkeyListActivity.this, R.string.pubkey_import_parse_problem, Toast.LENGTH_LONG).show(); | |
524 } | |
525 } | |
526 | |
527 private void saveKeyToFile(final String keyString, final String nickName, int keyType) { | |
528 final int titleId, messageId, successId, errorId; | |
529 final String errorString; | |
530 | |
531 if (keyType == KEYTYPE_PRIVATE) { | |
532 titleId = R.string.pubkey_private_save_as; | |
533 messageId = R.string.pubkey_private_save_as_desc; | |
534 successId = R.string.pubkey_private_export_success; | |
535 errorId = R.string.pubkey_private_export_problem; | |
536 errorString = "Error exporting private key"; | |
537 } | |
538 else { | |
539 titleId = R.string.pubkey_public_save_as; | |
540 messageId = R.string.pubkey_public_save_as_desc; | |
541 errorId = R.string.pubkey_public_export_problem; | |
542 successId = R.string.pubkey_public_export_success; | |
543 errorString = "Error exporting public key"; | |
544 } | |
545 | |
132
265a4733edcb
read deployment.connections on startup for new host entries
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
546 final String sdcard = Environment.getExternalStorageDirectory().getAbsolutePath(); |
0 | 547 final EditText fileName = new EditText(PubkeyListActivity.this); |
548 fileName.setSingleLine(); | |
549 | |
550 if (nickName != null) { | |
551 if (keyType == KEYTYPE_PRIVATE) | |
132
265a4733edcb
read deployment.connections on startup for new host entries
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
552 fileName.setText(sdcard + File.separator + nickName.trim()); |
0 | 553 else |
132
265a4733edcb
read deployment.connections on startup for new host entries
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
554 fileName.setText(sdcard + File.separator + nickName.trim() + ".pub"); |
0 | 555 } |
556 | |
557 new AlertDialog.Builder(PubkeyListActivity.this) | |
558 .setTitle(titleId) | |
559 .setMessage(messageId) | |
560 .setView(fileName) | |
561 .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { | |
562 public void onClick(DialogInterface dialog, int whichButton) { | |
563 File keyFile = new File(fileName.getText().toString()); | |
564 | |
565 if (!keyFile.exists()) { | |
566 try { | |
567 keyFile.createNewFile(); | |
568 } | |
569 catch (IOException e) { | |
570 Log.e(TAG, errorString); | |
571 Toast.makeText(PubkeyListActivity.this, | |
572 errorId, | |
573 Toast.LENGTH_LONG).show(); | |
574 return; | |
575 } | |
576 } | |
577 | |
578 FileOutputStream fout = null; | |
579 | |
580 try { | |
581 fout = new FileOutputStream(keyFile); | |
582 fout.write(keyString.getBytes(), 0, keyString.getBytes().length); | |
583 fout.flush(); | |
584 } | |
585 catch (Exception e) { | |
586 Log.e(TAG, errorString); | |
587 Toast.makeText(PubkeyListActivity.this, | |
588 errorId, | |
589 Toast.LENGTH_LONG).show(); | |
590 return; | |
591 } | |
592 | |
593 Toast.makeText(PubkeyListActivity.this, | |
594 getResources().getString(successId, keyFile.getPath().toString()), | |
595 Toast.LENGTH_LONG).show(); | |
596 } | |
597 }).setNegativeButton(android.R.string.cancel, null).create().show(); | |
598 } | |
599 | |
600 public void fileSelected(File f) { | |
601 Log.d(TAG, "File chooser returned " + f); | |
602 readKeyFromFile(f); | |
603 } | |
604 | |
605 class PubkeyAdapter extends ArrayAdapter<PubkeyBean> { | |
606 private List<PubkeyBean> pubkeys; | |
607 | |
608 class ViewHolder { | |
609 public TextView nickname; | |
610 public TextView caption; | |
611 public ImageView icon; | |
612 } | |
613 | |
614 public PubkeyAdapter(Context context, List<PubkeyBean> pubkeys) { | |
615 super(context, R.layout.item_pubkey, pubkeys); | |
616 this.pubkeys = pubkeys; | |
617 } | |
618 | |
619 @Override | |
620 public View getView(int position, View convertView, ViewGroup parent) { | |
621 ViewHolder holder; | |
622 | |
623 if (convertView == null) { | |
624 convertView = inflater.inflate(R.layout.item_pubkey, null, false); | |
625 holder = new ViewHolder(); | |
626 holder.nickname = (TextView) convertView.findViewById(android.R.id.text1); | |
627 holder.caption = (TextView) convertView.findViewById(android.R.id.text2); | |
628 holder.icon = (ImageView) convertView.findViewById(android.R.id.icon1); | |
629 convertView.setTag(holder); | |
630 } | |
631 else | |
632 holder = (ViewHolder) convertView.getTag(); | |
633 | |
634 PubkeyBean pubkey = pubkeys.get(position); | |
635 holder.nickname.setText(pubkey.getNickname()); | |
636 boolean imported = PubkeyDatabase.KEY_TYPE_IMPORTED.equals(pubkey.getType()); | |
637 | |
638 if (imported) { | |
639 try { | |
640 PEMStructure struct = PEMDecoder.parsePEM(new String(pubkey.getPrivateKey()).toCharArray()); | |
298
ab3a99f11a36
add ecdsa key support everywhere
Carl Byington <carl@five-ten-sg.com>
parents:
273
diff
changeset
|
641 String type = (struct.pemType == PEMDecoder.PEM_RSA_PRIVATE_KEY) ? "RSA" : |
300
349847b2e318
add ecdsa key support everywhere
Carl Byington <carl@five-ten-sg.com>
parents:
298
diff
changeset
|
642 (struct.pemType == PEMDecoder.PEM_DSA_PRIVATE_KEY) ? "DSA" : "EC"; |
0 | 643 holder.caption.setText(String.format("%s unknown-bit", type)); |
644 } | |
645 catch (IOException e) { | |
646 Log.e(TAG, "Error decoding IMPORTED public key at " + pubkey.getId(), e); | |
647 } | |
648 } | |
649 else { | |
650 try { | |
651 holder.caption.setText(pubkey.getDescription()); | |
652 } | |
653 catch (Exception e) { | |
654 Log.e(TAG, "Error decoding public key at " + pubkey.getId(), e); | |
655 holder.caption.setText(R.string.pubkey_unknown_format); | |
656 } | |
657 } | |
658 | |
659 if (bound == null) { | |
660 holder.icon.setVisibility(View.GONE); | |
661 } | |
662 else { | |
663 holder.icon.setVisibility(View.VISIBLE); | |
664 | |
665 if (bound.isKeyLoaded(pubkey.getNickname())) | |
666 holder.icon.setImageState(new int[] { android.R.attr.state_checked }, true); | |
667 else | |
668 holder.icon.setImageState(new int[] { }, true); | |
669 } | |
670 | |
671 return convertView; | |
672 } | |
673 } | |
674 } |