├── .editorconfig ├── .gitignore ├── .idea ├── gradle.xml └── runConfigurations.xml ├── .tx └── config ├── LICENSE ├── PGPAuth ├── build.gradle ├── lint.xml └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── org │ │ └── lf_net │ │ └── pgpunlocker │ │ ├── AboutActivity.java │ │ ├── AutoResetEvent.java │ │ ├── Logic.java │ │ ├── MainActivity.java │ │ ├── PGPKeyPreference.java │ │ ├── Server.java │ │ ├── ServerAdapter.java │ │ ├── ServerDeleteActivity.java │ │ ├── ServerEditActivity.java │ │ ├── ServerManager.java │ │ └── SettingsActivity.java │ └── res │ ├── drawable-hdpi │ └── ic_launcher.png │ ├── drawable-mdpi │ └── ic_launcher.png │ ├── drawable-xhdpi │ └── ic_launcher.png │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ ├── activity_about.xml │ ├── activity_main.xml │ ├── activity_server_delete.xml │ ├── activity_server_edit.xml │ └── listview_item_server.xml │ ├── menu │ └── mainmenu.xml │ ├── values-de │ └── strings.xml │ ├── values-eo │ └── strings.xml │ ├── values-fr │ └── strings.xml │ ├── values-it │ └── strings.xml │ ├── values-ja │ └── strings.xml │ ├── values-ru_RU │ └── strings.xml │ ├── values-v14 │ └── styles.xml │ ├── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── preferences.xml ├── README.md ├── build.gradle └── settings.gradle /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 4 10 | curly_bracket_next_line = true 11 | indent_brace_style = GNU 12 | 13 | 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | /*/build/ 3 | 4 | # Crashlytics configuations 5 | com_crashlytics_export_strings.xml 6 | 7 | # Local configuration file (sdk path, etc) 8 | local.properties 9 | 10 | # Gradle generated files 11 | .gradle/ 12 | 13 | # Signing files 14 | .signing/ 15 | 16 | # User-specific configurations 17 | .idea/libraries/ 18 | .idea/workspace.xml 19 | .idea/tasks.xml 20 | .idea/.name 21 | .idea/compiler.xml 22 | .idea/copyright/profiles_settings.xml 23 | .idea/encodings.xml 24 | .idea/misc.xml 25 | .idea/modules.xml 26 | .idea/scopes/scope_settings.xml 27 | .idea/vcs.xml 28 | *.iml 29 | 30 | # OS-specific files 31 | .DS_Store 32 | .DS_Store? 33 | ._* 34 | .Spotlight-V100 35 | .Trashes 36 | ehthumbs.db 37 | Thumbs.db 38 | 39 | # language-specific strings (managed by transifex) 40 | # XXX: translations are added to repo at the moment 41 | # to allow automated builds in F-Droid 42 | #PGPAuth/src/main/res/values-*/strings.xml 43 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | 4 | [pgpauth.Strings] 5 | file_filter = PGPAuth/src/main/res/values-/strings.xml 6 | source_file = PGPAuth/src/main/res/values/strings.xml 7 | source_lang = en 8 | type = Android 9 | 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Addition to the MIT-license for PGPAuth: 2 | It is not neccessary, but it would be really great if you would let me know 3 | when you are creating a product with PGPAuth. 4 | 5 | 6 | 7 | 8 | The MIT License (MIT) 9 | 10 | Copyright (c) 2013-2016 Moritz Grosch (LittleFox) 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy 13 | of this software and associated documentation files (the "Software"), to deal 14 | in the Software without restriction, including without limitation the rights 15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | copies of the Software, and to permit persons to whom the Software is 17 | furnished to do so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in 20 | all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | THE SOFTWARE. 29 | 30 | -------------------------------------------------------------------------------- /PGPAuth/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 18 5 | buildToolsVersion '25.0.0' 6 | 7 | defaultConfig { 8 | applicationId "org.lf_net.pgpunlocker" 9 | minSdkVersion 9 10 | targetSdkVersion 18 11 | } 12 | 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile 'com.android.support:support-v4:18.0.0' 23 | compile 'org.sufficientlysecure:openpgp-api:11.0' 24 | } 25 | -------------------------------------------------------------------------------- /PGPAuth/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /PGPAuth/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 36 | 39 | 40 | 44 | 47 | 48 | 52 | 55 | 56 | 60 | android:parentActivityName=".MainActivity" > 61 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /PGPAuth/src/main/java/org/lf_net/pgpunlocker/AboutActivity.java: -------------------------------------------------------------------------------- 1 | package org.lf_net.pgpunlocker; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | 9 | public class AboutActivity extends Activity { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_about); 15 | } 16 | 17 | public void onWebsiteClick(View view) { 18 | Intent showWebsite = new Intent(Intent.ACTION_VIEW); 19 | showWebsite.setData(Uri.parse((String) view.getTag())); 20 | startActivity(showWebsite); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /PGPAuth/src/main/java/org/lf_net/pgpunlocker/AutoResetEvent.java: -------------------------------------------------------------------------------- 1 | /// From http://stackoverflow.com/a/13838191 2 | 3 | package org.lf_net.pgpunlocker; 4 | 5 | public class AutoResetEvent { 6 | private final Object _monitor = new Object(); 7 | private volatile boolean _isOpen = false; 8 | 9 | public AutoResetEvent(boolean open) { 10 | _isOpen = open; 11 | } 12 | 13 | public void waitOne() throws InterruptedException { 14 | synchronized (_monitor) { 15 | while (!_isOpen) { 16 | _monitor.wait(); 17 | } 18 | _isOpen = false; 19 | } 20 | } 21 | 22 | public void waitOne(long timeout) throws InterruptedException { 23 | synchronized (_monitor) { 24 | long t = System.currentTimeMillis(); 25 | while (!_isOpen) { 26 | _monitor.wait(timeout); 27 | // Check for timeout 28 | if (System.currentTimeMillis() - t >= timeout) 29 | break; 30 | } 31 | _isOpen = false; 32 | } 33 | } 34 | 35 | public void set() { 36 | synchronized (_monitor) { 37 | _isOpen = true; 38 | _monitor.notify(); 39 | } 40 | } 41 | 42 | public void reset() { 43 | _isOpen = false; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /PGPAuth/src/main/java/org/lf_net/pgpunlocker/Logic.java: -------------------------------------------------------------------------------- 1 | package org.lf_net.pgpunlocker; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.InputStream; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import org.apache.http.HttpResponse; 10 | import org.apache.http.NameValuePair; 11 | import org.apache.http.client.HttpClient; 12 | import org.apache.http.client.entity.UrlEncodedFormEntity; 13 | import org.apache.http.client.methods.HttpPost; 14 | import org.apache.http.impl.client.DefaultHttpClient; 15 | import org.apache.http.message.BasicNameValuePair; 16 | import org.openintents.openpgp.OpenPgpError; 17 | import org.openintents.openpgp.util.OpenPgpApi; 18 | import org.openintents.openpgp.util.OpenPgpServiceConnection; 19 | 20 | import android.app.PendingIntent; 21 | import android.content.Context; 22 | import android.content.Intent; 23 | import android.content.IntentSender; 24 | import android.content.pm.PackageInfo; 25 | import android.content.pm.PackageManager.NameNotFoundException; 26 | import android.webkit.URLUtil; 27 | 28 | public class Logic { 29 | 30 | OpenPgpServiceConnection _serviceConnection = null; 31 | Context _context; 32 | String _signedData = null; 33 | AutoResetEvent _event = new AutoResetEvent(false); 34 | GuiHelper _guiHelper; 35 | 36 | public static Logic Logic; 37 | 38 | public abstract class GuiHelper { 39 | public abstract void startActivityForResult(Intent intent, int requestCode); 40 | 41 | public abstract void startIntentSenderForResult(IntentSender intentSender, int requestCode); 42 | 43 | public abstract void showUserFeedback(String feedback); 44 | } 45 | 46 | public Logic(Context context, boolean forceAPG) { 47 | _context = context; 48 | 49 | boolean hasAPG = detectApg(); 50 | boolean hasOpenKeychain = detectOpenKeyChain(); 51 | 52 | if (hasOpenKeychain && !forceAPG) { 53 | _serviceConnection = new OpenPgpServiceConnection(context, "org.sufficientlysecure.keychain"); 54 | _serviceConnection.bindToService(); 55 | } 56 | 57 | if (!hasAPG && forceAPG) { 58 | throw new RuntimeException((String) context.getText(R.string.apg_forced_but_not_installed)); 59 | } 60 | 61 | if (!hasAPG && !hasOpenKeychain) { 62 | throw new RuntimeException((String) context.getText(R.string.apg_and_opengpg_keychain_not_installed)); 63 | } 64 | 65 | _event = new AutoResetEvent(false); 66 | } 67 | 68 | public void close() { 69 | if (_serviceConnection != null && _serviceConnection.isBound()) { 70 | _serviceConnection.unbindFromService(); 71 | } 72 | } 73 | 74 | public void doActionOnServerWithFeedback(String action, String server, String keyAPG) { 75 | String ret = doActionOnServer(action, server, keyAPG); 76 | _guiHelper.showUserFeedback(ret); 77 | } 78 | 79 | public String doActionOnServer(String action, String server, String keyAPG) { 80 | if (server == "" || !URLUtil.isValidUrl(server)) { 81 | if (server == "") { 82 | return _context.getString(R.string.no_server_set); 83 | } else if (!URLUtil.isValidUrl(server)) { 84 | return _context.getString(R.string.invalid_server_set); 85 | } else { 86 | return _context.getString(R.string.unknown_error); 87 | } 88 | } 89 | 90 | long timestamp = System.currentTimeMillis() / 1000; 91 | String request = action + ":" + timestamp; 92 | 93 | if (_serviceConnection == null) { 94 | Intent intent = new Intent("org.thialfihar.android.apg.intent.ENCRYPT_AND_RETURN"); 95 | intent.putExtra("intentVersion", 1); 96 | intent.setType("text/plain"); 97 | intent.putExtra("text", request); 98 | intent.putExtra("ascii_armor", true); 99 | 100 | if (keyAPG != "") { 101 | intent.putExtra("signatureKeyId", Long.parseLong(keyAPG)); 102 | } 103 | 104 | _guiHelper.startActivityForResult(intent, 1); 105 | } else { 106 | Intent intent = new Intent(); 107 | intent.setAction(OpenPgpApi.ACTION_SIGN); 108 | intent.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); 109 | intent.putExtra("PGPAuth_SIGNDATA", request); 110 | 111 | try { 112 | sendOpenKeychainIntent(intent); 113 | } catch (Exception e) { 114 | return e.getLocalizedMessage(); 115 | } 116 | } 117 | 118 | try { 119 | _event.waitOne(); 120 | } catch (InterruptedException e1) { 121 | return e1.getLocalizedMessage(); 122 | } 123 | 124 | if (_signedData == null) { 125 | return _context.getString(R.string.unknown_error); 126 | } 127 | 128 | try { 129 | HttpClient client = new DefaultHttpClient(); 130 | HttpPost req = new HttpPost(server); 131 | List httpParams = new ArrayList(); 132 | httpParams.add(new BasicNameValuePair("data", _signedData)); 133 | req.setEntity(new UrlEncodedFormEntity(httpParams)); 134 | 135 | HttpResponse response = client.execute(req); 136 | 137 | if (response.getStatusLine().getStatusCode() != 200) { 138 | return response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase(); 139 | } else { 140 | return _context.getResources().getString(android.R.string.ok); 141 | } 142 | } catch (Exception e) { 143 | return e.getMessage(); 144 | } finally { 145 | _signedData = null; 146 | _event.reset(); 147 | } 148 | } 149 | 150 | public void postResult(int requestCode, int resultCode, Intent data) { 151 | switch (requestCode) { 152 | case 1: { 153 | if (data != null && data.hasExtra("encryptedMessage")) { 154 | _signedData = data.getStringExtra("encryptedMessage"); 155 | } else { 156 | _signedData = null; 157 | } 158 | 159 | _event.set(); 160 | 161 | break; 162 | } 163 | case 2: { 164 | try { 165 | sendOpenKeychainIntent(data); 166 | } catch (Exception e) { 167 | _signedData = null; 168 | _event.set(); 169 | } 170 | break; 171 | } 172 | } 173 | } 174 | 175 | public void setGuiHelper(GuiHelper guiHelper) { 176 | _guiHelper = guiHelper; 177 | } 178 | 179 | private boolean detectApg() { 180 | try { 181 | PackageInfo pi = _context.getPackageManager().getPackageInfo("org.thialfihar.android.apg", 0); 182 | if (pi.versionCode >= 16) { 183 | return true; 184 | } 185 | } catch (NameNotFoundException e) { 186 | // not found 187 | } 188 | 189 | return false; 190 | } 191 | 192 | private boolean detectOpenKeyChain() { 193 | try { 194 | PackageInfo pi = _context.getPackageManager().getPackageInfo("org.sufficientlysecure.keychain", 0); 195 | 196 | if (pi.versionCode > 20000) { 197 | return true; 198 | } 199 | } catch (NameNotFoundException e) { 200 | // not found 201 | } 202 | 203 | return false; 204 | } 205 | 206 | private void sendOpenKeychainIntent(Intent data) throws Exception { 207 | InputStream is = new ByteArrayInputStream(data.getExtras().getString("PGPAuth_SIGNDATA").getBytes()); 208 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 209 | 210 | OpenPgpApi api = new OpenPgpApi(_context, _serviceConnection.getService()); 211 | Intent result = api.executeApi(data, is, os); 212 | 213 | switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { 214 | case OpenPgpApi.RESULT_CODE_SUCCESS: { 215 | _signedData = os.toString("UTF-8"); 216 | _event.set(); 217 | break; 218 | } 219 | case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: { 220 | PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT); 221 | _guiHelper.startIntentSenderForResult(pi.getIntentSender(), 2); 222 | break; 223 | } 224 | case OpenPgpApi.RESULT_CODE_ERROR: { 225 | OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR); 226 | throw new RuntimeException(error.getMessage()); 227 | } 228 | } 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /PGPAuth/src/main/java/org/lf_net/pgpunlocker/MainActivity.java: -------------------------------------------------------------------------------- 1 | package org.lf_net.pgpunlocker; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.content.IntentSender; 6 | import android.content.IntentSender.SendIntentException; 7 | import android.content.SharedPreferences; 8 | import android.net.Uri; 9 | import android.os.Bundle; 10 | import android.preference.PreferenceManager; 11 | import android.view.ContextMenu; 12 | import android.view.ContextMenu.ContextMenuInfo; 13 | import android.view.Menu; 14 | import android.view.MenuInflater; 15 | import android.view.MenuItem; 16 | import android.view.View; 17 | import android.widget.AdapterView.AdapterContextMenuInfo; 18 | import android.widget.ListView; 19 | import android.widget.Toast; 20 | 21 | public class MainActivity extends Activity { 22 | /** 23 | * Called when the activity is first created. 24 | */ 25 | @Override 26 | public void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | 29 | ServerManager.loadFromFile(this); 30 | 31 | Uri serverConfig = getIntent().getData(); 32 | 33 | if (serverConfig != null) { 34 | Intent intent = new Intent(this, ServerEditActivity.class); 35 | intent.setData(serverConfig); 36 | startActivity(intent); 37 | } 38 | 39 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); 40 | 41 | setContentView(R.layout.activity_main); 42 | 43 | ListView listViewServers = (ListView) findViewById(R.id.listViewServers); 44 | ServerAdapter adapter = new ServerAdapter(this, R.layout.listview_item_server); 45 | listViewServers.setAdapter(adapter); 46 | 47 | registerForContextMenu(listViewServers); 48 | 49 | try { 50 | Logic.Logic = new Logic(this, prefs.getBoolean("pref_forceapg", false)); 51 | 52 | Logic.GuiHelper guiHelper = Logic.Logic.new GuiHelper() { 53 | public void startActivityForResult(Intent intent, int requestCode) { 54 | MainActivity.this.startActivityForResult(intent, requestCode + 0x0000B000); 55 | } 56 | 57 | public void startIntentSenderForResult(IntentSender intentSender, int requestCode) { 58 | try { 59 | MainActivity.this.startIntentSenderForResult(intentSender, requestCode + 0x0000B000, null, 0, 0, 0); 60 | } catch (SendIntentException e) { 61 | // just fuck you 62 | } 63 | } 64 | 65 | public void showUserFeedback(final String feedback) { 66 | runOnUiThread(new Runnable() { 67 | public void run() { 68 | Toast.makeText(MainActivity.this, feedback, Toast.LENGTH_LONG).show(); 69 | } 70 | }); 71 | } 72 | }; 73 | 74 | Logic.Logic.setGuiHelper(guiHelper); 75 | } catch (Exception e) { 76 | Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show(); 77 | Intent intent = new Intent(this, SettingsActivity.class); 78 | startActivityForResult(intent, 0x0000A001); 79 | 80 | Toast.makeText(this, R.string.invalid_settings_detected, Toast.LENGTH_LONG).show(); 81 | } 82 | } 83 | 84 | @Override 85 | public void onDestroy() { 86 | if (Logic.Logic != null) { 87 | Logic.Logic.close(); 88 | } 89 | 90 | ServerManager.saveToFile(this); 91 | 92 | super.onDestroy(); 93 | } 94 | 95 | @Override 96 | public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) { 97 | super.onCreateContextMenu(menu, v, info); 98 | 99 | if (v == findViewById(R.id.listViewServers)) { 100 | AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) info; 101 | int index = menuInfo.position; 102 | 103 | Intent editIntent = new Intent(this, ServerEditActivity.class); 104 | editIntent.putExtra("ServerIndex", index); 105 | 106 | Intent deleteIntent = new Intent(this, ServerDeleteActivity.class); 107 | deleteIntent.putExtra("ServerIndex", index); 108 | 109 | Intent shareIntent = new Intent(Intent.ACTION_SEND); 110 | shareIntent.putExtra(Intent.EXTRA_TEXT, ServerManager.serverAtIndex(index).serializeForURL()); 111 | shareIntent.setType("text/plain"); 112 | 113 | menu.setHeaderTitle(R.string.contextmenu_title); 114 | 115 | MenuItem editItem = menu.add(0, v.getId(), 0, R.string.action_edit); 116 | editItem.setIntent(editIntent); 117 | 118 | MenuItem deleteItem = menu.add(0, v.getId(), 1, R.string.action_delete); 119 | deleteItem.setIntent(deleteIntent); 120 | 121 | MenuItem shareItem = menu.add(0, v.getId(), 2, R.string.action_share); 122 | shareItem.setIntent(Intent.createChooser(shareIntent, getText(R.string.action_share))); 123 | } 124 | } 125 | 126 | @Override 127 | public boolean onCreateOptionsMenu(Menu menu) { 128 | MenuInflater inflater = getMenuInflater(); 129 | inflater.inflate(R.menu.mainmenu, menu); 130 | return true; 131 | } 132 | 133 | @Override 134 | public boolean onOptionsItemSelected(MenuItem item) { 135 | switch (item.getItemId()) { 136 | case R.id.menuItemAbout: { 137 | Intent intent = new Intent(this, AboutActivity.class); 138 | startActivity(intent); 139 | break; 140 | } 141 | case R.id.menuItemAddServer: { 142 | ServerManager.addServer(); 143 | 144 | Intent intent = new Intent(this, ServerEditActivity.class); 145 | intent.putExtra("ServerIndex", ServerManager.count() - 1); 146 | startActivity(intent); 147 | break; 148 | } 149 | case R.id.menuItemSettings: { 150 | Intent intent = new Intent(this, SettingsActivity.class); 151 | startActivityForResult(intent, 0x0000A001); 152 | break; 153 | } 154 | default: 155 | return false; 156 | } 157 | 158 | return true; 159 | } 160 | 161 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 162 | 163 | if (requestCode == 0x0000A001) { 164 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); 165 | 166 | if (Logic.Logic != null) { 167 | Logic.Logic.close(); 168 | } 169 | 170 | try { 171 | Logic.Logic = new Logic(this, prefs.getBoolean("pref_forceapg", false)); 172 | } catch (Exception e) { 173 | Logic.Logic = null; 174 | Intent intent = new Intent(this, SettingsActivity.class); 175 | startActivityForResult(intent, 0x0000A001); 176 | 177 | Toast.makeText(this, R.string.invalid_settings_detected, Toast.LENGTH_LONG).show(); 178 | } 179 | } else if (requestCode > 0x0000B000 && requestCode < 0x0000C0000) { 180 | Logic.Logic.postResult(requestCode - 0x0000B000, resultCode, data); 181 | } else { 182 | super.onActivityResult(requestCode, resultCode, data); 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /PGPAuth/src/main/java/org/lf_net/pgpunlocker/PGPKeyPreference.java: -------------------------------------------------------------------------------- 1 | package org.lf_net.pgpunlocker; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.media.RingtoneManager; 6 | import android.preference.*; 7 | import android.util.AttributeSet; 8 | 9 | //Why I'm using a RingtonePreference? Because all the others don't have onActivityResult ... 10 | //http://yenliangl.blogspot.de/2011/04/preference-that-receives-activity.html 11 | public class PGPKeyPreference extends RingtonePreference { 12 | 13 | Context _context; 14 | 15 | public PGPKeyPreference(Context context) { 16 | super(context); 17 | _context = context; 18 | } 19 | 20 | public PGPKeyPreference(Context context, AttributeSet attr) { 21 | super(context, attr); 22 | _context = context; 23 | } 24 | 25 | public PGPKeyPreference(Context context, AttributeSet attr, int defStyle) { 26 | super(context, attr, defStyle); 27 | _context = context; 28 | } 29 | 30 | @Override 31 | protected void onPrepareRingtonePickerIntent(Intent intent) { 32 | // Remove all extras already placed by RingtonePreference 33 | intent.setAction(null); 34 | intent.removeExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI); 35 | intent.removeExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT); 36 | intent.removeExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI); 37 | intent.removeExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT); 38 | intent.removeExtra(RingtoneManager.EXTRA_RINGTONE_TYPE); 39 | 40 | intent.setAction("org.thialfihar.android.apg.intent.SELECT_SECRET_KEY"); 41 | intent.putExtra("intentVersion", 1); 42 | } 43 | 44 | @Override 45 | public boolean onActivityResult(int requestCode, int resultCode, Intent data) { 46 | if (super.onActivityResult(requestCode, resultCode, data)) { 47 | if (data != null && data.hasExtra("keyId")) { 48 | persistString(String.valueOf(data.getLongExtra("keyId", 0))); 49 | } 50 | } 51 | 52 | return false; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /PGPAuth/src/main/java/org/lf_net/pgpunlocker/Server.java: -------------------------------------------------------------------------------- 1 | package org.lf_net.pgpunlocker; 2 | 3 | import java.net.URLDecoder; 4 | import java.net.URLEncoder; 5 | 6 | import org.json.JSONException; 7 | import org.json.JSONObject; 8 | 9 | public class Server { 10 | final static String ServerConfigBaseURL = "https://pgpauth.lf-net.org/serverConfig?config="; 11 | 12 | String _name; 13 | String _url; 14 | String _apgKey; 15 | 16 | public Server(String name, String url) { 17 | this(name, url, ""); 18 | } 19 | 20 | public Server(String name, String url, String apgKey) { 21 | _name = name; 22 | _url = url; 23 | _apgKey = apgKey; 24 | } 25 | 26 | public String name() { 27 | return _name; 28 | } 29 | 30 | public String url() { 31 | return _url; 32 | } 33 | 34 | public String apgKey() { 35 | return _apgKey; 36 | } 37 | 38 | public void setName(String name) { 39 | _name = name; 40 | } 41 | 42 | public void setUrl(String url) { 43 | _url = url; 44 | } 45 | 46 | public void setApgKey(String apgKey) { 47 | _apgKey = apgKey; 48 | } 49 | 50 | public boolean isEmpty() { 51 | return _name == "" && _url == ""; 52 | } 53 | 54 | @Deprecated 55 | public static Server deserialize(String serialized) { 56 | String[] parts = serialized.split("\t"); 57 | 58 | if (parts.length == 2) { 59 | return new Server(parts[0], parts[1]); 60 | } 61 | 62 | if (parts.length == 3) { 63 | return new Server(parts[0], parts[1], parts[2]); 64 | } 65 | 66 | return null; 67 | } 68 | 69 | public JSONObject serializeJSON() { 70 | JSONObject ret = new JSONObject(); 71 | 72 | try { 73 | ret.put("name", _name); 74 | ret.put("url", _url); 75 | ret.put("apgKey", _apgKey); 76 | } catch (JSONException e) { 77 | // should not happen as we just serialize a bunch of strings 78 | return null; 79 | } 80 | 81 | return ret; 82 | } 83 | 84 | public static Server deserializeJSON(JSONObject obj) throws JSONException { 85 | try { 86 | String name = obj.getString("name"); 87 | String url = obj.getString("url"); 88 | String apgKey = obj.getString("apgKey"); 89 | 90 | return new Server(name, url, apgKey); 91 | } catch (JSONException e) { 92 | // should not happen as we just serialize a bunch of strings 93 | throw e; 94 | } 95 | } 96 | 97 | public String serializeForURL() { 98 | JSONObject ret = new JSONObject(); 99 | 100 | try { 101 | ret.put("name", _name); 102 | ret.put("url", _url); 103 | 104 | String jsonString = ret.toString(); 105 | String encoded = URLEncoder.encode(jsonString, "utf-8"); 106 | 107 | return ServerConfigBaseURL + encoded; 108 | } catch (Exception e) { 109 | return null; 110 | } 111 | } 112 | 113 | public static Server deserializeFromURL(String configUrl) { 114 | try { 115 | String encoded = configUrl.substring(ServerConfigBaseURL.length()); 116 | String jsonString = URLDecoder.decode(encoded, "utf-8"); 117 | 118 | JSONObject obj = new JSONObject(jsonString); 119 | 120 | String name = obj.getString("name"); 121 | String url = obj.getString("url"); 122 | 123 | return new Server(name, url); 124 | } catch (Exception e) { 125 | return null; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /PGPAuth/src/main/java/org/lf_net/pgpunlocker/ServerAdapter.java: -------------------------------------------------------------------------------- 1 | package org.lf_net.pgpunlocker; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Looper; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.View.OnClickListener; 10 | import android.view.ViewGroup; 11 | import android.widget.ArrayAdapter; 12 | import android.widget.Button; 13 | import android.widget.TextView; 14 | import android.widget.Toast; 15 | 16 | public class ServerAdapter extends ArrayAdapter { 17 | Context _context; 18 | int _layoutResourceId; 19 | 20 | public ServerAdapter(Context context, int layoutResourceId) { 21 | super(context, layoutResourceId); 22 | 23 | _context = context; 24 | _layoutResourceId = layoutResourceId; 25 | 26 | ServerManager.setObserver(new ServerManager.ServerManagerObserver() { 27 | @Override 28 | public void onSomethingChanged() { 29 | ServerAdapter.this.notifyDataSetChanged(); 30 | } 31 | }); 32 | } 33 | 34 | @Override 35 | public int getCount() { 36 | return ServerManager.count(); 37 | } 38 | 39 | @Override 40 | public View getView(int position, View convertView, ViewGroup parent) { 41 | View row = convertView; 42 | ServerHolder holder = null; 43 | 44 | if (row == null) { 45 | LayoutInflater inflater = ((Activity) _context).getLayoutInflater(); 46 | row = inflater.inflate(_layoutResourceId, parent, false); 47 | 48 | holder = new ServerHolder(); 49 | holder.nameView = (TextView) row.findViewById(R.id.textViewServerName); 50 | holder.urlView = (TextView) row.findViewById(R.id.textViewServerURL); 51 | holder.lockButton = (Button) row.findViewById(R.id.buttonLock); 52 | holder.unlockButton = (Button) row.findViewById(R.id.buttonUnlock); 53 | 54 | row.setTag(holder); 55 | row.setClickable(true); 56 | row.setLongClickable(true); 57 | } else { 58 | holder = (ServerHolder) row.getTag(); 59 | } 60 | 61 | Server server = ServerManager.serverAtIndex(position); 62 | holder.nameView.setText(server.name()); 63 | holder.urlView.setText(server.url()); 64 | holder.lockButton.setTag(server); 65 | holder.unlockButton.setTag(server); 66 | holder.index = position; 67 | 68 | holder.lockButton.setOnClickListener(new OnClickListener() { 69 | @Override 70 | public void onClick(View v) { 71 | final Server server = (Server) v.getTag(); 72 | 73 | Thread runThread = new Thread(new Runnable() { 74 | @Override 75 | public void run() { 76 | Logic.Logic.doActionOnServerWithFeedback("close", server.url(), server.apgKey()); 77 | } 78 | }); 79 | 80 | runThread.start(); 81 | } 82 | }); 83 | 84 | holder.unlockButton.setOnClickListener(new OnClickListener() { 85 | @Override 86 | public void onClick(View v) { 87 | final Server server = (Server) v.getTag(); 88 | 89 | Thread runThread = new Thread(new Runnable() { 90 | @Override 91 | public void run() { 92 | Logic.Logic.doActionOnServerWithFeedback("open", server.url(), server.apgKey()); 93 | } 94 | }); 95 | 96 | runThread.start(); 97 | } 98 | }); 99 | 100 | row.setOnClickListener(new OnClickListener() { 101 | @Override 102 | public void onClick(View v) { 103 | ServerHolder holder = (ServerHolder) v.getTag(); 104 | 105 | Intent i = new Intent(_context, ServerEditActivity.class); 106 | i.putExtra("ServerIndex", holder.index); 107 | _context.startActivity(i); 108 | } 109 | }); 110 | 111 | return row; 112 | } 113 | 114 | public static class ServerHolder { 115 | TextView nameView; 116 | TextView urlView; 117 | Button lockButton; 118 | Button unlockButton; 119 | 120 | int index; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /PGPAuth/src/main/java/org/lf_net/pgpunlocker/ServerDeleteActivity.java: -------------------------------------------------------------------------------- 1 | package org.lf_net.pgpunlocker; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | 7 | public class ServerDeleteActivity extends Activity { 8 | 9 | int _serverIndex; 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_server_delete); 15 | 16 | Bundle extras = getIntent().getExtras(); 17 | if (extras != null) { 18 | _serverIndex = extras.getInt("ServerIndex"); 19 | } 20 | } 21 | 22 | public void onDeleteClicked(View view) { 23 | ServerManager.deleteServer(_serverIndex); 24 | ServerManager.saveToFile(this); 25 | finish(); 26 | } 27 | 28 | public void onCancelClicked(View view) { 29 | finish(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /PGPAuth/src/main/java/org/lf_net/pgpunlocker/ServerEditActivity.java: -------------------------------------------------------------------------------- 1 | package org.lf_net.pgpunlocker; 2 | 3 | import android.app.Activity; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.EditText; 8 | 9 | public class ServerEditActivity extends Activity { 10 | 11 | EditText _editTextName; 12 | EditText _editTextURL; 13 | 14 | Server _server; 15 | int _serverIndex; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_server_edit); 21 | 22 | _editTextName = (EditText) findViewById(R.id.editTextName); 23 | _editTextURL = (EditText) findViewById(R.id.editTextURL); 24 | 25 | Bundle extras = getIntent().getExtras(); 26 | if (extras != null) { 27 | _serverIndex = extras.getInt("ServerIndex"); 28 | _server = ServerManager.serverAtIndex(_serverIndex); 29 | } 30 | 31 | Uri serverConfig = getIntent().getData(); 32 | if (serverConfig != null) { 33 | ServerManager.addServer(); 34 | _serverIndex = ServerManager.count() - 1; 35 | _server = Server.deserializeFromURL(serverConfig.toString()); 36 | } 37 | 38 | if (_server != null) { 39 | _editTextName.setText(_server.name()); 40 | _editTextURL.setText(_server.url()); 41 | } 42 | } 43 | 44 | public void saveClicked(View view) { 45 | _server.setName(_editTextName.getText().toString()); 46 | _server.setUrl(_editTextURL.getText().toString()); 47 | 48 | ServerManager.replaceServer(_serverIndex, _server); 49 | ServerManager.saveToFile(this); 50 | 51 | finish(); 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /PGPAuth/src/main/java/org/lf_net/pgpunlocker/ServerManager.java: -------------------------------------------------------------------------------- 1 | package org.lf_net.pgpunlocker; 2 | 3 | import java.io.*; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import org.json.JSONArray; 8 | import org.json.JSONObject; 9 | 10 | import android.content.Context; 11 | import android.content.SharedPreferences; 12 | import android.preference.PreferenceManager; 13 | 14 | public class ServerManager { 15 | static public class ServerManagerObserver { 16 | public void onServerAdded(Server server) { 17 | } 18 | 19 | public void onServerReplaced(int serverIndex, Server newServer) { 20 | } 21 | 22 | public void onServerDeleted(int serverIndex) { 23 | } 24 | 25 | public void onSomethingChanged() { 26 | } 27 | } 28 | 29 | private static List _servers = new ArrayList(); 30 | private static ServerManagerObserver _observer; 31 | 32 | @SuppressWarnings("deprecation") 33 | public static void loadFromFileOld(Context context) { 34 | try { 35 | _servers.clear(); 36 | 37 | FileInputStream fileStream = context.openFileInput("Servers"); 38 | BufferedReader reader = new BufferedReader(new InputStreamReader(fileStream)); 39 | 40 | String line; 41 | 42 | do { 43 | line = reader.readLine(); 44 | 45 | if (line == null) { 46 | break; 47 | } 48 | 49 | Server server = Server.deserialize(line); 50 | 51 | if (server != null) { 52 | _servers.add(server); 53 | 54 | if (_observer != null) { 55 | _observer.onServerAdded(server); 56 | } 57 | } 58 | 59 | } while (line != null); 60 | 61 | reader.close(); 62 | fileStream.close(); 63 | 64 | if (_observer != null) { 65 | _observer.onSomethingChanged(); 66 | } 67 | 68 | } catch (FileNotFoundException e) { 69 | // maybe there was an even older version of PGPAuth installed ... 70 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 71 | String server = prefs.getString("pref_server", ""); 72 | 73 | if (server != "") { 74 | // there was an old version \o/ 75 | _servers.add(new Server("Migrated from old version", server)); 76 | } 77 | } catch (Exception e) { 78 | // shit happens 79 | } 80 | } 81 | 82 | public static void loadFromFile(Context context) { 83 | try { 84 | _servers.clear(); 85 | 86 | FileInputStream fileStream = context.openFileInput("Servers.json"); 87 | BufferedReader reader = new BufferedReader(new InputStreamReader(fileStream)); 88 | 89 | String jsonString = ""; 90 | while (reader.ready()) { 91 | jsonString += reader.readLine() + "\n"; 92 | } 93 | 94 | JSONObject obj = new JSONObject(jsonString); 95 | JSONArray serverArray = obj.getJSONArray("servers"); 96 | 97 | for (int i = 0; i < serverArray.length(); i++) { 98 | Server server = Server.deserializeJSON(serverArray.optJSONObject(i)); 99 | 100 | if (server != null && !server.isEmpty()) { 101 | _servers.add(server); 102 | } 103 | } 104 | 105 | reader.close(); 106 | 107 | } catch (FileNotFoundException e) { 108 | // old PGPAuth? 109 | loadFromFileOld(context); 110 | } catch (Exception e) { 111 | // a lot of shit happens 112 | } 113 | 114 | } 115 | 116 | public static void saveToFile(Context context) { 117 | try { 118 | FileOutputStream fileStream = context.openFileOutput("Servers.json", Context.MODE_PRIVATE); 119 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fileStream)); 120 | 121 | JSONArray serversArray = new JSONArray(); 122 | 123 | for (int i = 0; i < _servers.size(); i++) { 124 | serversArray.put(i, _servers.get(i).serializeJSON()); 125 | } 126 | 127 | JSONObject rootObject = new JSONObject(); 128 | rootObject.put("servers", serversArray); 129 | 130 | writer.write(rootObject.toString()); 131 | 132 | writer.close(); 133 | 134 | // delete old Servers-config - just in case it existed. 135 | context.deleteFile("Servers"); 136 | } catch (Exception e) { 137 | // more shit happens 138 | } 139 | } 140 | 141 | public static int count() { 142 | return _servers.size(); 143 | } 144 | 145 | public static Server serverAtIndex(int index) { 146 | return _servers.get(index); 147 | } 148 | 149 | public static void addServer() { 150 | _servers.add(new Server("", "")); 151 | 152 | if (_observer != null) { 153 | _observer.onServerAdded(_servers.get(count() - 1)); 154 | _observer.onSomethingChanged(); 155 | } 156 | } 157 | 158 | public static void replaceServer(int index, Server server) { 159 | _servers.set(index, server); 160 | 161 | if (_observer != null) { 162 | _observer.onServerReplaced(index, server); 163 | _observer.onSomethingChanged(); 164 | } 165 | } 166 | 167 | public static void deleteServer(int index) { 168 | _servers.remove(index); 169 | 170 | if (_observer != null) { 171 | _observer.onServerDeleted(index); 172 | _observer.onSomethingChanged(); 173 | } 174 | } 175 | 176 | public static void setObserver(ServerManagerObserver observer) { 177 | _observer = observer; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /PGPAuth/src/main/java/org/lf_net/pgpunlocker/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | 2 | package org.lf_net.pgpunlocker; 3 | 4 | import android.os.Bundle; 5 | import android.preference.PreferenceActivity; 6 | 7 | public class SettingsActivity extends PreferenceActivity { 8 | @SuppressWarnings("deprecation") 9 | @Override 10 | public void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | addPreferencesFromResource(R.xml.preferences); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PGPAuth/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PGPAuth/PGPAuth_Android/cb430207fce90873c536eaa6da8deb0d8b19166f/PGPAuth/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /PGPAuth/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PGPAuth/PGPAuth_Android/cb430207fce90873c536eaa6da8deb0d8b19166f/PGPAuth/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /PGPAuth/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PGPAuth/PGPAuth_Android/cb430207fce90873c536eaa6da8deb0d8b19166f/PGPAuth/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /PGPAuth/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PGPAuth/PGPAuth_Android/cb430207fce90873c536eaa6da8deb0d8b19166f/PGPAuth/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /PGPAuth/src/main/res/layout/activity_about.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | 17 | 24 | 25 | 30 | 31 | 36 | 37 |