Skip to content

Commit d3d7725

Browse files
authored
Merge pull request #23 from Jalen-Stephens/14-service-implement-analyzeservice-metadata-scraping-and-response
2 parents 201054e + 5befb2a commit d3d7725

File tree

12 files changed

+456
-4
lines changed

12 files changed

+456
-4
lines changed

.DS_Store

0 Bytes
Binary file not shown.

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,9 @@ build/
3535
### Enviroment Variables ###
3636
.env
3737
env.local.sh
38-
env.pooler.sh
38+
39+
### C2PA and Tools ###
40+
/tools/
41+
42+
43+
env.pooler.sh

citations.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,104 @@ Assisted in drafting a unit test suite for the `UserService` to validate identit
497497
498498
---
499499

500+
501+
502+
### Commit / Ticket Reference
503+
504+
* **Commit:** `feat(c2pa): c2pa tool successfully downloaded (pom.xml updated) only functional on macOS(refs #14)`
505+
* **Ticket:** `#14 — Service: Implement AnalyzeService core logic (Iteration 1)`
506+
* **Date:** October 21, 2025
507+
* **Team Member:** Isaac Schmidt
508+
509+
### **AI Tool Information**
510+
- **Tool Used:** OpenAI ChatGPT (GPT-5)
511+
- **Access Method:** ChatGPT Web (.edu academic access)
512+
- **Configuration:** Default model settings
513+
- **Cost:** $0 (no paid API calls)
514+
515+
---
516+
517+
### **Purpose of AI Assistance**
518+
Assistance was used to **debug and configure Maven build behavior** for the `AnalyzeService` Spring Boot service.
519+
The AI helped ensure that the **C2PAtool binary** (used for AI-image authenticity verification) is correctly downloaded, unpacked, and persisted across build phases so it remains executable both locally and in deployment.
520+
521+
---
522+
523+
### **Prompts / Interaction Summary**
524+
- Asked why `mvn package` wasn’t producing the `tools/c2patool` binary.
525+
- Requested possible solutions to `pom.xml` configuration using `download-maven-plugin` and `maven-antrun-plugin`.
526+
- Troubleshot successive build errors (e.g. "file is directory", missing binary).
527+
- Asked how to keep the binary after packaging and why Maven was deleting it.
528+
- Requested an explanation of the final working solution and how to preserve the executable between builds.
529+
530+
---
531+
532+
### **Resulting Artifacts**
533+
- **Edited File:** `pom.xml`
534+
- Added `download-maven-plugin` section to fetch `c2patool-v0.9.12-universal-apple-darwin.zip`.
535+
- Added `maven-antrun-plugin` section to unzip, copy, chmod, and retain the binary.
536+
- **New Directory:** `tools/` (containing executable `c2patool`)
537+
- **Build Artifact:** Verified Maven package with `tools/c2patool` present and executable.
538+
539+
---
540+
541+
### **Verification**
542+
- Ran `mvn clean package` to confirm the binary appears at `./tools/c2patool`.
543+
- Executed `./tools/c2patool --version` to verify the file runs successfully.
544+
- Rebuilt the Spring Boot JAR to ensure the `tools/` directory remains intact after packaging.
545+
- Manually inspected Maven logs and filesystem to confirm that no cleanup phase deletes the binary.
546+
547+
---
548+
549+
550+
551+
### Commit / Ticket Reference
552+
553+
* **Commit:** `feat(c2pa): c2pa tool successfully downloaded (pom.xml updated) only functional on macOS(refs #14)`
554+
* **Ticket:** `#14 — Service: Implement AnalyzeService core logic (Iteration 1)`
555+
* **Date:** October 21, 2025
556+
* **Team Member:** Isaac Schmidt
557+
558+
### **AI Tool Information**
559+
- **Tool Used:** OpenAI ChatGPT (GPT-5)
560+
- **Access Method:** ChatGPT Web (.edu academic access)
561+
- **Configuration:** Default model settings
562+
- **Cost:** $0 (no paid API calls)
563+
564+
---
565+
566+
### **Purpose of AI Assistance**
567+
Assistance was used to **debug and configure Maven build behavior** for the `AnalyzeService` Spring Boot service.
568+
The AI helped ensure that the **C2PAtool binary** (used for AI-image authenticity verification) is correctly downloaded, unpacked, and persisted across build phases so it remains executable both locally and in deployment.
569+
570+
---
571+
572+
### **Prompts / Interaction Summary**
573+
- Asked why `mvn package` wasn’t producing the `tools/c2patool` binary.
574+
- Requested possible solutions to `pom.xml` configuration using `download-maven-plugin` and `maven-antrun-plugin`.
575+
- Troubleshot successive build errors (e.g. "file is directory", missing binary).
576+
- Asked how to keep the binary after packaging and why Maven was deleting it.
577+
- Requested an explanation of the final working solution and how to preserve the executable between builds.
578+
579+
---
580+
581+
### **Resulting Artifacts**
582+
- **Edited File:** `pom.xml`
583+
- Added `download-maven-plugin` section to fetch `c2patool-v0.9.12-universal-apple-darwin.zip`.
584+
- Added `maven-antrun-plugin` section to unzip, copy, chmod, and retain the binary.
585+
- **New Directory:** `tools/` (containing executable `c2patool`)
586+
- **Build Artifact:** Verified Maven package with `tools/c2patool` present and executable.
587+
588+
---
589+
590+
### **Verification**
591+
- Ran `mvn clean package` to confirm the binary appears at `./tools/c2patool`.
592+
- Executed `./tools/c2patool --version` to verify the file runs successfully.
593+
- Rebuilt the Spring Boot JAR to ensure the `tools/` directory remains intact after packaging.
594+
- Manually inspected Maven logs and filesystem to confirm that no cleanup phase deletes the binary.
595+
596+
---
597+
500598
### **Commit / Ticket Reference**
501599

502600
* **Commit:** `feat(auth): add Supabase auth proxy + /auth endpoints + JWKS resource server config (refs #7)`

pom.xml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@
2121
<properties>
2222
<java.version>17</java.version>
2323
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
24+
25+
<!-- C2PA tool download configuration (macOS universal ZIP) -->
26+
<c2pa.version>v0.23.4</c2pa.version>
27+
<c2pa.url>https://github.com/contentauth/c2pa-rs/releases/download/c2patool-{c2pa.version}/c2patool-{c2pa.version}-universal-apple-darwin.zip</c2pa.url>
28+
<c2pa.unpack.dir>${project.basedir}/tools</c2pa.unpack.dir>
29+
<c2pa.unpack.archive>${c2pa.unpack.dir}/c2patool.zip</c2pa.unpack.archive>
30+
<!-- Folder name created by the ZIP for v0.23.4 (contains the binary named "c2patool") -->
31+
<c2pa.unzipped.folder>c2patool-${c2pa.version}-universal-apple-darwin</c2pa.unzipped.folder>
2432
</properties>
2533

2634
<dependencyManagement>
@@ -81,6 +89,12 @@
8189
<groupId>org.springframework.boot</groupId>
8290
<artifactId>spring-boot-starter-test</artifactId>
8391
<scope>test</scope>
92+
<exclusions>
93+
<exclusion>
94+
<groupId>org.mockito</groupId>
95+
<artifactId>mockito-core</artifactId>
96+
</exclusion>
97+
</exclusions>
8498
</dependency>
8599

86100
<!-- API tests (optional but nice for iteration 1) -->
@@ -135,6 +149,33 @@
135149
<version>4.12.0</version>
136150
<scope>test</scope>
137151
</dependency>
152+
<!-- Metadata Extractor library -->
153+
<dependency>
154+
<groupId>com.drewnoakes</groupId>
155+
<artifactId>metadata-extractor</artifactId>
156+
<version>2.18.0</version>
157+
</dependency>
158+
159+
<dependency>
160+
<groupId>com.fasterxml.jackson.core</groupId>
161+
<artifactId>jackson-databind</artifactId>
162+
<version>2.17.1</version>
163+
</dependency>
164+
165+
<!-- Mockito core (re-added with specific version) -->
166+
<dependency>
167+
<groupId>org.mockito</groupId>
168+
<artifactId>mockito-core</artifactId>
169+
<scope>test</scope>
170+
</dependency>
171+
172+
<dependency>
173+
<groupId>org.mockito</groupId>
174+
<artifactId>mockito-inline</artifactId>
175+
<version>5.2.0</version> <!-- Use the latest version -->
176+
<scope>test</scope>
177+
</dependency>
178+
138179
</dependencies>
139180

140181
<build>
@@ -146,6 +187,7 @@
146187
</extension>
147188
</extensions>
148189
<finalName>${project.artifactId}-${project.version}</finalName>
190+
149191
<plugins>
150192
<!-- Spring Boot (single declaration) -->
151193
<plugin>
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package dev.coms4156.project.metadetect.c2pa;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import java.util.Iterator;
6+
import java.util.Map;
7+
8+
/** Parses C2PA manifest JSON into structured data. */
9+
10+
public final class C2paJsonParser {
11+
private static final ObjectMapper objectMapper = new ObjectMapper();
12+
13+
private C2paJsonParser() {}
14+
15+
/**
16+
* Parses the C2PA manifest JSON string into a structured Map.
17+
*
18+
* @param jsonString The C2PA manifest JSON string.
19+
* @return A Map representing the parsed manifest.
20+
* @throws Exception if parsing fails.
21+
*
22+
*/
23+
24+
public static Map<String, Object> parseManifestJson(String jsonString) throws Exception {
25+
try {
26+
JsonNode root = objectMapper.readTree(jsonString);
27+
28+
JsonNode manifests = root.get("manifests");
29+
if (manifests != null && manifests.isArray() && manifests.size() > 0) {
30+
JsonNode firstManifest = manifests.get(0);
31+
return parseJsonNode(firstManifest);
32+
} else {
33+
throw new Exception("No manifests found in C2PA JSON");
34+
}
35+
} catch (Exception ignore) {
36+
throw new Exception("Failed to parse C2PA JSON", ignore);
37+
}
38+
}
39+
40+
private static Map<String, Object> parseJsonNode(JsonNode node) {
41+
Map<String, Object> result = new java.util.LinkedHashMap<>();
42+
43+
Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
44+
while (fields.hasNext()) {
45+
Map.Entry<String, JsonNode> entry = fields.next();
46+
String key = entry.getKey();
47+
JsonNode valueNode = entry.getValue();
48+
Object value;
49+
50+
if (valueNode.isObject()) {
51+
value = parseJsonNode(valueNode);
52+
} else if (valueNode.isArray()) {
53+
java.util.List<Object> list = new java.util.ArrayList<>();
54+
for (JsonNode arrayItem : valueNode) {
55+
if (arrayItem.isObject()) {
56+
list.add(parseJsonNode(arrayItem));
57+
} else if (arrayItem.isArray()) {
58+
// Nested arrays are not expected in C2PA manifests; handle as needed
59+
list.add(arrayItem.toString());
60+
} else if (arrayItem.isValueNode()) {
61+
list.add(arrayItem.asText());
62+
}
63+
}
64+
value = list;
65+
} else if (valueNode.isValueNode()) {
66+
value = valueNode.asText();
67+
} else {
68+
value = null; // or handle other types as needed
69+
}
70+
result.put(key, value);
71+
}
72+
return result;
73+
}
74+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package dev.coms4156.project.metadetect.c2pa;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.io.InputStream;
6+
import java.io.InterruptedIOException;
7+
import java.nio.charset.StandardCharsets;
8+
import java.nio.file.Files;
9+
import java.util.Scanner;
10+
import java.util.concurrent.TimeUnit;
11+
12+
13+
/** Invokes the C2PA command-line tool to extract manifests from images.*/
14+
public class C2paToolInvoker {
15+
16+
private final String c2paToolPath;
17+
18+
public C2paToolInvoker(String c2paToolPath) {
19+
this.c2paToolPath = c2paToolPath;
20+
}
21+
22+
/**
23+
* Executes the C2PA tool to extract the manifest from the given image file.
24+
*
25+
* @param imageFile The image file to analyze.
26+
* @return JSON string of the C2PA manifest.
27+
* @throws IOException if the tool fails or the file is invalid.
28+
*
29+
*/
30+
public String extractManifest(File imageFile) throws IOException {
31+
// Create a temporary file for the output
32+
33+
34+
35+
// Command to invoke the C2PA tool
36+
ProcessBuilder processBuilder = new ProcessBuilder(
37+
c2paToolPath,
38+
imageFile.getAbsolutePath(),
39+
"-d"
40+
);
41+
42+
System.out.println("C2PA Tool Path: " + c2paToolPath);
43+
System.out.println("Image File Path: " + imageFile.getAbsolutePath());
44+
System.out.println("Executing command: " + String.join(" ", processBuilder.command()));
45+
46+
// Print the command for debugging
47+
System.out.println("Executing command: " + String.join(" ", processBuilder.command()));
48+
49+
// Start the process
50+
Process process = processBuilder.start();
51+
52+
try {
53+
// Wait for the process to complete
54+
int exitCode = process.waitFor();
55+
if (exitCode != 0) {
56+
throw new IOException("C2PA tool failed with exit code " + exitCode);
57+
}
58+
// Read the output file and return its contents as a string
59+
return " "; // placeholder
60+
} catch (InterruptedException e) {
61+
throw new IOException("C2PA tool execution was interrupted", e);
62+
}
63+
}
64+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package dev.coms4156.project.metadetect.config;
2+
3+
import dev.coms4156.project.metadetect.c2pa.C2paToolInvoker;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
7+
/** Configuation class to provide constants to other processes. */
8+
9+
@Configuration
10+
public class AppConfig {
11+
12+
/**
13+
* Creates a C2paToolInvoker bean with the specified tool path.
14+
* This method initializes the C2paToolInvoker with the path to the C2PA tool binary.
15+
* The tool is used to extract metadata and manifests from image files.
16+
*
17+
* @return a C2paToolInvoker instance configured with the tool path.
18+
*/
19+
20+
@Bean
21+
public C2paToolInvoker c2paToolInvoker() {
22+
// Path to the C2PA tool binary
23+
String c2paToolPath = "tools/c2patool/c2patool";
24+
return new C2paToolInvoker(c2paToolPath);
25+
}
26+
}

0 commit comments

Comments
 (0)