/******************************************************************************* * Copyright (C) 2015 Connor Lanigan (email: dev@connorlanigan.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package de.norvos.axolotl.stores; import static de.norvos.i18n.Translations.translate; import java.io.IOException; import java.sql.SQLException; import java.util.List; import java.util.Random; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.libaxolotl.InvalidKeyIdException; import org.whispersystems.libaxolotl.state.PreKeyRecord; import org.whispersystems.libaxolotl.util.KeyHelper; import org.whispersystems.libaxolotl.util.Medium; import de.norvos.persistence.tables.AccountDataTable; import de.norvos.persistence.tables.PreKeyTable; import de.norvos.utils.Errors; import de.norvos.utils.UnreachableCodeException; /** * Contains the prekey-related data for the TextSecure protocol. * * @author Connor Lanigan */ public class PreKeyStore implements org.whispersystems.libaxolotl.state.PreKeyStore { private static PreKeyStore instance; final static Logger LOGGER = LoggerFactory.getLogger(PreKeyStore.class); synchronized public static PreKeyStore getInstance() { if (instance == null) { instance = new PreKeyStore(); } return instance; } private PreKeyStore() { } @Override public boolean containsPreKey(final int preKeyId) { try { return PreKeyTable.getInstance().getKey(preKeyId) != null; } catch (final SQLException e) { LOGGER.error("PreKey could not be fetched from database.", e); Errors.showError(translate("unexpected_quit")); Errors.stopApplication(); throw new UnreachableCodeException(); } } public int getLastIndex() { return PreKeyTable.getInstance().getLastIndex(); } public PreKeyRecord getLastResortKey() { try { final byte[] record = AccountDataTable.getInstance().getBinary("lastResortKey"); if (record == null) { return null; } return new PreKeyRecord(record); } catch (IOException | SQLException e) { LOGGER.error("Last Resort key could not be fetched from database.", e); Errors.showError(translate("unexpected_quit")); Errors.stopApplication(); throw new UnreachableCodeException(); } } public List<PreKeyRecord> initialize() { final int numberOfKeys = 100; final int startingId = (new Random()).nextInt(Medium.MAX_VALUE - numberOfKeys); storeLastResortKey(KeyHelper.generateLastResortPreKey()); final List<PreKeyRecord> list = KeyHelper.generatePreKeys(startingId, numberOfKeys); for (final PreKeyRecord key : list) { storePreKey(key.getId(), key); } return list; } @Override public PreKeyRecord loadPreKey(final int preKeyId) throws InvalidKeyIdException { try { final PreKeyRecord record = PreKeyTable.getInstance().getKey(preKeyId); if (record == null) { throw new InvalidKeyIdException("Key id " + preKeyId + " has no associated PreKeyRecord."); } return PreKeyTable.getInstance().getKey(preKeyId); } catch (final SQLException e) { LOGGER.error("PreKey could not be fetched from database.", e); Errors.showError(translate("unexpected_quit")); Errors.stopApplication(); throw new UnreachableCodeException(); } } @Override public void removePreKey(final int preKeyId) { try { PreKeyTable.getInstance().deleteKey(preKeyId); } catch (final SQLException e) { LOGGER.error("PreKey could not be removed from database.", e); Errors.showError(translate("unexpected_quit")); Errors.stopApplication(); throw new UnreachableCodeException(); } } @SuppressWarnings("static-method") private void storeLastResortKey(final PreKeyRecord record) { try { AccountDataTable.getInstance().storeBinary("lastResortKey", record.serialize()); } catch (final SQLException e) { LOGGER.error("Last Resort Key could not be stored to database.", e); Errors.showError(translate("unexpected_quit")); Errors.stopApplication(); throw new UnreachableCodeException(); } } @Override public void storePreKey(final int preKeyId, final PreKeyRecord record) { try { PreKeyTable.getInstance().storeKey(preKeyId, record); } catch (final SQLException e) { LOGGER.error("PreKey could not be stored to database.", e); Errors.showError(translate("unexpected_quit")); Errors.stopApplication(); throw new UnreachableCodeException(); } } }