/*
* Copyright (C) 2005-2012 NAUMEN. All rights reserved.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation and appearing in the file LICENSE.GPL included in the
* packaging of this file.
*
*/
package ru.naumen.servacc.ui;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import org.eclipse.swt.widgets.Shell;
import ru.naumen.servacc.FileResource;
import ru.naumen.servacc.HTTPResource;
import ru.naumen.servacc.MessageListener;
import ru.naumen.servacc.activechannel.ActiveChannelsRegistry;
import ru.naumen.servacc.config2.ActiveChannelsConfig;
import ru.naumen.servacc.config2.CompositeConfig;
import ru.naumen.servacc.config2.Config;
import ru.naumen.servacc.config2.i.IConfig;
import ru.naumen.servacc.exception.ServerAccessException;
import ru.naumen.servacc.settings.ListProvider;
import ru.naumen.servacc.util.StringEncrypter;
import ru.naumen.servacc.util.StringEncrypter.EncryptionException;
import ru.naumen.servacc.util.Util;
public class ConfigLoader
{
private Map<String, String[]> authCache = new HashMap<>();
private final Shell shell;
private final ListProvider sourceListProvider;
private final MessageListener listener;
private final ActiveChannelsRegistry acRegistry;
public ConfigLoader(Shell shell, ListProvider sourceListProvider, MessageListener listener, ActiveChannelsRegistry acRegistry)
{
this.shell = shell;
this.sourceListProvider = sourceListProvider;
this.listener = listener;
this.acRegistry = acRegistry;
}
public IConfig loadConfig()
{
CompositeConfig compositeConfig = new CompositeConfig();
Collection<String> sources = sourceListProvider.list();
for (String source : sources)
{
try
{
IConfig config = loadConfig(source);
if (config != null)
{
compositeConfig.add(config);
}
}
catch (Exception e)
{
listener.notify(e.getLocalizedMessage());
}
}
compositeConfig.add(new ActiveChannelsConfig(acRegistry));
return compositeConfig;
}
private IConfig loadConfig(String source) throws Exception
{
if (source.startsWith("http://") || source.startsWith("https://"))
{
return loadConfigViaHTTP(source);
}
else if (source.startsWith(FileResource.URI_PREFIX))
{
return loadConfigFromFile(source);
}
else
{
throw new ServerAccessException("Unknown source type: " + source);
}
}
private IConfig loadConfigViaHTTP(String url) throws Exception
{
HTTPResource resource = new HTTPResource(url);
String[] auth = authCache.get(url);
if (auth != null && auth.length == 2)
{
resource.setAuthentication(auth[0], auth[1]);
}
while (true)
{
try
{
return new Config(resource.getInputStream());
}
catch (HTTPResource.NotAuthenticatedError e)
{
AuthenticationDialog dialog = new AuthenticationDialog(shell);
dialog.setURL(url);
if (dialog.show())
{
String login = dialog.getLogin();
String password = dialog.getPassword();
resource.setAuthentication(login, password);
authCache.put(url, new String[]{ login, password });
}
else
{
return null;
}
}
finally
{
resource.close();
}
}
}
private IConfig loadConfigFromFile(String source) throws Exception
{
InputStream stream = getConfigStream(source);
try
{
return stream == null ? null : new Config(stream);
}
catch (Exception e)
{
stream.close();
throw e;
}
}
private InputStream getConfigStream(String source) throws IOException
{
String password = null;
String[] auth = authCache.get(source);
if (auth != null && auth.length == 2)
{
password = auth[1];
}
while (true)
{
try
{
return FileResource.getConfigStream(source, password);
}
catch (EncryptionException e)
{
AuthenticationDialog dialog = new AuthenticationDialog(shell, true);
dialog.setURL(source);
if (dialog.show())
{
password = dialog.getPassword();
authCache.put(source, new String[]{ null, password });
}
else
{
return null;
}
}
}
}
public void encryptLocalAccounts()
{
try
{
Collection<String> configSources = sourceListProvider.list();
int encryptableFiles = 0;
for (String configURL : configSources)
{
if (!configURL.startsWith(FileResource.URI_PREFIX) || FileResource.isConfigEncrypted(configURL))
{
continue;
}
encryptableFiles++;
String password = askForPassword(configURL);
if (Util.isEmptyOrNull(password))
{
continue;
}
String content = new Scanner(getConfigStream(configURL)).useDelimiter("\\A").next();
byte[] encryptedContent = new StringEncrypter("DESede", password).encrypt(content).getBytes();
try(OutputStream os = new FileOutputStream(configURL.substring(FileResource.URI_PREFIX.length()))) {
os.write(FileResource.ENCRYPTED_HEADER);
os.write(System.getProperty("line.separator").getBytes());
os.write(encryptedContent);
}
}
if (encryptableFiles < 1)
{
listener.notify("All accounts are already encrypted");
}
}
catch (Exception e)
{
listener.notify(e.getMessage());
}
}
private String askForPassword(String configURL)
{
EncryptDialog dialog = new EncryptDialog(shell);
dialog.setURL(configURL);
dialog.show();
return dialog.getPassword();
}
public void decryptLocalAccounts()
{
try
{
Collection<String> configSources = sourceListProvider.list();
int decryptableFiles = 0;
for (String configURL : configSources)
{
String filePath = configURL.substring(FileResource.URI_PREFIX.length());
if (!configURL.startsWith(FileResource.URI_PREFIX) || !FileResource.isConfigEncrypted(configURL))
{
continue;
}
decryptableFiles++;
InputStream stream = getConfigStream(configURL);
if (stream == null)
{
continue;
}
String content = new Scanner(stream).useDelimiter("\\A").next();
stream.close();
try(FileOutputStream os = new FileOutputStream(filePath)) {
os.write(content.getBytes());
}
}
if (decryptableFiles < 1)
{
listener.notify("All accounts are already decrypted");
}
}
catch (IOException e)
{
listener.notify(e.getMessage());
}
}
}