Skip to content
Permalink
Browse files

Favour Secret tokens over String tokens (jenkinsci#60)

* Bump version to 1.5.0

Breaking changes.

* Deprecate String usage in favour of Secret for tokens

* Add compatible since attribute
  • Loading branch information...
mezpahlan committed Apr 30, 2019
1 parent 687963b commit 9b91ae234905ba56303186f912bbcf357ca760fd
@@ -11,12 +11,13 @@
</parent>

<artifactId>hockeyapp</artifactId>
<version>1.4.1-SNAPSHOT</version>
<version>1.5.0-SNAPSHOT</version>
<packaging>hpi</packaging>

<properties>
<jenkins.version>2.73.3</jenkins.version>
<java.level>8</java.level>
<hpi.compatibleSinceVersion>1.5.0</hpi.compatibleSinceVersion>
</properties>

<name>HockeyApp Plugin</name>
@@ -7,6 +7,7 @@
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.util.FormValidation;
import hudson.util.Secret;
import jenkins.model.Jenkins;
import net.hockeyapp.jenkins.RadioButtonSupport;
import net.hockeyapp.jenkins.RadioButtonSupportDescriptor;
@@ -32,8 +33,8 @@
@Deprecated
public long schemaVersion; // TODO: Fix Findbugs gracefully.

public String apiToken;

@Deprecated
public transient String apiToken;
@SuppressFBWarnings(value = {"URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"}, justification = "Breaks binary compatibility if removed.")
@Deprecated
public String appId; // TODO: Fix Findbugs gracefully.
@@ -48,16 +49,25 @@
public OldVersionHolder oldVersionHolder;
public RadioButtonSupport releaseNotesMethod;
public RadioButtonSupport uploadMethod;
private Secret apiTokenSecret;

@DataBoundConstructor
@Deprecated
public HockeyappApplication(String apiToken, String appId, boolean notifyTeam,
String filePath, String dsymPath, String libsPath,
String tags, String teams, boolean mandatory,
boolean downloadAllowed, OldVersionHolder oldVersionHolder,
RadioButtonSupport releaseNotesMethod, RadioButtonSupport uploadMethod) {
this.schemaVersion = SCHEMA_VERSION_NUMBER;
this.apiToken = Util.fixEmptyAndTrim(apiToken);
this.appId = Util.fixEmptyAndTrim(appId);
this(Secret.fromString(apiToken), notifyTeam, filePath, dsymPath, libsPath, tags, teams, mandatory,
downloadAllowed, oldVersionHolder, releaseNotesMethod, uploadMethod);
}

@DataBoundConstructor
public HockeyappApplication(Secret apiTokenSecret, boolean notifyTeam,
String filePath, String dsymPath, String libsPath,
String tags, String teams, boolean mandatory,
boolean downloadAllowed, OldVersionHolder oldVersionHolder,
RadioButtonSupport releaseNotesMethod, RadioButtonSupport uploadMethod) {
this.apiTokenSecret = apiTokenSecret;
this.notifyTeam = notifyTeam;
this.filePath = Util.fixEmptyAndTrim(filePath);
this.dsymPath = Util.fixEmptyAndTrim(dsymPath);
@@ -98,6 +108,23 @@ public String getStrategyOldVersions() {
return new DescriptorImpl();
}

protected Object readResolve() {
if (apiToken != null) {
final Secret secret = Secret.fromString(apiToken);
setApiTokenSecret(secret);
}

return this;
}

public Secret getApiTokenSecret() {
return apiTokenSecret;
}

public void setApiTokenSecret(Secret apiTokenSecret) {
this.apiTokenSecret = apiTokenSecret;
}

public static class OldVersionHolder {
private String numberOldVersions;
// Defaults per https://support.hockeyapp.net/kb/api/api-versions#delete-multiple-versions
@@ -165,9 +192,9 @@ public FormValidation doCheckApiToken(@QueryParameter String value) {
(HockeyappRecorder.DescriptorImpl) activeInstance.getDescriptorOrDie(HockeyappRecorder.class);

if (hockeyappRecorderDescriptor != null) {
String defaultToken = hockeyappRecorderDescriptor.getDefaultToken();
Secret defaultToken = hockeyappRecorderDescriptor.getDefaultTokenSecret();

if (defaultToken != null && defaultToken.length() > 0) {
if (defaultToken != null) {
return FormValidation.warning("Default API Token is used.");
}
}
@@ -25,6 +25,7 @@
import hudson.tasks.Recorder;
import hudson.util.FormValidation;
import hudson.util.RunList;
import hudson.util.Secret;
import jenkins.model.Jenkins;
import jenkins.tasks.SimpleBuildStep;
import net.hockeyapp.jenkins.releaseNotes.FileReleaseNotes;
@@ -180,10 +181,12 @@ public BuildStepMonitor getRequiredMonitorService() {

// Not a getter since build has to know proper value
public String fetchApiToken(HockeyappApplication application) {
if (application.apiToken == null) {
return getDescriptor().getDefaultToken();
final Secret token = application.getApiTokenSecret();

if (token == null) {
return Secret.toString(getDescriptor().getDefaultTokenSecret());
} else {
return application.apiToken;
return Secret.toString(token);
}
}

@@ -751,7 +754,9 @@ public String getBaseUrl() {
// point.
public static final class DescriptorImpl extends
BuildStepDescriptor<Publisher> {
private String defaultToken;
@Deprecated
private transient String defaultToken;
private Secret defaultTokenSecret;
private boolean globalDebugMode = false;
private String timeout;

@@ -760,16 +765,35 @@ public DescriptorImpl() {
load();
}

@Deprecated
public String getDefaultToken() {
return defaultToken;
}

@Deprecated
@SuppressWarnings("unused") // Used by Jenkins
public void setDefaultToken(String defaultToken) {
this.defaultToken = Util.fixEmptyAndTrim(defaultToken);
save();
}

public Object readResolve() {
if (defaultToken != null) {
final Secret secret = Secret.fromString(defaultToken);
setDefaultTokenSecret(secret);
}

return this;
}

public Secret getDefaultTokenSecret() {
return defaultTokenSecret;
}

public void setDefaultTokenSecret(Secret defaultTokenSecret) {
this.defaultTokenSecret = defaultTokenSecret;
}

public boolean getGlobalDebugMode() {
return this.globalDebugMode;

@@ -859,7 +883,6 @@ public FormValidation doCheckDebugMode(@QueryParameter String value) {
return FormValidation.ok();
}
}

}

private static class EnvAction implements EnvironmentContributingAction {
@@ -2,8 +2,9 @@
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler"
xmlns:f="/lib/form">

<f:entry title="${%API Token}" field="apiToken">
<f:textbox checkUrl="'descriptorByName/hockeyapp.HockeyappApplication/checkApiToken?value='+escape(this.value)"/>
<f:entry title="${%API Token}" field="apiTokenSecret">
<f:password
checkUrl="'descriptorByName/hockeyapp.HockeyappApplication/checkApiToken?value='+escape(this.value)"/>
</f:entry>
<f:entry title="${%Upload Method}">
<table width="100%">
@@ -27,7 +28,8 @@
</f:entry>

<f:entry title="${%App File} (${%.ipa, .app.zip, .apk})" field="filePath">
<f:textbox checkUrl="'descriptorByName/hockeyapp.HockeyappApplication/checkFilePath?value='+escape(this.value)"/>
<f:textbox
checkUrl="'descriptorByName/hockeyapp.HockeyappApplication/checkFilePath?value='+escape(this.value)"/>
</f:entry>
<f:entry title="${%Symbols} (${%.dSYM.zip or mapping.txt})" field="dsymPath">
<f:textbox/>
@@ -98,7 +100,8 @@
<f:entry>
<div align="right">
<input type="button" value="${%Add an application}..." class="repeatable-add show-if-last"/>
<input type="button" value="${%Delete}" class="repeatable-delete show-if-not-only" style="margin-left: 1em;"/>
<input type="button" value="${%Delete}" class="repeatable-delete show-if-not-only"
style="margin-left: 1em;"/>
</div>
</f:entry>
</j:jelly>
@@ -2,7 +2,7 @@
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:section title="${%Default HockeyApp Configuration}">
<f:entry title="${%Default API Token}" field="defaultToken">
<f:textbox/>
<f:password/>
</f:entry>
<f:entry title="${%HTTP Client Timeout}" field="timeout">
<f:textbox

0 comments on commit 9b91ae2

Please sign in to comment.
You can’t perform that action at this time.