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",
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;
}
// 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);
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) {
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;
}
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;
+ }
}
}
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;
}
}
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.*;
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();
}
return authPanel.getLogin();
}
- public char[] getPassword() {
- return authPanel.getPassword().toCharArray();
+ public String getPassword() {
+ return authPanel.getPassword();
}
+ public boolean isRememberPassword() {
+ return authPanel.isRememberPassword();
+ }
+
}
\ No newline at end of file