[Mercurial] IDEA-56180: remembering visited URLs, logins and passwords. Also fixed a bug which was preventing cloning (related to IDEA-55930).

This commit is contained in:
Kirill Likhodedov
2010-07-05 16:03:26 +04:00
parent cfcc2b88f9
commit d121fd00df
5 changed files with 122 additions and 12 deletions
+1
View File
@@ -15,6 +15,7 @@
<orderEntry type="module" module-name="testFramework" scope="TEST" />
<orderEntry type="module" module-name="platform-api" />
<orderEntry type="module" module-name="vcs-impl" />
<orderEntry type="module" module-name="platform-impl" />
</component>
</module>
@@ -15,6 +15,12 @@ package org.zmlx.hg4idea;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@State(
name = "hg4idea.settings",
@@ -27,6 +33,32 @@ public class HgGlobalSettings implements PersistentStateComponent<HgGlobalSettin
private String hgExecutable = HG;
// visited URL -> list of logins for this URL. Passwords are remembered in the PasswordSafe.
private Map<String, List<String>> myRememberedUrls = new HashMap<String, List<String>>();
/**
* Returns the rememebered urls which were accessed while working in the plugin.
* @return key is a String representation of a URL, value is the list (probably empty) of logins remembered for this URL.
*/
@NotNull
public Map<String, List<String>> getRememberedUrls() {
return myRememberedUrls;
}
/**
* Adds the information about visited URL.
* @param stringUrl String representation of the URL.
* @param username Login used to access the URL.
*/
public void addRememberedUrl(@NotNull String stringUrl, @NotNull String username) {
List<String> list = myRememberedUrls.get(stringUrl);
if (list == null) {
list = new LinkedList<String>();
myRememberedUrls.put(stringUrl, list);
}
list.add(username);
}
public static String getDefaultExecutable() {
return HG;
}
@@ -341,4 +341,7 @@ public class HgVcs extends AbstractVcs {
return globalSettings.getHgExecutable();
}
public HgGlobalSettings getGlobalSettings() {
return globalSettings;
}
}
@@ -12,22 +12,32 @@
// limitations under the License.
package org.zmlx.hg4idea.command;
import com.intellij.ide.passwordSafe.PasswordSafe;
import com.intellij.ide.passwordSafe.PasswordSafeException;
import com.intellij.idea.LoggerFactory;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcsUtil.VcsUtil;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.HgGlobalSettings;
import org.zmlx.hg4idea.HgVcs;
import org.zmlx.hg4idea.ui.HgUsernamePasswordDialog;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.*;
/**
* Base class for any command interacting with a remote repository and which needs authentication.
*/
class HgCommandAuthenticator {
private static final Logger LOG = Logger.getInstance(HgCommandAuthenticator.class.getName());
@Nullable
protected HgCommandResult executeCommandAndAuthenticateIfNecessary(Project project, VirtualFile localRepository, String remoteRepository, String command, List<String> arguments) {
HgCommandService service = HgCommandService.getInstance(project);
@@ -47,8 +57,20 @@ class HgCommandAuthenticator {
hgUrl.setUsername( runnable.getUserName() );
hgUrl.setPassword(String.valueOf( runnable.getPassword() ));
arguments.set(arguments.size() - 1, hgUrl.asString());
arguments.set(0, hgUrl.asString());
result = service.execute(localRepository, command, arguments);
if (result != null && result.getExitValue() == 0) {
final String key = keyForUrlAndLogin(runnable.getURL(), runnable.getUserName());
try {
PasswordSafe.getInstance().storePassword(project, HgCommandAuthenticator.class, key, runnable.getPassword());
HgVcs.getInstance(project).getGlobalSettings().addRememberedUrl(runnable.getURL(), runnable.getUserName());
}
catch (PasswordSafeException e) {
LOG.error("Couldn't store the password for key [" + key + "]", e);
}
}
}
}
} catch (URISyntaxException e) {
@@ -62,9 +84,11 @@ class HgCommandAuthenticator {
private final HgUrl hgUrl;
private String userName;
private char[] password;
private String myPassword;
private Project project;
private boolean ok = false;
private static final Logger LOG = Logger.getInstance(GetPasswordRunnable.class.getName());
private String myURL;
public GetPasswordRunnable(Project project, HgUrl hgUrl) {
this.hgUrl = hgUrl;
@@ -72,13 +96,50 @@ class HgCommandAuthenticator {
}
public void run() {
final HgUsernamePasswordDialog dialog = new HgUsernamePasswordDialog(project, hgUrl.getUsername());
dialog.show();
// get the string representation of the url
@Nullable String stringUrl = null;
try {
stringUrl = hgUrl.asString();
}
catch (URISyntaxException e) {
LOG.warn("Couldn't parse hgUrl: [" + hgUrl + "]", e);
}
// find if we've already been here
final HgGlobalSettings hgGlobalSettings = HgVcs.getInstance(project).getGlobalSettings();
final Map<String, List<String>> urls = hgGlobalSettings.getRememberedUrls();
@Nullable List<String> rememberedLoginsForUrl = urls.get(stringUrl);
String login = hgUrl.getUsername();
if (StringUtils.isBlank(login)) {
// find the last used login
if (rememberedLoginsForUrl != null && !rememberedLoginsForUrl.isEmpty()) {
login = rememberedLoginsForUrl.get(0);
}
}
String password = hgUrl.getPassword();
if (StringUtils.isBlank(password) && stringUrl != null) {
// if we've logged in with this login, search for password
final String key = keyForUrlAndLogin(stringUrl, login);
try {
password = PasswordSafe.getInstance().getPassword(project, HgCommandAuthenticator.class, key);
} catch (PasswordSafeException e) {
LOG.error("Couldn't get password for key [" + key + "]", e);
}
}
final HgUsernamePasswordDialog dialog = new HgUsernamePasswordDialog(project, login, password);
dialog.show();
if (dialog.isOK()) {
userName = dialog.getUsername();
password = dialog.getPassword();
myPassword = dialog.getPassword();
ok = true;
if (dialog.isRememberPassword() && stringUrl != null) {
myURL = stringUrl;
}
}
}
@@ -86,13 +147,21 @@ class HgCommandAuthenticator {
return userName;
}
public char[] getPassword() {
return password.clone();
public String getPassword() {
return myPassword;
}
public boolean isOk() {
return ok;
}
public String getURL() {
return myURL;
}
}
private static String keyForUrlAndLogin(String stringUrl, String login) {
return stringUrl + login;
}
}
@@ -15,6 +15,7 @@ package org.zmlx.hg4idea.ui;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.util.net.AuthenticationPanel;
import org.apache.commons.lang.StringUtils;
import org.zmlx.hg4idea.HgVcsMessages;
import javax.swing.*;
@@ -22,10 +23,10 @@ import javax.swing.*;
public class HgUsernamePasswordDialog extends DialogWrapper {
private AuthenticationPanel authPanel;
public HgUsernamePasswordDialog(Project project, String login) {
public HgUsernamePasswordDialog(Project project, String login, String password) {
super(project, false);
setTitle(HgVcsMessages.message("hgidea.dialog.login.password.required"));
authPanel = new AuthenticationPanel(null, login, "", false);
authPanel = new AuthenticationPanel(null, login, password, !StringUtils.isBlank(password));
init();
}
@@ -42,8 +43,12 @@ public class HgUsernamePasswordDialog extends DialogWrapper {
return authPanel.getLogin();
}
public char[] getPassword() {
return authPanel.getPassword().toCharArray();
public String getPassword() {
return authPanel.getPassword();
}
public boolean isRememberPassword() {
return authPanel.isRememberPassword();
}
}