IDEA-127343 Pass ModalityState to PasswordSafe.store/removePassword

Since PasswordSafe may request for the master password,
and since this request can be made from any thread, it needs the proper
ModalityState to execute invokeAndWait(), otherwise the master password
dialog won't appear above some modal progresses which requested the
password, just like in IDEA-127343.

getPassword & underlying methods actually showing the dialog were
patched in 1396322, but store- and removePassword may happen before
any getPassword request, so they also must be patched.
This commit is contained in:
Kirill Likhodedov
2014-07-17 16:24:56 +04:00
parent 0143935f68
commit 1a5cf59c9c
5 changed files with 93 additions and 35 deletions
@@ -25,15 +25,21 @@ import org.jetbrains.annotations.Nullable;
* The interface defines basic password management operations
*/
public interface PasswordStorage {
/**
* <p>Get password stored in a password safe.</p>
*
* <p><b>NB: </b>
* This method may be called from the background,
* and it may need to ask user to enter the master password to access the database by calling
* {@link Application#invokeAndWait(Runnable, ModalityState) invokeAndWait()} to show a modal dialog.
* So make sure not to call it from the read action.
* Calling this method from the dispatch thread is allowed.</p>
* @deprecated To remove in IDEA 15. Use {@link #getPassword(Project, Class, String, ModalityState)}
*/
@Deprecated
@Nullable
String getPassword(@Nullable Project project, @NotNull Class requestor, String key) throws PasswordSafeException;
/**
* Get password stored in a password safe.
* <p/>
* The method may be called from any thread. It may need to show a master password dialog to unlock the password database,
* and then will use {@link Application#invokeAndWait(Runnable, ModalityState) invokeAndWait()}.
* So make sure to pass correct {@link ModalityState} to the method to make sure the dialog is shown above all other dialog or progress
* windows.
*
* @param project the project, that is used to ask for the master password if this is the first access to password safe
* @param requestor the requestor class
@@ -41,28 +47,18 @@ public interface PasswordStorage {
* @return the stored password or null if the password record was not found or was removed
* @throws PasswordSafeException if password safe cannot be accessed
* @throws IllegalStateException if the method is called from the read action.
*
* @deprecated To remove in IDEA 15. Use {@link #getPassword(Project, Class, String, ModalityState)}
*/
@Deprecated
@Nullable
String getPassword(@Nullable Project project, @NotNull Class requestor, String key) throws PasswordSafeException;
@Nullable
String getPassword(@Nullable Project project, @NotNull Class requestor, String key,
@Nullable ModalityState state) throws PasswordSafeException;
/**
* Remove password stored in a password safe
*
* @param project the project, that is used to ask for the master password if this is the first access to password safe
* @param requestor the requestor class
* @param key the key for the password
* @return the plugin key
* @throws PasswordSafeException if password safe cannot be accessed
*/
void removePassword(@Nullable Project project, @NotNull Class requestor, String key) throws PasswordSafeException;
/**
* Store password in password safe
* <p/>
* The method may be called from any thread. It may need to show a master password dialog to unlock the password database,
* and then will use {@link Application#invokeAndWait(Runnable, ModalityState) invokeAndWait()}.
* So make sure to pass correct {@link ModalityState} to the method to make sure the dialog is shown above all other dialog or progress
* windows.
*
* @param project the project, that is used to ask for the master password if this is the first access to password safe
* @param requestor the requestor class
@@ -70,5 +66,36 @@ public interface PasswordStorage {
* @param value the value to store
* @throws PasswordSafeException if password safe cannot be accessed
*/
void storePassword(@Nullable Project project, @NotNull Class requestor, String key, String value,
@Nullable ModalityState modalityState) throws PasswordSafeException;
/**
* @deprecated To remove in IDEA 15. Use {@link #storePassword(Project, Class, String, String, ModalityState)}
*/
@Deprecated
void storePassword(@Nullable Project project, @NotNull Class requestor, String key, String value) throws PasswordSafeException;
/**
* @deprecated To remove in IDEA 15. Use {@link #removePassword(Project, Class, String, ModalityState)}
*/
@Deprecated
void removePassword(@Nullable Project project, @NotNull Class requestor, String key) throws PasswordSafeException;
/**
* Remove password stored in a password safe
* <p/>
* The method may be called from any thread. It may need to show a master password dialog to unlock the password database,
* and then will use {@link Application#invokeAndWait(Runnable, ModalityState) invokeAndWait()}.
* So make sure to pass correct {@link ModalityState} to the method to make sure the dialog is shown above all other dialog or progress
* windows.
*
* @param project the project, that is used to ask for the master password if this is the first access to password safe
* @param requestor the requestor class
* @param key the key for the password
* @return the plugin key
* @throws PasswordSafeException if password safe cannot be accessed
*/
void removePassword(@Nullable Project project, @NotNull Class requestor, String key,
@Nullable ModalityState modalityState) throws PasswordSafeException;
}
@@ -71,6 +71,7 @@ public class PasswordSafeImpl extends PasswordSafe {
}
@Nullable
@Override
public String getPassword(@Nullable Project project, @NotNull Class requester, String key) throws PasswordSafeException {
return getPassword(project, requester, key, null);
}
@@ -93,18 +94,32 @@ public class PasswordSafeImpl extends PasswordSafe {
return provider().getPassword(project, requester, key, modalityState);
}
public void removePassword(@Nullable Project project, @NotNull Class requester, String key) throws PasswordSafeException {
@Override
public void removePassword(@Nullable Project project, @NotNull Class requestor, String key) throws PasswordSafeException {
removePassword(project, requestor, key, null);
}
@Override
public void removePassword(@Nullable Project project, @NotNull Class requester, String key,
@Nullable ModalityState modalityState) throws PasswordSafeException {
if (mySettings.getProviderType().equals(PasswordSafeSettings.ProviderType.MASTER_PASSWORD)) {
getMemoryProvider().removePassword(project, requester, key);
}
provider().removePassword(project, requester, key);
provider().removePassword(project, requester, key, modalityState);
}
public void storePassword(@Nullable Project project, @NotNull Class requester, String key, String value) throws PasswordSafeException {
@Override
public void storePassword(@Nullable Project project, @NotNull Class requestor, String key, String value) throws PasswordSafeException {
storePassword(project, requestor, key, value, null);
}
@Override
public void storePassword(@Nullable Project project, @NotNull Class requester, String key, String value,
@Nullable ModalityState modalityState) throws PasswordSafeException {
if (mySettings.getProviderType().equals(PasswordSafeSettings.ProviderType.MASTER_PASSWORD)) {
getMemoryProvider().storePassword(project, requester, key, value);
}
provider().storePassword(project, requester, key, value);
provider().storePassword(project, requester, key, value, modalityState);
}
/**
@@ -45,4 +45,14 @@ public abstract class PasswordSafeProvider implements PasswordStorage {
return getPassword(project, requestor, key, null);
}
@Override
public void storePassword(@Nullable Project project, @NotNull Class requestor, String key, String value) throws PasswordSafeException {
storePassword(project, requestor, key, value, null);
}
@Override
public void removePassword(@Nullable Project project, @NotNull Class requestor, String key) throws PasswordSafeException {
removePassword(project, requestor, key, null);
}
}
@@ -76,8 +76,9 @@ public abstract class BasePasswordSafeProvider extends PasswordSafeProvider {
return EncryptionUtil.dbKey(key(project, requestor, modalityState), requestor, key);
}
public void removePassword(@Nullable Project project, @NotNull Class requester, String key) throws PasswordSafeException {
byte[] k = dbKey(project, requester, key, null);
public void removePassword(@Nullable Project project, @NotNull Class requester, String key,
@Nullable ModalityState modalityState) throws PasswordSafeException {
byte[] k = dbKey(project, requester, key, modalityState);
removeEncryptedPassword(k);
}
@@ -88,9 +89,10 @@ public abstract class BasePasswordSafeProvider extends PasswordSafeProvider {
*/
protected abstract void removeEncryptedPassword(byte[] key);
public void storePassword(@Nullable Project project, @NotNull Class requestor, String key, String value) throws PasswordSafeException {
byte[] k = dbKey(project, requestor, key, null);
byte[] ct = EncryptionUtil.encryptText(key(project, requestor, null), value);
public void storePassword(@Nullable Project project, @NotNull Class requestor, String key, String value,
@Nullable ModalityState modalityState) throws PasswordSafeException {
byte[] k = dbKey(project, requestor, key, modalityState);
byte[] ct = EncryptionUtil.encryptText(key(project, requestor, modalityState), value);
storeEncryptedPassword(k, ct);
}
@@ -49,11 +49,15 @@ public final class NilProvider extends PasswordSafeProvider {
return null;
}
public void removePassword(@Nullable Project project, @NotNull Class requester, String key) throws PasswordSafeException {
@Override
public void removePassword(@Nullable Project project, @NotNull Class requester, String key,
@Nullable ModalityState modalityState) throws PasswordSafeException {
// do nothing
}
public void storePassword(@Nullable Project project, @NotNull Class requester, String key, String value) throws PasswordSafeException {
@Override
public void storePassword(@Nullable Project project, @NotNull Class requester, String key, String value,
@Nullable ModalityState modalityState) throws PasswordSafeException {
// just forget about password
}
}