Cleaned up code, sanitized inputs

This commit is contained in:
Steven Tracey 2022-11-17 23:21:26 -05:00
parent b3b0f564be
commit 7cd5621171
5 changed files with 180 additions and 181 deletions

View File

@ -4,7 +4,7 @@ plugins {
}
group 'tech.nevets'
version '0.1.0'
version '1.0.0'
repositories {
mavenCentral()
@ -15,10 +15,10 @@ repositories {
}
dependencies {
implementation 'org.jetbrains:annotations-java5:23.0.0'
implementation 'com.sparkjava:spark-core:2.9.4'
implementation 'org.slf4j:slf4j-simple:2.0.3'
implementation 'com.google.code.gson:gson:2.10'
implementation 'org.jsoup:jsoup:1.15.3'
implementation 'org.apache.xmlgraphics:batik-svggen:1.16'
implementation 'org.apache.batik:org.apache.batik.dom:1.6.0-20081006'
}

View File

@ -1,12 +0,0 @@
package tech.nevets.codebadgerestapi;
public enum BadgeColor {
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
PURPLE,
LIGHTGRAY,
GRAY
}

View File

@ -5,22 +5,22 @@ import com.google.gson.JsonObject;
import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.batik.svggen.SVGGraphics2DIOException;
import org.slf4j.LoggerFactory;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;
import java.util.Map;
public class BadgeFactory {
public static byte[] genSVGBadge(String leftStr, String rightStr, Color secondaryColor) {
public static byte[] genSVGBadge(String leftStr, String rightStr, Color secondaryColor, boolean isRounded) {
DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
Document doc = domImpl.createDocument("http://www.w3.org/2000/svg", "svg", null);
SVGGraphics2D graphics2D = new SVGGraphics2D(doc);
@ -30,12 +30,23 @@ public class BadgeFactory {
FontMetrics fm = graphics2D.getFontMetrics();
int lWidth = fm.stringWidth(leftStr);
int rWidth = fm.stringWidth(rightStr);
int totalWidth = lWidth = lWidth + rWidth + 40;
int totalWidth = lWidth + rWidth + 40;
int totalHeight = 20;
graphics2D.setSVGCanvasSize(new Dimension(totalWidth, totalHeight));
graphics2D.setPaint(Color.GRAY);
graphics2D.fillRect(0, 0, totalWidth, totalHeight);
if (isRounded) {
graphics2D.fillRoundRect(0, 0, totalWidth, totalHeight, 10, 10);
} else {
graphics2D.fillRect(0, 0, totalWidth, totalHeight);
}
graphics2D.setPaint(secondaryColor);
graphics2D.fillRect(totalWidth - rWidth - 20, 0, rWidth + 20, totalHeight);
if (isRounded) {
graphics2D.fillRoundRect(totalWidth - rWidth - 20, 0, rWidth + 20, totalHeight, 10, 10);
} else {
graphics2D.fillRect(totalWidth - rWidth - 20, 0, rWidth + 20, totalHeight);
}
graphics2D.setPaint(Color.GRAY);
graphics2D.drawString(leftStr, 10, (totalHeight / 2) + 6);
graphics2D.drawString(rightStr, totalWidth - rWidth - 10, (totalHeight / 2) + 6);
@ -54,129 +65,88 @@ public class BadgeFactory {
return baos.toByteArray();
}
public static byte[] generateBadge(String leftStr, String rightStr, BadgeColor secondaryColor) {
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics2D = img.createGraphics();
Font font = new Font("Calibri", Font.PLAIN, 23);
graphics2D.setFont(font);
FontMetrics fontMetrics = graphics2D.getFontMetrics();
int lWidth = fontMetrics.stringWidth(leftStr);
int rWidth = fontMetrics.stringWidth(rightStr);
int height = fontMetrics.getHeight();
graphics2D.dispose();
int totalWidth = lWidth + rWidth + 20;
int totalHeight = 25;
int textY = 19;
BufferedImage baseBadgeImg;
BufferedImage secondaryImg;
try {
baseBadgeImg = ImageIO.read(BadgeFactory.class.getResourceAsStream("/badge-base-gray.png"));
switch (secondaryColor) {
case RED -> secondaryImg = ImageIO.read(BadgeFactory.class.getResourceAsStream("/badge-color-red.png"));
case ORANGE -> secondaryImg = ImageIO.read(BadgeFactory.class.getResourceAsStream("/badge-color-orange.png"));
case YELLOW -> secondaryImg = ImageIO.read(BadgeFactory.class.getResourceAsStream("/badge-color-yellow.png"));
case GREEN -> secondaryImg = ImageIO.read(BadgeFactory.class.getResourceAsStream("/badge-color-green.png"));
case BLUE -> secondaryImg = ImageIO.read(BadgeFactory.class.getResourceAsStream("/badge-color-blue.png"));
case PURPLE -> secondaryImg = ImageIO.read(BadgeFactory.class.getResourceAsStream("/badge-color-purple.png"));
case LIGHTGRAY -> secondaryImg = ImageIO.read(BadgeFactory.class.getResourceAsStream("/badge-color-light-gray.png"));
default -> secondaryImg = ImageIO.read(BadgeFactory.class.getResourceAsStream("/badge-base-gray.png"));
public static String getVersionFromGitBranch(String gitUrl, String org, String repo, String branch) {
String versionSourcesUrlBase;
if (org == null && repo == null) {
if (gitUrl.endsWith(".git")) {
versionSourcesUrlBase = gitUrl.substring(0, gitUrl.length() - 4) + "/raw/branch/" + branch;
} else {
versionSourcesUrlBase = gitUrl + "/raw/branch/" + branch;
}
} catch (IOException e) {
e.printStackTrace();
baseBadgeImg = null;
secondaryImg = null;
if (!gitUrl.startsWith("https://")) {
versionSourcesUrlBase = "https://" + versionSourcesUrlBase;
}
} else {
versionSourcesUrlBase = "https://" + gitUrl + "/" + org + "/" + repo + "/raw/branch/" + branch;
}
Map<Source, String> VERSION_SOURCES = new HashMap<>();
VERSION_SOURCES.put(Source.GRADLE_GROOVY, versionSourcesUrlBase + "/build.gradle");
VERSION_SOURCES.put(Source.GRADLE_KOTLIN,versionSourcesUrlBase + "/build.gradle.kts");
VERSION_SOURCES.put(Source.MAVEN, versionSourcesUrlBase + "/pom.xml");
VERSION_SOURCES.put(Source.VERSION_FILE, versionSourcesUrlBase + "/VERSION");
img = new BufferedImage(totalWidth, totalHeight, BufferedImage.TYPE_INT_ARGB);
graphics2D = img.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
graphics2D.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
graphics2D.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics2D.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
graphics2D.setFont(font);
graphics2D.drawImage(resizeImage(baseBadgeImg, totalWidth), 0, 0, totalWidth, totalHeight, null);
graphics2D.drawImage(secondaryImg, totalWidth - rWidth - 10, 0, rWidth + 10, totalHeight, null);
graphics2D.setColor(Color.GRAY);
graphics2D.drawString(leftStr, 5, textY - 1);
graphics2D.drawString(rightStr, totalWidth - rWidth - 5, textY - 1);
graphics2D.setColor(Color.WHITE);
graphics2D.drawString(leftStr, 5, textY);
graphics2D.drawString(rightStr, totalWidth - rWidth - 5, textY);
graphics2D.dispose();
VersionSource vs = new VersionSource();
ByteArrayOutputStream baos;
try {
baos = new ByteArrayOutputStream();
ImageIO.write(img, "png", baos);
} catch (IOException e) {
e.printStackTrace();
LoggerFactory.getLogger(BadgeFactory.class).info("not good thingy happened...");
return new byte[]{};
}
return baos.toByteArray();
}
private static BufferedImage resizeImage(BufferedImage originalImage, int targetWidth) {
BufferedImage resizedImage = new BufferedImage(targetWidth, 25, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics2D = resizedImage.createGraphics();
graphics2D.drawImage(originalImage, 0, 0, targetWidth, 25, null);
graphics2D.dispose();
return resizedImage;
}
public static String getVersionFromGitRepo(String gitUrl, String org, String repo, String branch) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.GET()
.header("accept", "text/plain")
.uri(URI.create("https://" + gitUrl + "/" + org + "/" + repo + "/raw/branch/" + branch + "/build.gradle"))
.build();
String responseString = "";
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
responseString = response.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
String[] split = responseString.split("\n");
String version = null;
for (String str : split) {
if (str.startsWith("version")) {
version = str.substring(9, str.length() - 1);
for (Map.Entry<Source, String> entry : VERSION_SOURCES.entrySet()) {
String content = getVersionIndicatorRaw(entry.getValue());
if (content != null) {
vs.content = content;
vs.source = entry.getKey();
break;
}
}
return version;
return extractVersionFromSource(vs);
}
public static String getVersionFromGitCommit(String gitUrl, String org, String repo, String commit) {
String versionSourcesUrlBase;
if (org == null && repo == null) {
if (gitUrl.endsWith(".git")) {
versionSourcesUrlBase = gitUrl.substring(0, gitUrl.length() - 4) + "/raw/commit/" + commit;
} else {
versionSourcesUrlBase = gitUrl + "/raw/branch/" + commit;
}
if (!gitUrl.startsWith("https://")) {
versionSourcesUrlBase = "https://" + versionSourcesUrlBase;
}
} else {
versionSourcesUrlBase = "https://" + gitUrl + "/" + org + "/" + repo + "/raw/commit/" + commit;
}
Map<Source, String> VERSION_SOURCES = new HashMap<>();
VERSION_SOURCES.put(Source.GRADLE_GROOVY, versionSourcesUrlBase + "/build.gradle");
VERSION_SOURCES.put(Source.GRADLE_KOTLIN,versionSourcesUrlBase + "/build.gradle.kts");
VERSION_SOURCES.put(Source.MAVEN, versionSourcesUrlBase + "/pom.xml");
VERSION_SOURCES.put(Source.VERSION_FILE, versionSourcesUrlBase + "/VERSION");
VersionSource vs = new VersionSource();
for (Map.Entry<Source, String> entry : VERSION_SOURCES.entrySet()) {
String content = getVersionIndicatorRaw(entry.getValue());
if (content != null) {
vs.content = content;
vs.source = entry.getKey();
break;
}
}
return extractVersionFromSource(vs);
}
public static String getLatestBuildStatusFromJenkins(String jenkinsUrl, String projectName) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.GET()
.header("accept", "application/json")
.uri(URI.create("https://" + jenkinsUrl + "/job/" + projectName + "/lastBuild/api/json"))
.build();
String responseString = "";
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
responseString = response.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
JsonObject json = new Gson().fromJson(responseString, JsonObject.class);
return json.get("result").getAsString();
return getJenkinsProjectJson(jenkinsUrl, projectName).get("result").getAsString();
}
public static String getLatestSuccessfulVersionFromJenkins(String jenkinsUrl, String projectName) {
JsonObject json = getJenkinsProjectJson(jenkinsUrl, projectName);
String gitUrl = json.get("actions").getAsJsonArray().get(2).getAsJsonObject().get("remoteUrls").getAsJsonArray().get(0).getAsString();
gitUrl = gitUrl.substring(0, gitUrl.length() - 4);
String commit = json.get("changeSet").getAsJsonObject().get("items").getAsJsonArray().get(0).getAsJsonObject().get("commitId").getAsString();
return getVersionFromGitCommit(gitUrl, null, null, commit);
}
private static JsonObject getJenkinsProjectJson(String jenkinsUrl, String projectName) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.GET()
@ -191,33 +161,64 @@ public class BadgeFactory {
e.printStackTrace();
}
JsonObject json = new Gson().fromJson(responseString, JsonObject.class);
String gitUrl = json.get("actions").getAsJsonArray().get(2).getAsJsonObject().get("remoteUrls").getAsJsonArray().get(0).getAsString();
gitUrl = gitUrl.substring(0, gitUrl.length() - 4);
String commit = json.get("changeSet").getAsJsonObject().get("items").getAsJsonArray().get(0).getAsJsonObject().get("commitId").getAsString();
return new Gson().fromJson(responseString, JsonObject.class);
}
private static String getVersionIndicatorRaw(String url) {
HttpClient gitClient = HttpClient.newHttpClient();
HttpRequest gitRequest = HttpRequest.newBuilder()
.GET()
.header("accept", "text/plain")
.uri(URI.create(gitUrl + "/raw/commit/" + commit + "/build.gradle"))
.uri(URI.create(url))
.build();
String gitResponseString = "";
try {
HttpResponse<String> response = gitClient.send(gitRequest, HttpResponse.BodyHandlers.ofString());
gitResponseString = response.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
return response.body();
} catch (final Exception e) {
return null;
}
}
String[] split = gitResponseString.split("\n");
String version = null;
for (String str : split) {
if (str.startsWith("version")) {
version = str.substring(9, str.length() - 1);
private static String extractVersionFromSource(VersionSource vs) {
String[] split = vs.content.split("\n");
switch (vs.source) {
case GRADLE_GROOVY -> {
for (String str : split) {
if (str.startsWith("version")) {
return str.substring(9, str.length() - 1);
}
}
}
case GRADLE_KOTLIN -> {
for (String str : split) {
if (str.startsWith("version =")) {
return str.substring(10, str.length() - 1);
}
}
}
case MAVEN -> {
for (String str : split) {
if (str.startsWith(" <version>")) {
return str.substring(11, str.length() - 1);
}
}
}
case VERSION_FILE -> {
return vs.content;
}
}
return "unknown";
}
return version;
enum Source {
GRADLE_GROOVY,
GRADLE_KOTLIN,
MAVEN,
VERSION_FILE
}
private static class VersionSource {
private Source source;
private String content;
}
}

View File

@ -1,17 +1,24 @@
package tech.nevets.codebadgerestapi;
import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;
import java.awt.*;
import static spark.Spark.*;
public class Server {
public static void main(String[] args) {
port(8080);
path("/badge", () -> {
before("/*");
get("/test/:left/:right/:color", (req, res) -> {
get("/test/:left/:right", (req, res) -> {
String left = Jsoup.clean(req.params(":left"), Safelist.relaxed());
String right = Jsoup.clean(req.params(":right"), Safelist.relaxed());
res.type("image/svg+xml");
Color color = Color.GRAY;
switch (req.params(":color").toLowerCase()) {
Color color;
switch (req.queryParams("color").toLowerCase()) {
case "red" -> color = Color.RED;
case "orange" -> color = Color.ORANGE;
case "yellow" -> color = Color.YELLOW;
@ -26,12 +33,30 @@ public class Server {
case "black" -> color = Color.BLACK;
default -> color = Color.GRAY;
}
return BadgeFactory.genSVGBadge(req.params(":left"), req.params(":right"), color);
boolean isRounded;
if (req.queryParams("rounded") == null) {
isRounded = false;
} else {
if (req.queryParams("rounded").equals("true")) {
isRounded = true;
} else {
isRounded = false;
}
}
return BadgeFactory.genSVGBadge(left, right, color, isRounded);
});
get("/version/*/:gitUrl/:org/:repo/:branch", (req, res) -> {
switch (req.splat()[0]) {
String splat0 = Jsoup.clean(req.splat()[0], Safelist.relaxed());
String gitUrl = Jsoup.clean(req.params(":gitUrl"), Safelist.relaxed());
String org = Jsoup.clean(req.params(":org"), Safelist.relaxed());
String repo = Jsoup.clean(req.params(":repo"), Safelist.relaxed());
String branch = Jsoup.clean(req.params(":branch"), Safelist.relaxed());
switch (splat0) {
case "gitea" -> {
return BadgeFactory.getVersionFromGitRepo(req.params(":gitUrl"), req.params(":org"), req.params(":repo"), req.params(":branch"));
res.type("image/svg+xml");
String version = BadgeFactory.getVersionFromGitBranch(gitUrl, org, repo, branch);
return BadgeFactory.genSVGBadge("Version", version, Color.GREEN, true);
}
case "github" -> {
res.status(405);
@ -41,33 +66,31 @@ public class Server {
res.status(405);
return "Not yet Implemented!";
}
case "test" -> {
res.type("image/png");
String version = BadgeFactory.getVersionFromGitRepo(req.params(":gitUrl"), req.params(":org"), req.params(":repo"), req.params(":branch"));
return BadgeFactory.generateBadge("Version", version, BadgeColor.GREEN);
}
}
res.status(404);
return "Not Found!";
});
get("/buildStatus/*/:ciUrl/:projectName", (req, res) -> {
switch (req.splat()[0]) {
String splat0 = Jsoup.clean(req.splat()[0], Safelist.relaxed());
String ciUrl = Jsoup.clean(req.params(":ciUrl"), Safelist.relaxed());
String projectName = Jsoup.clean(req.params(":projectName"), Safelist.relaxed());
switch (splat0) {
case "jenkins" -> {
res.type("image/png");
String buildStatus = BadgeFactory.getLatestBuildStatusFromJenkins(req.params(":ciUrl"), req.params(":projectName"));
BadgeColor badgeColor = BadgeColor.GRAY;
String buildStatus = BadgeFactory.getLatestBuildStatusFromJenkins(ciUrl, projectName);
Color badgeColor = Color.GRAY;
switch (buildStatus) {
case "SUCCESS" -> {
buildStatus = "passing";
badgeColor = BadgeColor.GREEN;
badgeColor = Color.GREEN;
}
case "FAILURE" -> {
buildStatus = "failing";
badgeColor = BadgeColor.RED;
badgeColor = Color.RED;
}
}
return BadgeFactory.generateBadge("Build", buildStatus, badgeColor);
return BadgeFactory.genSVGBadge("Build", buildStatus, badgeColor, true);
}
case "circleci" -> {
res.status(405);
@ -77,19 +100,18 @@ public class Server {
res.status(405);
return "Not yet Implemented!";
}
case "test" -> {
res.type("image/svg+xml");
}
}
res.status(404);
return "Not Found!";
});
get("/latestSuccessfulVersion/*/:ciUrl/:projectName", (req, res) -> {
switch (req.splat()[0]) {
String splat0 = Jsoup.clean(req.splat()[0], Safelist.relaxed());
String ciUrl = Jsoup.clean(req.params(":ciUrl"), Safelist.relaxed());
String projectName = Jsoup.clean(req.params(":projectName"), Safelist.relaxed());
switch (splat0) {
case "jenkins" -> {
return BadgeFactory.getLatestSuccessfulVersionFromJenkins(req.params(":ciUrl"), req.params(":projectName"));
return BadgeFactory.getLatestSuccessfulVersionFromJenkins(ciUrl, projectName);
}
case "circleci" -> {
res.status(405);

View File

@ -1,12 +0,0 @@
package tech.nevets.codebadgerestapi;
import java.awt.*;
public class askjdf {
public static void main(String[] args) {
for (Font font : GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts()) {
System.out.println(font.getName());
}
}
}