clean up package structure
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
package org.sufficientlysecure.keychain.daos;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||
import android.arch.persistence.db.SupportSQLiteQuery;
|
||||
import android.database.Cursor;
|
||||
|
||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
||||
|
||||
|
||||
class AbstractDao {
|
||||
private final KeychainDatabase db;
|
||||
private final DatabaseNotifyManager databaseNotifyManager;
|
||||
|
||||
AbstractDao(KeychainDatabase db, DatabaseNotifyManager databaseNotifyManager) {
|
||||
this.db = db;
|
||||
this.databaseNotifyManager = databaseNotifyManager;
|
||||
}
|
||||
|
||||
SupportSQLiteDatabase getReadableDb() {
|
||||
return db.getReadableDatabase();
|
||||
}
|
||||
|
||||
SupportSQLiteDatabase getWritableDb() {
|
||||
return db.getWritableDatabase();
|
||||
}
|
||||
|
||||
DatabaseNotifyManager getDatabaseNotifyManager() {
|
||||
return databaseNotifyManager;
|
||||
}
|
||||
|
||||
<T> List<T> mapAllRows(SupportSQLiteQuery query, Mapper<T> mapper) {
|
||||
ArrayList<T> result = new ArrayList<>();
|
||||
try (Cursor cursor = getReadableDb().query(query)) {
|
||||
while (cursor.moveToNext()) {
|
||||
T item = mapper.map(cursor);
|
||||
result.add(item);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
<T> T mapSingleRowOrThrow(SupportSQLiteQuery query, Mapper<T> mapper) throws NotFoundException {
|
||||
T result = mapSingleRow(query, mapper);
|
||||
if (result == null) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
<T> T mapSingleRow(SupportSQLiteQuery query, Mapper<T> mapper) {
|
||||
try (Cursor cursor = getReadableDb().query(query)) {
|
||||
if (cursor.moveToNext()) {
|
||||
return mapper.map(cursor);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
interface Mapper<T> {
|
||||
T map(Cursor cursor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.daos;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
||||
import com.squareup.sqldelight.SqlDelightQuery;
|
||||
import org.sufficientlysecure.keychain.ApiAllowedKeysModel.InsertAllowedKey;
|
||||
import org.sufficientlysecure.keychain.ApiAppsModel;
|
||||
import org.sufficientlysecure.keychain.ApiAppsModel.DeleteByPackageName;
|
||||
import org.sufficientlysecure.keychain.ApiAppsModel.InsertApiApp;
|
||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||
import org.sufficientlysecure.keychain.model.ApiAllowedKey;
|
||||
import org.sufficientlysecure.keychain.model.ApiApp;
|
||||
|
||||
|
||||
public class ApiAppDao extends AbstractDao {
|
||||
public static ApiAppDao getInstance(Context context) {
|
||||
KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context);
|
||||
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||
|
||||
return new ApiAppDao(keychainDatabase, databaseNotifyManager);
|
||||
}
|
||||
|
||||
private ApiAppDao(KeychainDatabase keychainDatabase, DatabaseNotifyManager databaseNotifyManager) {
|
||||
super(keychainDatabase, databaseNotifyManager);
|
||||
}
|
||||
|
||||
public ApiApp getApiApp(String packageName) {
|
||||
try (Cursor cursor = getReadableDb().query(ApiApp.FACTORY.selectByPackageName(packageName))) {
|
||||
if (cursor.moveToFirst()) {
|
||||
return ApiApp.FACTORY.selectByPackageNameMapper().map(cursor);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getApiAppCertificate(String packageName) {
|
||||
try (Cursor cursor = getReadableDb().query(ApiApp.FACTORY.getCertificate(packageName))) {
|
||||
if (cursor.moveToFirst()) {
|
||||
return ApiApp.FACTORY.getCertificateMapper().map(cursor);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void insertApiApp(ApiApp apiApp) {
|
||||
ApiApp existingApiApp = getApiApp(apiApp.package_name());
|
||||
if (existingApiApp != null) {
|
||||
if (!Arrays.equals(existingApiApp.package_signature(), apiApp.package_signature())) {
|
||||
throw new IllegalStateException("Inserting existing api with different signature?!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
InsertApiApp statement = new ApiAppsModel.InsertApiApp(getWritableDb());
|
||||
statement.bind(apiApp.package_name(), apiApp.package_signature());
|
||||
statement.executeInsert();
|
||||
}
|
||||
|
||||
public void deleteApiApp(String packageName) {
|
||||
DeleteByPackageName deleteByPackageName = new DeleteByPackageName(getWritableDb());
|
||||
deleteByPackageName.bind(packageName);
|
||||
deleteByPackageName.executeUpdateDelete();
|
||||
}
|
||||
|
||||
public HashSet<Long> getAllowedKeyIdsForApp(String packageName) {
|
||||
SqlDelightQuery allowedKeys = ApiAllowedKey.FACTORY.getAllowedKeys(packageName);
|
||||
HashSet<Long> keyIds = new HashSet<>();
|
||||
try (Cursor cursor = getReadableDb().query(allowedKeys)) {
|
||||
while (cursor.moveToNext()) {
|
||||
long allowedKeyId = ApiAllowedKey.FACTORY.getAllowedKeysMapper().map(cursor);
|
||||
keyIds.add(allowedKeyId);
|
||||
}
|
||||
}
|
||||
return keyIds;
|
||||
}
|
||||
|
||||
public void saveAllowedKeyIdsForApp(String packageName, Set<Long> allowedKeyIds) {
|
||||
ApiAllowedKey.DeleteByPackageName deleteByPackageName = new ApiAllowedKey.DeleteByPackageName(getWritableDb());
|
||||
deleteByPackageName.bind(packageName);
|
||||
deleteByPackageName.executeUpdateDelete();
|
||||
|
||||
InsertAllowedKey statement = new InsertAllowedKey(getWritableDb());
|
||||
for (Long keyId : allowedKeyIds) {
|
||||
statement.bind(packageName, keyId);
|
||||
statement.execute();
|
||||
}
|
||||
}
|
||||
|
||||
public void addAllowedKeyIdForApp(String packageName, long allowedKeyId) {
|
||||
InsertAllowedKey statement = new InsertAllowedKey(getWritableDb());
|
||||
statement.bind(packageName, allowedKeyId);
|
||||
statement.execute();
|
||||
}
|
||||
|
||||
public List<ApiApp> getAllApiApps() {
|
||||
SqlDelightQuery query = ApiApp.FACTORY.selectAll();
|
||||
|
||||
ArrayList<ApiApp> result = new ArrayList<>();
|
||||
try (Cursor cursor = getReadableDb().query(query)) {
|
||||
while (cursor.moveToNext()) {
|
||||
ApiApp apiApp = ApiApp.FACTORY.selectAllMapper().map(cursor);
|
||||
result.add(apiApp);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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.daos;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.squareup.sqldelight.SqlDelightQuery;
|
||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.DeleteByIdentifier;
|
||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.DeleteByMasterKeyId;
|
||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.InsertPeer;
|
||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.UpdateGossipKey;
|
||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.UpdateKey;
|
||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.UpdateLastSeen;
|
||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||
import org.sufficientlysecure.keychain.model.AutocryptPeer;
|
||||
import org.sufficientlysecure.keychain.model.AutocryptPeer.AutocryptKeyStatus;
|
||||
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
|
||||
|
||||
|
||||
public class AutocryptPeerDao extends AbstractDao {
|
||||
public static AutocryptPeerDao getInstance(Context context) {
|
||||
KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context);
|
||||
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||
|
||||
return new AutocryptPeerDao(keychainDatabase, databaseNotifyManager);
|
||||
}
|
||||
|
||||
private AutocryptPeerDao(KeychainDatabase database, DatabaseNotifyManager databaseNotifyManager) {
|
||||
super(database, databaseNotifyManager);
|
||||
}
|
||||
|
||||
public Long getMasterKeyIdForAutocryptPeer(String autocryptId) {
|
||||
SqlDelightQuery query = AutocryptPeer.FACTORY.selectMasterKeyIdByIdentifier(autocryptId);
|
||||
try (Cursor cursor = getReadableDb().query(query)) {
|
||||
if (cursor.moveToFirst()) {
|
||||
return AutocryptPeer.FACTORY.selectMasterKeyIdByIdentifierMapper().map(cursor);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public AutocryptPeer getAutocryptPeer(String packageName, String autocryptId) {
|
||||
List<AutocryptPeer> autocryptPeers = getAutocryptPeers(packageName, autocryptId);
|
||||
if (!autocryptPeers.isEmpty()) {
|
||||
return autocryptPeers.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<AutocryptPeer> getAutocryptPeers(String packageName, String... autocryptId) {
|
||||
ArrayList<AutocryptPeer> result = new ArrayList<>(autocryptId.length);
|
||||
SqlDelightQuery query = AutocryptPeer.FACTORY.selectByIdentifiers(packageName, autocryptId);
|
||||
try (Cursor cursor = getReadableDb().query(query)) {
|
||||
if (cursor.moveToNext()) {
|
||||
AutocryptPeer autocryptPeer = AutocryptPeer.PEER_MAPPER.map(cursor);
|
||||
result.add(autocryptPeer);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<AutocryptKeyStatus> getAutocryptKeyStatus(String packageName, String[] autocryptIds) {
|
||||
ArrayList<AutocryptKeyStatus> result = new ArrayList<>(autocryptIds.length);
|
||||
SqlDelightQuery query = AutocryptPeer.FACTORY.selectAutocryptKeyStatus(packageName, autocryptIds, System.currentTimeMillis());
|
||||
try (Cursor cursor = getReadableDb().query(query)) {
|
||||
if (cursor.moveToNext()) {
|
||||
AutocryptKeyStatus autocryptPeer = AutocryptPeer.KEY_STATUS_MAPPER.map(cursor);
|
||||
result.add(autocryptPeer);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void insertOrUpdateLastSeen(String packageName, String autocryptId, Date date) {
|
||||
UpdateLastSeen updateStatement = new UpdateLastSeen(getWritableDb(), AutocryptPeer.FACTORY);
|
||||
updateStatement.bind(packageName, autocryptId, date);
|
||||
int updated = updateStatement.executeUpdateDelete();
|
||||
|
||||
if (updated == 0) {
|
||||
InsertPeer insertStatement = new InsertPeer(getWritableDb(), AutocryptPeer.FACTORY);
|
||||
insertStatement.bind(packageName, autocryptId, date);
|
||||
insertStatement.executeInsert();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateKey(String packageName, String autocryptId, Date effectiveDate, long masterKeyId,
|
||||
boolean isMutual) {
|
||||
UpdateKey updateStatement = new UpdateKey(getWritableDb(), AutocryptPeer.FACTORY);
|
||||
updateStatement.bind(packageName, autocryptId, effectiveDate, masterKeyId, isMutual);
|
||||
int rowsUpdated = updateStatement.executeUpdateDelete();
|
||||
if (rowsUpdated == 0) {
|
||||
throw new IllegalStateException("No rows updated! Was this peer inserted before the update?");
|
||||
}
|
||||
getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId);
|
||||
}
|
||||
|
||||
public void updateKeyGossip(String packageName, String autocryptId, Date effectiveDate, long masterKeyId,
|
||||
GossipOrigin origin) {
|
||||
UpdateGossipKey updateStatement = new UpdateGossipKey(getWritableDb(), AutocryptPeer.FACTORY);
|
||||
updateStatement.bind(packageName, autocryptId, effectiveDate, masterKeyId, origin);
|
||||
int rowsUpdated = updateStatement.executeUpdateDelete();
|
||||
if (rowsUpdated == 0) {
|
||||
throw new IllegalStateException("No rows updated! Was this peer inserted before the update?");
|
||||
}
|
||||
getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId);
|
||||
}
|
||||
|
||||
public List<AutocryptPeer> getAutocryptPeersForKey(long masterKeyId) {
|
||||
ArrayList<AutocryptPeer> result = new ArrayList<>();
|
||||
SqlDelightQuery query = AutocryptPeer.FACTORY.selectByMasterKeyId(masterKeyId);
|
||||
try (Cursor cursor = getReadableDb().query(query)) {
|
||||
if (cursor.moveToNext()) {
|
||||
AutocryptPeer autocryptPeer = AutocryptPeer.PEER_MAPPER.map(cursor);
|
||||
result.add(autocryptPeer);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void deleteByIdentifier(String packageName, String autocryptId) {
|
||||
Long masterKeyId = getMasterKeyIdForAutocryptPeer(autocryptId);
|
||||
DeleteByIdentifier deleteStatement = new DeleteByIdentifier(getReadableDb());
|
||||
deleteStatement.bind(packageName, autocryptId);
|
||||
deleteStatement.execute();
|
||||
if (masterKeyId != null) {
|
||||
getDatabaseNotifyManager().notifyAutocryptDelete(autocryptId, masterKeyId);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteByMasterKeyId(long masterKeyId) {
|
||||
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(getReadableDb());
|
||||
deleteStatement.bind(masterKeyId);
|
||||
deleteStatement.execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.sufficientlysecure.keychain.daos;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
||||
import com.squareup.sqldelight.SqlDelightQuery;
|
||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||
import org.sufficientlysecure.keychain.model.Certification;
|
||||
import org.sufficientlysecure.keychain.model.Certification.CertDetails;
|
||||
|
||||
|
||||
public class CertificationDao extends AbstractDao {
|
||||
public static CertificationDao getInstance(Context context) {
|
||||
KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context);
|
||||
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||
|
||||
return new CertificationDao(keychainDatabase, databaseNotifyManager);
|
||||
}
|
||||
|
||||
private CertificationDao(KeychainDatabase keychainDatabase, DatabaseNotifyManager databaseNotifyManager) {
|
||||
super(keychainDatabase, databaseNotifyManager);
|
||||
}
|
||||
|
||||
public CertDetails getVerifyingCertDetails(long masterKeyId, int userPacketRank) {
|
||||
SqlDelightQuery query = Certification.FACTORY.selectVerifyingCertDetails(masterKeyId, userPacketRank);
|
||||
try (Cursor cursor = getReadableDb().query(query)) {
|
||||
if (cursor.moveToFirst()) {
|
||||
return Certification.CERT_DETAILS_MAPPER.map(cursor);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.sufficientlysecure.keychain.daos;
|
||||
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
|
||||
|
||||
public class DatabaseNotifyManager {
|
||||
private static final Uri BASE_URI = Uri.parse("content://" + Constants.PROVIDER_AUTHORITY);
|
||||
|
||||
private ContentResolver contentResolver;
|
||||
|
||||
public static DatabaseNotifyManager create(Context context) {
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
return new DatabaseNotifyManager(contentResolver);
|
||||
}
|
||||
|
||||
private DatabaseNotifyManager(ContentResolver contentResolver) {
|
||||
this.contentResolver = contentResolver;
|
||||
}
|
||||
|
||||
public void notifyKeyChange(long masterKeyId) {
|
||||
Uri uri = getNotifyUriMasterKeyId(masterKeyId);
|
||||
contentResolver.notifyChange(uri, null);
|
||||
}
|
||||
|
||||
public void notifyAutocryptDelete(String autocryptId, Long masterKeyId) {
|
||||
Uri uri = getNotifyUriMasterKeyId(masterKeyId);
|
||||
contentResolver.notifyChange(uri, null);
|
||||
}
|
||||
|
||||
public void notifyAutocryptUpdate(String autocryptId, long masterKeyId) {
|
||||
Uri uri = getNotifyUriMasterKeyId(masterKeyId);
|
||||
contentResolver.notifyChange(uri, null);
|
||||
}
|
||||
|
||||
public void notifyKeyMetadataChange(long masterKeyId) {
|
||||
Uri uri = getNotifyUriMasterKeyId(masterKeyId);
|
||||
contentResolver.notifyChange(uri, null);
|
||||
}
|
||||
|
||||
public static Uri getNotifyUriAllKeys() {
|
||||
return BASE_URI;
|
||||
}
|
||||
|
||||
public static Uri getNotifyUriMasterKeyId(long masterKeyId) {
|
||||
return BASE_URI.buildUpon().appendPath(Long.toString(masterKeyId)).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.sufficientlysecure.keychain.daos;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
||||
import com.squareup.sqldelight.SqlDelightQuery;
|
||||
import org.sufficientlysecure.keychain.KeyMetadataModel.ReplaceKeyMetadata;
|
||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||
import org.sufficientlysecure.keychain.model.KeyMetadata;
|
||||
|
||||
|
||||
public class KeyMetadataDao extends AbstractDao {
|
||||
public static KeyMetadataDao create(Context context) {
|
||||
KeychainDatabase database = KeychainDatabase.getInstance(context);
|
||||
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||
|
||||
return new KeyMetadataDao(database, databaseNotifyManager);
|
||||
}
|
||||
|
||||
private KeyMetadataDao(KeychainDatabase database, DatabaseNotifyManager databaseNotifyManager) {
|
||||
super(database, databaseNotifyManager);
|
||||
}
|
||||
|
||||
public KeyMetadata getKeyMetadata(long masterKeyId) {
|
||||
SqlDelightQuery query = KeyMetadata.FACTORY.selectByMasterKeyId(masterKeyId);
|
||||
try (Cursor cursor = getReadableDb().query(query)) {
|
||||
if (cursor.moveToFirst()) {
|
||||
return KeyMetadata.FACTORY.selectByMasterKeyIdMapper().map(cursor);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void resetAllLastUpdatedTimes() {
|
||||
new KeyMetadata.DeleteAllLastUpdatedTimes(getWritableDb()).execute();
|
||||
}
|
||||
|
||||
public void renewKeyLastUpdatedTime(long masterKeyId, boolean seenOnKeyservers) {
|
||||
ReplaceKeyMetadata replaceStatement = new ReplaceKeyMetadata(getWritableDb(), KeyMetadata.FACTORY);
|
||||
replaceStatement.bind(masterKeyId, new Date(), seenOnKeyservers);
|
||||
replaceStatement.executeInsert();
|
||||
|
||||
getDatabaseNotifyManager().notifyKeyMetadataChange(masterKeyId);
|
||||
}
|
||||
|
||||
public List<byte[]> getFingerprintsForKeysOlderThan(long olderThan, TimeUnit timeUnit) {
|
||||
SqlDelightQuery query = KeyMetadata.FACTORY.selectFingerprintsForKeysOlderThan(new Date(timeUnit.toMillis(olderThan)));
|
||||
|
||||
List<byte[]> fingerprintList = new ArrayList<>();
|
||||
try (Cursor cursor = getReadableDb().query(query)) {
|
||||
while (cursor.moveToNext()) {
|
||||
byte[] fingerprint = KeyMetadata.FACTORY.selectFingerprintsForKeysOlderThanMapper().map(cursor);
|
||||
fingerprintList.add(fingerprint);
|
||||
}
|
||||
}
|
||||
return fingerprintList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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.daos;
|
||||
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.annotation.WorkerThread;
|
||||
|
||||
import com.squareup.sqldelight.SqlDelightQuery;
|
||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||
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.UserPacket;
|
||||
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
@WorkerThread
|
||||
public class KeyRepository extends AbstractDao {
|
||||
final ContentResolver contentResolver;
|
||||
final LocalPublicKeyStorage mLocalPublicKeyStorage;
|
||||
final LocalSecretKeyStorage localSecretKeyStorage;
|
||||
|
||||
OperationLog mLog;
|
||||
int mIndent;
|
||||
|
||||
public static KeyRepository create(Context context) {
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context);
|
||||
LocalSecretKeyStorage localSecretKeyStorage = LocalSecretKeyStorage.getInstance(context);
|
||||
KeychainDatabase database = KeychainDatabase.getInstance(context);
|
||||
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||
|
||||
return new KeyRepository(contentResolver, database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage);
|
||||
}
|
||||
|
||||
private KeyRepository(ContentResolver contentResolver, KeychainDatabase database,
|
||||
DatabaseNotifyManager databaseNotifyManager,
|
||||
LocalPublicKeyStorage localPublicKeyStorage,
|
||||
LocalSecretKeyStorage localSecretKeyStorage) {
|
||||
this(contentResolver, database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage, new OperationLog(), 0);
|
||||
}
|
||||
|
||||
KeyRepository(ContentResolver contentResolver, KeychainDatabase database,
|
||||
DatabaseNotifyManager databaseNotifyManager,
|
||||
LocalPublicKeyStorage localPublicKeyStorage,
|
||||
LocalSecretKeyStorage localSecretKeyStorage,
|
||||
OperationLog log, int indent) {
|
||||
super(database, databaseNotifyManager);
|
||||
this.contentResolver = contentResolver;
|
||||
mLocalPublicKeyStorage = localPublicKeyStorage;
|
||||
this.localSecretKeyStorage = localSecretKeyStorage;
|
||||
mIndent = indent;
|
||||
mLog = log;
|
||||
}
|
||||
|
||||
public OperationLog getLog() {
|
||||
return mLog;
|
||||
}
|
||||
|
||||
public void log(LogType type) {
|
||||
if (mLog != null) {
|
||||
mLog.add(type, mIndent);
|
||||
}
|
||||
}
|
||||
|
||||
public void log(LogType type, Object... parameters) {
|
||||
if (mLog != null) {
|
||||
mLog.add(type, mIndent, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearLog() {
|
||||
mLog = new OperationLog();
|
||||
}
|
||||
|
||||
public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long masterKeyId) throws NotFoundException {
|
||||
UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
|
||||
if (unifiedKeyInfo == null) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
byte[] publicKeyData = loadPublicKeyRingData(masterKeyId);
|
||||
return new CanonicalizedPublicKeyRing(publicKeyData, unifiedKeyInfo.verified());
|
||||
}
|
||||
|
||||
public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(long masterKeyId) throws NotFoundException {
|
||||
UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
|
||||
if (unifiedKeyInfo == null || !unifiedKeyInfo.has_any_secret()) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
byte[] secretKeyData = loadSecretKeyRingData(masterKeyId);
|
||||
if (secretKeyData == null) {
|
||||
throw new IllegalStateException("Missing expected secret key data!");
|
||||
}
|
||||
return new CanonicalizedSecretKeyRing(secretKeyData, unifiedKeyInfo.verified());
|
||||
}
|
||||
|
||||
public List<Long> getAllMasterKeyIds() {
|
||||
SqlDelightQuery query = KeyRingPublic.FACTORY.selectAllMasterKeyIds();
|
||||
return mapAllRows(query, KeyRingPublic.FACTORY.selectAllMasterKeyIdsMapper()::map);
|
||||
}
|
||||
|
||||
public List<Long> getMasterKeyIdsBySigner(List<Long> signerMasterKeyIds) {
|
||||
long[] signerKeyIds = getLongListAsArray(signerMasterKeyIds);
|
||||
SqlDelightQuery query = KeySignature.FACTORY.selectMasterKeyIdsBySigner(signerKeyIds);
|
||||
return mapAllRows(query, KeySignature.FACTORY.selectMasterKeyIdsBySignerMapper()::map);
|
||||
}
|
||||
|
||||
public Long getMasterKeyIdBySubkeyId(long subKeyId) {
|
||||
SqlDelightQuery query = SubKey.FACTORY.selectMasterKeyIdBySubkey(subKeyId);
|
||||
return mapSingleRow(query, SubKey.FACTORY.selectMasterKeyIdBySubkeyMapper()::map);
|
||||
}
|
||||
|
||||
public UnifiedKeyInfo getUnifiedKeyInfo(long masterKeyId) {
|
||||
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyId(masterKeyId);
|
||||
return mapSingleRow(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map);
|
||||
}
|
||||
|
||||
public List<UnifiedKeyInfo> getUnifiedKeyInfo(long... masterKeyIds) {
|
||||
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyIds(masterKeyIds);
|
||||
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map);
|
||||
}
|
||||
|
||||
public List<UnifiedKeyInfo> getUnifiedKeyInfosByMailAddress(String mailAddress) {
|
||||
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%');
|
||||
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map);
|
||||
}
|
||||
|
||||
public List<UnifiedKeyInfo> getAllUnifiedKeyInfo() {
|
||||
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfo();
|
||||
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map);
|
||||
}
|
||||
|
||||
public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithSecret() {
|
||||
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfoWithSecret();
|
||||
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map);
|
||||
}
|
||||
|
||||
public List<UserId> getUserIds(long... masterKeyIds) {
|
||||
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyIds);
|
||||
return mapAllRows(query, UserPacket.USER_ID_MAPPER::map);
|
||||
}
|
||||
|
||||
public List<String> getConfirmedUserIds(long masterKeyId) {
|
||||
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyIdAndVerification(
|
||||
Certification.FACTORY, masterKeyId, VerificationStatus.VERIFIED_SECRET);
|
||||
return mapAllRows(query, (cursor) -> UserPacket.USER_ID_MAPPER.map(cursor).user_id());
|
||||
}
|
||||
|
||||
public List<SubKey> getSubKeysByMasterKeyId(long masterKeyId) {
|
||||
SqlDelightQuery query = SubKey.FACTORY.selectSubkeysByMasterKeyId(masterKeyId);
|
||||
return mapAllRows(query, SubKey.SUBKEY_MAPPER::map);
|
||||
}
|
||||
|
||||
public SecretKeyType getSecretKeyType(long keyId) throws NotFoundException {
|
||||
SqlDelightQuery query = SubKey.FACTORY.selectSecretKeyType(keyId);
|
||||
return mapSingleRowOrThrow(query, SubKey.SKT_MAPPER::map);
|
||||
}
|
||||
|
||||
public byte[] getFingerprintByKeyId(long keyId) throws NotFoundException {
|
||||
SqlDelightQuery query = SubKey.FACTORY.selectFingerprintByKeyId(keyId);
|
||||
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectFingerprintByKeyIdMapper()::map);
|
||||
}
|
||||
|
||||
private byte[] getKeyRingAsArmoredData(byte[] data) throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ArmoredOutputStream aos = new ArmoredOutputStream(bos);
|
||||
|
||||
aos.write(data);
|
||||
aos.close();
|
||||
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public String getPublicKeyRingAsArmoredString(long masterKeyId) throws NotFoundException, IOException {
|
||||
byte[] data = loadPublicKeyRingData(masterKeyId);
|
||||
byte[] armoredData = getKeyRingAsArmoredData(data);
|
||||
return new String(armoredData);
|
||||
}
|
||||
|
||||
public byte[] getSecretKeyRingAsArmoredData(long masterKeyId) throws NotFoundException, IOException {
|
||||
byte[] data = loadSecretKeyRingData(masterKeyId);
|
||||
return getKeyRingAsArmoredData(data);
|
||||
}
|
||||
|
||||
public ContentResolver getContentResolver() {
|
||||
return contentResolver;
|
||||
}
|
||||
|
||||
public final byte[] loadPublicKeyRingData(long masterKeyId) throws NotFoundException {
|
||||
SqlDelightQuery query = KeyRingPublic.FACTORY.selectByMasterKeyId(masterKeyId);
|
||||
try (Cursor cursor = getReadableDb().query(query)) {
|
||||
if (cursor.moveToFirst()) {
|
||||
KeyRingPublic keyRingPublic = KeyRingPublic.MAPPER.map(cursor);
|
||||
byte[] keyRingData = keyRingPublic.key_ring_data();
|
||||
if (keyRingData == null) {
|
||||
keyRingData = mLocalPublicKeyStorage.readPublicKey(masterKeyId);
|
||||
}
|
||||
return keyRingData;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Timber.e(e, "Error reading public key from storage!");
|
||||
}
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
public final byte[] loadSecretKeyRingData(long masterKeyId) throws NotFoundException {
|
||||
try {
|
||||
return localSecretKeyStorage.readSecretKey(masterKeyId);
|
||||
} catch (IOException e) {
|
||||
Timber.e(e, "Error reading secret key from storage!");
|
||||
throw new NotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
public long getSecretSignId(long masterKeyId) throws NotFoundException {
|
||||
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyId(masterKeyId);
|
||||
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyIdMapper()::map);
|
||||
}
|
||||
|
||||
public long getSecretAuthenticationId(long masterKeyId) throws NotFoundException {
|
||||
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyId(masterKeyId);
|
||||
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyIdMapper()::map);
|
||||
}
|
||||
|
||||
public static class NotFoundException extends Exception {
|
||||
public NotFoundException() {
|
||||
}
|
||||
|
||||
public NotFoundException(String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
|
||||
private long[] getLongListAsArray(List<Long> longList) {
|
||||
long[] longs = new long[longList.size()];
|
||||
int i = 0;
|
||||
for (Long aLong : longList) {
|
||||
longs[i++] = aLong;
|
||||
}
|
||||
return longs;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.daos;
|
||||
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import okhttp3.internal.Util;
|
||||
|
||||
|
||||
class LocalPublicKeyStorage {
|
||||
private static final String FORMAT_STR_PUBLIC_KEY = "0x%016x.pub";
|
||||
private static final String PUBLIC_KEYS_DIR_NAME = "public_keys";
|
||||
|
||||
|
||||
private final File localPublicKeysDir;
|
||||
|
||||
|
||||
public static LocalPublicKeyStorage getInstance(Context context) {
|
||||
File localPublicKeysDir = new File(context.getFilesDir(), PUBLIC_KEYS_DIR_NAME);
|
||||
return new LocalPublicKeyStorage(localPublicKeysDir);
|
||||
}
|
||||
|
||||
private LocalPublicKeyStorage(File localPublicKeysDir) {
|
||||
this.localPublicKeysDir = localPublicKeysDir;
|
||||
}
|
||||
|
||||
private File getPublicKeyFile(long masterKeyId) throws IOException {
|
||||
if (!localPublicKeysDir.exists()) {
|
||||
localPublicKeysDir.mkdir();
|
||||
}
|
||||
if (!localPublicKeysDir.isDirectory()) {
|
||||
throw new IOException("Failed creating public key directory!");
|
||||
}
|
||||
|
||||
String keyFilename = String.format(FORMAT_STR_PUBLIC_KEY, masterKeyId);
|
||||
return new File(localPublicKeysDir, keyFilename);
|
||||
}
|
||||
|
||||
void writePublicKey(long masterKeyId, byte[] encoded) throws IOException {
|
||||
File publicKeyFile = getPublicKeyFile(masterKeyId);
|
||||
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(publicKeyFile);
|
||||
try {
|
||||
fileOutputStream.write(encoded);
|
||||
} finally {
|
||||
Util.closeQuietly(fileOutputStream);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] readPublicKey(long masterKeyId) throws IOException {
|
||||
File publicKeyFile = getPublicKeyFile(masterKeyId);
|
||||
|
||||
try {
|
||||
FileInputStream fileInputStream = new FileInputStream(publicKeyFile);
|
||||
return readIntoByteArray(fileInputStream);
|
||||
} catch (FileNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] readIntoByteArray(FileInputStream fileInputStream) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
byte[] buf = new byte[128];
|
||||
int bytesRead;
|
||||
while ((bytesRead = fileInputStream.read(buf)) != -1) {
|
||||
baos.write(buf, 0, bytesRead);
|
||||
}
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
void deletePublicKey(long masterKeyId) throws IOException {
|
||||
File publicKeyFile = getPublicKeyFile(masterKeyId);
|
||||
if (publicKeyFile.exists()) {
|
||||
boolean deleteSuccess = publicKeyFile.delete();
|
||||
if (!deleteSuccess) {
|
||||
throw new IOException("File exists, but could not be deleted!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.daos;
|
||||
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import okhttp3.internal.Util;
|
||||
|
||||
|
||||
public class LocalSecretKeyStorage {
|
||||
private static final String FORMAT_STR_SECRET_KEY = "0x%016x.sec";
|
||||
private static final String SECRET_KEYS_DIR_NAME = "secret_keys";
|
||||
|
||||
|
||||
private final File localSecretKeysDir;
|
||||
|
||||
|
||||
public static LocalSecretKeyStorage getInstance(Context context) {
|
||||
File localSecretKeysDir = new File(context.getFilesDir(), SECRET_KEYS_DIR_NAME);
|
||||
return new LocalSecretKeyStorage(localSecretKeysDir);
|
||||
}
|
||||
|
||||
private LocalSecretKeyStorage(File localSecretKeysDir) {
|
||||
this.localSecretKeysDir = localSecretKeysDir;
|
||||
}
|
||||
|
||||
private File getSecretKeyFile(long masterKeyId) throws IOException {
|
||||
if (!localSecretKeysDir.exists()) {
|
||||
localSecretKeysDir.mkdir();
|
||||
}
|
||||
if (!localSecretKeysDir.isDirectory()) {
|
||||
throw new IOException("Failed creating public key directory!");
|
||||
}
|
||||
|
||||
String keyFilename = String.format(FORMAT_STR_SECRET_KEY, masterKeyId);
|
||||
return new File(localSecretKeysDir, keyFilename);
|
||||
}
|
||||
|
||||
public void writeSecretKey(long masterKeyId, byte[] encoded) throws IOException {
|
||||
File publicKeyFile = getSecretKeyFile(masterKeyId);
|
||||
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(publicKeyFile);
|
||||
try {
|
||||
fileOutputStream.write(encoded);
|
||||
} finally {
|
||||
Util.closeQuietly(fileOutputStream);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] readSecretKey(long masterKeyId) throws IOException {
|
||||
File publicKeyFile = getSecretKeyFile(masterKeyId);
|
||||
|
||||
try {
|
||||
FileInputStream fileInputStream = new FileInputStream(publicKeyFile);
|
||||
return readIntoByteArray(fileInputStream);
|
||||
} catch (FileNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] readIntoByteArray(FileInputStream fileInputStream) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
byte[] buf = new byte[128];
|
||||
int bytesRead;
|
||||
while ((bytesRead = fileInputStream.read(buf)) != -1) {
|
||||
baos.write(buf, 0, bytesRead);
|
||||
}
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
void deleteSecretKey(long masterKeyId) throws IOException {
|
||||
File publicKeyFile = getSecretKeyFile(masterKeyId);
|
||||
if (publicKeyFile.exists()) {
|
||||
boolean deleteSuccess = publicKeyFile.delete();
|
||||
if (!deleteSuccess) {
|
||||
throw new IOException("File exists, but could not be deleted!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.daos;
|
||||
|
||||
|
||||
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||
import android.arch.persistence.db.SupportSQLiteQuery;
|
||||
import android.arch.persistence.db.SupportSQLiteQueryBuilder;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.OverriddenWarnings;
|
||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||
import org.sufficientlysecure.keychain.KeychainDatabase.Tables;
|
||||
|
||||
|
||||
public class OverriddenWarningsDao {
|
||||
private final Context context;
|
||||
private KeychainDatabase keychainDatabase;
|
||||
|
||||
public static OverriddenWarningsDao createOverriddenWarningsRepository(Context context) {
|
||||
return new OverriddenWarningsDao(context);
|
||||
}
|
||||
|
||||
private OverriddenWarningsDao(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
private KeychainDatabase getDb() {
|
||||
if (keychainDatabase == null) {
|
||||
keychainDatabase = KeychainDatabase.getInstance(context);
|
||||
}
|
||||
return keychainDatabase;
|
||||
}
|
||||
|
||||
public boolean isWarningOverridden(String identifier) {
|
||||
SupportSQLiteDatabase db = getDb().getReadableDatabase();
|
||||
SupportSQLiteQuery query = SupportSQLiteQueryBuilder
|
||||
.builder(Tables.OVERRIDDEN_WARNINGS)
|
||||
.columns(new String[] { "COUNT(*) FROM " })
|
||||
.selection(OverriddenWarnings.IDENTIFIER + " = ?", new String[] { identifier })
|
||||
.create();
|
||||
Cursor cursor = db.query(query);
|
||||
|
||||
try {
|
||||
cursor.moveToFirst();
|
||||
return cursor.getInt(0) > 0;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void putOverride(String identifier) {
|
||||
SupportSQLiteDatabase db = getDb().getWritableDatabase();
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(OverriddenWarnings.IDENTIFIER, identifier);
|
||||
db.insert(Tables.OVERRIDDEN_WARNINGS, SQLiteDatabase.CONFLICT_REPLACE, cv);
|
||||
}
|
||||
|
||||
public void deleteOverride(String identifier) {
|
||||
SupportSQLiteDatabase db = getDb().getWritableDatabase();
|
||||
db.delete(Tables.OVERRIDDEN_WARNINGS, OverriddenWarnings.IDENTIFIER + " = ?", new String[] { identifier });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user