Skip to content
This repository was archived by the owner on Feb 11, 2020. It is now read-only.

Commit 9b91ae2

Browse files
authored
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
1 parent 687963b commit 9b91ae2

File tree

5 files changed

+73
-19
lines changed

5 files changed

+73
-19
lines changed

pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111
</parent>
1212

1313
<artifactId>hockeyapp</artifactId>
14-
<version>1.4.1-SNAPSHOT</version>
14+
<version>1.5.0-SNAPSHOT</version>
1515
<packaging>hpi</packaging>
1616

1717
<properties>
1818
<jenkins.version>2.73.3</jenkins.version>
1919
<java.level>8</java.level>
20+
<hpi.compatibleSinceVersion>1.5.0</hpi.compatibleSinceVersion>
2021
</properties>
2122

2223
<name>HockeyApp Plugin</name>

src/main/java/hockeyapp/HockeyappApplication.java

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import hudson.model.Describable;
88
import hudson.model.Descriptor;
99
import hudson.util.FormValidation;
10+
import hudson.util.Secret;
1011
import jenkins.model.Jenkins;
1112
import net.hockeyapp.jenkins.RadioButtonSupport;
1213
import net.hockeyapp.jenkins.RadioButtonSupportDescriptor;
@@ -32,8 +33,8 @@ public class HockeyappApplication implements Describable<HockeyappApplication> {
3233
@Deprecated
3334
public long schemaVersion; // TODO: Fix Findbugs gracefully.
3435

35-
public String apiToken;
36-
36+
@Deprecated
37+
public transient String apiToken;
3738
@SuppressFBWarnings(value = {"URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"}, justification = "Breaks binary compatibility if removed.")
3839
@Deprecated
3940
public String appId; // TODO: Fix Findbugs gracefully.
@@ -48,16 +49,25 @@ public class HockeyappApplication implements Describable<HockeyappApplication> {
4849
public OldVersionHolder oldVersionHolder;
4950
public RadioButtonSupport releaseNotesMethod;
5051
public RadioButtonSupport uploadMethod;
52+
private Secret apiTokenSecret;
5153

52-
@DataBoundConstructor
54+
@Deprecated
5355
public HockeyappApplication(String apiToken, String appId, boolean notifyTeam,
5456
String filePath, String dsymPath, String libsPath,
5557
String tags, String teams, boolean mandatory,
5658
boolean downloadAllowed, OldVersionHolder oldVersionHolder,
5759
RadioButtonSupport releaseNotesMethod, RadioButtonSupport uploadMethod) {
58-
this.schemaVersion = SCHEMA_VERSION_NUMBER;
59-
this.apiToken = Util.fixEmptyAndTrim(apiToken);
60-
this.appId = Util.fixEmptyAndTrim(appId);
60+
this(Secret.fromString(apiToken), notifyTeam, filePath, dsymPath, libsPath, tags, teams, mandatory,
61+
downloadAllowed, oldVersionHolder, releaseNotesMethod, uploadMethod);
62+
}
63+
64+
@DataBoundConstructor
65+
public HockeyappApplication(Secret apiTokenSecret, boolean notifyTeam,
66+
String filePath, String dsymPath, String libsPath,
67+
String tags, String teams, boolean mandatory,
68+
boolean downloadAllowed, OldVersionHolder oldVersionHolder,
69+
RadioButtonSupport releaseNotesMethod, RadioButtonSupport uploadMethod) {
70+
this.apiTokenSecret = apiTokenSecret;
6171
this.notifyTeam = notifyTeam;
6272
this.filePath = Util.fixEmptyAndTrim(filePath);
6373
this.dsymPath = Util.fixEmptyAndTrim(dsymPath);
@@ -98,6 +108,23 @@ public Descriptor<HockeyappApplication> getDescriptor() {
98108
return new DescriptorImpl();
99109
}
100110

111+
protected Object readResolve() {
112+
if (apiToken != null) {
113+
final Secret secret = Secret.fromString(apiToken);
114+
setApiTokenSecret(secret);
115+
}
116+
117+
return this;
118+
}
119+
120+
public Secret getApiTokenSecret() {
121+
return apiTokenSecret;
122+
}
123+
124+
public void setApiTokenSecret(Secret apiTokenSecret) {
125+
this.apiTokenSecret = apiTokenSecret;
126+
}
127+
101128
public static class OldVersionHolder {
102129
private String numberOldVersions;
103130
// Defaults per https://support.hockeyapp.net/kb/api/api-versions#delete-multiple-versions
@@ -165,9 +192,9 @@ public FormValidation doCheckApiToken(@QueryParameter String value) {
165192
(HockeyappRecorder.DescriptorImpl) activeInstance.getDescriptorOrDie(HockeyappRecorder.class);
166193

167194
if (hockeyappRecorderDescriptor != null) {
168-
String defaultToken = hockeyappRecorderDescriptor.getDefaultToken();
195+
Secret defaultToken = hockeyappRecorderDescriptor.getDefaultTokenSecret();
169196

170-
if (defaultToken != null && defaultToken.length() > 0) {
197+
if (defaultToken != null) {
171198
return FormValidation.warning("Default API Token is used.");
172199
}
173200
}

src/main/java/hockeyapp/HockeyappRecorder.java

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import hudson.tasks.Recorder;
2626
import hudson.util.FormValidation;
2727
import hudson.util.RunList;
28+
import hudson.util.Secret;
2829
import jenkins.model.Jenkins;
2930
import jenkins.tasks.SimpleBuildStep;
3031
import net.hockeyapp.jenkins.releaseNotes.FileReleaseNotes;
@@ -180,10 +181,12 @@ public BuildStepMonitor getRequiredMonitorService() {
180181

181182
// Not a getter since build has to know proper value
182183
public String fetchApiToken(HockeyappApplication application) {
183-
if (application.apiToken == null) {
184-
return getDescriptor().getDefaultToken();
184+
final Secret token = application.getApiTokenSecret();
185+
186+
if (token == null) {
187+
return Secret.toString(getDescriptor().getDefaultTokenSecret());
185188
} else {
186-
return application.apiToken;
189+
return Secret.toString(token);
187190
}
188191
}
189192

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

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

768+
@Deprecated
763769
public String getDefaultToken() {
764770
return defaultToken;
765771
}
766772

773+
@Deprecated
767774
@SuppressWarnings("unused") // Used by Jenkins
768775
public void setDefaultToken(String defaultToken) {
769776
this.defaultToken = Util.fixEmptyAndTrim(defaultToken);
770777
save();
771778
}
772779

780+
public Object readResolve() {
781+
if (defaultToken != null) {
782+
final Secret secret = Secret.fromString(defaultToken);
783+
setDefaultTokenSecret(secret);
784+
}
785+
786+
return this;
787+
}
788+
789+
public Secret getDefaultTokenSecret() {
790+
return defaultTokenSecret;
791+
}
792+
793+
public void setDefaultTokenSecret(Secret defaultTokenSecret) {
794+
this.defaultTokenSecret = defaultTokenSecret;
795+
}
796+
773797
public boolean getGlobalDebugMode() {
774798
return this.globalDebugMode;
775799

@@ -859,7 +883,6 @@ public FormValidation doCheckDebugMode(@QueryParameter String value) {
859883
return FormValidation.ok();
860884
}
861885
}
862-
863886
}
864887

865888
private static class EnvAction implements EnvironmentContributingAction {

src/main/resources/hockeyapp/HockeyappApplication/config.jelly

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler"
33
xmlns:f="/lib/form">
44

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

2930
<f:entry title="${%App File} (${%.ipa, .app.zip, .apk})" field="filePath">
30-
<f:textbox checkUrl="'descriptorByName/hockeyapp.HockeyappApplication/checkFilePath?value='+escape(this.value)"/>
31+
<f:textbox
32+
checkUrl="'descriptorByName/hockeyapp.HockeyappApplication/checkFilePath?value='+escape(this.value)"/>
3133
</f:entry>
3234
<f:entry title="${%Symbols} (${%.dSYM.zip or mapping.txt})" field="dsymPath">
3335
<f:textbox/>
@@ -98,7 +100,8 @@
98100
<f:entry>
99101
<div align="right">
100102
<input type="button" value="${%Add an application}..." class="repeatable-add show-if-last"/>
101-
<input type="button" value="${%Delete}" class="repeatable-delete show-if-not-only" style="margin-left: 1em;"/>
103+
<input type="button" value="${%Delete}" class="repeatable-delete show-if-not-only"
104+
style="margin-left: 1em;"/>
102105
</div>
103106
</f:entry>
104107
</j:jelly>

src/main/resources/hockeyapp/HockeyappRecorder/global.jelly

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
33
<f:section title="${%Default HockeyApp Configuration}">
44
<f:entry title="${%Default API Token}" field="defaultToken">
5-
<f:textbox/>
5+
<f:password/>
66
</f:entry>
77
<f:entry title="${%HTTP Client Timeout}" field="timeout">
88
<f:textbox

0 commit comments

Comments
 (0)