/*
* Copyright 2017 ThoughtWorks, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.thoughtworks.go.config.materials.svn;
import com.thoughtworks.go.config.*;
import com.thoughtworks.go.config.materials.Filter;
import com.thoughtworks.go.config.materials.PasswordAwareMaterial;
import com.thoughtworks.go.config.materials.ScmMaterialConfig;
import com.thoughtworks.go.config.preprocessor.SkipParameterResolution;
import com.thoughtworks.go.domain.ConfigErrors;
import com.thoughtworks.go.security.GoCipher;
import com.thoughtworks.go.util.StringUtil;
import com.thoughtworks.go.util.command.UrlArgument;
import javax.annotation.PostConstruct;
import java.util.Map;
import static com.thoughtworks.go.util.ExceptionUtils.bomb;
import static com.thoughtworks.go.util.ExceptionUtils.bombIfNull;
import static java.lang.String.format;
import static org.apache.commons.lang.StringUtils.isNotEmpty;
@ConfigTag(value = "svn", label = "Subversion")
public class SvnMaterialConfig extends ScmMaterialConfig implements ParamsAttributeAware, PasswordEncrypter, PasswordAwareMaterial {
@ConfigAttribute(value = ScmMaterialConfig.URL)
private UrlArgument url;
@ConfigAttribute(value = ScmMaterialConfig.USERNAME, allowNull = true)
private String userName;
@SkipParameterResolution
@ConfigAttribute(value = "password", allowNull = true)
private String password;
@ConfigAttribute(value = "encryptedPassword", allowNull = true)
private String encryptedPassword;
@ConfigAttribute(value = "checkexternals", allowNull = true, label = "Check externals")
private boolean checkExternals;
public static final String URL = ScmMaterialConfig.URL;
public static final String USERNAME = "userName";
public static final String CHECK_EXTERNALS = "checkExternals";
private final GoCipher goCipher;
public static final String TYPE = "SvnMaterial";
public SvnMaterialConfig() {
this(new GoCipher());
}
private SvnMaterialConfig(GoCipher goCipher) {
super(TYPE);
this.goCipher = goCipher;
}
public SvnMaterialConfig(String url, boolean checkExternals) {
this(url, null, null, checkExternals);
}
public SvnMaterialConfig(String url, String userName, String password, boolean checkExternals) {
this(url, userName, password, checkExternals, new GoCipher());
}
public SvnMaterialConfig(String url, String userName, String password, boolean checkExternals, GoCipher goCipher) {
this(goCipher);
bombIfNull(url, "null url");
this.url = new UrlArgument(url);
this.userName = userName;
setPassword(password);
this.checkExternals = checkExternals;
}
public SvnMaterialConfig(String url, String userName, boolean checkExternals, GoCipher goCipher) {
this(goCipher);
bombIfNull(url, "null url");
this.url = new UrlArgument(url);
this.userName = userName;
this.checkExternals = checkExternals;
}
public SvnMaterialConfig(String url, String userName, String password, boolean checkExternals, String folder) {
this(url, userName, password, checkExternals);
this.folder = folder;
}
public SvnMaterialConfig(UrlArgument url, String userName, String password, boolean checkExternals, GoCipher goCipher, boolean autoUpdate, Filter filter, boolean invertFilter, String folder, CaseInsensitiveString name) {
super(name, filter, invertFilter, folder, autoUpdate, TYPE, new ConfigErrors());
this.url = url;
this.userName = userName;
this.checkExternals = checkExternals;
this.goCipher = goCipher;
this.setPassword(password);
}
//for tests
protected SvnMaterialConfig(UrlArgument url, String password, String encryptedPassword, GoCipher goCipher, Filter filter, boolean invertFilter, String folder) {
super(new CaseInsensitiveString("test"), filter, invertFilter, folder, true, TYPE, new ConfigErrors());
this.url = url;
this.password = password;
this.encryptedPassword = encryptedPassword;
this.goCipher = goCipher;
}
public GoCipher getGoCipher() {
return goCipher;
}
@Override
public void setPassword(String password) {
resetPassword(password);
}
private void resetPassword(String passwordToSet) {
if (StringUtil.isBlank(passwordToSet)) {
encryptedPassword = null;
}
setPasswordIfNotBlank(passwordToSet);
}
private void setPasswordIfNotBlank(String password) {
if (StringUtil.isBlank(password)) {
return;
}
try {
this.encryptedPassword = this.goCipher.encrypt(password);
} catch (Exception e) {
bomb("Password encryption failed. Please verify your cipher key.", e);
}
this.password = null;
}
@Override
public String getUserName() {
return userName;
}
@Override
public String getPassword() {
return currentPassword();
}
@Override
public boolean isCheckExternals() {
return checkExternals;
}
public String currentPassword() {
try {
return StringUtil.isBlank(encryptedPassword) ? null : this.goCipher.decrypt(encryptedPassword);
} catch (Exception e) {
throw new RuntimeException("Could not decrypt the password to get the real password", e);
}
}
@Override
public String getEncryptedPassword() {
return encryptedPassword;
}
public void setEncryptedPassword(String encryptedPassword) {
this.encryptedPassword = encryptedPassword;
}
@PostConstruct
@Override
public void ensureEncrypted() {
setPasswordIfNotBlank(password);
}
@Override
public String getUrl() {
return url != null ? url.forCommandline() : null;
}
@Override
public void setUrl(String url) {
if (url != null) {
this.url = new UrlArgument(url);
}
}
@Override
protected UrlArgument getUrlArgument() {
return url;
}
@Override
public String getLongDescription() {
return String.format("URL: %s, Username: %s, CheckExternals: %s", url.forDisplay(), userName, checkExternals);
}
@Override
protected String getLocation() {
return url == null ? null : url.forDisplay();
}
@Override
public void validateConcreteScmMaterial() {
if (StringUtil.isBlank(url.forDisplay())) {
errors().add(URL, "URL cannot be blank");
}
if (isNotEmpty(this.password) && isNotEmpty(this.encryptedPassword)) {
addError("password", "You may only specify `password` or `encrypted_password`, not both!");
addError("encryptedPassword", "You may only specify `password` or `encrypted_password`, not both!");
}
if (isNotEmpty(this.encryptedPassword)) {
try {
currentPassword();
} catch (Exception e) {
addError("encryptedPassword", format("Encrypted password value for svn material with url '%s' is invalid. This usually happens when the cipher text is modified to have an invalid value.",
this.getUriForDisplay()));
}
}
}
@Override
protected void appendCriteria(Map parameters) {
parameters.put(ScmMaterialConfig.URL, url.forCommandline());
parameters.put(ScmMaterialConfig.USERNAME, userName);
parameters.put("checkExternals", checkExternals);
}
@Override
protected void appendAttributes(Map parameters) {
parameters.put(ScmMaterialConfig.URL, url);
parameters.put(ScmMaterialConfig.USERNAME, userName);
parameters.put("checkExternals", checkExternals);
}
@Override
public String getTypeForDisplay() {
return "Subversion";
}
@Override
public boolean matches(String name, String regex) {
if (!regex.startsWith("/")) {
regex = "/" + regex;
}
return name.matches(regex);
}
public String folderFor(String folderForExternal) {
return getFolder() == null ? folderForExternal : getFolder() + "/" + folderForExternal;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
SvnMaterialConfig that = (SvnMaterialConfig) o;
if (checkExternals != that.checkExternals) {
return false;
}
if (url != null ? !url.equals(that.url) : that.url != null) {
return false;
}
if (userName != null ? !userName.equals(that.userName) : that.userName != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (url != null ? url.hashCode() : 0);
result = 31 * result + (userName != null ? userName.hashCode() : 0);
result = 31 * result + (checkExternals ? 1 : 0);
return result;
}
@Override
public void setConfigAttributes(Object attributes) {
if (attributes == null) {
return;
}
super.setConfigAttributes(attributes);
Map map = (Map) attributes;
if (map.containsKey(URL)) {
this.url = new UrlArgument((String) map.get(URL));
}
if (map.containsKey(USERNAME)) {
this.userName = (String) map.get(USERNAME);
}
if (map.containsKey(PASSWORD_CHANGED) && "1".equals(map.get(PASSWORD_CHANGED))) {
String passwordToSet = (String) map.get(PASSWORD);
resetPassword(passwordToSet);
}
this.checkExternals = "true".equals(map.get(CHECK_EXTERNALS));
}
public void setCheckExternals(boolean checkExternals) {
this.checkExternals = checkExternals;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "SvnMaterialConfig{" +
"url=" + url +
", userName='" + userName + '\'' +
", checkExternals=" + checkExternals +
'}';
}
}