Merge pull request #2586 from open-keychain/drop-more-stuff

Drop more stuff
This commit is contained in:
Vincent Breitmoser 2020-09-08 11:12:44 +02:00 committed by GitHub
commit 258cd4c836
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
96 changed files with 140 additions and 3872 deletions

View file

@ -49,9 +49,6 @@ dependencies {
// Nordpol
implementation 'com.fidesmo:nordpol-android:0.1.22'
// piwik
implementation 'org.piwik.sdk:piwik-sdk:3.0.3'
// libs as submodules
implementation project(':openpgp-api-lib')
implementation project(':nfcsweetspot')

View file

@ -54,21 +54,6 @@
<!-- CAMERA permission requested by ZXing library -->
<!-- contact group -->
<!--
AUTHENTICATE_ACCOUNTS and MANAGE_ACCOUNTS removed in Android >= 6,
see https://code.google.com/p/android-developer-preview/issues/detail?id=2592
also READ_PROFILE, WRITE_PROFILE?
-->
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.WRITE_PROFILE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<!-- storage group -->
<!--
No need on >= Android 4.4 for WRITE_EXTERNAL_STORAGE, because we use Storage Access Framework,
@ -1012,36 +997,6 @@
</intent-filter>
</service>
<!-- Contact Sync services -->
<service
android:name=".service.DummyAccountService"
android:exported="true"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/account_desc" />
</service>
<service
android:name=".service.ContactSyncAdapterService"
android:exported="true"
android:process=":sync"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_adapter_contacts" />
<meta-data
android:name="android.provider.CONTACTS_STRUCTURE"
android:resource="@xml/sync_adapter_contacts_structure" />
</service>
<!-- Storage Provider for temporary decrypted files.
For security considerations, read class! -->
<provider

View file

@ -20,8 +20,6 @@ package org.sufficientlysecure.keychain;
import java.io.File;
import java.net.Proxy;
import java.util.Arrays;
import java.util.List;
import android.os.Environment;
@ -159,10 +157,6 @@ public final class Constants {
public static final String KEY_SIGNATURES_TABLE_INITIALIZED = "key_signatures_table_initialized";
public static final String KEY_ANALYTICS_ASKED_POLITELY = "analytics_asked";
public static final String KEY_ANALYTICS_CONSENT = "analytics_consent";
public static final String KEY_ANALYTICS_LAST_ASKED = "analytics_last_asked";
public static final class Theme {
public static final String LIGHT = "light";
public static final String DARK = "dark";
@ -173,14 +167,6 @@ public final class Constants {
public static final String TYPE_HTTP = "proxyHttp";
public static final String TYPE_SOCKS = "proxySocks";
}
// we generally only track booleans. never snoop around in the user's string settings!!
public static final List<String> ANALYTICS_PREFS = Arrays.asList(USE_NORMAL_PROXY, USE_TOR_PROXY,
SYNC_CONTACTS, SYNC_KEYSERVER, ENABLE_WIFI_SYNC_ONLY,
EXPERIMENTAL_USB_ALLOW_UNTESTED,
PASSPHRASE_CACHE_SUBS, SEARCH_KEYSERVER, SEARCH_WEB_KEY_DIRECTORY,
TEXT_USE_COMPRESSION, TEXT_SELF_ENCRYPT, FILE_USE_COMPRESSION, FILE_SELF_ENCRYPT, USE_ARMOR,
USE_NUMKEYPAD_FOR_SECURITY_TOKEN_PIN, ENCRYPT_FILENAMES);
}
/**

View file

@ -30,15 +30,15 @@ import android.app.Application;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.widget.Toast;
import androidx.annotation.Nullable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.analytics.AnalyticsManager;
import org.sufficientlysecure.keychain.keysync.KeyserverSyncManager;
import org.sufficientlysecure.keychain.network.TlsCertificatePinning;
import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.util.PRNGFixes;
import org.sufficientlysecure.keychain.util.Preferences;
import timber.log.Timber;
@ -46,8 +46,6 @@ import timber.log.Timber.DebugTree;
public class KeychainApplication extends Application {
AnalyticsManager analyticsManager;
/**
* Called when the application is starting, before any activity, service, or receiver objects
* (excluding content providers) have been created.
@ -88,15 +86,9 @@ public class KeychainApplication extends Application {
}
*/
// Add OpenKeychain account to Android to link contacts with keys and keyserver sync
createAccountIfNecessary(this);
Preferences preferences = Preferences.getPreferences(this);
if (preferences.isAppExecutedFirstTime()) {
preferences.setAppExecutedFirstTime(false);
ContactSyncAdapterService.enableContactsSync(this);
preferences.setPrefVersionToCurrentVersion();
}
@ -116,36 +108,6 @@ public class KeychainApplication extends Application {
KeyserverSyncManager.updateKeyserverSyncScheduleAsync(this, false);
TemporaryFileProvider.scheduleCleanupImmediately(getApplicationContext());
analyticsManager = AnalyticsManager.getInstance(getApplicationContext());
analyticsManager.initialize(this);
}
/**
* @return the OpenKeychain contact/keyserver sync account if it exists or was successfully
* created, null otherwise
*/
public static @Nullable Account createAccountIfNecessary(Context context) {
try {
AccountManager manager = AccountManager.get(context);
Account[] accounts = manager.getAccountsByType(Constants.ACCOUNT_TYPE);
Account account = new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE);
if (accounts.length == 0) {
if (!manager.addAccountExplicitly(account, null, null)) {
Timber.d("error when adding account via addAccountExplicitly");
return null;
} else {
return account;
}
} else {
return accounts[0];
}
} catch (SecurityException e) {
Timber.e(e, "SecurityException when adding the account");
Toast.makeText(context, R.string.reinstall_openkeychain, Toast.LENGTH_LONG).show();
return null;
}
}
public static HashMap<String,Bitmap> qrCodeCache = new HashMap<>();
@ -167,10 +129,6 @@ public class KeychainApplication extends Application {
}
}
public AnalyticsManager getAnalyticsManager() {
return analyticsManager;
}
public static String getProcessName() {
if (Build.VERSION.SDK_INT >= 28)
return Application.getProcessName();

View file

@ -1,95 +0,0 @@
package org.sufficientlysecure.keychain.analytics;
import java.util.concurrent.TimeUnit;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.preference.PreferenceActivity;
import android.text.method.LinkMovementMethod;
import android.widget.TextView;
import org.sufficientlysecure.keychain.BuildConfig;
import org.sufficientlysecure.keychain.KeychainApplication;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.SettingsActivity;
import org.sufficientlysecure.keychain.ui.SettingsActivity.ExperimentalPrefsFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.Preferences;
public class AnalyticsConsentRequester {
private final Activity activity;
public static AnalyticsConsentRequester getInstance(Activity activity) {
return new AnalyticsConsentRequester(activity);
}
private AnalyticsConsentRequester(Activity activity) {
this.activity = activity;
}
public void maybeAskForAnalytics() {
Preferences preferences = Preferences.getPreferences(activity);
if (preferences.isAnalyticsHasConsent()) {
return;
}
boolean askedBeforeAndWasRejected =
preferences.isAnalyticsAskedPolitely() && !preferences.isAnalyticsHasConsent();
if (askedBeforeAndWasRejected) {
return;
}
try {
long firstInstallTime =
activity.getPackageManager().getPackageInfo(BuildConfig.APPLICATION_ID, 0).firstInstallTime;
long threeDaysAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(3);
boolean installedLessThanThreeDaysAgo = firstInstallTime > threeDaysAgo;
if (installedLessThanThreeDaysAgo) {
return;
}
} catch (NameNotFoundException e) {
return;
}
long twentyFourHoursAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1);
boolean askedLessThan24HoursAgo = preferences.getAnalyticsLastAsked() > twentyFourHoursAgo;
if (askedLessThan24HoursAgo) {
return;
}
preferences.setAnalyticsLastAskedNow();
AnalyticsManager analyticsManager = ((KeychainApplication) activity.getApplication()).getAnalyticsManager();
AlertDialog alertDialog = new Builder(activity)
.setMessage(R.string.dialog_analytics_consent)
.setPositiveButton(R.string.button_analytics_yes, (dialog, which) -> {
preferences.setAnalyticsAskedPolitely();
preferences.setAnalyticsGotUserConsent(true);
analyticsManager.refreshSettings(activity);
Notify.create(activity, R.string.snack_analytics_accept, Style.OK,
this::startExperimentalSettingsActivity, R.string.snackbutton_analytics_settings).show();
})
.setNegativeButton(R.string.button_analytics_no, (dialog, which) -> {
preferences.setAnalyticsAskedPolitely();
preferences.setAnalyticsGotUserConsent(false);
analyticsManager.refreshSettings(activity);
Notify.create(activity, R.string.snack_analytics_reject, Style.OK,
this::startExperimentalSettingsActivity, R.string.snackbutton_analytics_settings).show();
})
.show();
alertDialog.<TextView>findViewById(android.R.id.message).setMovementMethod(LinkMovementMethod.getInstance());
}
private void startExperimentalSettingsActivity() {
Intent resultIntent = new Intent(activity, SettingsActivity.class);
String experimentalPrefsName = ExperimentalPrefsFragment.class.getName();
resultIntent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, experimentalPrefsName);
activity.startActivity(resultIntent);
}
}

View file

@ -1,180 +0,0 @@
package org.sufficientlysecure.keychain.analytics;
import android.app.Activity;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import org.piwik.sdk.Piwik;
import org.piwik.sdk.Tracker;
import org.piwik.sdk.TrackerConfig;
import org.piwik.sdk.extra.DownloadTracker.Extra.ApkChecksum;
import org.piwik.sdk.extra.TrackHelper;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Constants.Defaults;
import org.sufficientlysecure.keychain.Constants.Pref;
import org.sufficientlysecure.keychain.util.Preferences;
import timber.log.Timber;
public class AnalyticsManager implements OnSharedPreferenceChangeListener {
private Tracker piwikTracker;
public static AnalyticsManager getInstance(Context context) {
return new AnalyticsManager(context);
}
private AnalyticsManager(Context context) {
refreshSettings(context);
}
public void initialize(Application application) {
if (piwikTracker != null) {
TrackHelper.track().download().identifier(new ApkChecksum(application)).with(piwikTracker);
}
application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if (piwikTracker == null) {
return;
}
TrackHelper.track().screen(activity.getClass().getSimpleName()).with(piwikTracker);
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
});
Preferences preferences = Preferences.getPreferences(application);
preferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
// we generally only track booleans. never snoop around in the user's string settings!!
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (piwikTracker == null) {
return;
}
// small exception: check if the user uses a custom keyserver, or one of the well-known ones
if (Pref.KEY_SERVERS.equals(key)) {
Timber.d("Tracking pref %s", key);
String keyServers = sharedPreferences.getString(Pref.KEY_SERVERS, Defaults.KEY_SERVERS);
String current = keyServers.substring(keyServers.indexOf(','));
String coarseGranularityKeyserver;
if (current.contains("keyserver.ubuntu.com")) {
coarseGranularityKeyserver = "ubuntu";
} else if (current.contains("pgp.mit.edu")) {
coarseGranularityKeyserver = "mit";
} else if (current.contains("pool.sks-keyservers.net")) {
coarseGranularityKeyserver = "pool";
} else {
coarseGranularityKeyserver = "custom";
}
TrackHelper.track().interaction("pref_" + Pref.KEY_SERVERS, coarseGranularityKeyserver).with(piwikTracker);
return;
}
// unpack an enum
if (Pref.THEME.equals(key)) {
String value = sharedPreferences.getString(Pref.THEME, "empty");
TrackHelper.track().interaction("pref_" + Pref.THEME, value).with(piwikTracker);
return;
}
// all other values we track are individual booleans
if (Pref.ANALYTICS_PREFS.contains(key)) {
Timber.d("Tracking pref %s", key);
if (!sharedPreferences.contains(key)) {
TrackHelper.track().interaction("pref_" + key, "empty").with(piwikTracker);
return;
}
boolean value = sharedPreferences.getBoolean(key, false);
TrackHelper.track().interaction("pref_" + key, value ? "true" : "false").with(piwikTracker);
}
}
public void trackFragmentImpression(String opClassName, String fragmentName) {
if (piwikTracker == null) {
return;
}
TrackHelper.track().screen(opClassName + "/" + fragmentName).with(piwikTracker);
}
public void trackInternalServiceCall(String opClassName) {
if (piwikTracker == null) {
return;
}
TrackHelper.track()
.interaction("internalApiCall", opClassName)
.with(piwikTracker);
}
public void trackApiServiceCall(String opClassName, String currentCallingPackage) {
if (piwikTracker == null) {
return;
}
TrackHelper.track()
.interaction("externalApiCall", opClassName)
.piece(currentCallingPackage.replace(".", "/"))
.with(piwikTracker);
}
public synchronized void refreshSettings(Context context) {
boolean shouldEnableAnalytics = shouldEnableAnalytics(context);
boolean analyticsEnabled = piwikTracker != null;
if (shouldEnableAnalytics != analyticsEnabled) {
if (shouldEnableAnalytics) {
TrackerConfig trackerConfig;
if (Constants.DEBUG) {
trackerConfig = new TrackerConfig("https://piwik.openkeychain.org/", 3, "OpenKeychainDebug");
} else {
trackerConfig = new TrackerConfig("https://piwik.openkeychain.org/", 2, "OpenKeychain");
}
piwikTracker = Piwik.getInstance(context).newTracker(trackerConfig);
piwikTracker.setDispatchInterval(60000);
piwikTracker.setOptOut(false);
} else {
piwikTracker.setOptOut(true);
piwikTracker = null;
}
}
}
private boolean shouldEnableAnalytics(Context context) {
Preferences preferences = Preferences.getPreferences(context);
return preferences.isAnalyticsHasConsent() && !preferences.getUseTorProxy();
}
}

View file

@ -18,7 +18,6 @@
package org.sufficientlysecure.keychain.keysync;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@ -29,11 +28,10 @@ import android.os.Build.VERSION_CODES;
import androidx.annotation.WorkerThread;
import androidx.work.Constraints.Builder;
import androidx.work.ExistingPeriodicWorkPolicy;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkInfo;
import androidx.work.WorkInfo.State;
import androidx.work.WorkManager;
import org.sufficientlysecure.keychain.util.Preferences;
import timber.log.Timber;
@ -43,7 +41,8 @@ public class KeyserverSyncManager {
private static final long SYNC_INTERVAL = 3;
private static final TimeUnit SYNC_INTERVAL_UNIT = TimeUnit.DAYS;
private static final String PERIODIC_WORK_TAG = "keyserverSync";
private static final String LEGACY_PERIODIC_WORK_TAG = "keyserverSync";
private static final String WORK_UNIQUE_NAME = "periodicKeyserverSync";
public static void updateKeyserverSyncScheduleAsync(Context context, boolean forceReschedule) {
new AsyncTask<Void,Void,Void>() {
@ -60,27 +59,12 @@ public class KeyserverSyncManager {
Preferences prefs = Preferences.getPreferences(context);
WorkManager workManager = WorkManager.getInstance(context);
UUID workUuid = prefs.getKeyserverSyncWorkUuid();
try {
WorkInfo info = workUuid != null ? workManager.getWorkInfoById(workUuid).get() : null;
boolean workIsScheduled = info != null && info.getState() != State.CANCELLED;
if (workIsScheduled == prefs.isKeyserverSyncEnabled()) {
if (!forceReschedule) {
Timber.d("Key sync already scheduled, no changes necessary");
return;
}
Timber.d("Key sync already scheduled, but forcing reschedule");
}
} catch (ExecutionException | InterruptedException e) {
Timber.e(e, "Error getting info for scheduled key sync work?");
}
Timber.d("Cancelling sync tasks…");
workManager.cancelAllWorkByTag(PERIODIC_WORK_TAG);
// Cancel work that was scheduled by tag, as we used to do.
workManager.cancelAllWorkByTag(LEGACY_PERIODIC_WORK_TAG);
if (!prefs.isKeyserverSyncEnabled()) {
Timber.d("Key sync disabled");
workManager.cancelUniqueWork(WORK_UNIQUE_NAME);
return;
}
@ -96,10 +80,12 @@ public class KeyserverSyncManager {
PeriodicWorkRequest workRequest =
new PeriodicWorkRequest.Builder(KeyserverSyncWorker.class, SYNC_INTERVAL, SYNC_INTERVAL_UNIT)
.setConstraints(constraints.build())
.addTag(PERIODIC_WORK_TAG)
.build();
try {
workManager.enqueue(workRequest).getResult().get();
ExistingPeriodicWorkPolicy policy = forceReschedule
? ExistingPeriodicWorkPolicy.REPLACE
: ExistingPeriodicWorkPolicy.KEEP;
workManager.enqueueUniquePeriodicWork(WORK_UNIQUE_NAME, policy, workRequest).getResult().get();
Timber.d("Work id: %s", workRequest.getId());
prefs.setKeyserverSyncScheduled(workRequest.getId());
} catch (InterruptedException | ExecutionException e) {

View file

@ -43,7 +43,6 @@ import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.UploadKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
@ -254,9 +253,6 @@ public class CertifyOperation extends BaseReadWriteOperation<CertifyActionsParce
uploadOk, uploadError);
}
// since only verified keys are synced to contacts, we need to initiate a sync now
ContactSyncAdapterService.requestContactsSync();
log.add(LogType.MSG_CRT_SUCCESS, 0);
if (uploadError != 0) {
return new CertifyResult(CertifyResult.RESULT_WARNINGS, log, certifyOk, certifyError, uploadOk,

View file

@ -30,7 +30,6 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.Operat
import org.sufficientlysecure.keychain.operations.results.UpdateTrustResult;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.DeleteKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@ -101,9 +100,6 @@ public class DeleteOperation extends BaseReadWriteOperation<DeleteKeyringParcel>
int result = DeleteResult.RESULT_OK;
if (success > 0) {
// make sure new data is synced into contacts
ContactSyncAdapterService.requestContactsSync();
log.add(LogType.MSG_DEL_OK, 0, success);
}
if (fail > 0) {

View file

@ -38,7 +38,6 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.UploadKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@ -182,9 +181,6 @@ public class EditKeyOperation extends BaseReadWriteOperation<SaveKeyringParcel>
updateProgress(R.string.progress_done, 100, 100);
// make sure new data is synced into contacts
ContactSyncAdapterService.requestContactsSync();
log.add(LogType.MSG_ED_SUCCESS, 0);
return new EditKeyResult(EditKeyResult.RESULT_OK, log, ring.getMasterKeyId());

View file

@ -32,9 +32,9 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
@ -55,7 +55,6 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
@ -134,9 +133,6 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
}
/**
* Since the introduction of multithreaded import, we expect calling functions to handle the
* contact-to-key sync i.e ContactSyncAdapterService.requestContactsSync()
*
* @param entries keys to import
* @param numTotalKeys number of keys to import
* @param hkpKeyserver contains uri of keyserver to import from, if it is an import from cloud
@ -274,11 +270,6 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
}
}
// Special: make sure new data is synced into contacts
// disabling sync right now since it reduces speed while multi-threading
// so, we expect calling functions to take care of it. KeychainService handles this
// ContactSyncAdapterService.requestContactsSync();
// convert to long array
long[] importedMasterKeyIdsArray = new long[importedMasterKeyIds.size()];
for (int i = 0; i < importedMasterKeyIds.size(); ++i) {
@ -476,10 +467,6 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
result = multiThreadedKeyImport(keyList, keyServer, proxy, skipSave, forceReinsert);
}
if (!skipSave) {
ContactSyncAdapterService.requestContactsSync();
}
return result;
}

View file

@ -26,7 +26,6 @@ import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.app.Application;
import android.content.ClipDescription;
import android.content.ContentProvider;
import android.content.ContentResolver;
@ -41,6 +40,7 @@ import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import androidx.annotation.NonNull;
import androidx.work.ExistingWorkPolicy;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import androidx.work.Worker;
@ -77,6 +77,7 @@ public class TemporaryFileProvider extends ContentProvider {
public static final String AUTHORITY = Constants.TEMP_FILE_PROVIDER_AUTHORITY;
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
private static final int DB_VERSION = 3;
public static final String WORK_NAME_CLEANUP = "cleanup";
interface TemporaryFileColumns {
String COLUMN_UUID = "id";
@ -315,20 +316,22 @@ public class TemporaryFileProvider extends ContentProvider {
public static void scheduleCleanupAfterTtl(Context context) {
OneTimeWorkRequest cleanupWork = new OneTimeWorkRequest.Builder(CleanupWorker.class)
.setInitialDelay(Constants.TEMPFILE_TTL, TimeUnit.MILLISECONDS).build();
workManagerEnqueue(context, cleanupWork);
workManagerEnqueueCleanup(context, cleanupWork);
}
public static void scheduleCleanupImmediately(Context context) {
OneTimeWorkRequest cleanupWork = new OneTimeWorkRequest.Builder(CleanupWorker.class).build();
workManagerEnqueue(context, cleanupWork);
workManagerEnqueueCleanup(context, cleanupWork);
}
private static void workManagerEnqueue(Context context, OneTimeWorkRequest cleanupWork) {
private static void workManagerEnqueueCleanup(Context context, OneTimeWorkRequest cleanupWork) {
// work manager is only available on the main thread
if (!BuildConfig.APPLICATION_ID.equals(KeychainApplication.getProcessName())) {
return;
}
WorkManager.getInstance(context).enqueue(cleanupWork);
WorkManager
.getInstance(context)
.enqueueUniqueWork(TemporaryFileProvider.WORK_NAME_CLEANUP, ExistingWorkPolicy.REPLACE, cleanupWork);
}
public static class CleanupWorker extends Worker {

View file

@ -38,10 +38,10 @@ import android.os.Messenger;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.openintents.openpgp.AutocryptPeerUpdate;
import org.openintents.openpgp.IOpenPgpService;
@ -52,9 +52,12 @@ import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.OpenPgpSignatureResult.AutocryptPeerResult;
import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.daos.OverriddenWarningsDao;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.KeychainApplication;
import org.sufficientlysecure.keychain.analytics.AnalyticsManager;
import org.sufficientlysecure.keychain.operations.BackupOperation;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.ExportResult;
@ -69,12 +72,7 @@ import org.sufficientlysecure.keychain.pgp.PgpSignEncryptData;
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.SecurityProblem;
import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptStatus;
import org.sufficientlysecure.keychain.daos.OverriddenWarningsDao;
import org.sufficientlysecure.keychain.remote.OpenPgpServiceKeyIdExtractor.KeyIdResult;
import org.sufficientlysecure.keychain.remote.OpenPgpServiceKeyIdExtractor.KeyIdResultStatus;
import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
@ -101,7 +99,6 @@ public class OpenPgpService extends Service {
private ApiAppDao mApiAppDao;
private OpenPgpServiceKeyIdExtractor mKeyIdExtractor;
private ApiPendingIntentFactory mApiPendingIntentFactory;
private AnalyticsManager analyticsManager;
@Override
public void onCreate() {
@ -111,8 +108,6 @@ public class OpenPgpService extends Service {
mApiPermissionHelper = new ApiPermissionHelper(this, mApiAppDao);
mApiPendingIntentFactory = new ApiPendingIntentFactory(getBaseContext());
mKeyIdExtractor = OpenPgpServiceKeyIdExtractor.getInstance(getContentResolver(), mApiPendingIntentFactory);
analyticsManager = ((KeychainApplication) getApplication()).getAnalyticsManager();
}
private Intent signImpl(Intent data, InputStream inputStream,
@ -1032,8 +1027,6 @@ public class OpenPgpService extends Service {
return errorResult;
}
analyticsManager.trackApiServiceCall(data.getAction(), mApiPermissionHelper.getCurrentCallingPackage());
Progressable progressable = null;
if (data.hasExtra(OpenPgpApi.EXTRA_PROGRESS_MESSENGER)) {
Messenger messenger = data.getParcelableExtra(OpenPgpApi.EXTRA_PROGRESS_MESSENGER);

View file

@ -40,17 +40,15 @@ import org.openintents.ssh.authentication.response.PublicKeyResponse;
import org.openintents.ssh.authentication.response.SigningResponse;
import org.openintents.ssh.authentication.response.SshPublicKeyResponse;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.KeychainApplication;
import org.sufficientlysecure.keychain.analytics.AnalyticsManager;
import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.SshPublicKey;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ssh.AuthenticationData;
@ -67,8 +65,6 @@ public class SshAuthenticationService extends Service {
private ApiAppDao mApiAppDao;
private ApiPendingIntentFactory mApiPendingIntentFactory;
private AnalyticsManager analyticsManager;
private static final List<Integer> SUPPORTED_VERSIONS = Collections.unmodifiableList(Collections.singletonList(1));
private static final int INVALID_API_VERSION = -1;
@ -82,8 +78,6 @@ public class SshAuthenticationService extends Service {
mApiAppDao = ApiAppDao.getInstance(this);
mApiPendingIntentFactory = new ApiPendingIntentFactory(getBaseContext());
analyticsManager = ((KeychainApplication) getApplication()).getAnalyticsManager();
}
private final ISshAuthenticationService.Stub mSSHAgent = new ISshAuthenticationService.Stub() {
@ -109,8 +103,6 @@ public class SshAuthenticationService extends Service {
}
private Intent executeInternal(Intent intent) {
analyticsManager.trackApiServiceCall(intent.getAction(), mApiPermissionHelper.getCurrentCallingPackage());
switch (intent.getAction()) {
case SshAuthenticationApi.ACTION_SIGN:
return authenticate(intent);

View file

@ -1,177 +0,0 @@
/*
* Copyright (C) 2017 Schürmann & Breitmoser GbR
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.service;
import android.accounts.Account;
import android.app.PendingIntent;
import android.app.Service;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SyncResult;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceActivity;
import android.provider.ContactsContract;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.KeychainApplication;
import org.sufficientlysecure.keychain.NotificationChannelManager;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.SettingsActivity;
import org.sufficientlysecure.keychain.util.ContactHelper;
import timber.log.Timber;
public class ContactSyncAdapterService extends Service {
private static final int NOTIFICATION_ID_SYNC_SETTINGS = 13;
private class ContactSyncAdapter extends AbstractThreadedSyncAdapter {
// private final AtomicBoolean importDone = new AtomicBoolean(false);
public ContactSyncAdapter() {
super(ContactSyncAdapterService.this, true);
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider,
final SyncResult syncResult) {
Timber.d("Performing a contact sync!");
new ContactHelper(ContactSyncAdapterService.this).writeKeysToContacts();
// importKeys();
}
@Override
public void onSecurityException(Account account, Bundle extras, String authority, SyncResult syncResult) {
super.onSecurityException(account, extras, authority, syncResult);
// deactivate sync
ContentResolver.setSyncAutomatically(account, authority, false);
NotificationChannelManager.getInstance(getContext()).createNotificationChannelsIfNecessary();
// show notification linking to sync settings
Intent resultIntent = new Intent(ContactSyncAdapterService.this, SettingsActivity.class);
resultIntent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT,
SettingsActivity.SyncPrefsFragment.class.getName());
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
ContactSyncAdapterService.this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(ContactSyncAdapterService.this, NotificationChannelManager.PERMISSION_REQUESTS)
.setAutoCancel(true)
.setSmallIcon(R.drawable.ic_stat_notify_24dp)
.setColor(getResources().getColor(R.color.primary))
.setContentTitle(getString(R.string.sync_notification_permission_required_title))
.setContentText(getString(R.string.sync_notification_permission_required_text))
.setContentIntent(resultPendingIntent);
NotificationManagerCompat.from(ContactSyncAdapterService.this)
.notify(NOTIFICATION_ID_SYNC_SETTINGS, mBuilder.build());
}
}
@Override
public IBinder onBind(Intent intent) {
return new ContactSyncAdapter().getSyncAdapterBinder();
}
public static void requestContactsSync() {
// if user has disabled automatic sync, do nothing
boolean isSyncEnabled = ContentResolver.getSyncAutomatically(new Account
(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE), ContactsContract.AUTHORITY);
if (!isSyncEnabled) {
return;
}
Bundle extras = new Bundle();
// no need to wait, do it immediately
extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
ContentResolver.requestSync(
new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE),
ContactsContract.AUTHORITY,
extras);
}
public static void enableContactsSync(Context context) {
Account account = KeychainApplication.createAccountIfNecessary(context);
if (account == null) {
return;
}
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1);
ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true);
}
// TODO: Import is currently disabled, until we implement proper origin management
// private static void importKeys() {
// importDone.set(false);
// KeychainApplication.setupAccountAsNeeded(ContactSyncAdapterService.this);
// EmailKeyHelper.importContacts(getContext(), new Messenger(new Handler(Looper.getMainLooper(),
// new Handler.Callback() {
// @Override
// public boolean handleMessage(Message msg) {
// Bundle data = msg.getInputData();
// switch (msg.arg1) {
// case KeychainIntentServiceHandler.MESSAGE_OKAY:
// Log.d(Constants.TAG, "Syncing... Done.");
// synchronized (importDone) {
// importDone.set(true);
// importDone.notifyAll();
// }
// return true;
// case KeychainIntentServiceHandler.MESSAGE_UPDATE_PROGRESS:
// if (data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS) &&
// data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS_MAX)) {
// Log.d(Constants.TAG, "Syncing... Progress: " +
// data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS) + "/" +
// data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS_MAX));
// return false;
// }
// default:
// Log.d(Constants.TAG, "Syncing... " + msg.toString());
// return false;
// }
// }
// })));
// synchronized (importDone) {
// try {
// if (!importDone.get()) importDone.wait();
// } catch (InterruptedException e) {
// Log.w(Constants.TAG, e);
// return;
// }
// }
// }
}

View file

@ -1,133 +0,0 @@
/*
* Copyright (C) 2017 Schürmann & Breitmoser GbR
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.service;
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.NetworkErrorException;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.widget.Toast;
import org.sufficientlysecure.keychain.R;
import timber.log.Timber;
/**
* This service actually does nothing, it's sole task is to show a Toast if the use tries to create an account.
*/
public class DummyAccountService extends Service {
private class Toaster {
private static final String TOAST_MESSAGE = "toast_message";
private Context context;
private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Toast.makeText(context, msg.getData().getString(TOAST_MESSAGE), Toast.LENGTH_LONG).show();
return true;
}
});
private Toaster(Context context) {
this.context = context;
}
public void toast(int resourceId) {
toast(context.getString(resourceId));
}
public void toast(String message) {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString(TOAST_MESSAGE, message);
msg.setData(bundle);
handler.sendMessage(msg);
}
}
private class Authenticator extends AbstractAccountAuthenticator {
public Authenticator() {
super(DummyAccountService.this);
}
@Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
Timber.d("DummyAccountService.editProperties");
return null;
}
@Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType,
String[] requiredFeatures, Bundle options) throws NetworkErrorException {
response.onResult(new Bundle());
toaster.toast(R.string.account_no_manual_account_creation);
Timber.d("DummyAccountService.addAccount");
return null;
}
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options)
throws NetworkErrorException {
Timber.d("DummyAccountService.confirmCredentials");
return null;
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType,
Bundle options) throws NetworkErrorException {
Timber.d("DummyAccountService.getAuthToken");
return null;
}
@Override
public String getAuthTokenLabel(String authTokenType) {
Timber.d("DummyAccountService.getAuthTokenLabel");
return null;
}
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType,
Bundle options) throws NetworkErrorException {
Timber.d("DummyAccountService.updateCredentials");
return null;
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features)
throws NetworkErrorException {
Timber.d("DummyAccountService.hasFeatures");
return null;
}
}
private Toaster toaster;
@Override
public IBinder onBind(Intent intent) {
toaster = new Toaster(this);
return new Authenticator().getIBinder();
}
}

View file

@ -25,10 +25,8 @@ import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Parcelable;
import androidx.core.os.CancellationSignal;
import org.sufficientlysecure.keychain.KeychainApplication;
import org.sufficientlysecure.keychain.analytics.AnalyticsManager;
import androidx.core.os.CancellationSignal;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.operations.BackupOperation;
import org.sufficientlysecure.keychain.operations.BaseOperation;
@ -54,20 +52,15 @@ import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
public class KeychainServiceTask {
private final AnalyticsManager analyticsManager;
public static KeychainServiceTask create(Activity activity) {
Context context = activity.getApplicationContext();
KeyWritableRepository keyRepository = KeyWritableRepository.create(context);
AnalyticsManager analyticsManager = ((KeychainApplication) activity.getApplication()).getAnalyticsManager();
return new KeychainServiceTask(context, keyRepository, analyticsManager);
return new KeychainServiceTask(context, keyRepository);
}
private KeychainServiceTask(Context context, KeyWritableRepository keyRepository, AnalyticsManager analyticsManager) {
private KeychainServiceTask(Context context, KeyWritableRepository keyRepository) {
this.context = context;
this.keyRepository = keyRepository;
this.analyticsManager = analyticsManager;
}
private final Context context;
@ -128,8 +121,6 @@ public class KeychainServiceTask {
return null;
}
analyticsManager.trackInternalServiceCall(op.getClass().getSimpleName());