From 51c1b2c80c8e0067b90b6515edf85476e5e3ba54 Mon Sep 17 00:00:00 2001 From: axtloss Date: Mon, 15 May 2023 09:11:55 +0200 Subject: Add files --- pom.xml | 67 +++++++++ .../java/io/github/jshipit/DockerAPIHelper.java | 162 +++++++++++++++++++++ src/main/java/io/github/jshipit/Main.java | 41 ++++++ 3 files changed, 270 insertions(+) create mode 100755 pom.xml create mode 100755 src/main/java/io/github/jshipit/DockerAPIHelper.java create mode 100755 src/main/java/io/github/jshipit/Main.java diff --git a/pom.xml b/pom.xml new file mode 100755 index 0000000..4146647 --- /dev/null +++ b/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + + io.github.jshipit + JavaShipit + 1.0-SNAPSHOT + + + 20 + 20 + UTF-8 + + + + com.github.docker-java + docker-java + 3.3.0 + + + com.github.docker-java + docker-java-transport-httpclient5 + 3.3.0 + + + commons-cli + commons-cli + 1.5.0 + + + com.fasterxml.jackson.core + jackson-databind + 2.14.2 + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.5.0 + + + + io.github.jshipit.Main + + + + jar-with-dependencies + + + + + assemble-all + package + + single + + + + + + + \ No newline at end of file diff --git a/src/main/java/io/github/jshipit/DockerAPIHelper.java b/src/main/java/io/github/jshipit/DockerAPIHelper.java new file mode 100755 index 0000000..dca582e --- /dev/null +++ b/src/main/java/io/github/jshipit/DockerAPIHelper.java @@ -0,0 +1,162 @@ +package io.github.jshipit; + + + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.node.ArrayNode; + +import java.io.*; +import java.net.*; +import java.util.Scanner; + +public class DockerAPIHelper { + + private String apiToken; + private String apiRepo; + private String authURL; + private String repository; + private String image; + + private String tag; + + public DockerAPIHelper(String apiRepo, String authURL, String repository, String image, String tag) { + System.out.println("DockerAPIHelper constructor"); + this.apiRepo = apiRepo; + this.repository = repository; + this.authURL = authURL; + this.image = image; + this.tag = tag; + try { + apiToken = generateAPIToken(); + } catch (IOException | RuntimeException e) { + System.out.println("IOException | RuntimeException"); + e.printStackTrace(); + } + } + + public String generateAPIToken() throws IOException, RuntimeException { + URL url_obj = null; + try { + url_obj = new URI(this.authURL + "?scope=repository:" + this.repository + "/" + this.image + ":pull" + "&service=" + this.apiRepo).toURL(); + System.out.println(url_obj.toString()); + } catch (URISyntaxException | MalformedURLException e) { + System.out.println("URISyntaxException | MalformedURLException"); + e.printStackTrace(); + } + + + assert url_obj != null; + HttpURLConnection con = (HttpURLConnection) url_obj.openConnection(); + con.setRequestMethod("GET"); + con.connect(); + if (con.getResponseCode() != 200) { + System.out.println("Error: " + con.getResponseCode()); + throw new RuntimeException("Failed : HTTP error code : " + + con.getResponseCode()); + } else { + System.out.println("Success: " + con.getResponseCode()); + String output = ""; + Scanner scanner = new Scanner(url_obj.openStream()); + while (scanner.hasNext()) { + output += scanner.nextLine(); + } + scanner.close(); + System.out.println(output); + ObjectMapper mapper = new ObjectMapper(); + JsonNode token = mapper.readTree(output); + System.out.println(token.get("token").asText()); + return token.get("token").asText(); + } + } + + public JsonNode fetchManifestJson() throws IOException, RuntimeException { + URL url_obj = null; + try { + String repo = this.apiRepo.replace("registry", "registry-1"); + url_obj = new URI("https://" + repo + "/v2/" + this.repository + "/" + this.image + "/manifests/"+this.tag).toURL(); + System.out.println(url_obj.toString()); + } catch(URISyntaxException | MalformedURLException e) { + System.out.println("URISyntaxException | MalformedURLException"); + e.printStackTrace(); + } + + assert url_obj != null; + HttpURLConnection con = (HttpURLConnection) url_obj.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("Authorization", "Bearer " + this.apiToken); + con.setRequestProperty("Accept", "application/vnd.docker.distribution.manifest.v2+json"); + con.connect(); + + if (con.getResponseCode() != 200) { + System.out.println("Error: " + con.getResponseCode()); + throw new RuntimeException("Failed : HTTP error code : " + + con.getResponseCode()); + } else { + System.out.println("Success: " + con.getResponseCode()); + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + StringBuffer content = new StringBuffer(); + while ((inputLine = in.readLine()) != null) { + content.append(inputLine); + } + in.close(); + con.disconnect(); + ObjectMapper mapper = new ObjectMapper(); + JsonNode manifest = mapper.readTree(content.toString()); + return manifest; + } + } + + public void fetchBlob(String digest, String tmpdir) throws IOException, RuntimeException { + URL url_obj = null; + try { + String repo = this.apiRepo.replace("registry", "registry-1"); + url_obj = new URI("https://" + repo + "/v2/" + this.repository + "/" + this.image + "/blobs/"+digest).toURL(); + System.out.println(url_obj.toString()); + } catch(URISyntaxException | MalformedURLException e) { + System.out.println("URISyntaxException | MalformedURLException"); + e.printStackTrace(); + } + + assert url_obj != null; + HttpURLConnection con = (HttpURLConnection) url_obj.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("Authorization", "Bearer " + this.apiToken); + con.setRequestProperty("Accept", "application/vnd.docker.distribution.manifest.v2+json"); + con.connect(); + + if (con.getResponseCode() != 200) { + System.out.println("Error: " + con.getResponseCode()); + throw new RuntimeException("Failed : HTTP error code : " + + con.getResponseCode()); + } else { + System.out.println("Success: " + con.getResponseCode()); + } + // Stream file download and output progress + InputStream inputStream = con.getInputStream(); + FileOutputStream outputStream = new FileOutputStream(tmpdir+"/"+digest.replace("sha256:", "")+"layer.tar"); + + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + + outputStream.close(); + inputStream.close(); + System.out.println("File downloaded successfully."); + } + + public String getApiToken() { + return apiToken; + } + + public String getImage() { + return image; + } + + public String getTag() { + return tag; + } +} diff --git a/src/main/java/io/github/jshipit/Main.java b/src/main/java/io/github/jshipit/Main.java new file mode 100755 index 0000000..df1cea7 --- /dev/null +++ b/src/main/java/io/github/jshipit/Main.java @@ -0,0 +1,41 @@ +package io.github.jshipit; + +import com.fasterxml.jackson.databind.JsonNode; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class Main { + public static void main(String[] args) { + DockerAPIHelper api = new DockerAPIHelper("registry.docker.io", "https://auth.docker.io/token", "library", "archlinux", "latest"); + JsonNode manifest = null; + + System.out.println("API Token: " + api.getApiToken()); + try { + manifest = api.fetchManifestJson(); + } catch (IOException e) { + + } + + System.out.println("Manifest: " + manifest); + + Path path = Path.of("./tmp_"+api.getImage()+"_"+api.getTag()); + try { + Files.createDirectory(path); + } catch (IOException e) { + System.out.println("Failed to create directory: " + path); + return; + } + + JsonNode layers = manifest.get("layers"); + for (JsonNode layer : layers) { + System.out.println("Layer: " + layer); + try { + api.fetchBlob(layer.get("digest").asText(), path.toString()); + } catch (IOException e) { + + } + } + } +} \ No newline at end of file -- cgit v1.2.3