Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/* Copyright (C) 2011 [Gobierno de Espana]
* This file is part of "Cliente @Firma".
* "Cliente @Firma" 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 2 of the License, or (at your option) any later version.
* - or The European Software License; either version 1.1 or (at your option) any later version.
* You may contact the copyright holder at: [email protected]
*/
package es.gob.afirma.standalone.ui.restoreconfig;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.security.GeneralSecurityException;
import java.security.KeyStoreException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import es.gob.afirma.core.misc.BoundedBufferedReader;
import es.gob.afirma.core.misc.Platform;
import es.gob.afirma.keystores.mozilla.MozillaKeyStoreUtilities;
/**Contiene la lógica para realizar las tareas de restauración
* asociadas al navegador Firefox para Windows, Linux y MacOsX. */
final class RestoreConfigFirefox {
static final class MozillaProfileNotFoundException extends Exception {
/** Versión de serialización. */
private static final long serialVersionUID = 5429606644925911457L;
}
private static final Logger LOGGER = Logger.getLogger("es.gob.afirma"); //$NON-NLS-1$
private static final String SSL_ROOT_CERTIFICATE_FILENAME = "AutoFirma_ROOT.cer"; //$NON-NLS-1$
static final String DIR_CERTUTIL = "certutil"; //$NON-NLS-1$
private static final String LINUX_UNINSTALLSCRIPT_NAME = "uninstallRestore-"; //$NON-NLS-1$
private static final String LINUX_SCRIPT_NAME = "installRestore-"; //$NON-NLS-1$
private static final String LINUX_MOZILLA_PATH = "/.mozilla/firefox/profiles.ini";//$NON-NLS-1$
private static final String LINUX_CHROME_PATH = "/.pki/nssdb";//$NON-NLS-1$
private static final String LINUX_CHROMIUM_PREFS_PATH = "/.config/chromium/Local State";//$NON-NLS-1$
private static final String LINUX_CHROME_PREFS_PATH = "/.config/google-chrome/Local State";//$NON-NLS-1$
private static final String MACOSX_MOZILLA_PATH = "/Library/Application Support/firefox/profiles.ini";//$NON-NLS-1$
private static String WINDOWS_MOZILLA_PATH = "\\AppData\\Roaming\\Mozilla\\Firefox\\profiles.ini"; //$NON-NLS-1$
private static final String GET_USER_SCRIPT = "scriptGetUsers";//$NON-NLS-1$
private static final String SCRIPT_EXT = ".sh";//$NON-NLS-1$
static final String CERTUTIL_EXE;
private static final String FILE_CERTUTIL;
private static final String RESOURCE_BASE;
private static String USERS_WINDOWS_PATH;
static {
try {
USERS_WINDOWS_PATH = new File(System.getProperty("user.home")).getParentFile().getAbsolutePath() + File.separator; //$NON-NLS-1$;
}
catch (final Exception e) {
LOGGER.warning("No se ha podido identificar el directorio de usuarios: " + e); //$NON-NLS-1$
USERS_WINDOWS_PATH = "C:/Users/"; //$NON-NLS-1$
}
}
/** Nombre del usuario por defecto en Windows. Este usuario es el que se usa como base para
* crear nuevos usuarios y no se debería tocar. */
private static String DEFAULT_WINDOWS_USER_NAME = "Default"; //$NON-NLS-1$
static {
switch(Platform.getOS()) {
case WINDOWS:
CERTUTIL_EXE = "certutil.exe"; //$NON-NLS-1$
FILE_CERTUTIL = "certutil.windows.zip"; //$NON-NLS-1$
RESOURCE_BASE = "/windows/"; //$NON-NLS-1$
break;
case MACOSX:
CERTUTIL_EXE = "certutil"; //$NON-NLS-1$
FILE_CERTUTIL = "certutil.osx.zip"; //$NON-NLS-1$
RESOURCE_BASE = "/osx/"; //$NON-NLS-1$
break;
case LINUX:
CERTUTIL_EXE = "certutil"; //$NON-NLS-1$
FILE_CERTUTIL = "certutil.linux.zip"; //$NON-NLS-1$
RESOURCE_BASE = "/linux/"; //$NON-NLS-1$
break;
default:
throw new IllegalStateException(
"Sistema operativo no soportado: " + Platform.getOS() //$NON-NLS-1$
);
}
}
private RestoreConfigFirefox() {
// No instanciable
}
/** Genera el script que elimina el warning al ejecutar AutoFirma desde Chrome para LINUX.
* En linux genera el script que hay que ejecutar para realizar la instalación pero no lo ejecuta, de eso se encarga el instalador Debian.
* @param targetDir Directorio de instalación del sistema
* @param userDir Directorio de usuario dentro del sistema operativo.
* @param browserPath Directorio de configuración de Chromium o Google Chrome.
*
*
En LINUX contiene el contenido del script a ejecutar.
*
*/
private static void createScriptsRemoveExecutionWarningInChrome(final File targetDir, final String userDir, final String browserPath) {
final String[] commandInstall = new String[] {
"sed", //$NON-NLS-1$
"s/\\\"protocol_handler\\\":{\\\"excluded_schemes\\\":{/\\\"protocol_handler\\\":{\\\"excluded_schemes\\\":{\\\"afirma\\\":false,/g", //$NON-NLS-1$
escapePath(userDir + browserPath),
">", //$NON-NLS-1$
escapePath(userDir + browserPath) + "1", //$NON-NLS-1$
};
final String[] commandUninstall = new String[] {
"sed", //$NON-NLS-1$
"s/\\\"afirma\\\":false,//g", //$NON-NLS-1$
escapePath(userDir + browserPath),
">", //$NON-NLS-1$
escapePath(userDir + browserPath) + "1", //$NON-NLS-1$
};
//Se reemplaza el fichero generado por el original
final String[] commandCopy = new String[] {
"\\cp", //$NON-NLS-1$
escapePath(userDir + browserPath) + "1", //$NON-NLS-1$
escapePath(userDir + browserPath),
};
// Generamos el script de instalacion y desistalacion
try {
final StringBuilder sb = new StringBuilder();
for (final String s : commandInstall) {
sb.append(s);
sb.append(' ');
}
final StringBuilder uninstall = new StringBuilder();
for (final String s : commandUninstall) {
uninstall.append(s);
uninstall.append(' ');
}
uninstall.append("\n"); //$NON-NLS-1$
sb.append("\n"); //$NON-NLS-1$
for (final String s : commandCopy) {
sb.append(s);
sb.append(' ');
}
for (final String s : commandCopy) {
uninstall.append(s);
uninstall.append(' ');
}
String path = null;
String uninstallPath = null;
sb.append("\n"); //$NON-NLS-1$
uninstall.append("\n"); //$NON-NLS-1$
// Obtenemos la ruta de los scripts
final Random r = new Random();
path = new File(targetDir, LINUX_SCRIPT_NAME + r.nextInt() + ".sh").getAbsolutePath(); //$NON-NLS-1$
uninstallPath = new File(targetDir, LINUX_UNINSTALLSCRIPT_NAME + r.nextInt() + ".sh").getAbsolutePath(); //$NON-NLS-1$
final File installScript = new File(path);
final File uninstallScript = new File(uninstallPath);
try (
final FileOutputStream fout = new FileOutputStream(installScript, true);
final FileOutputStream foutUninstall = new FileOutputStream(
uninstallScript, true
);
) {
fout.write(sb.toString().getBytes());
foutUninstall.write(uninstall.toString().getBytes());
}
}
catch (final Exception e) {
LOGGER.severe(
"Excepcion en la creacion del script linux para la modificacion del fichero de protocolos de Google Chrome: " + e //$NON-NLS-1$
);
}
}
/** Genera el script que elimina el warning al ejecutar AutoFirma desde Chrome para LINUX.
* En Linux genera el script que hay que ejecutar para realizar la instalación pero no lo ejecuta, de eso se encarga el instalador Debian.
* @param targetDir Directorio de instalación del sistema.
* @param usersDirs Directorio donde estan las carpetas de los usuarios. */
static void removeAppExecutionWarningInChrome(final File targetDir, final List usersDirs) {
for ( final String userDir : usersDirs) {
// Montamos el script de instalacion y desinstalacion que
// incluya el protocolo "afirma" en el fichero Local State
if ( Platform.OS.LINUX.equals(Platform.getOS()) ) {
final File fileChrome = new File(escapePath(userDir) + LINUX_CHROME_PREFS_PATH);
final File fileChromium = new File(escapePath(userDir) + LINUX_CHROMIUM_PREFS_PATH);
if( fileChrome.isFile() ) {
createScriptsRemoveExecutionWarningInChrome(targetDir, userDir, LINUX_CHROME_PREFS_PATH);
}
if ( fileChromium.isFile() ) {
createScriptsRemoveExecutionWarningInChrome(targetDir, userDir, LINUX_CHROMIUM_PREFS_PATH);
}
}
}
}
/** Instala el certificado en el almacén del sistema de Linux (el usado por Chrome).
* @param workingDir Directorio en el que se encuentra el subdirectorio de certutil.
* @param rootCertFile Fichero del certificado raíz a instalar.
* @param usersDirs Listado de directorios de usuario.
* @throws IOException Cuando ocurre un error en el tratamiento de datos. */
static void installRootCAChromeKeyStore(final File workingDir,
final File rootCertFile,
final List usersDirs ) throws IOException {
if ( !Platform.OS.LINUX.equals(Platform.getOS()) ) {
return;
}
final String certUtilPath = getCertUtilPath(workingDir);
for ( final String userDir : usersDirs) {
final File file = new File(escapePath(userDir) + LINUX_CHROME_PATH);
if( file.isDirectory()) {
final String[] certutilCommands = new String[] {
certUtilPath, // 0
"-d", //$NON-NLS-1$ // 1
"sql:" + escapePath(userDir) + LINUX_CHROME_PATH, //$NON-NLS-1$ // 2
"-A", //$NON-NLS-1$ // 3
"-n", //$NON-NLS-1$ // 4
"\"" + RestoreConfigUtil.CERT_ALIAS + "\"", //$NON-NLS-1$ //$NON-NLS-2$ // 5
"-i", //$NON-NLS-1$ // 6
escapePath(rootCertFile.getAbsolutePath()), // 7
"-t", //$NON-NLS-1$ // 8
"\"TCP,TCP,TCP\"" //$NON-NLS-1$ // 9
};
execCommandLineCertUtil(workingDir, certutilCommands, true);
}
}
}
/** Inicia la restauración del certificado para la comunicación entre Firefox y Autofirma en Windows.
* @param targetDir Directorio de la aplicación en el que ya se encuentra el certificado.
* @throws MozillaProfileNotFoundException Si no se encuentra el directorio de perfil de usuario de Mozilla Firefox.
* @throws IOException Cuando hay un error escribiendo o leyendo datos.
* @throws KeyStoreException Cuando ocurre un error durante la importación. */
static void installRootCAMozillaKeyStore(final File targetDir) throws MozillaProfileNotFoundException, IOException, KeyStoreException {
installRootCAMozillaKeyStore(targetDir, null);
}
/** Inicia la restauración del certificado para la comunicación entre Firefox y Autofirma en Windows.
* @param targetDir Directorio de la aplicación.
* @param certFile Fichero con el certificado a instalar.
* @throws MozillaProfileNotFoundException Si no se encuentra el perfil de usuario de Mozilla Firefox.
* @throws IOException Cuando hay errores leyendo o escribiendo datos.
* @throws KeyStoreException Cuando ocurre un error durante la importación. */
static void installRootCAMozillaKeyStore(final File targetDir, final File certFile)
throws MozillaProfileNotFoundException, IOException, KeyStoreException {
final ArrayList firefoxProfilesDir = getFirefoxProfilesDir();
if (firefoxProfilesDir == null || firefoxProfilesDir.isEmpty()) {
throw new MozillaProfileNotFoundException();
}
Set profile = null;
for (final File firefoxDir : firefoxProfilesDir) {
// En Windows recibimos un unico directorio de perfil, lo convertimos a una estructura Set
profile = new HashSet<>(Arrays.asList(firefoxDir.listFiles()));
RestoreConfigFirefox.importCARootOnFirefoxKeyStore(targetDir, certFile, profile);
}
}
/** Genera el script de instalació del certificado en Firefox para MacOSX y LINUX.
* En ambos casos, es necesario crear un script intermedio con el comando certutil y sus argumentos
* y posteriormente ejecutarlo como un comando de consola.
* @param targetDir Directorio de instalación del sistema
* @param certFile Fichero del certificado que debemos instalar.
* @param usersDirs Listado de carpetas de los usuarios.
* @throws MozillaProfileNotFoundException No se ha encontrado el directorio de perfiles de Mozilla.
* @throws KeyStoreException Cuando ocurre un error durante la importación. */
static void installRootCAMozillaKeyStore(final File targetDir,
final File certFile,
final List usersDirs ) throws MozillaProfileNotFoundException,
KeyStoreException {
// dados los usuarios sacamos el directorio de perfiles de mozilla en caso de que lo tengan
final List mozillaUsersProfilesPath = getMozillaUsersProfilesPath(usersDirs);
// para cada usuario tenemos sus distintos directorios de perfiles
final Set profiles = getProfiles(mozillaUsersProfilesPath);
if (profiles.isEmpty()){
throw new MozillaProfileNotFoundException();
}
RestoreConfigFirefox.importCARootOnFirefoxKeyStore(targetDir, certFile, profiles);
}
/**
* Desinstala el certificado de firefox para Windows y Linux.
* @param targetDir Directorio de instalación del sistema
*/
public static void uninstallRootCAMozillaKeyStore(final File targetDir) {
try {
executeCertUtilToDelete(targetDir);
}
catch (final Exception e) {
LOGGER.warning("No se pudo desinstalar el certificado SSL raiz del almacen de Mozilla Firefox: " + e); //$NON-NLS-1$
}
}
/** Genera y ejecuta el script de desinstalación del certificado de Firefox
* para macOS.
* @param targetDir Directorio bajo el que se encuentra certutil.
* @param usersDirs Listado con los directorios de los usuarios del sistema.
* @throws IOException Cuando hay errores leyendo o escribiendo datos. */
static void generateUninstallScriptMac(final File targetDir, final List usersDirs) throws IOException {
final StringBuilder sb = new StringBuilder(RestoreConfigMacOSX.OSX_GET_USERS_COMMAND);
final File scriptFile = File.createTempFile(GET_USER_SCRIPT, SCRIPT_EXT);
try {
RestoreConfigMacOSX.writeScriptFile(scriptFile.getAbsolutePath(), sb, true);
}
catch (final IOException e) {
LOGGER.log(Level.WARNING, " Ha ocurrido un error al generar el script de desinstalacion: " + e, e); //$NON-NLS-1$
}
RestoreConfigMacOSX.addExexPermissionsToFile(scriptFile);
scriptFile.delete();
// dados los usuarios sacamos el directorio de perfiles de mozilla en caso de que lo tengan
final List mozillaUsersProfilesPath = getMozillaUsersProfilesPath(usersDirs);
// Si no se encuentra el fichero de perfiles de firefox, abortamos la operacion
if (mozillaUsersProfilesPath == null) {
LOGGER.info("No se encuentra el fichero de perfiles de Firefox, por lo que no se desinstalaran certificados"); //$NON-NLS-1$
return;
}
// para cada usuario tenemos sus distintos directorios de perfiles
final Set profiles = getProfiles(mozillaUsersProfilesPath);
if (profiles.isEmpty()) {
LOGGER.info("No se han encontrado perfiles de Mozilla de los que desinstalar los certificados"); //$NON-NLS-1$
return;
}
final File certutilFile = new File(getCertUtilPath(targetDir));
if (!certutilFile.exists() || !certutilFile.isFile() || !certutilFile.canExecute()) {
throw new IOException("No se encuentra o no se puede leer el ejecutable para la instalacion en Firefox"); //$NON-NLS-1$
}
for (final File profile : profiles) {
if (!profile.isDirectory()) {
continue;
}
final String scriptUninstall = "max=$(" //$NON-NLS-1$
+ escapePath(certutilFile.getAbsolutePath())
+ " -L -d " //$NON-NLS-1$
+ escapePath(profile.getAbsolutePath())
+ " | grep AutoFirma | wc -l);for ((i=0; i<$max; i++));do " //$NON-NLS-1$
+ escapePath(certutilFile.getAbsolutePath())
+ " -D -d " //$NON-NLS-1$
+ escapePath(profile.getAbsolutePath())
+ " -n \"SocketAutoFirma\";done"; //$NON-NLS-1$
final String[] certutilCommands = scriptUninstall.split(" "); //$NON-NLS-1$
execCommandLineCertUtil(targetDir, certutilCommands, true);
}
}
/** Elimina la carpeta certutil generada durante el proceso de instalación.
* @param targetDir Directorio en el que se copia certUtil. */
static void removeConfigurationFiles(final File targetDir) {
if (!targetDir.exists()) {
return;
}
RestoreConfigFirefox.deleteConfigDir(targetDir);
}
/**
* Cambia los permisos de un fichero para poder ejecutarlo en Linux
* @param f Fichero sobre se cambian los permisos
*/
static void addExexPermissionsToFile(final File f) {
final Set perms = new HashSet<>();
perms.add(PosixFilePermission.OWNER_EXECUTE);
perms.add(PosixFilePermission.GROUP_EXECUTE);
perms.add(PosixFilePermission.OTHERS_EXECUTE);
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.GROUP_READ);
perms.add(PosixFilePermission.OTHERS_READ);
perms.add(PosixFilePermission.OWNER_WRITE);
perms.add(PosixFilePermission.GROUP_WRITE);
perms.add(PosixFilePermission.OTHERS_WRITE);
try {
Files.setPosixFilePermissions(
Paths.get(f.getAbsolutePath()),
perms
);
}
catch (final Exception e) {
LOGGER.warning(
"No se ha podido dar permiso de ejecucion a '" + f.getAbsolutePath() + "': " + e//$NON-NLS-1$ //$NON-NLS-2$
);
}
}
private static String escapePath(final String path) {
if (path == null) {
throw new IllegalArgumentException(
"La ruta a 'escapar' no puede ser nula" //$NON-NLS-1$
);
}
if (Platform.OS.WINDOWS.equals(Platform.getOS())) {
if (path.contains(" ")) { //$NON-NLS-1$
return "\"" + path + "\""; //$NON-NLS-1$ //$NON-NLS-2$
}
return path;
}
return path.replace(" ", "\\ "); //$NON-NLS-1$ //$NON-NLS-2$
}
/** Obtiene el path para la llamada a CertUtil.
* @param workingDir Ruta en la que buscar el ejecutable CertUtil.
* @return Referencia a CertUtil.
* @throws IOException Se lanza cuando hay un problema con el fichero CertUtil. */
public static String getCertUtilPath(final File workingDir) throws IOException {
String certUtilPath = null;
//En linux se trabaja con la dependencia del certutil
if (Platform.OS.LINUX.equals(Platform.getOS())) {
certUtilPath = CERTUTIL_EXE;
}
else {
final File certutilFile = new File(workingDir.getAbsolutePath() + File.separator +
DIR_CERTUTIL + File.separator + CERTUTIL_EXE);
if (!certutilFile.exists() || !certutilFile.isFile()) {
throw new IOException("No se encuentra el ejecutable CertUtil para la instalacion en Firefox"); //$NON-NLS-1$
}
if (!certutilFile.canExecute() && Platform.OS.MACOSX.equals(Platform.getOS())) {
RestoreConfigMacOSX.addExexPermissionsToAllFilesOnDirectory(certutilFile.getParentFile());
}
if (!certutilFile.canExecute()) {
throw new IOException("No hay permisos de ejecucion para Mozilla CertUtil"); //$NON-NLS-1$
}
certUtilPath = certutilFile.getAbsolutePath();
}
return certUtilPath;
}
/** Ejecuta la utilidad Mozilla CertUtil para la instalación del certificado raíz de confianza en Firefox.
* @param workingDir Ruta en la que buscar el ejecutable certutil.
* @param certFile Certificado raíz.
* @param profilesDir Listado de directorios de perfiles de usuario de Mozilla Firefox.
* @throws IOException Cuando ocurre un error en el tratamiento de datos.
* @throws KeyStoreException Cuando ocurre un error en la inserción del certificado en el KeyStore. */
private static void executeCertUtilToImport(final File workingDir,
final File certFile,
final Set profilesDir) throws IOException,
KeyStoreException {
final String certUtilPath = getCertUtilPath(workingDir);
boolean error = false;
if ( Platform.OS.MACOSX.equals(Platform.getOS()) && certUtilPath != null) {
RestoreConfigMacOSX.writeScriptFile(RestoreConfigMacOSX.mac_script_path, new StringBuilder(RestoreConfigMacOSX.EXPORT_PATH).append(certUtilPath.substring(0,certUtilPath.lastIndexOf(File.separator) )), true);
RestoreConfigMacOSX.writeScriptFile(RestoreConfigMacOSX.mac_script_path, new StringBuilder(RestoreConfigMacOSX.EXPORT_LIBRARY_LD).append(certUtilPath.substring(0,certUtilPath.lastIndexOf(File.separator) )), true);
}
File certificateFile = certFile;
if (certificateFile == null) {
certificateFile = new File(workingDir, SSL_ROOT_CERTIFICATE_FILENAME);
}
// Obtenemos todos los directorios de perfil de Firefox del usuario
for (final File profileDir : profilesDir) {
if (!profileDir.isDirectory()) {
continue;
}
final String[] certutilCommands = new String[] {
escapePath(certUtilPath),
"-A", //$NON-NLS-1$
"-d", //$NON-NLS-1$
escapePath(profileDir.getAbsolutePath()),
"-i", //$NON-NLS-1$
escapePath(certificateFile.getAbsolutePath()),
"-n", //$NON-NLS-1$
"\"" + RestoreConfigUtil.CERT_ALIAS + "\"", //$NON-NLS-1$ //$NON-NLS-2$
"-t", //$NON-NLS-1$
"\"C,,\"" //$NON-NLS-1$
};
error = execCommandLineCertUtil(workingDir, certutilCommands, false);
}
if (error) {
throw new KeyStoreException(
"Error en la instalacion del certificado de CA en alguno de los perfiles de usuario " //$NON-NLS-1$
+ "de Firefox. Es posible que la aplicacion funcione en su propio perfil. Si desea que la aplicacion se " //$NON-NLS-1$
+ "ejecute correctamente en todos los perfiles, desinstalela y vuelvala a instalar." //$NON-NLS-1$
);
}
}
/** Prepara los comandos de instalacion con certutil para la instalacion del certificado
* SSL y los ejecuta.
* En MACOSX y Linux, se escribiran scripts intermedios que luego se ejecutaran como comandos.
* En Windows se ejecuta certutil directamente como comando.
* @param workingDir Directorio en el que se encuentra el subdirectorio de certutil.
* @param command Comando a ejecutar, con el nombre de comando y sus parámetros
* separados en un array.
* @param chromeImport Indica si se esta realizando la importacion en el almacen del
* sistema de Linux o en un almacen de Firefox.
* @return true si la ejecución de CertUtil terminó con error,
* false si se ejecutó correctamente.
* @throws IOException Si no se pudo realizar la propia ejecución.
**/
private static boolean execCommandLineCertUtil(final File workingDir, final String[] command, final boolean chromeImport)
throws IOException {
boolean error = false;
final StringBuilder sb = new StringBuilder();
for (final String s : command) {
sb.append(s);
sb.append(' ');
}
if (Platform.OS.MACOSX.equals(Platform.getOS())) {
RestoreConfigMacOSX.writeScriptFile(RestoreConfigMacOSX.mac_script_path, sb, true);
return false;
}
else if (Platform.OS.LINUX.equals(Platform.getOS())) {
// Ejecutamos el comando certutil en Linux
final StringBuilder uninstall = new StringBuilder();
String path = null;
String uninstallPath = null;
if(chromeImport) {
//En Linux tambien se instala para todos los perfiles de
// usuario del almacen de Chrome
// Tenemos en command[7] la ruta del fichero .crt, sacamos de
// ahi la ruta del directorio de instalacion
uninstall.append(command[0] + ' ');
uninstall.append("-D" + ' '); //$NON-NLS-1$
uninstall.append("-d" + ' ');//$NON-NLS-1$
uninstall.append(command[2] + ' ');
uninstall.append("-n" + ' ');//$NON-NLS-1$
uninstall.append(command[5] + ' ');
}
else {
// tenemos en command[5] la ruta del fichero .cer, sacamos de
// ahi la ruta del directorio de instalacion
uninstall.append(command[0] + ' ');
uninstall.append("-D" + ' '); //$NON-NLS-1$
uninstall.append("-d" + ' ');//$NON-NLS-1$
uninstall.append(command[3] + ' ');
uninstall.append("-n" + ' ');//$NON-NLS-1$
uninstall.append(command[7] + ' ');
}
final Random r = new Random();
path = new File(workingDir, LINUX_SCRIPT_NAME + r.nextInt() + ".sh").getAbsolutePath(); //$NON-NLS-1$
uninstallPath = new File(workingDir, LINUX_UNINSTALLSCRIPT_NAME + r.nextInt() + ".sh").getAbsolutePath(); //$NON-NLS-1$
final File installScript = new File(path);
final File uninstallScript = new File(uninstallPath);
try (
final FileOutputStream fout = new FileOutputStream(installScript, true);
final FileOutputStream foutUninstall = new FileOutputStream(
uninstallScript, true
);
) {
fout.write(sb.toString().getBytes());
foutUninstall.write(uninstall.toString().getBytes());
}
catch (final Exception e) {
LOGGER.severe(
"No se han podido generar los script para la instalacion de los certificados: " + e //$NON-NLS-1$
);
return true;
}
addExexPermissionsToFile(uninstallScript);
addExexPermissionsToFile(installScript);
// Primero desinstalamos las posibles versiones previas del certificado
try {
execCommand(new String[] {uninstallPath});
}
catch (final Exception e) {
LOGGER.warning(
"Error en la ejecucion del script para la desinstalacion del certificado del almacen de confianza: " + e); //$NON-NLS-1$
return true;
}
try {
error = execCommand(new String[] {path});
}
catch (final Exception e) {
LOGGER.severe(
"Excepcion en la ejecucion del script para la instalacion del certificado en el almacen de confianza: " + e); //$NON-NLS-1$
return true;
}
if (!uninstallScript.delete()) {
LOGGER.warning("No puedo eliminar el fichero de script: " + uninstallScript.getName()); //$NON-NLS-1$
}
if (!installScript.delete()) {
LOGGER.warning("No puedo eliminar el fichero de script: " + installScript.getName()); //$NON-NLS-1$
}
return error;
}
else {
LOGGER.info("Se ejecutara el siguiente comando:\n" + sb.toString()); //$NON-NLS-1$
final Process process = new ProcessBuilder(command).start();
// Cuando se instala correctamente no hay salida de ningun tipo, asi que se interpreta
// cualquier salida como un error
String line;
try (
final InputStream resIs = process.getInputStream();
final BufferedReader resReader = new BoundedBufferedReader(
new InputStreamReader(resIs),
256, // Maximo 256 lineas de salida
1024 // Maximo 1024 caracteres por linea
);
) {
while ((line = resReader.readLine()) != null) {
LOGGER.severe(line);
return true;
}
}
try (
final InputStream errIs = process.getErrorStream();
final BufferedReader errReader = new BoundedBufferedReader(
new InputStreamReader(errIs),
256, // Maximo 256 lineas de salida
1024 // Maximo 1024 caracteres por linea
);
) {
while ((line = errReader.readLine()) != null) {
LOGGER.severe(line);
return true;
}
}
}
return false;
}
private static void importCARootOnFirefoxKeyStore (final File workingDir,
final File certFile,
final Set profilesDir) throws KeyStoreException {
try {
// Usamos CertUtil para instalar el certificado en Firefox.
executeCertUtilToImport(workingDir, certFile, profilesDir);
} catch (final Exception e) {
LOGGER.warning("No se pudo instalar la CA del certificado SSL para el socket en el almacen de Firefox. Probablemente no se este ejecutando AutoFirma como administrador: " + e //$NON-NLS-1$
);
throw new KeyStoreException("Error al instalar la CA de confianza en el almacen de Firefox", e); //$NON-NLS-1$
}
}
/** Ejecuta la aplicacion Mozilla CertUtil para eliminar el certificado de confianza raíz
* SSL de Firefox.
* @param targetDir Directorio padre en el que se encuentra el directorio de certUtil.
* @throws IOException Cuando no se encuentra o puede leer alguno de los ficheros necesarios.
* @throws GeneralSecurityException Cuando no se puede ejecutar. */
private static void executeCertUtilToDelete(final File targetDir) throws IOException, GeneralSecurityException {
final String certUtilPath = getCertUtilPath(targetDir);
//Se obtienen todos los usuarios para los que se va a desinstalar el certificado en Firefox
final File usersBaseDir = new File(USERS_WINDOWS_PATH);
final String[] userDirNames = usersBaseDir.list((current, name) -> new File(current, name).isDirectory());
//Para Windows XP la ruta de los perfiles de Firefox y de los usuarios es diferente
if(System.getProperty("os.name") != null && System.getProperty("os.name").contains("XP")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
WINDOWS_MOZILLA_PATH = "\\Application Data\\Mozilla\\Firefox\\profiles.ini"; //$NON-NLS-1$
USERS_WINDOWS_PATH = "C:\\Documents and Settings\\"; //$NON-NLS-1$
}
// Obtenemos todos los directorios de perfil de Firefox del usuario
boolean error = false;
for(final String userDirName : userDirNames) {
// Nos saltamos siempre el usuario por defecto del sistema para
// evitar corromperlo
if (DEFAULT_WINDOWS_USER_NAME.equalsIgnoreCase(userDirName)) {
continue;
}
LOGGER.info("Se comprueba la existencia del perfil de Firefox: " + USERS_WINDOWS_PATH + userDirName + WINDOWS_MOZILLA_PATH); //$NON-NLS-1$
if(new File(USERS_WINDOWS_PATH + userDirName + WINDOWS_MOZILLA_PATH).exists()) {
final File profilesDir = new File(
MozillaKeyStoreUtilities.getMozillaUserProfileDirectoryWindows(
USERS_WINDOWS_PATH + userDirName + WINDOWS_MOZILLA_PATH
)
).getParentFile();
for (final File profileDir : profilesDir.listFiles()) {
if (!profileDir.isDirectory()) {
continue;
}
final String[] certutilCommands = new String[] {
"\"" + certUtilPath + "\"", //$NON-NLS-1$ //$NON-NLS-2$
"-D", //$NON-NLS-1$
"-d", //$NON-NLS-1$
"\"" + profileDir.getAbsolutePath() + "\"", //$NON-NLS-1$ //$NON-NLS-2$
"-n", //$NON-NLS-1$
"\"" + RestoreConfigUtil.CERT_ALIAS + "\"", //$NON-NLS-1$ //$NON-NLS-2$
};
final Process process = new ProcessBuilder(certutilCommands).start();
LOGGER.info("Comando certutil ejecutado: " + Arrays.toString(certutilCommands)); //$NON-NLS-1$
// Cuando se instala correctamente no hay salida de ningun tipo, asi que se interpreta
// cualquier salida como un error
String line;
try (
final InputStream resIs = process.getInputStream();
final BufferedReader resReader = new BoundedBufferedReader(
new InputStreamReader(resIs),
256, // Maximo 256 lineas de salida
1024 // Maximo 1024 caracteres por linea
);
) {
while ((line = resReader.readLine()) != null) {
error = true;
LOGGER.severe(line);
}
}
try (
final InputStream errIs = process.getErrorStream();
final BufferedReader errReader = new BoundedBufferedReader(
new InputStreamReader(errIs),
256, // Maximo 256 lineas de salida
1024 // Maximo 1024 caracteres por linea
);
) {
while ((line = errReader.readLine()) != null) {
error = true;
LOGGER.severe(line);
}
}
}
}
}
if (error) {
throw new KeyStoreException("Error en el borrado del certificado de CA en alguno de los perfiles de usuario de Firefox"); //$NON-NLS-1$
}
}
/**
* Elimina los ficheros de configuración de certutil
* @param appConfigDir Directorio de instalación de la aplicación
*/
private static void deleteConfigDir(final File appConfigDir) {
RestoreConfigUtil.deleteDir(new File(appConfigDir, DIR_CERTUTIL));
}
/**
* Descomprime y copia los ficheros de configuración de certutil
* @param workingDir Directorio al que descomprimir las herramientas de configuración
* @throws IOException Cuando ocurre un error al descomprimir o copiar.
*/
static void copyConfigurationFiles(final File workingDir) throws IOException {
final File certutil = new File(workingDir, DIR_CERTUTIL);
if (!certutil.exists()) {
uncompressResource(RESOURCE_BASE + FILE_CERTUTIL, workingDir);
if (Platform.OS.MACOSX.equals(Platform.getOS())) {
RestoreConfigMacOSX.addExexPermissionsToAllFilesOnDirectory(certutil);
}
}
}
/** Descomprime un fichero ZIP de recurso al disco.
* @param resource Ruta del recurso ZIP.
* @param outDir Directorio local en el que descomprimir.
* @throws IOException Cuando ocurre un error al descomprimir.
**/
private static void uncompressResource(final String resource, final File outDir) throws IOException {
int n;
ZipEntry entry;
final byte[] buffer = new byte[1024];
try (final ZipInputStream zipIs = new ZipInputStream(
RestoreConfigFirefox.class.getResourceAsStream(resource));) {
// en linux el funcionamiento es ligeramente diferente
if (Platform.OS.LINUX == Platform.getOS()) {
while ((entry = zipIs.getNextEntry()) != null) {
new File(outDir, "certutil").mkdirs(); //$NON-NLS-1$
try (
final FileOutputStream outFis = new FileOutputStream(
new File(
outDir,
entry.getName()
)
);
) {
while ((n = zipIs.read(buffer)) > 0) {
outFis.write(buffer, 0, n);
}
outFis.flush();
}
zipIs.closeEntry();
}
}
else {
while ((entry = zipIs.getNextEntry()) != null) {
final File outFile = new File(outDir, entry.getName());
if (entry.isDirectory()) {
outFile.mkdirs();
}
else {
if (!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdirs();
}
try (final FileOutputStream outFis = new FileOutputStream(outFile);) {
while ((n = zipIs.read(buffer)) > 0) {
outFis.write(buffer, 0, n);
}
outFis.flush();
}
}
zipIs.closeEntry();
}
}
}
}
/**
* Obtiene los perfiles de usuarios de Firefox en Windows
* @return Array de Files con los perfiles de usuarios de Firefox
*/
private static ArrayList getFirefoxProfilesDir() {
final ArrayList fileList = new ArrayList<>();
//Para Windows XP la ruta de los perfiles de Firefox y de los usuarios es diferente
LOGGER.info("Version de Windows detectada: " + System.getProperty("os.name")); //$NON-NLS-1$ //$NON-NLS-2$
if(System.getProperty("os.name") != null && System.getProperty("os.name").contains("XP")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
WINDOWS_MOZILLA_PATH = "\\Application Data\\Mozilla\\Firefox\\profiles.ini"; //$NON-NLS-1$
USERS_WINDOWS_PATH = "C:\\Documents and Settings\\"; //$NON-NLS-1$
}
// Se obtienen todos los usuarios para los que se va a instalar el
// certificado en Firefox
final File usersBaseDir = new File(USERS_WINDOWS_PATH);
final String[] userDirNames = usersBaseDir.list((current, name) -> new File(current, name).isDirectory());
try {
for(final String userDirName : userDirNames) {
// Nos saltamos siempre el usuario por defecto del sistema para evitar corromperlo
if (DEFAULT_WINDOWS_USER_NAME.equalsIgnoreCase(userDirName)) {
continue;
}
if(new File(USERS_WINDOWS_PATH + userDirName + WINDOWS_MOZILLA_PATH).exists()) {
fileList.add(
new File(
MozillaKeyStoreUtilities.getMozillaUserProfileDirectoryWindows(
USERS_WINDOWS_PATH + userDirName + WINDOWS_MOZILLA_PATH)
).getParentFile());
LOGGER.info("Se usa el perfil de Firefox: " + USERS_WINDOWS_PATH + userDirName + WINDOWS_MOZILLA_PATH); //$NON-NLS-1$
}
}
}
catch (final Exception e) {
LOGGER.warning("No se encontro el directorio de perfiles de Mozilla Firefox: " + e); //$NON-NLS-1$
}
return fileList;
}
/** Devuelve un listado con los directorios donde se encuentra el fichero profiles.ini de firefox en Linux y en OS X.
* @param users Listado de usuarios del sistema.
* @return Listado de directorios donde se encuentra el fichero profiles.ini. */
private static List getMozillaUsersProfilesPath(final List users){
String pathProfile = null;
final List path = new ArrayList<>();
if (Platform.OS.LINUX.equals(Platform.getOS())) {
pathProfile = LINUX_MOZILLA_PATH;
}
else if (Platform.OS.MACOSX.equals(Platform.getOS())) {
pathProfile = MACOSX_MOZILLA_PATH;
}
else {
throw new IllegalArgumentException("Sistema operativo no soportado: " + Platform.getOS()); //$NON-NLS-1$
}
for (final String usr: users){
final File mozillaPath = new File(usr + pathProfile);
// comprobamos que el fichero exista
if (mozillaPath.exists() && mozillaPath.isFile()){
path.add(mozillaPath);
LOGGER.info("Ruta: " + mozillaPath ); //$NON-NLS-1$
}
}
return path;
}
/** Devuelve un listado de directorios donde se encuentran los perfiles de usuario de firefox en Linux.
* @param profilesPath Listado de directorios que contienen un fichero profiles.ini.
* @return Listado de directorios donde se encuentran los perfiles de usuario de Firefox. */
private static Set getProfiles(final List profilesPath){
final String PATH = "Path="; //$NON-NLS-1$
final Set profile = new HashSet<>();
for (final File path: profilesPath){
String line;
try (
final InputStream resIs = new FileInputStream(path);
final BufferedReader resReader = new BoundedBufferedReader(
new InputStreamReader(resIs),
256, // Maximo 256 lineas de salida (256 perfiles por "profiles.ini")
2048 // Maximo 2048 caracteres por linea
);
) {
while ((line = resReader.readLine()) != null) {
if (line.startsWith(PATH)){
final File file = new File(
path.getAbsolutePath().substring(
0, path.getAbsolutePath().lastIndexOf("/") + 1) + line.substring(PATH.length() //$NON-NLS-1$
)
);
if (file.exists() && file.isDirectory()){
profile.add(file);
}
}
}
}
catch (final Exception e) {
LOGGER.severe("Error al buscar los directorios de perfiles de Firefox: " + e); //$NON-NLS-1$
}
}
return profile;
}
/** Ejecuta un comando de consola.
* @param command Nombre del comando y sus argumentos
* @return {@code true} si la ejecución devolvioacute; algún error {@code false} en caso contrario.
* @throws IOException Si hay problemas ejecutando el comando. */
private static boolean execCommand(final String[] command) throws IOException {
LOGGER.info("Se ejecutara el siguiente comando:\n" + Arrays.toString(command)); //$NON-NLS-1$
final Process process = new ProcessBuilder(command).start();
// Cuando se instala correctamente no hay salida de ningun tipo, asi que se interpreta
// cualquier salida como un error
final StringBuffer buffer = new StringBuffer();
try (
final InputStream resIs = process.getInputStream();
final BufferedReader resReader = new BoundedBufferedReader(
new InputStreamReader(resIs),
256, // Maximo 256 lineas de salida
1024 // Maximo 1024 caracteres por linea
);
) {
String line;
while ((line = resReader.readLine()) != null) {
buffer.append(line).append("\n"); //$NON-NLS-1$
}
if (buffer.length() > 0) {
LOGGER.info("Salida estandar:\n" + buffer.toString()); //$NON-NLS-1$
return false;
}
}
buffer.setLength(0);
try (
final InputStream errIs = process.getErrorStream();
final BufferedReader errReader = new BoundedBufferedReader(
new InputStreamReader(errIs),
256, // Maximo 256 lineas de salida
1024 // Maximo 1024 caracteres por linea
);
) {
String line;
while ((line = errReader.readLine()) != null) {
buffer.append(line).append("\n"); //$NON-NLS-1$
}
if (buffer.length() > 0) {
LOGGER.info("Salida de error:\n" + buffer.toString()); //$NON-NLS-1$
return false;
}
}
return false;
}
}