diff --git a/.run/local-middleware-dummy.run.xml b/.run/local-middleware-dummy.run.xml deleted file mode 100644 index e7605cf..0000000 --- a/.run/local-middleware-dummy.run.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/.run/local-middleware.run.xml b/.run/local-middleware.run.xml deleted file mode 100644 index c63a2f3..0000000 --- a/.run/local-middleware.run.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file diff --git a/legalconsenthub-middleware/.gitattributes b/legalconsenthub-middleware/.gitattributes deleted file mode 100644 index 8af972c..0000000 --- a/legalconsenthub-middleware/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -/gradlew text eol=lf -*.bat text eol=crlf -*.jar binary diff --git a/legalconsenthub-middleware/DUMMY_MODE.md b/legalconsenthub-middleware/DUMMY_MODE.md deleted file mode 100644 index c273c9e..0000000 --- a/legalconsenthub-middleware/DUMMY_MODE.md +++ /dev/null @@ -1,125 +0,0 @@ -# Dummy Mode Configuration - -This document explains how to use the dummy/mock mode in the legalconsenthub-middleware application. - -## Overview - -Dummy mode allows you to test the middleware API endpoints without requiring a physical smart card connected to your system. Instead of interacting with real smart card hardware via OpenSC, the application returns predefined dummy data. - -## How to Enable Dummy Mode - -### Option 1: Using Spring Profiles - -Start the application with the `dummy` profile: - -```bash -# Using Gradle -./gradlew bootRun --args='--spring.profiles.active=dummy' - -# Using JAR -java -jar build/libs/legalconsenthub-middleware-*.jar --spring.profiles.active=dummy - -# Using environment variable -export SPRING_PROFILES_ACTIVE=dummy -./gradlew bootRun -``` - -### Option 2: Using IntelliJ IDEA Run Configuration - -A pre-configured run configuration named `local-middleware-dummy` is available in the `.run` directory. Simply: - -1. Open the project in IntelliJ IDEA -2. Select "local-middleware-dummy" from the run configurations dropdown -3. Click the run button - -### Option 3: Manual Configuration - -You can also manually set the dummy mode property: - -```bash -./gradlew bootRun --args='--dummy.mode.enabled=true' -``` - -## What Gets Mocked - -### Smart Card Information -- **Smart Card Info**: Always returns a successful response with dummy smart card information -- **Certificates**: Always returns a successful response with two dummy certificates - -### Signature Operations -- **Sign PDF Hash**: Always returns a successful dummy signature -- **Verify Signature**: Always returns a successful verification result - -## Dummy Data - -### Smart Card Info -```json -{ - "isPresent": true, - "label": "DUMMY Smart Card", - "serialNumber": "12345678", - "manufacturer": "Dummy Corp", - "model": "DummyCard 2024" -} -``` - -### Available Certificates -1. **Certificate 1**: - - ID: `01` - - Subject: `CN=John Doe, O=Example Company, L=Berlin, C=DE` - - Issuer: `CN=Dummy CA, O=Dummy Corp, C=DE` - -2. **Certificate 2**: - - ID: `02` - - Subject: `CN=Jane Smith, O=Test Organization, L=Munich, C=DE` - - Issuer: `CN=Test CA, O=Test Corp, C=DE` - -## Testing Signature Verification - -The dummy implementation always returns successful responses: - -- **All signatures**: Any signature verification request will return `isValid: true` -- **Consistent behavior**: All requests return successful responses for predictable testing -- **No validation**: The dummy mode doesn't perform actual signature validation - -## API Endpoints - -All original API endpoints remain the same when running in dummy mode: - -- `GET /smart-card/info` - Returns dummy smart card information -- `GET /smart-card/certificates` - Returns dummy certificates -- `POST /sign-pdf-hash` - Creates dummy signatures -- `POST /verify-signature` - Verifies dummy signatures - -## Development Benefits - -Using dummy mode provides several advantages during development: - -1. **No Hardware Dependency**: Test frontend functionality without smart card hardware -2. **Consistent Data**: Predictable responses make testing easier -3. **Fast Development**: No waiting for smart card operations or PIN entry -4. **Error Testing**: Easily test error scenarios by using invalid certificate IDs -5. **CI/CD Integration**: Run automated tests without smart card hardware - -## Switching Back to Real Mode - -To disable dummy mode and use real smart card operations: - -1. Remove the `dummy` profile from `SPRING_PROFILES_ACTIVE` -2. Ensure your smart card is connected and OpenSC is properly configured -3. Start the application normally - -```bash -# Normal mode (default) -./gradlew bootRun - -# Or explicitly disable dummy mode -./gradlew bootRun --args='--dummy.mode.enabled=false' -``` - -## Notes - -- In dummy mode, all responses are successful and verification details are prefixed with "DUMMY:" to clearly indicate mock responses -- The dummy controllers return hardcoded successful responses without any actual processing -- All dummy responses include realistic data structures that match the real API responses -- Perfect for frontend testing where you need predictable successful responses \ No newline at end of file diff --git a/legalconsenthub-middleware/api/legalconsenthub-middleware.yml b/legalconsenthub-middleware/api/legalconsenthub-middleware.yml deleted file mode 100644 index e335fa2..0000000 --- a/legalconsenthub-middleware/api/legalconsenthub-middleware.yml +++ /dev/null @@ -1,240 +0,0 @@ -openapi: "3.0.3" -info: - title: legalconsenthub-middleware - version: 0.1.0 - description: Middleware for digital signature services using OpenSC pkcs11-tool for hash signing. - contact: - name: Denis Lugowski - email: denis.lugowski@gmail.com - -servers: - - url: http://localhost:8081 - -security: - - bearerAuth: [] - -paths: - ####### Smart Card Operations ####### - /smart-card/info: - get: - summary: Get smart card information - operationId: getSmartCardInfo - tags: - - smart-card - responses: - "200": - description: Smart card information - content: - application/json: - schema: - $ref: "#/components/schemas/SmartCardInfoDto" - "400": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/BadRequest" - "401": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/Unauthorized" - "404": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/NotFound" - "500": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServerError" - "503": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" - - /smart-card/certificates: - get: - summary: Get available certificates on smart card - operationId: getSmartCardCertificates - tags: - - smart-card - responses: - "200": - description: List of available certificates - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/CertificateDto" - "400": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/BadRequest" - "401": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/Unauthorized" - "404": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/NotFound" - "500": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServerError" - "503": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" - - ####### PDF Hash Signing Operations ####### - /sign-pdf-hash: - post: - summary: Calculate hash from PDF and sign it using smart card - operationId: signPdfHash - tags: - - signature - requestBody: - required: true - content: - multipart/form-data: - schema: - $ref: "#/components/schemas/SignPdfHashRequestDto" - responses: - "200": - description: Base64 encoded signature - content: - text/plain: - schema: - type: string - description: Base64 encoded signature - "400": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/BadRequest" - "401": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/Unauthorized" - "404": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/NotFound" - "500": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServerError" - "503": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" - - /verify-signature: - post: - summary: Verify a signature against a document - operationId: verifySignature - tags: - - signature - requestBody: - required: true - content: - multipart/form-data: - schema: - $ref: "#/components/schemas/VerifySignatureRequestDto" - responses: - "200": - description: Signature verification result - content: - application/json: - schema: - $ref: "#/components/schemas/VerifySignatureResponseDto" - "400": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/BadRequest" - "401": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/Unauthorized" - "404": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/NotFound" - "500": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServerError" - "503": - $ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable" - -components: - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT - - schemas: - ####### Smart Card DTOs ####### - SmartCardInfoDto: - type: object - required: - - isPresent - - label - properties: - isPresent: - type: boolean - label: - type: string - serialNumber: - type: string - manufacturer: - type: string - model: - type: string - - CertificateDto: - type: object - required: - - id - - subject - - issuer - - validFrom - - validTo - - keyUsage - properties: - id: - type: string - subject: - type: string - issuer: - type: string - validFrom: - type: string - format: date-time - validTo: - type: string - format: date-time - keyUsage: - type: array - items: - type: string - fingerprint: - type: string - - ####### PDF Hash Signing DTOs ####### - SignPdfHashRequestDto: - type: object - required: - - document - - certificateId - properties: - document: - type: string - format: binary - description: PDF document to calculate hash from - certificateId: - type: string - description: ID of the certificate to use for signing - hashAlgorithm: - type: string - enum: [SHA1, SHA256, SHA384, SHA512] - default: SHA256 - description: Hash algorithm to use - - VerifySignatureRequestDto: - type: object - required: - - document - - signature - properties: - document: - type: string - format: binary - description: Document to verify signature against - signature: - type: string - description: Base64 encoded signature to verify - certificateId: - type: string - description: ID of the certificate to use for verification (optional, will use embedded certificate if not provided) - hashAlgorithm: - type: string - enum: [SHA1, SHA256, SHA384, SHA512] - default: SHA256 - description: Hash algorithm used for verification - - VerifySignatureResponseDto: - type: object - required: - - isValid - properties: - isValid: - type: boolean - description: Whether the signature is valid - certificateInfo: - $ref: "#/components/schemas/CertificateDto" - description: Information about the certificate used for signing - verificationDetails: - type: string - description: Additional details about the verification process diff --git a/legalconsenthub-middleware/build.gradle b/legalconsenthub-middleware/build.gradle deleted file mode 100644 index b35dfbe..0000000 --- a/legalconsenthub-middleware/build.gradle +++ /dev/null @@ -1,66 +0,0 @@ -plugins { - id 'org.jetbrains.kotlin.jvm' version '1.9.25' - id 'org.jetbrains.kotlin.plugin.spring' version '1.9.25' - id 'org.springframework.boot' version '3.5.3' - id 'io.spring.dependency-management' version '1.1.7' - id 'org.openapi.generator' version '7.11.0' -} - -group = 'com.betriebsratkanzlei' -version = '0.0.1-SNAPSHOT' - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } -} - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'com.fasterxml.jackson.module:jackson-module-kotlin' - implementation 'org.jetbrains.kotlin:kotlin-reflect' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6' - implementation 'org.springdoc:springdoc-openapi-ui:1.8.0' - - // Apache commons for file operations and process execution - implementation 'commons-io:commons-io:2.17.0' - implementation 'org.apache.commons:commons-exec:1.4.0' - - developmentOnly 'org.springframework.boot:spring-boot-devtools' -} - -kotlin { - compilerOptions { - freeCompilerArgs.addAll '-Xjsr305=strict' - } -} - -def generatedSourcesServerMiddlewareDir = "$buildDir/generated/server".toString() - -sourceSets { - main { - kotlin.srcDirs += generatedSourcesServerMiddlewareDir + '/src/main/kotlin' - } -} - -task generate_middleware_server(type: org.openapitools.generator.gradle.plugin.tasks.GenerateTask) { - generatorName = 'kotlin-spring' - inputSpec = "$rootDir/api/legalconsenthub-middleware.yml".toString() - outputDir = generatedSourcesServerMiddlewareDir - apiPackage = 'com.betriebsratkanzlei.legalconsenthub_middleware_api.api' - modelPackage = 'com.betriebsratkanzlei.legalconsenthub_middleware_api.model' - groupId = 'com.betriebsratkanzlei' - id = 'legalconsenthub_middleware_api' - configOptions = [useTags : 'true', - enumPropertyNaming: 'original', - interfaceOnly : 'true', - useSpringBoot3 : 'true'] - typeMappings = [DateTime: "LocalDateTime"] - importMappings = [LocalDateTime: "java.time.LocalDateTime"] -} - -compileKotlin.dependsOn(tasks.generate_middleware_server) diff --git a/legalconsenthub-middleware/gradle/wrapper/gradle-wrapper.jar b/legalconsenthub-middleware/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 1b33c55..0000000 Binary files a/legalconsenthub-middleware/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/legalconsenthub-middleware/gradle/wrapper/gradle-wrapper.properties b/legalconsenthub-middleware/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index ff23a68..0000000 --- a/legalconsenthub-middleware/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/legalconsenthub-middleware/gradlew b/legalconsenthub-middleware/gradlew deleted file mode 100755 index 23d15a9..0000000 --- a/legalconsenthub-middleware/gradlew +++ /dev/null @@ -1,251 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH="\\\"\\\"" - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/legalconsenthub-middleware/gradlew.bat b/legalconsenthub-middleware/gradlew.bat deleted file mode 100644 index db3a6ac..0000000 --- a/legalconsenthub-middleware/gradlew.bat +++ /dev/null @@ -1,94 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH= - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/legalconsenthub-middleware/settings.gradle b/legalconsenthub-middleware/settings.gradle deleted file mode 100644 index 35d7e71..0000000 --- a/legalconsenthub-middleware/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'legalconsenthub-middleware' diff --git a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/LegalconsenthubMiddlewareApplication.kt b/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/LegalconsenthubMiddlewareApplication.kt deleted file mode 100644 index 67303e4..0000000 --- a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/LegalconsenthubMiddlewareApplication.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.betriebsratkanzlei.legalconsenthub_middleware - -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.boot.runApplication - -@SpringBootApplication -class LegalconsenthubMiddlewareApplication - -fun main(args: Array) { - runApplication(*args) -} diff --git a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/exception/GlobalExceptionHandler.kt b/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/exception/GlobalExceptionHandler.kt deleted file mode 100644 index ba00be7..0000000 --- a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/exception/GlobalExceptionHandler.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.betriebsratkanzlei.legalconsenthub_middleware.exception - -import com.betriebsratkanzlei.legalconsenthub_middleware.smartcard.SmartCardNotFoundException -import com.betriebsratkanzlei.legalconsenthub_middleware.smartcard.SmartCardReadException -import com.betriebsratkanzlei.legalconsenthub_middleware.smartcard.SmartCardUnavailableException -import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.ExceptionHandler -import org.springframework.web.bind.annotation.RestControllerAdvice -import java.time.Instant - -@RestControllerAdvice -class GlobalExceptionHandler { - - @ExceptionHandler(SmartCardNotFoundException::class) - fun handleSmartCardNotFoundException(ex: SmartCardNotFoundException): ResponseEntity> { - val problem = mutableMapOf() - problem["type"] = "https://problems-registry.smartbear.com/not-found" - problem["title"] = "Smart Card Not Found" - problem["status"] = HttpStatus.NOT_FOUND.value() - problem["detail"] = ex.message ?: "Smart card not found" - problem["instance"] = "/smart-card/info" - problem["timestamp"] = Instant.now().toString() - - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .header("Content-Type", "application/problem+json") - .body(problem) - } - - @ExceptionHandler(SmartCardReadException::class) - fun handleSmartCardReadException(ex: SmartCardReadException): ResponseEntity> { - val problem = mutableMapOf() - problem["type"] = "https://problems-registry.smartbear.com/server-error" - problem["title"] = "Smart Card Read Error" - problem["status"] = HttpStatus.INTERNAL_SERVER_ERROR.value() - problem["detail"] = ex.message ?: "Error reading smart card" - problem["instance"] = "/smart-card/info" - problem["timestamp"] = Instant.now().toString() - - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .header("Content-Type", "application/problem+json") - .body(problem) - } - - @ExceptionHandler(SmartCardUnavailableException::class) - fun handleSmartCardUnavailableException(ex: SmartCardUnavailableException): ResponseEntity> { - val problem = mutableMapOf() - problem["type"] = "https://problems-registry.smartbear.com/service-unavailable" - problem["title"] = "Smart Card Service Unavailable" - problem["status"] = HttpStatus.SERVICE_UNAVAILABLE.value() - problem["detail"] = ex.message ?: "Smart card service unavailable" - problem["instance"] = "/smart-card/info" - problem["timestamp"] = Instant.now().toString() - - return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE) - .header("Content-Type", "application/problem+json") - .body(problem) - } - - @ExceptionHandler(Exception::class) - fun handleGenericException(ex: Exception): ResponseEntity> { - val problem = mutableMapOf() - problem["type"] = "about:blank" - problem["title"] = "Internal Server Error" - problem["status"] = HttpStatus.INTERNAL_SERVER_ERROR.value() - problem["detail"] = "An unexpected error occurred: ${ex.message ?: "Unknown error"}" - problem["timestamp"] = Instant.now().toString() - - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .header("Content-Type", "application/problem+json") - .body(problem) - } -} \ No newline at end of file diff --git a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/signature/DummySignatureController.kt b/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/signature/DummySignatureController.kt deleted file mode 100644 index 2df4caf..0000000 --- a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/signature/DummySignatureController.kt +++ /dev/null @@ -1,53 +0,0 @@ -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 { - // 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 { - // 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) - } -} \ No newline at end of file diff --git a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/signature/SignatureController.kt b/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/signature/SignatureController.kt deleted file mode 100644 index a278dd4..0000000 --- a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/signature/SignatureController.kt +++ /dev/null @@ -1,43 +0,0 @@ -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 { - - override fun signPdfHash( - document: MultipartFile, - certificateId: String, - hashAlgorithm: String - ): ResponseEntity { - val signature = signatureService.signPdfHash( - document = document.bytes, - certificateId = certificateId, - hashAlgorithm = hashAlgorithm - ) - return ResponseEntity.ok(signature) - } - - override fun verifySignature( - document: MultipartFile, - signature: String, - certificateId: String?, - hashAlgorithm: String - ): ResponseEntity { - val verificationResult = signatureService.verifySignature( - document = document.bytes, - signature = signature, - certificateId = certificateId, - hashAlgorithm = hashAlgorithm - ) - return ResponseEntity.ok(verificationResult) - } -} diff --git a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/signature/SignatureService.kt b/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/signature/SignatureService.kt deleted file mode 100644 index ef8a051..0000000 --- a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/signature/SignatureService.kt +++ /dev/null @@ -1,65 +0,0 @@ -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 -) { - - fun signPdfHash( - document: ByteArray, - certificateId: String, - hashAlgorithm: String - ): String { - val hashBase64 = smartCardService.calculateHash(document, hashAlgorithm) - - val certificates = smartCardService.getSmartCardCertificates() - certificates.find { it.id == certificateId } - ?: throw IllegalArgumentException("Certificate not found: $certificateId") - - // Sign the hash using smart card (PIN will be entered on device) - return smartCardService.signHash(hashBase64, certificateId) - } - - fun verifySignature( - document: ByteArray, - signature: String, - certificateId: String?, - hashAlgorithm: String - ): VerifySignatureResponseDto { - try { - val certificates = smartCardService.getSmartCardCertificates() - val certificate = if (certificateId != null) { - certificates.find { it.id == certificateId } - ?: throw IllegalArgumentException("Certificate not found: $certificateId") - } else { - // If no specific certificate ID provided, try to find the certificate from the signature - // For now, we'll use the first available certificate - certificates.firstOrNull() - ?: throw IllegalArgumentException("No certificates available for verification") - } - - val isValid = smartCardService.verifySignature(document, signature, certificate.id, hashAlgorithm) - - return VerifySignatureResponseDto( - isValid = isValid, - certificateInfo = certificate, - verificationDetails = "Signature verified using pkcs11-tool with ${hashAlgorithm} algorithm" - ) - - } catch (e: Exception) { - return VerifySignatureResponseDto( - isValid = false, - certificateInfo = null, - verificationDetails = "Verification failed: ${e.message}" - ) - } - } -} diff --git a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/DummySmartCardController.kt b/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/DummySmartCardController.kt deleted file mode 100644 index c5e7078..0000000 --- a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/DummySmartCardController.kt +++ /dev/null @@ -1,51 +0,0 @@ -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 { - // 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> { - // 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) - } -} \ No newline at end of file diff --git a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/SmartCardController.kt b/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/SmartCardController.kt deleted file mode 100644 index 5cc4c50..0000000 --- a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/SmartCardController.kt +++ /dev/null @@ -1,26 +0,0 @@ -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 { - - override fun getSmartCardInfo(): ResponseEntity { - val smartCardInfo = smartCardService.getSmartCardInfo() - return ResponseEntity.ok(smartCardInfo) - } - - override fun getSmartCardCertificates(): ResponseEntity> { - val certificates = smartCardService.getSmartCardCertificates() - return ResponseEntity.ok(certificates) - } -} \ No newline at end of file diff --git a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/SmartCardExceptions.kt b/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/SmartCardExceptions.kt deleted file mode 100644 index 6f53ce2..0000000 --- a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/SmartCardExceptions.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.betriebsratkanzlei.legalconsenthub_middleware.smartcard - -class SmartCardNotFoundException(message: String) : RuntimeException(message) -class SmartCardReadException(message: String, cause: Throwable? = null) : RuntimeException(message, cause) -class SmartCardUnavailableException(message: String) : RuntimeException(message) \ No newline at end of file diff --git a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/SmartCardService.kt b/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/SmartCardService.kt deleted file mode 100644 index 2b4d23e..0000000 --- a/legalconsenthub-middleware/src/main/kotlin/com/betriebsratkanzlei/legalconsenthub_middleware/smartcard/SmartCardService.kt +++ /dev/null @@ -1,283 +0,0 @@ -package com.betriebsratkanzlei.legalconsenthub_middleware.smartcard - -import com.betriebsratkanzlei.legalconsenthub_middleware_api.model.CertificateDto -import com.betriebsratkanzlei.legalconsenthub_middleware_api.model.SmartCardInfoDto -import jakarta.annotation.PostConstruct -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 -import java.io.File -import java.time.LocalDateTime -import java.util.* -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 -) { - - private lateinit var resolvedLibraryPath: String - - @PostConstruct - fun init() { - resolvedLibraryPath = resolveLibraryPath() - } - - - // macOS doesn't allow loading native libraries using classpath URLs. The library needs to be loaded from an absolute file path. - private fun resolveLibraryPath(): String { - val resource = resourceLoader.getResource(openscPkcs11LibPath) - if (!resource.exists()) { - throw IllegalStateException("PKCS11 library not found: $openscPkcs11LibPath") - } - - val tempFile = Files.createTempFile("opensc-pkcs11", ".so").toFile() - tempFile.deleteOnExit() - - resource.inputStream.use { input -> - Files.copy(input, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING) - } - - tempFile.setExecutable(true) - tempFile.setReadable(true) - - return tempFile.absolutePath - } - - fun getSmartCardInfo(): SmartCardInfoDto { - val commandLine = CommandLine.parse("pkcs11-tool --module $resolvedLibraryPath --show-info") - val executor = DefaultExecutor() - val outputStream = ByteArrayOutputStream() - val errorStream = ByteArrayOutputStream() - - executor.streamHandler = PumpStreamHandler(outputStream, errorStream) - - return try { - val exitCode = executor.execute(commandLine) - - if (exitCode == 0) { - val output = outputStream.toString() - parseSmartCardInfo(output) - } else { - val errorOutput = errorStream.toString() - throw SmartCardNotFoundException("No smart card detected: $errorOutput") - } - } catch (e: SmartCardNotFoundException) { - throw e - } catch (e: Exception) { - throw SmartCardReadException("Error reading smart card: ${e.message}", e) - } - } - - fun getSmartCardCertificates(): List { - val commandLine = CommandLine.parse("pkcs11-tool --module $resolvedLibraryPath --list-objects --type cert") - val executor = DefaultExecutor() - val outputStream = ByteArrayOutputStream() - val errorStream = ByteArrayOutputStream() - - executor.streamHandler = PumpStreamHandler(outputStream, errorStream) - - return try { - val exitCode = executor.execute(commandLine) - - if (exitCode == 0) { - val output = outputStream.toString() - parseCertificates(output) - } else { - val errorOutput = errorStream.toString() - throw SmartCardNotFoundException("No smart card detected or no certificates found: $errorOutput") - } - } catch (e: SmartCardNotFoundException) { - throw e - } catch (e: Exception) { - throw SmartCardReadException("Error reading smart card certificates: ${e.message}", e) - } - } - - fun signHash(hash: String, certificateId: String): String { - val hashBytes = Base64.getDecoder().decode(hash) - - val tempFile = File.createTempFile("hash_to_sign", ".bin") - - return try { - tempFile.writeBytes(hashBytes) - - // Build pkcs11-tool command to sign the hash (PIN will be prompted on device) - val commandLine = - CommandLine.parse("pkcs11-tool --module $resolvedLibraryPath --sign --mechanism RSA-PKCS --id $certificateId --input-file ${tempFile.absolutePath}") - - val executor = DefaultExecutor() - val outputStream = ByteArrayOutputStream() - val errorStream = ByteArrayOutputStream() - - executor.streamHandler = PumpStreamHandler(outputStream, errorStream) - - val exitCode = executor.execute(commandLine) - - if (exitCode == 0) { - val signature = outputStream.toByteArray() - Base64.getEncoder().encodeToString(signature) - } else { - val errorOutput = errorStream.toString() - throw RuntimeException("Failed to sign hash: $errorOutput") - } - } catch (e: Exception) { - throw RuntimeException("Error signing hash: ${e.message}", e) - } finally { - if (tempFile.exists()) { - tempFile.delete() - } - } - } - - fun calculateHash(document: ByteArray, hashAlgorithm: String): String { - return try { - val javaHashAlgorithm = when (hashAlgorithm.uppercase()) { - "SHA1" -> "SHA-1" - "SHA256" -> "SHA-256" - "SHA384" -> "SHA-384" - "SHA512" -> "SHA-512" - else -> "SHA-256" - } - - val messageDigest = java.security.MessageDigest.getInstance(javaHashAlgorithm) - val hashBytes = messageDigest.digest(document) - - Base64.getEncoder().encodeToString(hashBytes) - } catch (e: Exception) { - throw RuntimeException("Error calculating hash: ${e.message}", e) - } - } - - fun verifySignature(originalData: ByteArray, signature: String, certificateId: String, hashAlgorithm: String = "SHA256"): Boolean { - return try { - val signatureBytes = Base64.getDecoder().decode(signature) - - // Calculate hash of the original data using the same algorithm that was used for signing - val hashBase64 = calculateHash(originalData, hashAlgorithm) - val hashBytes = Base64.getDecoder().decode(hashBase64) - - val hashFile = File.createTempFile("hash_to_verify", ".bin") - val signatureFile = File.createTempFile("signature_to_verify", ".bin") - - try { - hashFile.writeBytes(hashBytes) - signatureFile.writeBytes(signatureBytes) - - // Verify against the hash, not the original document, since the signature was created from the hash - val verifyCommand = CommandLine.parse("pkcs11-tool --module $resolvedLibraryPath -m RSA-PKCS --verify --id $certificateId --input-file ${hashFile.absolutePath} --signature-file ${signatureFile.absolutePath}") - - val executor = DefaultExecutor() - val outputStream = ByteArrayOutputStream() - val errorStream = ByteArrayOutputStream() - - executor.streamHandler = PumpStreamHandler(outputStream, errorStream) - val exitCode = executor.execute(verifyCommand) - - if (exitCode == 0) { - println("Signature verification successful") - true - } else { - println("Signature verification failed: ${errorStream.toString()}") - false - } - - } finally { - if (hashFile.exists()) hashFile.delete() - if (signatureFile.exists()) signatureFile.delete() - } - } catch (e: Exception) { - println("Error during signature verification: ${e.message}") - // If any error occurs during verification, consider it invalid - false - } - } - - private fun parseSmartCardInfo(output: String): SmartCardInfoDto { - val lines = output.split("\n") - var label = "Unknown" - var serialNumber: String? = null - var manufacturer: String? = null - var model: String? = null - - for (line in lines) { - when { - line.contains("Token label") -> { - label = line.split(":").getOrNull(1)?.trim() ?: "Unknown" - } - - line.contains("Serial number") -> { - serialNumber = line.split(":").getOrNull(1)?.trim() - } - - line.contains("Manufacturer") -> { - manufacturer = line.split(":").getOrNull(1)?.trim() - } - - line.contains("Model") -> { - model = line.split(":").getOrNull(1)?.trim() - } - } - } - - return SmartCardInfoDto( - isPresent = true, - label = label, - serialNumber = serialNumber, - manufacturer = manufacturer, - model = model - ) - } - - private fun parseCertificates(output: String): List { - val certificates = mutableListOf() - val lines = output.split("\n") - - // This is a simplified parser - in reality, you'd need more sophisticated parsing - var currentId: String? = null - var currentLabel: String? = null - - for (line in lines) { - when { - line.contains("Certificate Object") -> { - currentId = UUID.randomUUID().toString() - currentLabel = null - } - - line.contains("label:") -> { - currentLabel = line.split(":").getOrNull(1)?.trim() - } - - line.contains("ID:") -> { - val id = line.split(":").getOrNull(1)?.trim() - if (currentId != null && currentLabel != null) { - certificates.add(createCertificateDto(currentLabel, id)) - } - } - } - } - - return certificates - } - - // TODO: Replace with actual certificate parsing logic - private fun createCertificateDto(label: String, keyId: String?): CertificateDto { - return CertificateDto( - id = keyId ?: "", - subject = label, - issuer = "Unknown Issuer", - validFrom = LocalDateTime.now().minusYears(1), - validTo = LocalDateTime.now().plusYears(3), - keyUsage = listOf("digitalSignature", "keyEncipherment"), - fingerprint = "Unknown" - ) - } -} diff --git a/legalconsenthub-middleware/src/main/resources/application-dummy.yaml b/legalconsenthub-middleware/src/main/resources/application-dummy.yaml deleted file mode 100644 index d5b14ad..0000000 --- a/legalconsenthub-middleware/src/main/resources/application-dummy.yaml +++ /dev/null @@ -1,28 +0,0 @@ -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 \ No newline at end of file diff --git a/legalconsenthub-middleware/src/main/resources/application.yaml b/legalconsenthub-middleware/src/main/resources/application.yaml deleted file mode 100644 index 7976d4c..0000000 --- a/legalconsenthub-middleware/src/main/resources/application.yaml +++ /dev/null @@ -1,29 +0,0 @@ -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 - -#springdoc: -# api-docs: -# path: /v3/api-docs -# swagger-ui: -# path: /swagger-ui.html -# operationsSorter: method - -opensc: - pkcs11: - library: - path: classpath:binaries/opensc-pkcs11.so diff --git a/legalconsenthub-middleware/src/main/resources/binaries/opensc-pkcs11.so b/legalconsenthub-middleware/src/main/resources/binaries/opensc-pkcs11.so deleted file mode 100755 index bed24c5..0000000 Binary files a/legalconsenthub-middleware/src/main/resources/binaries/opensc-pkcs11.so and /dev/null differ