/* * * Panbox - encryption for cloud storage * Copyright (C) 2014-2015 by Fraunhofer SIT and Sirrix AG * * 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/>. * * Additonally, third party code may be provided with notices and open source * licenses from communities and third parties that govern the use of those * portions, and any licenses granted hereunder do not alter any rights and * obligations you may have under such open source licenses, however, the * disclaimer of warranty and limitation of liability provisions of the GPLv3 * will apply to all the product. * */ package org.panbox.desktop.common.devicemgmt; import org.apache.log4j.Logger; import org.panbox.Settings; import org.panbox.core.devicemgmt.DeviceType; import org.panbox.core.identitymgmt.AbstractIdentity; import org.panbox.desktop.common.gui.devices.PanboxDevice; import org.panbox.desktop.common.identitymgmt.sqlightimpl.IdentityManager; import java.security.KeyPair; import java.security.PublicKey; import java.security.UnrecoverableKeyException; import java.security.cert.X509Certificate; import java.sql.*; import java.util.ArrayList; import java.util.List; public class DeviceManagerImpl implements IDeviceManager { private static final String COL_TYPE = "type"; private static final String COL_NAME = "name"; private static final Logger logger = Logger.getLogger("org.panbox"); private final String DEVICESDB = Settings.getInstance().getDevicesDBPath(); private final String DEVICESDB_CONNECT_STRING = "jdbc:sqlite:" + DEVICESDB; private static final String TABLE_DEVICES = "devices"; private static final String QUERY_DEVICENAME_NO_CASE = "SELECT * FROM " + TABLE_DEVICES + " WHERE LOWER(name)=LOWER(?);"; private static final String QUERY_DEVICENAME = "SELECT * FROM " + TABLE_DEVICES + " WHERE name=?;"; private static final String QUERY_ALL_DEVICES = "SELECT * FROM " + TABLE_DEVICES; private static final String DELETE_DEVICE = "DELETE FROM " + TABLE_DEVICES + " WHERE name=?;"; private static final String INSERT_DEVICE = "insert into " + TABLE_DEVICES + " VALUES (NULL, (?), (?))"; private static final String CREATE_TABLES = "create table " + TABLE_DEVICES + " (id INTEGER PRIMARY KEY AUTOINCREMENT, name string, type string)"; private static final String DROP_TABLES = "drop table if exists " + TABLE_DEVICES; private static final String QUERY_TABLES = "SELECT name FROM sqlite_master WHERE type='table' AND name='" + TABLE_DEVICES + "';"; private final IdentityManager identityManager; // private final AddressbookManager aBookMgr; private AbstractIdentity identity; private static DeviceManagerImpl instance = null; private Connection connection = null; private DeviceManagerImpl() throws DeviceManagerException { // create a database connection try { connection = DriverManager.getConnection(DEVICESDB_CONNECT_STRING); } catch (SQLException ex) { throw new DeviceManagerException( "Could not get connection for SQL DB: " + DEVICESDB_CONNECT_STRING, ex); } identityManager = IdentityManager.getInstance(); try { Statement s = connection.createStatement(); ResultSet rs = s.executeQuery(QUERY_TABLES); if (!rs.next()) { logger.debug("DeviceManager database did not exist. Creating a new one now..."); createTables(s); } else { logger.debug("DeviceManager database exists. Will use that one..."); } } catch (SQLException ex) { throw new DeviceManagerException( "Failed to run SQL command init: ", ex); } } public static DeviceManagerImpl getInstance() throws DeviceManagerException { if (instance == null) { instance = new DeviceManagerImpl(); } return instance; } private void createTables(Statement statement) throws DeviceManagerException { logger.debug("ShareManager : createTables"); try { statement.executeUpdate(DROP_TABLES); statement.executeUpdate(CREATE_TABLES); } catch (SQLException ex) { throw new DeviceManagerException( "Failed to run SQL command during createTables: ", ex); } } @Override public void addThisDevice(String name, KeyPair deviceKeyPair, DeviceType type) throws DeviceManagerException { // 1. Add device key to identity key store identity.addDeviceKey(deviceKeyPair, name); // 2. Add meta data entry to devicelist manager logger.debug("ShareManager : addDevice(" + name + "," + type + ")"); try { addDeviceToDB(name, type); } catch (SQLException ex) { throw new DeviceManagerException("Failed to run addThisDevice: ", ex); } } @Override public void addThisDevice(String name, KeyPair deviceKeyPair, DeviceType type, char[] password) throws DeviceManagerException { // 1. Add device key to identity key store identity.addDeviceKey(deviceKeyPair, name, password); // 2. Add meta data entry to devicelist manager logger.debug("ShareManager : addDevice[protected](" + name + "," + type + ")"); try { addDeviceToDB(name, type); } catch (SQLException ex) { throw new DeviceManagerException("Failed to run addThisDevice[protected]: ", ex); } } private void addDeviceToDB(String name, DeviceType type) throws SQLException { PreparedStatement pStatement = connection .prepareStatement(INSERT_DEVICE); pStatement.setString(1, name); pStatement.setString(2, (type == null ? DeviceType.DESKTOP.toString() : type.toString())); pStatement.execute(); pStatement.close(); } @Override public void addDevice(String name, X509Certificate deviceCert, DeviceType type) throws DeviceManagerException { // 1. Add device key to identity key store identity.addDeviceCert(deviceCert, name); identityManager.storeMyIdentity(identity); // 2. Add meta data entry to devicelist manager logger.debug("ShareManager : addDevice(" + name + "," + type + ")"); try { addDeviceToDB(name, type); } catch (SQLException ex) { throw new DeviceManagerException("Failed to run addDevice: ", ex); } } @Override public void removeDevice(PanboxDevice device) throws DeviceManagerException { logger.debug("ShareManager : removeDevice(" + device.getDeviceName() + ")"); try { PreparedStatement pStmt = connection .prepareStatement(DELETE_DEVICE); pStmt.setQueryTimeout(30); // set timeout to 30 sec. pStmt.setString(1, device.getDeviceName()); pStmt.executeUpdate(); } catch (SQLException ex) { throw new DeviceManagerException( "Failed to run SQL command removeDevice: ", ex); } } @Override public List<PanboxDevice> getDeviceList() throws DeviceManagerException { logger.debug("ShareManager : getDeviceList"); List<PanboxDevice> shares = new ArrayList<PanboxDevice>(); try { Statement statement = connection.createStatement(); statement.setQueryTimeout(30); // set timeout to 30 sec. ResultSet rs = statement.executeQuery(QUERY_ALL_DEVICES); while (rs.next()) { PanboxDevice device = createPanboxDeviceWrapper( rs.getString(COL_NAME), DeviceType.valueOf(rs .getString(COL_TYPE).toUpperCase())); shares.add(device); } } catch (SQLException ex) { throw new DeviceManagerException( "Failed to run getInstalledShares: ", ex); } return shares; } @Override public PanboxDevice getDevice(String name) throws DeviceManagerException { logger.debug("ShareManager : getDevice(" + name + ")"); try { PreparedStatement pStmt = connection .prepareStatement(QUERY_DEVICENAME); pStmt.setQueryTimeout(30); // set timeout to 30 sec. pStmt.setString(1, name); ResultSet rs = pStmt.executeQuery(); if (rs.next()) { PanboxDevice device = createPanboxDeviceWrapper( rs.getString(COL_NAME), DeviceType.valueOf(rs .getString(COL_TYPE).toUpperCase())); pStmt.close(); return device; } pStmt.close(); } catch (SQLException ex) { throw new DeviceManagerException("Failed to run getDevice: ", ex); } throw new DeviceManagerException("No entry found for getDevice(" + name + ")."); } // TODO: This method is just a temporary fix: // The Problem is, that aliases stored in java keystores are not necessarily // case sensitive. This is plattfrom/implementation specific and a known // fact. Therefore we can not expect, that searching a device by an alias // taken from a java keystore will match a case sensitive query. // Obviously this is not a very good solution. We should enforce, for // example lower case when creating devicekeys to circumvent this problem @Override public PanboxDevice getDeviceIgnoreCase(String name) throws DeviceManagerException { logger.debug("ShareManager : getDeviceIgnoreCase(" + name + ")"); try { PreparedStatement pStmt = connection .prepareStatement(QUERY_DEVICENAME_NO_CASE); pStmt.setQueryTimeout(30); // set timeout to 30 sec. pStmt.setString(1, name); ResultSet rs = pStmt.executeQuery(); if (rs.next()) { PanboxDevice device = createPanboxDeviceWrapper( rs.getString(COL_NAME), DeviceType.valueOf(rs .getString(COL_TYPE).toUpperCase())); pStmt.close(); return device; } pStmt.close(); } catch (SQLException ex) { throw new DeviceManagerException("Failed to run getDevice: ", ex); } throw new DeviceManagerException("No entry found for getDevice(" + name + ")."); } private PanboxDevice createPanboxDeviceWrapper(String deviceName, DeviceType deviceType) { PublicKey dpKey; try { dpKey = identity.getPublicKeyForDevice(deviceName); } catch (UnrecoverableKeyException e) { // TODO Auto-generated catch block throw new RuntimeException(e); } return new PanboxDevice(deviceName, deviceType, dpKey); } public void setIdentity(AbstractIdentity id) { this.identity = id; } }