/*
*
* 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;
import org.apache.log4j.Logger;
import org.panbox.core.pairing.PAKCorePairingHandler.PairingType;
import java.io.File;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Locale;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
public class Settings {
private static final Logger logger = Logger.getLogger("org.panbox");
private static Settings instance = null;
private String language;
private String panboxMountDir;
private String panboxConfDir;
private String deviceName;
private boolean expertMode;
private InetAddress pairingAddress;
private NetworkInterface pairingInterface;
private PairingType pairingType;
private String dropboxAccessToken;
private String dropboxSynchronizationDir;
private boolean uriHandlerSupported;
private boolean mailtoSchemeSupported;
private boolean clipboardHandlerSupported;
/*
* In case protected device key option has been activated the device key
* will also be encrypted with the identity password instead of using a well
* known password - this gives some extra security, but lowers the usability
* since identity password is needed to get entered on each PanBox app
* startup. Default value is false.
*/
// TODO: We need some extra check if old value was false and it has been set
// to true afterwards - Re-encryption of the device key is needed!
private boolean protectedDeviceKey;
private final Preferences prefs;
private final static String PANBOX_DEFAULT_CONF_DIR = System
.getProperty("user.home") + File.separator + ".panbox";
private Settings(Preferences prefs) {
this.prefs = prefs;
language = prefs.get("language", Locale.getDefault().toString());
protectedDeviceKey = Boolean.valueOf(prefs.get("protectedDeviceKey",
"false"));
if(OS.getOperatingSystem().isWindows()) {
panboxMountDir = prefs.get("mountDir", "P:\\");
} else if(OS.getOperatingSystem().isLinux()) {
panboxMountDir = prefs.get("mountDir", System.getProperty("user.home")
+ File.separator + "panbox");
if (!dirExists(panboxMountDir)) {
logger.warn("Panbox mount-directory (" + panboxMountDir
+ ") does not exist. Will create it now!");
new File(panboxMountDir).mkdir();
}
}
panboxConfDir = prefs.get("confDir", "");
if (!dirExists(panboxConfDir)) {
logger.error("Panbox directory for configuration (" + panboxConfDir
+ ") does not exists, reset to default: "
+ PANBOX_DEFAULT_CONF_DIR);
panboxConfDir = PANBOX_DEFAULT_CONF_DIR;
}
// Make sure that config directory exists when accessing PANBOX_CONF_DIR
File pbConf = new File(panboxConfDir);
if (!pbConf.exists()) {
pbConf.mkdir();
prefs.put("confDir", panboxConfDir);
}
String hostname = "panbox-device";
try {
hostname = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
logger.warn("Unable to read default device name! (UnknownHostException)");
} catch (Exception e) {
logger.warn("Unable to read default device name! (RuntimeException)");
}
deviceName = prefs.get("deviceName", hostname);
expertMode = Boolean.valueOf(prefs.get("expertMode", "false"));
dropboxAccessToken = prefs.get("dropboxAccessToken", "");
dropboxSynchronizationDir = prefs.get("dropboxSynchronizationDir", "");
mailtoSchemeSupported = Boolean.valueOf(prefs.get(
"mailtoSchemeSupported", "true"));
uriHandlerSupported = Boolean.valueOf(prefs.get("uriHandlerSupported",
"true"));
clipboardHandlerSupported = Boolean.valueOf(prefs.get(
"clipboardHandlerSupported", "true"));
String pairingAddressStr = prefs.get("pairingAddress", "127.0.0.1");
if (pairingAddressStr.equals("127.0.0.1")) {
setPairingAddressAndInterface();
} else {
try {
pairingAddress = InetAddress.getByName(pairingAddressStr);
pairingInterface = NetworkInterface
.getByInetAddress(pairingAddress);
} catch (UnknownHostException | SocketException e) {
logger.warn("Old network configuration has changed. Will reconfigure it now!");
setPairingAddressAndInterface();
}
}
// Set pairingType at default to SLAVE. We will set it to master when
// pairing has been finished and was MASTER.
pairingType = PairingType.valueOf(prefs.get("pairingType",
PairingType.SLAVE.toString()));
}
/**
* Determines best network connection for pairing
*
* Source:
* http://stackoverflow.com/questions/8462498/how-to-determine-internet
* -network-interface-in-java
*/
private void setPairingAddressAndInterface() {
// iterate over the network interfaces known to java
Enumeration<NetworkInterface> interfaces;
try {
interfaces = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
logger.warn("Could not get list of host interfaces. Pairing might not work!");
return;
}
OUTER: for (NetworkInterface interface_ : Collections.list(interfaces)) {
// we shouldn't care about loopback addresses
try {
if (interface_.isLoopback())
continue;
} catch (SocketException e) {
logger.warn("Problems determining if loopback device. Will ignore it.");
continue;
}
// we should skip interfaces from VirtualBox
if(interface_.toString().contains("VirtualBox")) {
continue;
}
// if you don't expect the interface to be up you can skip this
// though it would question the usability of the rest of the code
try {
if (!interface_.isUp())
continue;
} catch (SocketException e) {
logger.warn("Problems determining if device is up. Will ignore it.");
continue;
}
// iterate over the addresses associated with the interface
Enumeration<InetAddress> addresses = interface_.getInetAddresses();
for (InetAddress address : Collections.list(addresses)) {
// look only for ipv4 addresses
if (address instanceof Inet6Address)
continue;
// use a timeout big enough for your needs
try {
if (!address.isReachable(3000))
continue;
} catch (IOException e) {
logger.warn("Problems determining if loopback device. Will ignore it.");
continue;
}
// java 7's try-with-resources statement, so that
// we close the socket immediately after use
try (SocketChannel socket = SocketChannel.open()) {
// again, use a big enough timeout
socket.socket().setSoTimeout(3000);
//socket.socket().setReuseAddress(true);
socket.socket().setKeepAlive(false);
socket.configureBlocking(false);
// bind the socket to your local interface
socket.bind(new InetSocketAddress(address, 8080));
// try to connect to *somewhere*
socket.connect(new InetSocketAddress("panbox.org", 80));
socket.close();
} catch (IOException ex) {
logger.warn(
"Could not use network address "
+ address.getHostAddress(), ex);
continue;
}
pairingInterface = interface_;
pairingAddress = address;
// stops at the first *working* solution
break OUTER;
}
}
}
private Settings() {
this.prefs = null;
}
public static Settings getInstance() {
if (instance == null) {
Preferences prefs = null;
if (OS.getOperatingSystem().isWindows()) {
prefs = new PreferencesRegistryWrapper();
} else {
prefs = Preferences.userNodeForPackage(Settings.class);
}
instance = new Settings(prefs);
}
return instance;
}
private boolean dirExists(String dir) {
File f = new File(dir);
return (f.exists() && f.isDirectory());
}
public String getLanguage() {
return language;
}
public Locale getLocale() {
if (!language.equals("system_default")) {
String[] split = language.split("_");
return new Locale(split[0], split[1]);
} else {
return Locale.getDefault();
}
}
/* LANGUAGE */
public void setLanguage(String lang) {
language = lang;
prefs.put("language", lang);
}
public String getMountDir() {
return panboxMountDir;
}
/* MOUNT_DIR */
public void setMountDir(String dir) {
// if (dirExists(dir)) {
panboxMountDir = dir;
prefs.put("mountDir", dir);
// } else {
// logger.warn("[setMountDir] Directory '" + dir + "' does not exists");
// }
}
public String getConfDir() {
return panboxConfDir;
}
public void setConfDir(String dir) {
if (dirExists(dir)) {
panboxConfDir = dir;
prefs.put("confDir", dir);
} else {
logger.warn("[setConfDir] Directory '" + dir + "' does not exists");
}
}
public String getKeystorePath() {
return panboxConfDir + File.separator + "keystore.jks";
}
public String getIdentityPath() {
return panboxConfDir + File.separator + "identity.db";
}
public String getAdressbook() {
return panboxConfDir + File.separator + "addressbook.db";
}
public String getSharesDBPath() {
return panboxConfDir + File.separator + "shares.db";
}
public String getDevicesDBPath() {
return panboxConfDir + File.separator + "devices.db";
}
public String getDeviceName() {
return deviceName;
}
/* Device name shall not be changed after creation of the identity */
public void setDeviceName(String panboxDeviceName) {
this.deviceName = panboxDeviceName;
prefs.put("deviceName", panboxDeviceName);
}
public void setExpertMode(boolean panboxExpertMode) {
expertMode = panboxExpertMode;
prefs.put("expertMode", Boolean.toString(panboxExpertMode));
}
public boolean getExpertMode() {
return expertMode;
}
public boolean isUriHandlerSupported() {
return uriHandlerSupported;
}
public void setUriHandlerSupported(boolean uriHandlerSupported) {
this.uriHandlerSupported = uriHandlerSupported;
prefs.put("uriHandlerSupported",
Boolean.toString(this.uriHandlerSupported));
}
public boolean isMailtoSchemeSupported() {
return mailtoSchemeSupported;
}
public void setMailtoSchemeSupported(boolean mailtoSchemeSupported) {
this.mailtoSchemeSupported = mailtoSchemeSupported;
prefs.put("mailtoSchemeSupported",
Boolean.toString(this.mailtoSchemeSupported));
}
public boolean isClipboardHandlerSupported() {
return clipboardHandlerSupported;
}
public void setClipboardHandlerSupported(boolean clipboardHandlerSupported) {
this.clipboardHandlerSupported = clipboardHandlerSupported;
prefs.put("clipboardHandlerSupported",
Boolean.toString(this.clipboardHandlerSupported));
}
public String getDropboxAccessToken() {
return dropboxAccessToken;
}
public void setDropboxAccessToken(String dropboxAccessToken) {
this.dropboxAccessToken = dropboxAccessToken;
prefs.put("dropboxAccessToken", dropboxAccessToken);
}
public String getDropboxSynchronizationDir() {
return dropboxSynchronizationDir;
}
public void setDropboxSynchronizationDir(String dropboxSynchronizationDir) {
this.dropboxSynchronizationDir = dropboxSynchronizationDir;
prefs.put("dropboxSynchronizationDir", dropboxSynchronizationDir);
}
public InetAddress getPairingAddress() {
return pairingAddress;
}
public NetworkInterface getPairingInterface() {
return pairingInterface;
}
public void setPairingAddress(InetAddress pairingAddress) {
this.pairingAddress = pairingAddress;
prefs.put("pairingAddress", pairingAddress.getHostAddress());
}
public void flush() {
try {
prefs.flush();
} catch (BackingStoreException e) {
e.printStackTrace();
}
}
public PairingType getPairingType() {
return pairingType;
}
public void setPairingType(PairingType pairingType) {
this.pairingType = pairingType;
prefs.put("pairingType", pairingType.toString());
}
public boolean isSlave() {
return !isMaster();
}
public boolean isMaster() {
return pairingType == PairingType.MASTER;
}
public boolean isProtectedDeviceKey() {
return protectedDeviceKey;
}
public void setProtectedDeviceKey(boolean protectedDeviceKey) {
this.protectedDeviceKey = protectedDeviceKey;
prefs.put("protectedDeviceKey",
Boolean.toString(this.protectedDeviceKey));
}
}