mirror of
https://gitlab.rlp.net/proj-wise2526-video2document/video2document.git
synced 2026-06-15 18:01:52 +02:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eec0b2d356 | |||
| 77dcf6d812 | |||
| b9881d55e7 | |||
| a7a8170cd5 | |||
| 15a4807567 | |||
| 3bbd82eddc | |||
| 55555bcc37 |
@@ -88,6 +88,27 @@ Show your appreciation to those who have contributed to the project.
|
||||
|
||||
## License
|
||||
For open source projects, say how it is licensed.
|
||||
---
|
||||
|
||||
## Project status
|
||||
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
||||
## Sprint 4 – Secure API Key Management
|
||||
|
||||
In Sprint 4, secure handling of API keys was implemented for the V2D (Video to Document) framework.
|
||||
|
||||
### Implementation Overview
|
||||
- API keys are **not stored in the source code**
|
||||
- The backend loads the key from an **environment variable**
|
||||
- A single configuration works for all users without manual setup
|
||||
- Secrets are protected from being exposed in the repository or frontend
|
||||
|
||||
### Configuration
|
||||
The backend expects the following environment variable:
|
||||
|
||||
|
||||
This variable is injected at runtime by the deployment or CI/CD environment and referenced in `application.yml`.
|
||||
|
||||
### Security Benefits
|
||||
- Prevents accidental exposure of API keys
|
||||
- Ensures secure collaboration in GitLab
|
||||
- Follows best practices for secret management
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
spring:
|
||||
application:
|
||||
name: v2d-document
|
||||
|
||||
app:
|
||||
external:
|
||||
apiKey: ${LLM_API_KEY:}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.v2d.document.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "app.external")
|
||||
public class AppProperties {
|
||||
private String apiKey;
|
||||
|
||||
public String getApiKey() { return apiKey; }
|
||||
public void setApiKey(String apiKey) { this.apiKey = apiKey; }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.v2d.document.controller;
|
||||
|
||||
import com.v2d.document.service.ExternalApiService;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/generate")
|
||||
public class GenerateController {
|
||||
|
||||
private final ExternalApiService externalApiService;
|
||||
|
||||
public GenerateController(ExternalApiService externalApiService) {
|
||||
this.externalApiService = externalApiService;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<String> generate(@RequestBody Map<String,Object> body) {
|
||||
// Build provider payload from the user's body (transform safely)
|
||||
String payload = "{\"text\": \"use this text\"}"; // adapt for real usage
|
||||
String providerResponse = externalApiService.callProvider(payload);
|
||||
return ResponseEntity.ok(providerResponse);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.v2d.document.service;
|
||||
|
||||
import com.v2d.document.config.AppProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
|
||||
@Service
|
||||
public class ExternalApiService {
|
||||
private final Logger log = LoggerFactory.getLogger(ExternalApiService.class);
|
||||
private final AppProperties props;
|
||||
private final HttpClient http = HttpClient.newHttpClient();
|
||||
|
||||
public ExternalApiService(AppProperties props) {
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
public String callProvider(String jsonPayload) {
|
||||
String key = props.getApiKey();
|
||||
if (key == null || key.isBlank()) {
|
||||
log.warn("External API key is not configured.");
|
||||
throw new IllegalStateException("External API key missing");
|
||||
}
|
||||
|
||||
try {
|
||||
HttpRequest req = HttpRequest.newBuilder()
|
||||
.uri(URI.create("https://api.example.com/endpoint")) // replace with real endpoint
|
||||
.header("Authorization", "Bearer " + key)
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
|
||||
.build();
|
||||
|
||||
HttpResponse<String> resp = http.send(req, HttpResponse.BodyHandlers.ofString());
|
||||
return resp.body();
|
||||
} catch (Exception e) {
|
||||
log.error("External API call failed: {}", e.getMessage());
|
||||
throw new RuntimeException("External API call failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.v2d.document.service;
|
||||
|
||||
import com.v2d.document.config.AppProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
|
||||
@Service
|
||||
public class ExternalApiService {
|
||||
private final Logger log = LoggerFactory.getLogger(ExternalApiService.class);
|
||||
private final AppProperties props;
|
||||
private final HttpClient http = HttpClient.newHttpClient();
|
||||
|
||||
public ExternalApiService(AppProperties props) {
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
public String callProvider(String jsonPayload) {
|
||||
String key = props.getApiKey();
|
||||
if (key == null || key.isBlank()) {
|
||||
log.warn("External API key is not configured.");
|
||||
throw new IllegalStateException("External API key missing");
|
||||
}
|
||||
|
||||
try {
|
||||
HttpRequest req = HttpRequest.newBuilder()
|
||||
.uri(URI.create("https://api.example.com/endpoint")) // replace with real endpoint
|
||||
.header("Authorization", "Bearer " + key)
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
|
||||
.build();
|
||||
|
||||
HttpResponse<String> resp = http.send(req, HttpResponse.BodyHandlers.ofString());
|
||||
return resp.body();
|
||||
} catch (Exception e) {
|
||||
log.error("External API call failed: {}", e.getMessage());
|
||||
throw new RuntimeException("External API call failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.v2d.document.config;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class AppPropertiesTest {
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withUserConfiguration(AppProperties.class)
|
||||
.withPropertyValues("app.external.apiKey=TEST_KEY");
|
||||
|
||||
@Test
|
||||
void bindsApiKey() {
|
||||
contextRunner.run(context -> {
|
||||
AppProperties props = context.getBean(AppProperties.class);
|
||||
assertThat(props.getApiKey()).isEqualTo("TEST_KEY");
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user