package com.intellij.lang.javascript.flex.actions.airpackage; import com.intellij.lang.javascript.flex.projectStructure.model.AirSigningOptions; import com.intellij.openapi.project.Project; import com.intellij.util.xmlb.annotations.Transient; import gnu.trove.THashMap; import org.jetbrains.annotations.Nullable; import java.io.FileInputStream; import java.io.IOException; import java.security.*; import java.security.cert.CertificateException; import java.util.Map; public class PasswordStore { public static class SigningOptionsException extends Exception { public final boolean wrongKeystorePassword; public final boolean wrongKeyPassword; public SigningOptionsException(final String message) { this(message, false, false); } public SigningOptionsException(final String message, final boolean wrongKeystorePassword, final boolean wrongKeyPassword) { super(message); this.wrongKeystorePassword = wrongKeystorePassword; this.wrongKeyPassword = wrongKeyPassword; } } @Transient private boolean rememberPasswords = true; /** * key is either keystorePath or keystorePath + "*" + keyAlias */ @Transient private Map<String, String> myStoredPasswords = new THashMap<>(); public static PasswordStore getInstance(final Project project) { return AirPackageProjectParameters.getPasswordStore(project); } public boolean isRememberPasswords() { return rememberPasswords; } public void setRememberPasswords(final boolean rememberPasswords) { this.rememberPasswords = rememberPasswords; } @Nullable public String getKeystorePassword(final String keystorePath) { return myStoredPasswords.get(keystorePath); } @Nullable public String getKeyPassword(final String keystorePath, final String keyAlias) { return myStoredPasswords.get(keystorePath + "*" + keyAlias); } public void clearPasswords() { myStoredPasswords.clear(); } public void storeKeystorePassword(final String keystorePath, final String keystorePassword) { myStoredPasswords.put(keystorePath, keystorePassword); } public void storeKeyPassword(final String keystorePath, final String keyAlias, final String keyPassword) { myStoredPasswords.put(keystorePath + "*" + keyAlias, keyPassword); } public static boolean isPasswordKnown(final Project project, final AirSigningOptions signingOptions) { final PasswordStore passwordStore = getInstance(project); final String keystorePassword = passwordStore.getKeystorePassword(signingOptions.getKeystorePath()); final String keyPassword = signingOptions.getKeyAlias().isEmpty() ? "" : passwordStore.getKeyPassword(signingOptions.getKeystorePath(), signingOptions.getKeyAlias()); if (keystorePassword == null || keyPassword == null) { return false; } try { checkPassword(signingOptions, keystorePassword, keyPassword); } catch (SigningOptionsException e) { return false; } return true; } public static void checkPassword(final AirSigningOptions signingOptions, final String keystorePassword, String keyPassword) throws SigningOptionsException { final KeyStore keyStore; try { keyStore = signingOptions.getProvider().isEmpty() ? KeyStore.getInstance(signingOptions.getKeystoreType()) : KeyStore.getInstance(signingOptions.getKeystoreType(), signingOptions.getProvider()); } catch (KeyStoreException ex) { throw new SigningOptionsException("Keystore type is not available: " + signingOptions.getKeystoreType()); } catch (NoSuchProviderException ex) { throw new SigningOptionsException("Provider is not available: " + signingOptions.getProvider()); } try { try { keyStore.load(new FileInputStream(signingOptions.getKeystorePath()), keystorePassword.toCharArray()); } catch (IOException ex) { throw new SigningOptionsException("Incorrect keystore password", true, false); } catch (CertificateException ex) { throw new SigningOptionsException("Failed to load a certificate"); } String keyAlias = signingOptions.getKeyAlias(); if (keyAlias.isEmpty()) { if (!keyStore.aliases().hasMoreElements()) { throw new SigningOptionsException("Failed to obtain the key."); } keyAlias = keyStore.aliases().nextElement(); } try { if (keyPassword.isEmpty()) keyPassword = keystorePassword; final PrivateKey key = (PrivateKey)keyStore.getKey(keyAlias, keyPassword.toCharArray()); } catch (UnrecoverableKeyException ex) { throw new SigningOptionsException("Incorrect key password", false, true); } } catch (KeyStoreException ex) { throw new RuntimeException("Failed to load keystore"); } catch (NoSuchAlgorithmException ex) { throw new SigningOptionsException("required crypto algorithm not available"); } } }