Use SQLDelight for inserts instead of KeychainProvider
This commit is contained in:
@@ -880,13 +880,10 @@
|
|||||||
android:name=".service.KeychainService"
|
android:name=".service.KeychainService"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
<!-- label is made to be "Keyserver Sync" since that is the only context in which
|
|
||||||
the user will see it-->
|
|
||||||
<provider
|
<provider
|
||||||
android:name=".provider.KeychainProvider"
|
android:name=".provider.KeychainProvider"
|
||||||
android:authorities="${applicationId}.provider"
|
android:authorities="${applicationId}.provider"
|
||||||
android:exported="false"
|
android:exported="false" />
|
||||||
android:label="@string/keyserver_sync_settings_title" />
|
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name=".remote.KeychainExternalProvider"
|
android:name=".remote.KeychainExternalProvider"
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package org.sufficientlysecure.keychain.daos;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.CertsModel.InsertCert;
|
||||||
|
import org.sufficientlysecure.keychain.KeyRingsPublicModel.InsertKeyRingPublic;
|
||||||
|
import org.sufficientlysecure.keychain.KeySignaturesModel.InsertKeySignature;
|
||||||
|
import org.sufficientlysecure.keychain.KeysModel.InsertKey;
|
||||||
|
import org.sufficientlysecure.keychain.UserPacketsModel.InsertUserPacket;
|
||||||
|
import org.sufficientlysecure.keychain.model.Certification;
|
||||||
|
import org.sufficientlysecure.keychain.model.KeyRingPublic;
|
||||||
|
import org.sufficientlysecure.keychain.model.KeySignature;
|
||||||
|
import org.sufficientlysecure.keychain.model.SubKey;
|
||||||
|
import org.sufficientlysecure.keychain.model.UserPacket;
|
||||||
|
|
||||||
|
|
||||||
|
public class DatabaseBatchInteractor {
|
||||||
|
private final SupportSQLiteDatabase db;
|
||||||
|
|
||||||
|
private final InsertKeyRingPublic insertKeyRingPublicStatement;
|
||||||
|
private final InsertKey insertSubKeyStatement;
|
||||||
|
private final InsertUserPacket insertUserPacketStatement;
|
||||||
|
private final InsertCert insertCertificationStatement;
|
||||||
|
private final InsertKeySignature insertKeySignerStatement;
|
||||||
|
|
||||||
|
DatabaseBatchInteractor(SupportSQLiteDatabase db) {
|
||||||
|
this.db = db;
|
||||||
|
|
||||||
|
insertKeyRingPublicStatement = KeyRingPublic.createInsertStatement(db);
|
||||||
|
insertSubKeyStatement = SubKey.createInsertStatement(db);
|
||||||
|
insertUserPacketStatement = UserPacket.createInsertStatement(db);
|
||||||
|
insertCertificationStatement = Certification.createInsertStatement(db);
|
||||||
|
insertKeySignerStatement = KeySignature.createInsertStatement(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SupportSQLiteDatabase getDb() {
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyBatch(List<BatchOp> operations) {
|
||||||
|
for (BatchOp op : operations) {
|
||||||
|
if (op.keyRingPublic != null) {
|
||||||
|
op.keyRingPublic.bindTo(insertKeyRingPublicStatement);
|
||||||
|
insertKeyRingPublicStatement.executeInsert();
|
||||||
|
} else if (op.subKey != null) {
|
||||||
|
op.subKey.bindTo(insertSubKeyStatement);
|
||||||
|
insertSubKeyStatement.executeInsert();
|
||||||
|
} else if (op.userPacket != null) {
|
||||||
|
op.userPacket.bindTo(insertUserPacketStatement);
|
||||||
|
insertUserPacketStatement.executeInsert();
|
||||||
|
} else if (op.certification != null) {
|
||||||
|
op.certification.bindTo(insertCertificationStatement);
|
||||||
|
insertCertificationStatement.executeInsert();
|
||||||
|
} else if (op.keySignature != null) {
|
||||||
|
op.keySignature.bindTo(insertKeySignerStatement);
|
||||||
|
insertKeySignerStatement.executeInsert();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BatchOp createInsertKeyRingPublic(KeyRingPublic keyRingPublic) {
|
||||||
|
return new BatchOp(keyRingPublic, null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BatchOp createInsertSubKey(SubKey subKey) {
|
||||||
|
return new BatchOp(null, subKey, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BatchOp createInsertUserPacket(UserPacket userPacket) {
|
||||||
|
return new BatchOp(null, null, userPacket, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BatchOp createInsertCertification(Certification certification) {
|
||||||
|
return new BatchOp(null, null, null, certification, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BatchOp createInsertSignerKey(KeySignature keySignature) {
|
||||||
|
return new BatchOp(null, null, null, null, keySignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BatchOp {
|
||||||
|
final KeyRingPublic keyRingPublic;
|
||||||
|
final SubKey subKey;
|
||||||
|
final UserPacket userPacket;
|
||||||
|
final Certification certification;
|
||||||
|
final KeySignature keySignature;
|
||||||
|
|
||||||
|
BatchOp(KeyRingPublic keyRingPublic, SubKey subKey, UserPacket userPacket,
|
||||||
|
Certification certification, KeySignature keySignature) {
|
||||||
|
this.subKey = subKey;
|
||||||
|
this.keyRingPublic = keyRingPublic;
|
||||||
|
this.userPacket = userPacket;
|
||||||
|
this.certification = certification;
|
||||||
|
this.keySignature = keySignature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,11 @@ public class DatabaseNotifyManager {
|
|||||||
this.contentResolver = contentResolver;
|
this.contentResolver = contentResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void notifyAllKeysChange() {
|
||||||
|
Uri uri = getNotifyUriAllKeys();
|
||||||
|
contentResolver.notifyChange(uri, null);
|
||||||
|
}
|
||||||
|
|
||||||
public void notifyKeyChange(long masterKeyId) {
|
public void notifyKeyChange(long masterKeyId) {
|
||||||
Uri uri = getNotifyUriMasterKeyId(masterKeyId);
|
Uri uri = getNotifyUriMasterKeyId(masterKeyId);
|
||||||
contentResolver.notifyChange(uri, null);
|
contentResolver.notifyChange(uri, null);
|
||||||
|
|||||||
@@ -25,21 +25,24 @@ import java.util.Collections;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.content.ContentProviderOperation;
|
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.OperationApplicationException;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.util.LongSparseArray;
|
import android.support.v4.util.LongSparseArray;
|
||||||
|
|
||||||
import org.openintents.openpgp.util.OpenPgpUtils;
|
import org.openintents.openpgp.util.OpenPgpUtils;
|
||||||
import org.sufficientlysecure.keychain.KeyRingsPublicModel.DeleteByMasterKeyId;
|
import org.sufficientlysecure.keychain.KeyRingsPublicModel.DeleteByMasterKeyId;
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
|
import org.sufficientlysecure.keychain.KeysModel.UpdateHasSecretByKeyId;
|
||||||
|
import org.sufficientlysecure.keychain.KeysModel.UpdateHasSecretByMasterKeyId;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.CustomColumnAdapters;
|
import org.sufficientlysecure.keychain.daos.DatabaseBatchInteractor.BatchOp;
|
||||||
|
import org.sufficientlysecure.keychain.model.Certification;
|
||||||
|
import org.sufficientlysecure.keychain.model.KeyRingPublic;
|
||||||
|
import org.sufficientlysecure.keychain.model.KeySignature;
|
||||||
|
import org.sufficientlysecure.keychain.model.SubKey;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
||||||
|
import org.sufficientlysecure.keychain.model.UserPacket;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||||
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
||||||
@@ -58,12 +61,6 @@ import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
|
|||||||
import org.sufficientlysecure.keychain.pgp.WrappedSignature;
|
import org.sufficientlysecure.keychain.pgp.WrappedSignature;
|
||||||
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeySignatures;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
@@ -87,6 +84,7 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
private final Context context;
|
private final Context context;
|
||||||
private final DatabaseNotifyManager databaseNotifyManager;
|
private final DatabaseNotifyManager databaseNotifyManager;
|
||||||
private AutocryptPeerDao autocryptPeerDao;
|
private AutocryptPeerDao autocryptPeerDao;
|
||||||
|
private DatabaseBatchInteractor databaseBatchInteractor;
|
||||||
|
|
||||||
public static KeyWritableRepository create(Context context) {
|
public static KeyWritableRepository create(Context context) {
|
||||||
LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context);
|
LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context);
|
||||||
@@ -116,6 +114,7 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.databaseNotifyManager = databaseNotifyManager;
|
this.databaseNotifyManager = databaseNotifyManager;
|
||||||
this.autocryptPeerDao = autocryptPeerDao;
|
this.autocryptPeerDao = autocryptPeerDao;
|
||||||
|
this.databaseBatchInteractor = new DatabaseBatchInteractor(getWritableDb());
|
||||||
}
|
}
|
||||||
|
|
||||||
private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() {
|
private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() {
|
||||||
@@ -177,27 +176,29 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
long masterKeyId = keyRing.getMasterKeyId();
|
long masterKeyId = keyRing.getMasterKeyId();
|
||||||
UncachedPublicKey masterKey = keyRing.getPublicKey();
|
UncachedPublicKey masterKey = keyRing.getPublicKey();
|
||||||
|
|
||||||
ArrayList<ContentProviderOperation> operations;
|
|
||||||
try {
|
|
||||||
|
|
||||||
log(LogType.MSG_IP_PREPARE);
|
log(LogType.MSG_IP_PREPARE);
|
||||||
mIndent += 1;
|
mIndent += 1;
|
||||||
|
|
||||||
// save all keys and userIds included in keyRing object in database
|
byte[] encodedKeyRing;
|
||||||
operations = new ArrayList<>();
|
|
||||||
|
|
||||||
log(LogType.MSG_IP_INSERT_KEYRING);
|
|
||||||
try {
|
try {
|
||||||
writePublicKeyRing(keyRing, masterKeyId, operations);
|
encodedKeyRing = keyRing.getEncoded();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log(LogType.MSG_IP_ENCODE_FAIL);
|
log(LogType.MSG_IP_ENCODE_FAIL);
|
||||||
return SaveKeyringResult.RESULT_ERROR;
|
return SaveKeyringResult.RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayList<BatchOp> operations = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
log(LogType.MSG_IP_INSERT_KEYRING);
|
||||||
|
|
||||||
|
byte[] encodedRingIfDbCachable = encodedKeyRing.length < MAX_CACHED_KEY_SIZE ? encodedKeyRing : null;
|
||||||
|
KeyRingPublic keyRingPublic = KeyRingPublic.create(masterKeyId, encodedRingIfDbCachable);
|
||||||
|
operations.add(DatabaseBatchInteractor.createInsertKeyRingPublic(keyRingPublic));
|
||||||
|
|
||||||
log(LogType.MSG_IP_INSERT_SUBKEYS);
|
log(LogType.MSG_IP_INSERT_SUBKEYS);
|
||||||
mIndent += 1;
|
mIndent += 1;
|
||||||
{ // insert subkeys
|
{ // insert subkeys
|
||||||
Uri uri = Keys.buildKeysUri(masterKeyId);
|
|
||||||
int rank = 0;
|
int rank = 0;
|
||||||
for (CanonicalizedPublicKey key : keyRing.publicKeyIterator()) {
|
for (CanonicalizedPublicKey key : keyRing.publicKeyIterator()) {
|
||||||
long keyId = key.getKeyId();
|
long keyId = key.getKeyId();
|
||||||
@@ -206,23 +207,7 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
);
|
);
|
||||||
mIndent += 1;
|
mIndent += 1;
|
||||||
|
|
||||||
ContentValues values = new ContentValues();
|
|
||||||
values.put(Keys.MASTER_KEY_ID, masterKeyId);
|
|
||||||
values.put(Keys.RANK, rank);
|
|
||||||
|
|
||||||
values.put(Keys.KEY_ID, key.getKeyId());
|
|
||||||
values.put(Keys.KEY_SIZE, key.getBitStrength());
|
|
||||||
values.put(Keys.KEY_CURVE_OID, key.getCurveOid());
|
|
||||||
values.put(Keys.ALGORITHM, key.getAlgorithm());
|
|
||||||
values.put(Keys.FINGERPRINT, key.getFingerprint());
|
|
||||||
|
|
||||||
boolean c = key.canCertify(), e = key.canEncrypt(), s = key.canSign(), a = key.canAuthenticate();
|
boolean c = key.canCertify(), e = key.canEncrypt(), s = key.canSign(), a = key.canAuthenticate();
|
||||||
values.put(Keys.CAN_CERTIFY, c);
|
|
||||||
values.put(Keys.CAN_ENCRYPT, e);
|
|
||||||
values.put(Keys.CAN_SIGN, s);
|
|
||||||
values.put(Keys.CAN_AUTHENTICATE, a);
|
|
||||||
values.put(Keys.IS_REVOKED, key.isRevoked());
|
|
||||||
values.put(Keys.IS_SECURE, key.isSecure());
|
|
||||||
|
|
||||||
// see above
|
// see above
|
||||||
if (masterKeyId == keyId) {
|
if (masterKeyId == keyId) {
|
||||||
@@ -240,22 +225,24 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Date creation = key.getCreationTime();
|
Date creation = key.getCreationTime();
|
||||||
values.put(Keys.CREATION, creation.getTime() / 1000);
|
Date expiry = key.getExpiryTime();
|
||||||
Date expiryDate = key.getExpiryTime();
|
if (expiry != null) {
|
||||||
if (expiryDate != null) {
|
|
||||||
values.put(Keys.EXPIRY, expiryDate.getTime() / 1000);
|
|
||||||
if (key.isExpired()) {
|
if (key.isExpired()) {
|
||||||
log(keyId == masterKeyId ?
|
log(keyId == masterKeyId ?
|
||||||
LogType.MSG_IP_MASTER_EXPIRED : LogType.MSG_IP_SUBKEY_EXPIRED,
|
LogType.MSG_IP_MASTER_EXPIRED : LogType.MSG_IP_SUBKEY_EXPIRED,
|
||||||
expiryDate.toString());
|
expiry.toString());
|
||||||
} else {
|
} else {
|
||||||
log(keyId == masterKeyId ?
|
log(keyId == masterKeyId ?
|
||||||
LogType.MSG_IP_MASTER_EXPIRES : LogType.MSG_IP_SUBKEY_EXPIRES,
|
LogType.MSG_IP_MASTER_EXPIRES : LogType.MSG_IP_SUBKEY_EXPIRES,
|
||||||
expiryDate.toString());
|
expiry.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operations.add(ContentProviderOperation.newInsert(uri).withValues(values).build());
|
SubKey subKey = SubKey.create(masterKeyId, rank, key.getKeyId(),
|
||||||
|
key.getBitStrength(), key.getCurveOid(), key.getAlgorithm(), key.getFingerprint(),
|
||||||
|
c, s, e, a, key.isRevoked(), SecretKeyType.UNAVAILABLE, key.isSecure(), creation, expiry);
|
||||||
|
operations.add(DatabaseBatchInteractor.createInsertSubKey(subKey));
|
||||||
|
|
||||||
++rank;
|
++rank;
|
||||||
mIndent -= 1;
|
mIndent -= 1;
|
||||||
}
|
}
|
||||||
@@ -312,10 +299,8 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
|
|
||||||
// keep a note about the issuer of this key signature
|
// keep a note about the issuer of this key signature
|
||||||
if (!signerKeyIds.contains(certId)) {
|
if (!signerKeyIds.contains(certId)) {
|
||||||
operations.add(ContentProviderOperation.newInsert(KeySignatures.CONTENT_URI)
|
KeySignature keySignature = KeySignature.create(masterKeyId, certId);
|
||||||
.withValue(KeySignatures.MASTER_KEY_ID, masterKeyId)
|
operations.add(DatabaseBatchInteractor.createInsertSignerKey(keySignature));
|
||||||
.withValue(KeySignatures.SIGNER_KEY_ID, certId)
|
|
||||||
.build());
|
|
||||||
signerKeyIds.add(certId);
|
signerKeyIds.add(certId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,7 +466,10 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
// iterate and put into db
|
// iterate and put into db
|
||||||
for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) {
|
for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) {
|
||||||
UserPacketItem item = uids.get(userIdRank);
|
UserPacketItem item = uids.get(userIdRank);
|
||||||
operations.add(buildUserIdOperations(masterKeyId, item, userIdRank));
|
Long type = item.type != null ? item.type.longValue() : null;
|
||||||
|
UserPacket userPacket = UserPacket.create(masterKeyId, userIdRank, type, item.userId, item.name, item.email,
|
||||||
|
item.comment, item.attributeData, item.isPrimary, item.selfRevocation != null);
|
||||||
|
operations.add(DatabaseBatchInteractor.createInsertUserPacket(userPacket));
|
||||||
|
|
||||||
if (item.selfRevocation != null) {
|
if (item.selfRevocation != null) {
|
||||||
operations.add(buildCertOperations(masterKeyId, userIdRank, item.selfRevocation,
|
operations.add(buildCertOperations(masterKeyId, userIdRank, item.selfRevocation,
|
||||||
@@ -519,9 +507,12 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
mIndent -= 1;
|
mIndent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SupportSQLiteDatabase db = databaseBatchInteractor.getDb();
|
||||||
try {
|
try {
|
||||||
|
db.beginTransaction();
|
||||||
|
|
||||||
// delete old version of this keyRing (from database only!), which also deletes all keys and userIds on cascade
|
// delete old version of this keyRing (from database only!), which also deletes all keys and userIds on cascade
|
||||||
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(getWritableDb());
|
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(db);
|
||||||
deleteStatement.bind(masterKeyId);
|
deleteStatement.bind(masterKeyId);
|
||||||
int deletedRows = deleteStatement.executeUpdateDelete();
|
int deletedRows = deleteStatement.executeUpdateDelete();
|
||||||
|
|
||||||
@@ -533,41 +524,25 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log(LogType.MSG_IP_APPLY_BATCH);
|
log(LogType.MSG_IP_APPLY_BATCH);
|
||||||
contentResolver.applyBatch(KeychainContract.CONTENT_AUTHORITY, operations);
|
databaseBatchInteractor.applyBatch(operations);
|
||||||
|
if (encodedKeyRing.length >= MAX_CACHED_KEY_SIZE) {
|
||||||
|
mLocalPublicKeyStorage.writePublicKey(masterKeyId, encodedKeyRing);
|
||||||
|
}
|
||||||
databaseNotifyManager.notifyKeyChange(masterKeyId);
|
databaseNotifyManager.notifyKeyChange(masterKeyId);
|
||||||
|
|
||||||
|
db.setTransactionSuccessful();
|
||||||
log(LogType.MSG_IP_SUCCESS);
|
log(LogType.MSG_IP_SUCCESS);
|
||||||
return result;
|
return result;
|
||||||
|
} catch (IOException e) {
|
||||||
} catch (RemoteException e) {
|
|
||||||
log(LogType.MSG_IP_ERROR_REMOTE_EX);
|
|
||||||
Timber.e(e, "RemoteException during import");
|
|
||||||
return SaveKeyringResult.RESULT_ERROR;
|
|
||||||
} catch (OperationApplicationException e) {
|
|
||||||
log(LogType.MSG_IP_ERROR_OP_EXC);
|
log(LogType.MSG_IP_ERROR_OP_EXC);
|
||||||
Timber.e(e, "OperationApplicationException during import");
|
Timber.e(e, "OperationApplicationException during import");
|
||||||
return SaveKeyringResult.RESULT_ERROR;
|
return SaveKeyringResult.RESULT_ERROR;
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writePublicKeyRing(CanonicalizedPublicKeyRing keyRing, long masterKeyId,
|
|
||||||
ArrayList<ContentProviderOperation> operations) throws IOException {
|
|
||||||
byte[] encodedKey = keyRing.getEncoded();
|
|
||||||
mLocalPublicKeyStorage.writePublicKey(masterKeyId, encodedKey);
|
|
||||||
|
|
||||||
ContentValues values = new ContentValues();
|
|
||||||
values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
|
|
||||||
if (encodedKey.length < MAX_CACHED_KEY_SIZE) {
|
|
||||||
values.put(KeyRingData.KEY_RING_DATA, encodedKey);
|
|
||||||
} else {
|
|
||||||
values.put(KeyRingData.KEY_RING_DATA, (byte[]) null);
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri uri = KeyRingData.buildPublicKeyRingUri(masterKeyId);
|
|
||||||
operations.add(ContentProviderOperation.newInsert(uri).withValues(values).build());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeSecretKeyRing(CanonicalizedSecretKeyRing keyRing, long masterKeyId) throws IOException {
|
private void writeSecretKeyRing(CanonicalizedSecretKeyRing keyRing, long masterKeyId) throws IOException {
|
||||||
byte[] encodedKey = keyRing.getEncoded();
|
byte[] encodedKey = keyRing.getEncoded();
|
||||||
localSecretKeyStorage.writeSecretKey(masterKeyId, encodedKey);
|
localSecretKeyStorage.writeSecretKey(masterKeyId, encodedKey);
|
||||||
@@ -655,12 +630,12 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Uri uri = Keys.buildKeysUri(masterKeyId);
|
UpdateHasSecretByMasterKeyId resetStatement =
|
||||||
|
SubKey.createUpdateHasSecretByMasterKeyIdStatement(getWritableDb());
|
||||||
|
resetStatement.bind(masterKeyId, SecretKeyType.GNU_DUMMY);
|
||||||
|
resetStatement.executeUpdateDelete();
|
||||||
|
|
||||||
// first, mark all keys as not available
|
UpdateHasSecretByKeyId updateStatement = SubKey.createUpdateHasSecretByKeyId(getWritableDb());
|
||||||
ContentValues values = new ContentValues();
|
|
||||||
values.put(Keys.HAS_SECRET, SecretKeyType.GNU_DUMMY.getNum());
|
|
||||||
contentResolver.update(uri, values, null, null);
|
|
||||||
|
|
||||||
// then, mark exactly the keys we have available
|
// then, mark exactly the keys we have available
|
||||||
log(LogType.MSG_IS_IMPORTING_SUBKEYS);
|
log(LogType.MSG_IS_IMPORTING_SUBKEYS);
|
||||||
@@ -668,36 +643,25 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
for (CanonicalizedSecretKey sub : keyRing.secretKeyIterator()) {
|
for (CanonicalizedSecretKey sub : keyRing.secretKeyIterator()) {
|
||||||
long id = sub.getKeyId();
|
long id = sub.getKeyId();
|
||||||
SecretKeyType mode = sub.getSecretKeyTypeSuperExpensive();
|
SecretKeyType mode = sub.getSecretKeyTypeSuperExpensive();
|
||||||
values.put(Keys.HAS_SECRET, mode.getNum());
|
updateStatement.bind(id, mode);
|
||||||
int upd = contentResolver.update(uri, values, Keys.KEY_ID + " = ?",
|
int upd = updateStatement.executeUpdateDelete();
|
||||||
new String[]{Long.toString(id)});
|
|
||||||
if (upd == 1) {
|
if (upd == 1) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case PASSPHRASE:
|
case PASSPHRASE:
|
||||||
log(LogType.MSG_IS_SUBKEY_OK,
|
log(LogType.MSG_IS_SUBKEY_OK, KeyFormattingUtils.convertKeyIdToHex(id));
|
||||||
KeyFormattingUtils.convertKeyIdToHex(id)
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case PASSPHRASE_EMPTY:
|
case PASSPHRASE_EMPTY:
|
||||||
log(LogType.MSG_IS_SUBKEY_EMPTY,
|
log(LogType.MSG_IS_SUBKEY_EMPTY, KeyFormattingUtils.convertKeyIdToHex(id));
|
||||||
KeyFormattingUtils.convertKeyIdToHex(id)
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case GNU_DUMMY:
|
case GNU_DUMMY:
|
||||||
log(LogType.MSG_IS_SUBKEY_STRIPPED,
|
log(LogType.MSG_IS_SUBKEY_STRIPPED, KeyFormattingUtils.convertKeyIdToHex(id));
|
||||||
KeyFormattingUtils.convertKeyIdToHex(id)
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case DIVERT_TO_CARD:
|
case DIVERT_TO_CARD:
|
||||||
log(LogType.MSG_IS_SUBKEY_DIVERT,
|
log(LogType.MSG_IS_SUBKEY_DIVERT, KeyFormattingUtils.convertKeyIdToHex(id));
|
||||||
KeyFormattingUtils.convertKeyIdToHex(id)
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log(LogType.MSG_IS_SUBKEY_NONEXISTENT,
|
log(LogType.MSG_IS_SUBKEY_NONEXISTENT, KeyFormattingUtils.convertKeyIdToHex(id));
|
||||||
KeyFormattingUtils.convertKeyIdToHex(id)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mIndent -= 1;
|
mIndent -= 1;
|
||||||
@@ -744,7 +708,7 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
|
|
||||||
// If there is an old keyring, merge it
|
// If there is an old keyring, merge it
|
||||||
try {
|
try {
|
||||||
UncachedKeyRing oldPublicRing = getCanonicalizedPublicKeyRing(masterKeyId).getUncachedKeyRing();
|
UncachedKeyRing oldPublicRing = UncachedKeyRing.decodeFromData(loadPublicKeyRingData(masterKeyId));
|
||||||
alreadyExists = true;
|
alreadyExists = true;
|
||||||
|
|
||||||
// Merge data from new public ring into the old one
|
// Merge data from new public ring into the old one
|
||||||
@@ -769,7 +733,7 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
log(LogType.MSG_IP_SUCCESS_IDENTICAL);
|
log(LogType.MSG_IP_SUCCESS_IDENTICAL);
|
||||||
return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog, canPublicRing);
|
return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog, canPublicRing);
|
||||||
}
|
}
|
||||||
} catch (NotFoundException e) {
|
} catch (PgpGeneralException | NotFoundException e) {
|
||||||
// Not an issue, just means we are dealing with a new keyring.
|
// Not an issue, just means we are dealing with a new keyring.
|
||||||
|
|
||||||
// Canonicalize this keyring, to assert a number of assumptions made about it.
|
// Canonicalize this keyring, to assert a number of assumptions made about it.
|
||||||
@@ -1046,46 +1010,14 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
return new UpdateTrustResult(UpdateTrustResult.RESULT_OK, log);
|
return new UpdateTrustResult(UpdateTrustResult.RESULT_OK, log);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private BatchOp buildCertOperations(long masterKeyId, int rank, WrappedSignature cert, VerificationStatus verificationStatus) {
|
||||||
* Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing
|
try {
|
||||||
*/
|
Certification certification = Certification.create(masterKeyId, rank, cert.getKeyId(),
|
||||||
private ContentProviderOperation
|
cert.getSignatureType(), verificationStatus, cert.getCreationTime(), cert.getEncoded());
|
||||||
buildCertOperations(long masterKeyId, int rank, WrappedSignature cert, VerificationStatus verificationStatus)
|
return DatabaseBatchInteractor.createInsertCertification(certification);
|
||||||
throws IOException {
|
} catch (IOException e) {
|
||||||
ContentValues values = new ContentValues();
|
throw new AssertionError(e);
|
||||||
values.put(Certs.MASTER_KEY_ID, masterKeyId);
|
|
||||||
values.put(Certs.RANK, rank);
|
|
||||||
values.put(Certs.KEY_ID_CERTIFIER, cert.getKeyId());
|
|
||||||
values.put(Certs.TYPE, cert.getSignatureType());
|
|
||||||
values.put(Certs.CREATION, cert.getCreationTime().getTime() / 1000);
|
|
||||||
values.put(Certs.VERIFIED, CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.encode(verificationStatus));
|
|
||||||
values.put(Certs.DATA, cert.getEncoded());
|
|
||||||
|
|
||||||
Uri uri = Certs.buildCertsUri(masterKeyId);
|
|
||||||
|
|
||||||
return ContentProviderOperation.newInsert(uri).withValues(values).build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing
|
|
||||||
*/
|
|
||||||
private ContentProviderOperation
|
|
||||||
buildUserIdOperations(long masterKeyId, UserPacketItem item, int rank) {
|
|
||||||
ContentValues values = new ContentValues();
|
|
||||||
values.put(UserPackets.MASTER_KEY_ID, masterKeyId);
|
|
||||||
values.put(UserPackets.TYPE, item.type);
|
|
||||||
values.put(UserPackets.USER_ID, item.userId);
|
|
||||||
values.put(UserPackets.NAME, item.name);
|
|
||||||
values.put(UserPackets.EMAIL, item.email);
|
|
||||||
values.put(UserPackets.COMMENT, item.comment);
|
|
||||||
values.put(UserPackets.ATTRIBUTE_DATA, item.attributeData);
|
|
||||||
values.put(UserPackets.IS_PRIMARY, item.isPrimary);
|
|
||||||
values.put(UserPackets.IS_REVOKED, item.selfRevocation != null);
|
|
||||||
values.put(UserPackets.RANK, rank);
|
|
||||||
|
|
||||||
Uri uri = UserPackets.buildUserIdsUri(masterKeyId);
|
|
||||||
|
|
||||||
return ContentProviderOperation.newInsert(uri).withValues(values).build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
package org.sufficientlysecure.keychain.model;
|
package org.sufficientlysecure.keychain.model;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||||
|
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
import org.sufficientlysecure.keychain.CertsModel;
|
import org.sufficientlysecure.keychain.CertsModel;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
||||||
|
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
@@ -13,6 +18,20 @@ public abstract class Certification implements CertsModel {
|
|||||||
public static final SelectVerifyingCertDetailsMapper<CertDetails> CERT_DETAILS_MAPPER =
|
public static final SelectVerifyingCertDetailsMapper<CertDetails> CERT_DETAILS_MAPPER =
|
||||||
new SelectVerifyingCertDetailsMapper<>(AutoValue_Certification_CertDetails::new);
|
new SelectVerifyingCertDetailsMapper<>(AutoValue_Certification_CertDetails::new);
|
||||||
|
|
||||||
|
public static Certification create(long masterKeyId, long rank, long keyIdCertifier, long type,
|
||||||
|
VerificationStatus verified, Date creation, byte[] data) {
|
||||||
|
long creationUnixTime = creation.getTime() / 1000;
|
||||||
|
return new AutoValue_Certification(masterKeyId, rank, keyIdCertifier, type, verified, creationUnixTime, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InsertCert createInsertStatement(SupportSQLiteDatabase db) {
|
||||||
|
return new InsertCert(db, FACTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindTo(InsertCert statement) {
|
||||||
|
statement.bind(master_key_id(), rank(), key_id_certifier(), type(), verified(), creation(), data());
|
||||||
|
}
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public static abstract class CertDetails implements CertsModel.SelectVerifyingCertDetailsModel {
|
public static abstract class CertDetails implements CertsModel.SelectVerifyingCertDetailsModel {
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,28 @@
|
|||||||
package org.sufficientlysecure.keychain.model;
|
package org.sufficientlysecure.keychain.model;
|
||||||
|
|
||||||
|
|
||||||
|
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||||
|
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
import org.sufficientlysecure.keychain.KeyRingsPublicModel;
|
import org.sufficientlysecure.keychain.KeyRingsPublicModel;
|
||||||
|
import org.sufficientlysecure.keychain.KeysModel.InsertKey;
|
||||||
|
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public abstract class KeyRingPublic implements KeyRingsPublicModel {
|
public abstract class KeyRingPublic implements KeyRingsPublicModel {
|
||||||
public static final Factory<KeyRingPublic> FACTORY = new Factory<>(AutoValue_KeyRingPublic::new);
|
public static final Factory<KeyRingPublic> FACTORY = new Factory<>(AutoValue_KeyRingPublic::new);
|
||||||
|
|
||||||
public static final Mapper<KeyRingPublic> MAPPER = new Mapper<>(FACTORY);
|
public static final Mapper<KeyRingPublic> MAPPER = new Mapper<>(FACTORY);
|
||||||
|
|
||||||
|
public static KeyRingPublic create(long masterKeyId, byte[] keyRingData) {
|
||||||
|
return new AutoValue_KeyRingPublic(masterKeyId, keyRingData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InsertKeyRingPublic createInsertStatement(SupportSQLiteDatabase db) {
|
||||||
|
return new InsertKeyRingPublic(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindTo(InsertKeyRingPublic statement) {
|
||||||
|
statement.bind(master_key_id(), key_ring_data());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package org.sufficientlysecure.keychain.model;
|
package org.sufficientlysecure.keychain.model;
|
||||||
|
|
||||||
|
|
||||||
|
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||||
|
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
import org.sufficientlysecure.keychain.KeySignaturesModel;
|
import org.sufficientlysecure.keychain.KeySignaturesModel;
|
||||||
|
|
||||||
@@ -10,4 +12,16 @@ public abstract class KeySignature implements KeySignaturesModel {
|
|||||||
public static final Factory<KeySignature> FACTORY = new Factory<>(AutoValue_KeySignature::new);
|
public static final Factory<KeySignature> FACTORY = new Factory<>(AutoValue_KeySignature::new);
|
||||||
|
|
||||||
public static final Mapper<KeySignature> MAPPER = new Mapper<>(FACTORY);
|
public static final Mapper<KeySignature> MAPPER = new Mapper<>(FACTORY);
|
||||||
|
|
||||||
|
public static InsertKeySignature createInsertStatement(SupportSQLiteDatabase db) {
|
||||||
|
return new InsertKeySignature(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindTo(InsertKeySignature statement) {
|
||||||
|
statement.bind(master_key_id(), signer_key_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeySignature create(long masterKeyId, long certId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,11 @@ package org.sufficientlysecure.keychain.model;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||||
|
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
import com.squareup.sqldelight.RowMapper;
|
import com.squareup.sqldelight.RowMapper;
|
||||||
import org.sufficientlysecure.keychain.KeysModel;
|
import org.sufficientlysecure.keychain.KeysModel;
|
||||||
@@ -26,6 +29,33 @@ public abstract class SubKey implements KeysModel {
|
|||||||
return expiry() != null;
|
return expiry() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SubKey create(long masterKeyId, long rank, long keyId, Integer keySize, String keyCurveOid,
|
||||||
|
int algorithm, byte[] fingerprint, boolean canCertify, boolean canSign, boolean canEncrypt, boolean canAuth,
|
||||||
|
boolean isRevoked, SecretKeyType hasSecret, boolean isSecure, Date creation, Date expiry) {
|
||||||
|
long creationUnixTime = creation.getTime() / 1000;
|
||||||
|
Long expiryUnixTime = expiry != null ? expiry.getTime() / 1000 : null;
|
||||||
|
return new AutoValue_SubKey(masterKeyId, rank, keyId, keySize, keyCurveOid, algorithm, fingerprint, canCertify,
|
||||||
|
canSign, canEncrypt, canAuth, isRevoked, hasSecret, isSecure, creationUnixTime, expiryUnixTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InsertKey createInsertStatement(SupportSQLiteDatabase db) {
|
||||||
|
return new InsertKey(db, FACTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UpdateHasSecretByMasterKeyId createUpdateHasSecretByMasterKeyIdStatement(SupportSQLiteDatabase db) {
|
||||||
|
return new UpdateHasSecretByMasterKeyId(db, FACTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UpdateHasSecretByKeyId createUpdateHasSecretByKeyId(SupportSQLiteDatabase db) {
|
||||||
|
return new UpdateHasSecretByKeyId(db, FACTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindTo(InsertKey statement) {
|
||||||
|
statement.bind(master_key_id(), rank(), key_id(), key_size(), key_curve_oid(), algorithm(), fingerprint(),
|
||||||
|
can_certify(), can_sign(), can_encrypt(), can_authenticate(), is_revoked(), has_secret(), is_secure(),
|
||||||
|
creation(), expiry());
|
||||||
|
}
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public static abstract class UnifiedKeyInfo implements KeysModel.UnifiedKeyViewModel {
|
public static abstract class UnifiedKeyInfo implements KeysModel.UnifiedKeyViewModel {
|
||||||
private List<String> autocryptPackageNames;
|
private List<String> autocryptPackageNames;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package org.sufficientlysecure.keychain.model;
|
package org.sufficientlysecure.keychain.model;
|
||||||
|
|
||||||
|
|
||||||
|
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
import org.sufficientlysecure.keychain.UserPacketsModel;
|
import org.sufficientlysecure.keychain.UserPacketsModel;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
|
||||||
|
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
@@ -17,6 +17,21 @@ public abstract class UserPacket implements UserPacketsModel {
|
|||||||
public static final SelectUserAttributesByTypeAndMasterKeyIdMapper<UserAttribute> USER_ATTRIBUTE_MAPPER =
|
public static final SelectUserAttributesByTypeAndMasterKeyIdMapper<UserAttribute> USER_ATTRIBUTE_MAPPER =
|
||||||
FACTORY.selectUserAttributesByTypeAndMasterKeyIdMapper(AutoValue_UserPacket_UserAttribute::new);
|
FACTORY.selectUserAttributesByTypeAndMasterKeyIdMapper(AutoValue_UserPacket_UserAttribute::new);
|
||||||
|
|
||||||
|
public static UserPacket create(long masterKeyId, int rank, Long type, String userId, String name, String email,
|
||||||
|
String comment, byte[] attribute_data, boolean isPrimary, boolean isRevoked) {
|
||||||
|
return new AutoValue_UserPacket(masterKeyId, rank, type,
|
||||||
|
userId, name, email, comment, attribute_data, isPrimary, isRevoked);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InsertUserPacket createInsertStatement(SupportSQLiteDatabase db) {
|
||||||
|
return new InsertUserPacket(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindTo(InsertUserPacket statement) {
|
||||||
|
statement.bind(master_key_id(), rank(), type(), user_id(), name(), email(), comment(), attribute_data(),
|
||||||
|
is_primary(), is_revoked());
|
||||||
|
}
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public static abstract class UserId implements SelectUserIdsByMasterKeyIdModel {
|
public static abstract class UserId implements SelectUserIdsByMasterKeyIdModel {
|
||||||
public boolean isVerified() {
|
public boolean isVerified() {
|
||||||
|
|||||||
@@ -339,7 +339,6 @@ public abstract class OperationResult implements Parcelable {
|
|||||||
MSG_IP_ENCODE_FAIL (LogLevel.DEBUG, R.string.msg_ip_encode_fail),
|
MSG_IP_ENCODE_FAIL (LogLevel.DEBUG, R.string.msg_ip_encode_fail),
|
||||||
MSG_IP_ERROR_IO_EXC (LogLevel.ERROR, R.string.msg_ip_error_io_exc),
|
MSG_IP_ERROR_IO_EXC (LogLevel.ERROR, R.string.msg_ip_error_io_exc),
|
||||||
MSG_IP_ERROR_OP_EXC (LogLevel.ERROR, R.string.msg_ip_error_op_exc),
|
MSG_IP_ERROR_OP_EXC (LogLevel.ERROR, R.string.msg_ip_error_op_exc),
|
||||||
MSG_IP_ERROR_REMOTE_EX (LogLevel.ERROR, R.string.msg_ip_error_remote_ex),
|
|
||||||
MSG_IP_FINGERPRINT_ERROR (LogLevel.ERROR, R.string.msg_ip_fingerprint_error),
|
MSG_IP_FINGERPRINT_ERROR (LogLevel.ERROR, R.string.msg_ip_fingerprint_error),
|
||||||
MSG_IP_FINGERPRINT_OK (LogLevel.INFO, R.string.msg_ip_fingerprint_ok),
|
MSG_IP_FINGERPRINT_OK (LogLevel.INFO, R.string.msg_ip_fingerprint_ok),
|
||||||
MSG_IP_INSERT_KEYRING (LogLevel.DEBUG, R.string.msg_ip_insert_keyring),
|
MSG_IP_INSERT_KEYRING (LogLevel.DEBUG, R.string.msg_ip_insert_keyring),
|
||||||
|
|||||||
@@ -17,18 +17,11 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.provider;
|
package org.sufficientlysecure.keychain.provider;
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.provider.BaseColumns;
|
import android.provider.BaseColumns;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
|
||||||
|
|
||||||
public class KeychainContract {
|
public class KeychainContract {
|
||||||
|
|
||||||
public interface KeyRingsColumns {
|
|
||||||
String MASTER_KEY_ID = "master_key_id"; // not a database id
|
|
||||||
String KEY_RING_DATA = "key_ring_data"; // PGPPublicKeyRing / PGPSecretKeyRing blob
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface KeysColumns {
|
public interface KeysColumns {
|
||||||
String MASTER_KEY_ID = "master_key_id"; // not a database id
|
String MASTER_KEY_ID = "master_key_id"; // not a database id
|
||||||
String RANK = "rank";
|
String RANK = "rank";
|
||||||
@@ -51,11 +44,6 @@ public class KeychainContract {
|
|||||||
String EXPIRY = "expiry";
|
String EXPIRY = "expiry";
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface KeySignaturesColumns {
|
|
||||||
String MASTER_KEY_ID = "master_key_id"; // not a database id
|
|
||||||
String SIGNER_KEY_ID = "signer_key_id";
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface UserPacketsColumns {
|
public interface UserPacketsColumns {
|
||||||
String MASTER_KEY_ID = "master_key_id"; // foreign key to key_rings._ID
|
String MASTER_KEY_ID = "master_key_id"; // foreign key to key_rings._ID
|
||||||
String TYPE = "type"; // not a database id
|
String TYPE = "type"; // not a database id
|
||||||
@@ -79,78 +67,15 @@ public class KeychainContract {
|
|||||||
String DATA = "data";
|
String DATA = "data";
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ApiAppsAllowedKeysColumns {
|
|
||||||
String KEY_ID = "key_id"; // not a database id
|
|
||||||
String PACKAGE_NAME = "package_name"; // foreign key to api_apps.package_name
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OverriddenWarnings {
|
|
||||||
String IDENTIFIER = "identifier";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String CONTENT_AUTHORITY = Constants.PROVIDER_AUTHORITY;
|
|
||||||
|
|
||||||
private static final Uri BASE_CONTENT_URI_INTERNAL = Uri
|
|
||||||
.parse("content://" + CONTENT_AUTHORITY);
|
|
||||||
|
|
||||||
public static final String BASE_KEY_RINGS = "key_rings";
|
|
||||||
|
|
||||||
public static final String BASE_KEY_SIGNATURES = "key_signatures";
|
|
||||||
|
|
||||||
public static final String PATH_PUBLIC = "public";
|
|
||||||
public static final String PATH_USER_IDS = "user_ids";
|
|
||||||
public static final String PATH_KEYS = "keys";
|
|
||||||
public static final String PATH_CERTS = "certs";
|
|
||||||
|
|
||||||
public static class KeyRings implements BaseColumns, KeysColumns, UserPacketsColumns {
|
|
||||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
|
||||||
.appendPath(BASE_KEY_RINGS).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class KeyRingData implements KeyRingsColumns, BaseColumns {
|
|
||||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
|
||||||
.appendPath(BASE_KEY_RINGS).build();
|
|
||||||
|
|
||||||
public static Uri buildPublicKeyRingUri(long masterKeyId) {
|
|
||||||
return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).appendPath(PATH_PUBLIC).build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Keys implements KeysColumns, BaseColumns {
|
public static class Keys implements KeysColumns, BaseColumns {
|
||||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
|
||||||
.appendPath(BASE_KEY_RINGS).build();
|
|
||||||
|
|
||||||
public static Uri buildKeysUri(long masterKeyId) {
|
|
||||||
return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).appendPath(PATH_KEYS).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class KeySignatures implements KeySignaturesColumns, BaseColumns {
|
|
||||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
|
||||||
.appendPath(BASE_KEY_SIGNATURES).build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class UserPackets implements UserPacketsColumns, BaseColumns {
|
public static class UserPackets implements UserPacketsColumns, BaseColumns {
|
||||||
public static final String VERIFIED = "verified";
|
|
||||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
|
||||||
.appendPath(BASE_KEY_RINGS).build();
|
|
||||||
|
|
||||||
public static Uri buildUserIdsUri(long masterKeyId) {
|
|
||||||
return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).appendPath(PATH_USER_IDS).build();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Certs implements CertsColumns, BaseColumns {
|
public static class Certs implements CertsColumns, BaseColumns {
|
||||||
public static final int VERIFIED_SECRET = 1;
|
public static final int VERIFIED_SECRET = 1;
|
||||||
public static final int VERIFIED_SELF = 2;
|
public static final int VERIFIED_SELF = 2;
|
||||||
|
|
||||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
|
||||||
.appendPath(BASE_KEY_RINGS).build();
|
|
||||||
|
|
||||||
public static Uri buildCertsUri(long masterKeyId) {
|
|
||||||
return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).appendPath(PATH_CERTS).build();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeychainContract() {
|
private KeychainContract() {
|
||||||
|
|||||||
@@ -1,225 +1,48 @@
|
|||||||
/*
|
|
||||||
* 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.provider;
|
package org.sufficientlysecure.keychain.provider;
|
||||||
|
|
||||||
|
|
||||||
import android.arch.persistence.db.SupportSQLiteDatabase;
|
|
||||||
import android.content.ContentProvider;
|
import android.content.ContentProvider;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.UriMatcher;
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteConstraintException;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
|
||||||
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeySignatures;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPacketsColumns;
|
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase.Tables;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
|
|
||||||
public class KeychainProvider extends ContentProvider {
|
public class KeychainProvider extends ContentProvider {
|
||||||
private static final int KEY_RING_KEYS = 201;
|
|
||||||
private static final int KEY_RING_USER_IDS = 202;
|
|
||||||
private static final int KEY_RING_PUBLIC = 203;
|
|
||||||
private static final int KEY_RING_CERTS = 205;
|
|
||||||
|
|
||||||
private static final int KEY_SIGNATURES = 700;
|
|
||||||
|
|
||||||
protected UriMatcher mUriMatcher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build and return a {@link UriMatcher} that catches all {@link Uri} variations supported by
|
|
||||||
* this {@link ContentProvider}.
|
|
||||||
*/
|
|
||||||
protected UriMatcher buildUriMatcher() {
|
|
||||||
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
|
|
||||||
|
|
||||||
String authority = KeychainContract.CONTENT_AUTHORITY;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* list key_ring specifics
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* key_rings/_/keys
|
|
||||||
* key_rings/_/user_ids
|
|
||||||
* key_rings/_/public
|
|
||||||
* key_rings/_/certs
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
|
||||||
+ KeychainContract.PATH_KEYS,
|
|
||||||
KEY_RING_KEYS);
|
|
||||||
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
|
||||||
+ KeychainContract.PATH_USER_IDS,
|
|
||||||
KEY_RING_USER_IDS);
|
|
||||||
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
|
||||||
+ KeychainContract.PATH_PUBLIC,
|
|
||||||
KEY_RING_PUBLIC);
|
|
||||||
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
|
||||||
+ KeychainContract.PATH_CERTS,
|
|
||||||
KEY_RING_CERTS);
|
|
||||||
|
|
||||||
matcher.addURI(authority, KeychainContract.BASE_KEY_SIGNATURES, KEY_SIGNATURES);
|
|
||||||
|
|
||||||
|
|
||||||
return matcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
private KeychainDatabase mKeychainDatabase;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreate() {
|
public boolean onCreate() {
|
||||||
mUriMatcher = buildUriMatcher();
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeychainDatabase getDb() {
|
@Nullable
|
||||||
if(mKeychainDatabase == null) {
|
@Override
|
||||||
mKeychainDatabase = KeychainDatabase.getInstance(getContext());
|
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
|
||||||
}
|
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
|
||||||
return mKeychainDatabase;
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public String getType(@NonNull Uri uri) {
|
public String getType(@NonNull Uri uri) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Cursor query(
|
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
|
||||||
@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Uri insert(@NonNull Uri uri, ContentValues values) {
|
|
||||||
Timber.d("insert(uri=" + uri + ", values=" + values.toString() + ")");
|
|
||||||
|
|
||||||
final SupportSQLiteDatabase db = getDb().getWritableDatabase();
|
|
||||||
|
|
||||||
Uri rowUri = null;
|
|
||||||
Long keyId = null;
|
|
||||||
try {
|
|
||||||
final int match = mUriMatcher.match(uri);
|
|
||||||
|
|
||||||
switch (match) {
|
|
||||||
case KEY_RING_PUBLIC: {
|
|
||||||
db.insert(Tables.KEY_RINGS_PUBLIC, SQLiteDatabase.CONFLICT_FAIL, values);
|
|
||||||
keyId = values.getAsLong(Keys.MASTER_KEY_ID);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KEY_RING_KEYS: {
|
|
||||||
db.insert(Tables.KEYS, SQLiteDatabase.CONFLICT_FAIL, values);
|
|
||||||
keyId = values.getAsLong(Keys.MASTER_KEY_ID);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KEY_RING_USER_IDS: {
|
|
||||||
// iff TYPE is null, user_id MUST be null as well
|
|
||||||
if (!(values.get(UserPacketsColumns.TYPE) == null
|
|
||||||
? (values.get(UserPacketsColumns.USER_ID) != null && values.get(UserPacketsColumns.ATTRIBUTE_DATA) == null)
|
|
||||||
: (values.get(UserPacketsColumns.ATTRIBUTE_DATA) != null && values.get(UserPacketsColumns.USER_ID) == null)
|
|
||||||
)) {
|
|
||||||
throw new AssertionError("Incorrect type for user packet! This is a bug!");
|
|
||||||
}
|
|
||||||
if (((Number) values.get(UserPacketsColumns.RANK)).intValue() == 0 && values.get(UserPacketsColumns.USER_ID) == null) {
|
|
||||||
throw new AssertionError("Rank 0 user packet must be a user id!");
|
|
||||||
}
|
|
||||||
db.insert(Tables.USER_PACKETS, SQLiteDatabase.CONFLICT_FAIL, values);
|
|
||||||
keyId = values.getAsLong(UserPackets.MASTER_KEY_ID);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KEY_RING_CERTS: {
|
|
||||||
// we replace here, keeping only the latest signature
|
|
||||||
// TODO this would be better handled in savePublicKeyRing directly!
|
|
||||||
db.insert(Tables.CERTS, SQLiteDatabase.CONFLICT_FAIL, values);
|
|
||||||
keyId = values.getAsLong(Certs.MASTER_KEY_ID);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KEY_SIGNATURES: {
|
|
||||||
db.insert(Tables.KEY_SIGNATURES, SQLiteDatabase.CONFLICT_FAIL, values);
|
|
||||||
rowUri = KeySignatures.CONTENT_URI;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
throw new UnsupportedOperationException("Unknown uri: " + uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyId != null) {
|
|
||||||
uri = DatabaseNotifyManager.getNotifyUriMasterKeyId(keyId);
|
|
||||||
rowUri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (SQLiteConstraintException e) {
|
|
||||||
Timber.d(e, "Constraint exception on insert! Entry already existing?");
|
|
||||||
}
|
|
||||||
|
|
||||||
return rowUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int delete(@NonNull Uri uri, String additionalSelection, String[] selectionArgs) {
|
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
|
||||||
Timber.v("update(uri=" + uri + ", values=" + values.toString() + ")");
|
throw new UnsupportedOperationException();
|
||||||
|
|
||||||
final SupportSQLiteDatabase db = getDb().getWritableDatabase();
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
try {
|
|
||||||
final int match = mUriMatcher.match(uri);
|
|
||||||
switch (match) {
|
|
||||||
case KEY_RING_KEYS: {
|
|
||||||
if (values.size() != 1 || !values.containsKey(Keys.HAS_SECRET)) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"Only has_secret column may be updated!");
|
|
||||||
}
|
|
||||||
// make sure we get a long value here
|
|
||||||
Long mkid = Long.parseLong(uri.getPathSegments().get(1));
|
|
||||||
String actualSelection = Keys.MASTER_KEY_ID + " = " + Long.toString(mkid);
|
|
||||||
if (!TextUtils.isEmpty(selection)) {
|
|
||||||
actualSelection += " AND (" + selection + ")";
|
|
||||||
}
|
|
||||||
count = db.update(Tables.KEYS, SQLiteDatabase.CONFLICT_FAIL, values, actualSelection, selectionArgs);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
throw new UnsupportedOperationException("Unknown uri: " + uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLiteConstraintException e) {
|
|
||||||
Timber.d(e, "Constraint exception on update! Entry already existing?");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
@Override
|
||||||
|
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
|
||||||
|
@Nullable String[] selectionArgs) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,13 +38,13 @@ import android.text.TextUtils;
|
|||||||
|
|
||||||
import org.sufficientlysecure.keychain.BuildConfig;
|
import org.sufficientlysecure.keychain.BuildConfig;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase.Tables;
|
import org.sufficientlysecure.keychain.KeychainDatabase.Tables;
|
||||||
|
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
||||||
|
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
|
import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptStatus;
|
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptStatus;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus;
|
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus;
|
||||||
@@ -200,7 +200,7 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// uri to watch is all /key_rings/
|
// uri to watch is all /key_rings/
|
||||||
uri = KeyRings.CONTENT_URI;
|
uri = DatabaseNotifyManager.getNotifyUriAllKeys();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// uri to watch is all /key_rings/
|
// uri to watch is all /key_rings/
|
||||||
uri = KeyRings.CONTENT_URI;
|
uri = DatabaseNotifyManager.getNotifyUriAllKeys();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,8 +52,11 @@ import eu.davidea.flexibleadapter.FlexibleAdapter.OnItemClickListener;
|
|||||||
import eu.davidea.flexibleadapter.FlexibleAdapter.OnItemLongClickListener;
|
import eu.davidea.flexibleadapter.FlexibleAdapter.OnItemLongClickListener;
|
||||||
import eu.davidea.flexibleadapter.SelectableAdapter.Mode;
|
import eu.davidea.flexibleadapter.SelectableAdapter.Mode;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
||||||
|
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
|
||||||
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.keysync.KeyserverSyncManager;
|
import org.sufficientlysecure.keychain.keysync.KeyserverSyncManager;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.KeySyncParcel;
|
import org.sufficientlysecure.keychain.operations.KeySyncParcel;
|
||||||
@@ -61,9 +64,6 @@ import org.sufficientlysecure.keychain.operations.results.BenchmarkResult;
|
|||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
|
||||||
import org.sufficientlysecure.keychain.service.BenchmarkInputParcel;
|
import org.sufficientlysecure.keychain.service.BenchmarkInputParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyDetailsItem;
|
import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyDetailsItem;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyDummyItem;
|
import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyDummyItem;
|
||||||
@@ -492,7 +492,7 @@ public class KeyListFragment extends RecyclerFragment<FlexibleAdapter<FlexibleKe
|
|||||||
try {
|
try {
|
||||||
KeychainDatabase.debugBackup(getActivity(), true);
|
KeychainDatabase.debugBackup(getActivity(), true);
|
||||||
Notify.create(getActivity(), "Restored debug_backup.db", Notify.Style.OK).show();
|
Notify.create(getActivity(), "Restored debug_backup.db", Notify.Style.OK).show();
|
||||||
getActivity().getContentResolver().notifyChange(KeyRings.CONTENT_URI, null);
|
DatabaseNotifyManager.create(requireContext()).notifyAllKeysChange();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Timber.e(e, "IO Error");
|
Timber.e(e, "IO Error");
|
||||||
Notify.create(getActivity(), "IO Error " + e.getMessage(), Notify.Style.ERROR).show();
|
Notify.create(getActivity(), "IO Error " + e.getMessage(), Notify.Style.ERROR).show();
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
|||||||
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
|
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
|
||||||
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.ViewKeyAdvActivity.ViewKeyAdvViewModel;
|
import org.sufficientlysecure.keychain.ui.ViewKeyAdvActivity.ViewKeyAdvViewModel;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
|||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
|
||||||
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo;
|
import org.sufficientlysecure.keychain.securitytoken.SecurityTokenInfo;
|
||||||
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.PromoteKeyringParcel;
|
import org.sufficientlysecure.keychain.service.PromoteKeyringParcel;
|
||||||
|
|||||||
@@ -19,12 +19,6 @@ package org.sufficientlysecure.keychain.ui.widget;
|
|||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.v4.app.LoaderManager;
|
|
||||||
import android.support.v4.content.CursorLoader;
|
|
||||||
import android.support.v4.content.Loader;
|
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -34,8 +28,6 @@ import android.widget.ViewAnimator;
|
|||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.Certification.CertDetails;
|
import org.sufficientlysecure.keychain.model.Certification.CertDetails;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
|
||||||
|
|
||||||
public class CertListWidget extends ViewAnimator {
|
public class CertListWidget extends ViewAnimator {
|
||||||
private TextView vCollapsed;
|
private TextView vCollapsed;
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ CREATE TABLE IF NOT EXISTS certs(
|
|||||||
FOREIGN KEY(master_key_id, rank) REFERENCES user_packets(master_key_id, rank) ON DELETE CASCADE
|
FOREIGN KEY(master_key_id, rank) REFERENCES user_packets(master_key_id, rank) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
insertCert:
|
||||||
|
INSERT INTO certs VALUES (?, ?, ?, ?, ?, ?, ?);
|
||||||
|
|
||||||
selectVerifyingCertDetails:
|
selectVerifyingCertDetails:
|
||||||
SELECT master_key_id AS masterKeyId, key_id_certifier AS signerMasterKeyId, creation * 1000 AS creation
|
SELECT master_key_id AS masterKeyId, key_id_certifier AS signerMasterKeyId, creation * 1000 AS creation
|
||||||
FROM certs
|
FROM certs
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ CREATE TABLE IF NOT EXISTS keyrings_public (
|
|||||||
key_ring_data BLOB NULL
|
key_ring_data BLOB NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
insertKeyRingPublic:
|
||||||
|
INSERT INTO keyrings_public VALUES (?, ?);
|
||||||
|
|
||||||
selectAllMasterKeyIds:
|
selectAllMasterKeyIds:
|
||||||
SELECT master_key_id
|
SELECT master_key_id
|
||||||
FROM keyrings_public;
|
FROM keyrings_public;
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ CREATE TABLE IF NOT EXISTS key_signatures (
|
|||||||
FOREIGN KEY(master_key_id) REFERENCES keyrings_public(master_key_id) ON DELETE CASCADE
|
FOREIGN KEY(master_key_id) REFERENCES keyrings_public(master_key_id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
insertKeySignature:
|
||||||
|
INSERT INTO key_signatures VALUES (?, ?);
|
||||||
|
|
||||||
selectMasterKeyIdsBySigner:
|
selectMasterKeyIdsBySigner:
|
||||||
SELECT master_key_id
|
SELECT master_key_id
|
||||||
FROM key_signatures WHERE signer_key_id IN ?;
|
FROM key_signatures WHERE signer_key_id IN ?;
|
||||||
@@ -23,6 +23,19 @@ CREATE TABLE IF NOT EXISTS keys (
|
|||||||
keyrings_public(master_key_id) ON DELETE CASCADE
|
keyrings_public(master_key_id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
insertKey:
|
||||||
|
INSERT INTO keys VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
|
|
||||||
|
updateHasSecretByMasterKeyId:
|
||||||
|
UPDATE keys
|
||||||
|
SET has_secret = ?2
|
||||||
|
WHERE master_key_id = ?1;
|
||||||
|
|
||||||
|
updateHasSecretByKeyId:
|
||||||
|
UPDATE keys
|
||||||
|
SET has_secret = ?2
|
||||||
|
WHERE key_id = ?1;
|
||||||
|
|
||||||
unifiedKeyView:
|
unifiedKeyView:
|
||||||
CREATE VIEW unifiedKeyView AS
|
CREATE VIEW unifiedKeyView AS
|
||||||
SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.user_id, user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, keys.can_certify, certs.verified,
|
SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.user_id, user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, keys.can_certify, certs.verified,
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ CREATE TABLE IF NOT EXISTS user_packets(
|
|||||||
keyrings_public(master_key_id) ON DELETE CASCADE
|
keyrings_public(master_key_id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
insertUserPacket:
|
||||||
|
INSERT INTO user_packets VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
|
|
||||||
selectUserIdsByMasterKeyId:
|
selectUserIdsByMasterKeyId:
|
||||||
SELECT user_packets.master_key_id, user_packets.rank, user_id, name, email, comment, is_primary, is_revoked, MIN(certs.verified) AS verified_int
|
SELECT user_packets.master_key_id, user_packets.rank, user_id, name, email, comment, is_primary, is_revoked, MIN(certs.verified) AS verified_int
|
||||||
FROM user_packets
|
FROM user_packets
|
||||||
|
|||||||
Reference in New Issue
Block a user