feat(fullstack): Add middleware API to frontend, add dummy signature mode for middleware

This commit is contained in:
2025-07-27 09:05:09 +02:00
parent 4d1280749f
commit 115a12bbf5
14 changed files with 373 additions and 2 deletions

View File

@@ -0,0 +1,53 @@
package com.betriebsratkanzlei.legalconsenthub_middleware.signature
import com.betriebsratkanzlei.legalconsenthub_middleware_api.api.SignatureApi
import com.betriebsratkanzlei.legalconsenthub_middleware_api.model.VerifySignatureResponseDto
import com.betriebsratkanzlei.legalconsenthub_middleware_api.model.CertificateDto
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile
import java.time.LocalDateTime
import java.util.*
@RestController
@ConditionalOnProperty(name = ["dummy.mode.enabled"], havingValue = "true")
class DummySignatureController : SignatureApi {
override fun signPdfHash(
document: MultipartFile,
certificateId: String,
hashAlgorithm: String
): ResponseEntity<String> {
// Always return a successful dummy signature
val dummySignature = "dummySignature_${certificateId}_${System.currentTimeMillis()}"
val encodedSignature = Base64.getEncoder().encodeToString(dummySignature.toByteArray())
return ResponseEntity.ok(encodedSignature)
}
override fun verifySignature(
document: MultipartFile,
signature: String,
certificateId: String?,
hashAlgorithm: String
): ResponseEntity<VerifySignatureResponseDto> {
// Always return successful verification with dummy certificate
val dummyCertificate = CertificateDto(
id = certificateId ?: "01",
subject = "CN=John Doe, O=Example Company, L=Berlin, C=DE",
issuer = "CN=Dummy CA, O=Dummy Corp, C=DE",
validFrom = LocalDateTime.now().minusYears(1),
validTo = LocalDateTime.now().plusYears(2),
keyUsage = listOf("digitalSignature", "keyEncipherment", "nonRepudiation"),
fingerprint = "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD"
)
val successfulResponse = VerifySignatureResponseDto(
isValid = true,
certificateInfo = dummyCertificate,
verificationDetails = "DUMMY: Signature verified successfully using ${hashAlgorithm} algorithm"
)
return ResponseEntity.ok(successfulResponse)
}
}

View File

@@ -2,11 +2,13 @@ package com.betriebsratkanzlei.legalconsenthub_middleware.signature
import com.betriebsratkanzlei.legalconsenthub_middleware_api.api.SignatureApi
import com.betriebsratkanzlei.legalconsenthub_middleware_api.model.VerifySignatureResponseDto
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile
@RestController
@ConditionalOnProperty(name = ["dummy.mode.enabled"], havingValue = "false", matchIfMissing = true)
class SignatureController(
private val signatureService: SignatureService
) : SignatureApi {

View File

@@ -3,10 +3,12 @@ package com.betriebsratkanzlei.legalconsenthub_middleware.signature
import com.betriebsratkanzlei.legalconsenthub_middleware.smartcard.SmartCardService
import com.betriebsratkanzlei.legalconsenthub_middleware_api.model.VerifySignatureResponseDto
import com.betriebsratkanzlei.legalconsenthub_middleware_api.model.CertificateDto
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Service
import java.util.*
@Service
@ConditionalOnProperty(name = ["dummy.mode.enabled"], havingValue = "false", matchIfMissing = true)
class SignatureService(
private val smartCardService: SmartCardService
) {

View File

@@ -0,0 +1,51 @@
package com.betriebsratkanzlei.legalconsenthub_middleware.smartcard
import com.betriebsratkanzlei.legalconsenthub_middleware_api.api.SmartCardApi
import com.betriebsratkanzlei.legalconsenthub_middleware_api.model.CertificateDto
import com.betriebsratkanzlei.legalconsenthub_middleware_api.model.SmartCardInfoDto
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RestController
import java.time.LocalDateTime
@RestController
@ConditionalOnProperty(name = ["dummy.mode.enabled"], havingValue = "true")
class DummySmartCardController : SmartCardApi {
override fun getSmartCardInfo(): ResponseEntity<SmartCardInfoDto> {
// Always return successful smart card info
val dummySmartCardInfo = SmartCardInfoDto(
isPresent = true,
label = "DUMMY Smart Card",
serialNumber = "12345678",
manufacturer = "Dummy Corp",
model = "DummyCard 2024"
)
return ResponseEntity.ok(dummySmartCardInfo)
}
override fun getSmartCardCertificates(): ResponseEntity<List<CertificateDto>> {
// Always return successful list of dummy certificates
val dummyCertificates = listOf(
CertificateDto(
id = "01",
subject = "CN=John Doe, O=Example Company, L=Berlin, C=DE",
issuer = "CN=Dummy CA, O=Dummy Corp, C=DE",
validFrom = LocalDateTime.now().minusYears(1),
validTo = LocalDateTime.now().plusYears(2),
keyUsage = listOf("digitalSignature", "keyEncipherment", "nonRepudiation"),
fingerprint = "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD"
),
CertificateDto(
id = "02",
subject = "CN=Jane Smith, O=Test Organization, L=Munich, C=DE",
issuer = "CN=Test CA, O=Test Corp, C=DE",
validFrom = LocalDateTime.now().minusMonths(6),
validTo = LocalDateTime.now().plusYears(3),
keyUsage = listOf("digitalSignature", "nonRepudiation"),
fingerprint = "11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44"
)
)
return ResponseEntity.ok(dummyCertificates)
}
}

View File

@@ -3,11 +3,13 @@ package com.betriebsratkanzlei.legalconsenthub_middleware.smartcard
import com.betriebsratkanzlei.legalconsenthub_middleware_api.api.SmartCardApi
import com.betriebsratkanzlei.legalconsenthub_middleware_api.model.CertificateDto
import com.betriebsratkanzlei.legalconsenthub_middleware_api.model.SmartCardInfoDto
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RestController
import java.time.LocalDateTime
@RestController
@ConditionalOnProperty(name = ["dummy.mode.enabled"], havingValue = "false", matchIfMissing = true)
class SmartCardController(
private val smartCardService: SmartCardService
) : SmartCardApi {

View File

@@ -7,6 +7,7 @@ import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor
import org.apache.commons.exec.PumpStreamHandler
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.core.io.ResourceLoader
import org.springframework.stereotype.Service
import java.io.ByteArrayOutputStream
@@ -17,6 +18,7 @@ import java.nio.file.Files
import java.nio.file.StandardCopyOption
@Service
@ConditionalOnProperty(name = ["dummy.mode.enabled"], havingValue = "false", matchIfMissing = true)
class SmartCardService(
@Value("\${opensc.pkcs11.library.path}") private val openscPkcs11LibPath: String,
private val resourceLoader: ResourceLoader

View File

@@ -0,0 +1,28 @@
spring:
application:
name: legalconsenthub-middleware
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
server:
port: 8081
servlet:
context-path: /
logging:
level:
com.betriebsratkanzlei.legalconsenthub_middleware: DEBUG
org.springframework.security: DEBUG
# Dummy mode configuration
dummy:
mode:
enabled: true
# OpenSC configuration (not used in dummy mode but kept for consistency)
opensc:
pkcs11:
library:
path: classpath:binaries/opensc-pkcs11.so