-
Notifications
You must be signed in to change notification settings - Fork 56
Escape user-supplied values when setting build description #146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,12 @@ | ||
package stashpullrequestbuilder.stashpullrequestbuilder; | ||
|
||
import hudson.model.Cause; | ||
import java.net.URI; | ||
import java.net.URISyntaxException; | ||
import java.util.Map; | ||
import java.util.TreeMap; | ||
import org.owasp.esapi.Encoder; | ||
import org.owasp.esapi.reference.DefaultEncoder; | ||
|
||
/** Created by Nathan McCarthy */ | ||
public class StashCause extends Cause { | ||
|
@@ -123,18 +127,38 @@ public Map<String, String> getEnvironmentVariables() { | |
|
||
@Override | ||
public String getShortDescription() { | ||
return "<a href=\"" | ||
+ stashHost | ||
+ "/projects/" | ||
+ this.getDestinationRepositoryOwner() | ||
+ "/repos/" | ||
+ this.getDestinationRepositoryName() | ||
+ "/pull-requests/" | ||
+ this.getPullRequestId() | ||
+ "\" >PR #" | ||
+ this.getPullRequestId() | ||
+ " " | ||
+ this.getPullRequestTitle() | ||
+ " </a>"; | ||
return "<a href='" + getEscapedUrl() + "'>" + getEscapedDescription() + " </a>"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please consider removing space before |
||
} | ||
|
||
String getEscapedUrl() { | ||
return getEncoder().encodeForHTMLAttribute(getPrUrl().toASCIIString()); | ||
} | ||
|
||
String getEscapedDescription() { | ||
return getEncoder() | ||
.encodeForHTML("PR #" + this.getPullRequestId() + " " + this.getPullRequestTitle()); | ||
} | ||
|
||
URI getPrUrl() { | ||
try { | ||
return new URI(stashHost) | ||
.resolve( | ||
new URI( | ||
null, | ||
null, | ||
"/projects/" | ||
+ this.getDestinationRepositoryOwner() | ||
+ "/repos/" | ||
+ this.getDestinationRepositoryName() | ||
+ "/pull-requests/" | ||
+ this.getPullRequestId(), | ||
null)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use |
||
} catch (URISyntaxException e) { | ||
throw new IllegalStateException(e); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sb-contrib detects an issue here: "Unconstrained method stashpullrequestbuilder.stashpullrequestbuilder.StashCause.getPrUrl() converts checked exception to unchecked [stashpullrequestbuilder.stashpullrequestbuilder.StashCause] At StashCause.java:[line 160] EXS_EXCEPTION_SOFTENING_NO_CONSTRAINTS" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hiding the exception was intentional: my rationale was that it's unlikely or impossible to happen given the arguments |
||
} | ||
} | ||
|
||
private static Encoder getEncoder() { | ||
return DefaultEncoder.getInstance(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ESAPI.Encoder=org.owasp.esapi.reference.DefaultEncoder | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The final newline is missing. It would be better to have it. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package stashpullrequestbuilder.stashpullrequestbuilder; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.object.HasToString.hasToString; | ||
import static org.junit.Assert.assertThat; | ||
|
||
import org.junit.Test; | ||
|
||
public class StashCauseTest { | ||
|
||
@Test | ||
public void short_description_doesnt_allow_injection() { | ||
|
||
StashCause stashCause = | ||
new StashCause( | ||
"", | ||
"", | ||
"", | ||
"", | ||
"", | ||
PULL_REQUEST_ID, | ||
OWNER, | ||
DESTINATION_REPOSITORY_NAME, | ||
PULL_REQUEST_TITLE, | ||
"", | ||
"", | ||
"", | ||
"", | ||
null); | ||
|
||
assertThat( | ||
stashCause.getShortDescription(), | ||
is( | ||
"<a href='/projects/owner%3C%3E&'%22/repos/name%3C%3E&'%22/pull-requests/id%3C%3E&'%22'>" | ||
+ "PR #id<>&'" title<>&'" </a>")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A shorter string would be more readable. We are testing that the escaping is done at all. It would be too much to test the underlying quoting algorithm. |
||
} | ||
|
||
@Test | ||
public void will_produce_valid_PR_url() { | ||
|
||
StashCause stashCause = | ||
new StashCause( | ||
"https://stash.host", | ||
"", | ||
"", | ||
"", | ||
"", | ||
PULL_REQUEST_ID, | ||
OWNER, | ||
DESTINATION_REPOSITORY_NAME, | ||
PULL_REQUEST_TITLE, | ||
"", | ||
"", | ||
"", | ||
"", | ||
null); | ||
|
||
assertThat( | ||
stashCause.getPrUrl(), | ||
hasToString( | ||
"https://stash.host/projects/owner%3C%3E&'%22/repos/name%3C%3E&'%22/pull-requests/id%3C%3E&'%22")); | ||
} | ||
|
||
@Test | ||
public void will_escape_PR_url() { | ||
|
||
StashCause stashCause = | ||
new StashCause( | ||
"https://stash.host", | ||
"", | ||
"", | ||
"", | ||
"", | ||
PULL_REQUEST_ID, | ||
OWNER, | ||
DESTINATION_REPOSITORY_NAME, | ||
PULL_REQUEST_TITLE, | ||
"", | ||
"", | ||
"", | ||
"", | ||
null); | ||
|
||
assertThat( | ||
stashCause.getEscapedUrl(), | ||
is( | ||
"https://stash.host/projects/owner%3C%3E&'%22/repos/name%3C%3E&'%22/pull-requests/id%3C%3E&'%22")); | ||
} | ||
|
||
@Test | ||
public void will_escape_PR_description() { | ||
|
||
StashCause stashCause = | ||
new StashCause( | ||
"https://stash.host", | ||
"", | ||
"", | ||
"", | ||
"", | ||
PULL_REQUEST_ID, | ||
OWNER, | ||
DESTINATION_REPOSITORY_NAME, | ||
PULL_REQUEST_TITLE, | ||
"", | ||
"", | ||
"", | ||
"", | ||
null); | ||
|
||
assertThat( | ||
stashCause.getEscapedDescription(), | ||
is("PR #id<>&'" title<>&'"")); | ||
} | ||
|
||
public static final String OWNER = "owner<>&'\""; | ||
public static final String DESTINATION_REPOSITORY_NAME = "name<>&'\""; | ||
public static final String PULL_REQUEST_ID = "id<>&'\""; | ||
public static final String PULL_REQUEST_TITLE = "title<>&'\""; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are using slf4j-api for poll logging. Dependency management should be preferred over exclusion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried that and I don't like the result. Essentially we would promise the code that it would find httpclient 4.5.8 and slf4j 1.7.26 on the server, which is not true. Or we would have to bundle those versions, which would bloat the hpi even more.