Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d59cb18666 | ||
|
|
a772b4fa09 | ||
|
|
b072c39fd9 | ||
|
|
1bc6b4149c | ||
|
|
5a5a8bb7ba | ||
|
|
b6eca59f23 | ||
|
|
7108424a92 | ||
|
|
400965ffc8 | ||
|
|
1895a04394 | ||
|
|
f8f137a30a | ||
|
|
f6a2d4784b | ||
|
|
526dc9f911 | ||
|
|
cce9f74eb9 | ||
|
|
0e3865618d | ||
|
|
d888ed1ae0 | ||
|
|
99d1b46d97 |
22
Dockerfile
22
Dockerfile
@@ -6,7 +6,6 @@ COPY scripts /scripts
|
|||||||
COPY pipeline /pipeline
|
COPY pipeline /pipeline
|
||||||
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
|
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
|
||||||
#COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/
|
#COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/
|
||||||
COPY build/libs/*.jar app.jar
|
|
||||||
|
|
||||||
ARG VERSION_TAG
|
ARG VERSION_TAG
|
||||||
|
|
||||||
@@ -19,6 +18,10 @@ ENV DOCKER_ENABLE_SECURITY=false \
|
|||||||
PGID=1000 \
|
PGID=1000 \
|
||||||
UMASK=022
|
UMASK=022
|
||||||
|
|
||||||
|
# Create non-root user first
|
||||||
|
RUN addgroup -S stirlingpdfgroup && \
|
||||||
|
adduser -S stirlingpdfuser -G stirlingpdfgroup
|
||||||
|
|
||||||
# JDK for app
|
# JDK for app
|
||||||
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
||||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
||||||
@@ -31,8 +34,6 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
|
|||||||
bash \
|
bash \
|
||||||
curl \
|
curl \
|
||||||
qpdf \
|
qpdf \
|
||||||
shadow \
|
|
||||||
su-exec \
|
|
||||||
openssl \
|
openssl \
|
||||||
openssl-dev \
|
openssl-dev \
|
||||||
openjdk21-jre \
|
openjdk21-jre \
|
||||||
@@ -50,15 +51,16 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
|
|||||||
# uno unoconv and HTML
|
# uno unoconv and HTML
|
||||||
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
||||||
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
||||||
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
|
|
||||||
fc-cache -f -v && \
|
fc-cache -f -v && \
|
||||||
chmod +x /scripts/* && \
|
|
||||||
chmod +x /scripts/init.sh && \
|
|
||||||
# User permissions
|
# User permissions
|
||||||
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
mkdir -p ${HOME} /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /scripts /usr/share/fonts/custom && \
|
||||||
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
chown -R stirlingpdfuser:stirlingpdfgroup ${HOME} /configs /logs /customFiles /pipeline /scripts /usr/share/fonts/custom && \
|
||||||
chown stirlingpdfuser:stirlingpdfgroup /app.jar && \
|
chmod -R 755 ${HOME} /configs /customFiles /pipeline /scripts /usr/share/fonts/custom && \
|
||||||
tesseract --list-langs
|
tesseract --list-langs && \
|
||||||
|
chmod -R 777 /logs
|
||||||
|
|
||||||
|
COPY build/libs/*.jar app.jar
|
||||||
|
RUN chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
||||||
|
|
||||||
EXPOSE 8080/tcp
|
EXPOSE 8080/tcp
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Build the application
|
# Build stage
|
||||||
FROM gradle:8.11-jdk17 AS build
|
FROM gradle:8.11-jdk17 AS build
|
||||||
|
|
||||||
# Set the working directory
|
# Set the working directory
|
||||||
@@ -7,18 +7,20 @@ WORKDIR /app
|
|||||||
# Copy the entire project to the working directory
|
# Copy the entire project to the working directory
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build the application with DOCKER_ENABLE_SECURITY=false
|
# Build the application
|
||||||
RUN DOCKER_ENABLE_SECURITY=true \
|
RUN DOCKER_ENABLE_SECURITY=true \
|
||||||
./gradlew clean build
|
./gradlew clean build
|
||||||
|
|
||||||
# Main stage
|
# Main stage
|
||||||
FROM alpine:3.20.3
|
FROM alpine:3.20.3
|
||||||
|
|
||||||
# Copy necessary files
|
# Create non-root user first
|
||||||
|
RUN addgroup -S stirlingpdfgroup && \
|
||||||
|
adduser -S stirlingpdfuser -G stirlingpdfgroup
|
||||||
|
|
||||||
COPY scripts /scripts
|
COPY scripts /scripts
|
||||||
COPY pipeline /pipeline
|
COPY pipeline /pipeline
|
||||||
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
|
COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
|
||||||
COPY --from=build /app/build/libs/*.jar app.jar
|
|
||||||
|
|
||||||
ARG VERSION_TAG
|
ARG VERSION_TAG
|
||||||
|
|
||||||
@@ -33,11 +35,15 @@ ENV DOCKER_ENABLE_SECURITY=false \
|
|||||||
FAT_DOCKER=true \
|
FAT_DOCKER=true \
|
||||||
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
|
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
|
||||||
|
|
||||||
|
# Create necessary directories with correct permissions
|
||||||
|
RUN mkdir -p ${HOME} /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /scripts /usr/share/fonts/custom && \
|
||||||
|
chown -R stirlingpdfuser:stirlingpdfgroup ${HOME} /configs /logs /customFiles /pipeline /scripts /usr/share/fonts/custom && \
|
||||||
|
chmod -R 755 ${HOME} /configs /logs /customFiles /pipeline /scripts /usr/share/fonts/custom
|
||||||
|
|
||||||
# JDK for app
|
# JDK and other dependencies
|
||||||
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories && \
|
||||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories && \
|
||||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
|
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
||||||
apk upgrade --no-cache -a && \
|
apk upgrade --no-cache -a && \
|
||||||
apk add --no-cache \
|
apk add --no-cache \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
@@ -45,39 +51,29 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
|
|||||||
tini \
|
tini \
|
||||||
bash \
|
bash \
|
||||||
curl \
|
curl \
|
||||||
shadow \
|
|
||||||
su-exec \
|
|
||||||
openssl \
|
openssl \
|
||||||
openssl-dev \
|
openssl-dev \
|
||||||
openjdk21-jre \
|
openjdk21-jre \
|
||||||
# Doc conversion
|
|
||||||
libreoffice \
|
libreoffice \
|
||||||
# pdftohtml
|
|
||||||
poppler-utils \
|
poppler-utils \
|
||||||
# OCR MY PDF (unpaper for descew and other advanced featues)
|
|
||||||
qpdf \
|
qpdf \
|
||||||
tesseract-ocr-data-eng \
|
tesseract-ocr-data-eng \
|
||||||
|
tesseract-ocr-data-fra \
|
||||||
font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra \
|
font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra \
|
||||||
# CV
|
|
||||||
py3-opencv \
|
py3-opencv \
|
||||||
# python3/pip
|
|
||||||
python3 \
|
python3 \
|
||||||
py3-pip && \
|
py3-pip && \
|
||||||
# uno unoconv and HTML
|
|
||||||
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
||||||
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
||||||
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
|
mkdir -p /usr/share/tessdata && \
|
||||||
fc-cache -f -v && \
|
chown -R stirlingpdfuser:stirlingpdfgroup /usr/share/tessdata /usr/share/fonts/opentype/noto && \
|
||||||
chmod +x /scripts/* && \
|
fc-cache -f -v
|
||||||
chmod +x /scripts/init.sh && \
|
|
||||||
# User permissions
|
COPY build/libs/*.jar app.jar
|
||||||
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
RUN chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
||||||
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
|
||||||
chown stirlingpdfuser:stirlingpdfgroup /app.jar && \
|
|
||||||
tesseract --list-langs
|
|
||||||
|
|
||||||
EXPOSE 8080/tcp
|
EXPOSE 8080/tcp
|
||||||
|
|
||||||
# Set user and run command
|
|
||||||
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
||||||
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]
|
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]
|
||||||
@@ -17,7 +17,10 @@ COPY scripts/download-security-jar.sh /scripts/download-security-jar.sh
|
|||||||
COPY scripts/init-without-ocr.sh /scripts/init-without-ocr.sh
|
COPY scripts/init-without-ocr.sh /scripts/init-without-ocr.sh
|
||||||
COPY scripts/installFonts.sh /scripts/installFonts.sh
|
COPY scripts/installFonts.sh /scripts/installFonts.sh
|
||||||
COPY pipeline /pipeline
|
COPY pipeline /pipeline
|
||||||
COPY build/libs/*.jar app.jar
|
|
||||||
|
# Create non-root user first
|
||||||
|
RUN addgroup -S stirlingpdfgroup && \
|
||||||
|
adduser -S stirlingpdfuser -G stirlingpdfgroup
|
||||||
|
|
||||||
# Set up necessary directories and permissions
|
# Set up necessary directories and permissions
|
||||||
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
||||||
@@ -30,18 +33,15 @@ RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /et
|
|||||||
tini \
|
tini \
|
||||||
bash \
|
bash \
|
||||||
curl \
|
curl \
|
||||||
shadow \
|
|
||||||
su-exec \
|
|
||||||
openjdk21-jre && \
|
openjdk21-jre && \
|
||||||
# User permissions
|
# User permissions
|
||||||
mkdir -p /configs /logs /customFiles /usr/share/fonts/opentype/noto && \
|
mkdir -p ${HOME} /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /scripts /usr/share/fonts/custom && \
|
||||||
chmod +x /scripts/*.sh && \
|
chown -R stirlingpdfuser:stirlingpdfgroup ${HOME} /configs /logs /customFiles /pipeline /scripts /usr/share/fonts/custom && \
|
||||||
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
chmod -R 755 ${HOME} /configs /customFiles /pipeline /scripts /usr/share/fonts/custom && \
|
||||||
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /configs /customFiles /pipeline && \
|
chmod -R 777 /logs
|
||||||
chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
|
||||||
|
|
||||||
# Set environment variables
|
COPY build/libs/*.jar app.jar
|
||||||
ENV ENDPOINTS_GROUPS_TO_REMOVE=CLI
|
RUN chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
||||||
|
|
||||||
EXPOSE 8080/tcp
|
EXPOSE 8080/tcp
|
||||||
|
|
||||||
|
|||||||
68
README.md
68
README.md
@@ -191,43 +191,43 @@ Stirling-PDF currently supports 37 languages!
|
|||||||
|
|
||||||
| Language | Progress |
|
| Language | Progress |
|
||||||
| -------------------------------------------- | -------------------------------------- |
|
| -------------------------------------------- | -------------------------------------- |
|
||||||
| Arabic (العربية) (ar_AR) |  |
|
| Arabic (العربية) (ar_AR) |  |
|
||||||
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
||||||
| Basque (Euskara) (eu_ES) |  |
|
| Basque (Euskara) (eu_ES) |  |
|
||||||
| Bulgarian (Български) (bg_BG) |  |
|
| Bulgarian (Български) (bg_BG) |  |
|
||||||
| Catalan (Català) (ca_CA) |  |
|
| Catalan (Català) (ca_CA) |  |
|
||||||
| Croatian (Hrvatski) (hr_HR) |  |
|
| Croatian (Hrvatski) (hr_HR) |  |
|
||||||
| Czech (Česky) (cs_CZ) |  |
|
| Czech (Česky) (cs_CZ) |  |
|
||||||
| Danish (Dansk) (da_DK) |  |
|
| Danish (Dansk) (da_DK) |  |
|
||||||
| Dutch (Nederlands) (nl_NL) |  |
|
| Dutch (Nederlands) (nl_NL) |  |
|
||||||
| English (English) (en_GB) |  |
|
| English (English) (en_GB) |  |
|
||||||
| English (US) (en_US) |  |
|
| English (US) (en_US) |  |
|
||||||
| French (Français) (fr_FR) |  |
|
| French (Français) (fr_FR) |  |
|
||||||
| German (Deutsch) (de_DE) |  |
|
| German (Deutsch) (de_DE) |  |
|
||||||
| Greek (Ελληνικά) (el_GR) |  |
|
| Greek (Ελληνικά) (el_GR) |  |
|
||||||
| Hindi (हिंदी) (hi_IN) |  |
|
| Hindi (हिंदी) (hi_IN) |  |
|
||||||
| Hungarian (Magyar) (hu_HU) |  |
|
| Hungarian (Magyar) (hu_HU) |  |
|
||||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||||
| Irish (Gaeilge) (ga_IE) |  |
|
| Irish (Gaeilge) (ga_IE) |  |
|
||||||
| Italian (Italiano) (it_IT) |  |
|
| Italian (Italiano) (it_IT) |  |
|
||||||
| Japanese (日本語) (ja_JP) |  |
|
| Japanese (日本語) (ja_JP) |  |
|
||||||
| Korean (한국어) (ko_KR) |  |
|
| Korean (한국어) (ko_KR) |  |
|
||||||
| Norwegian (Norsk) (no_NB) |  |
|
| Norwegian (Norsk) (no_NB) |  |
|
||||||
| Polish (Polski) (pl_PL) |  |
|
| Polish (Polski) (pl_PL) |  |
|
||||||
| Portuguese (Português) (pt_PT) |  |
|
| Portuguese (Português) (pt_PT) |  |
|
||||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||||
| Romanian (Română) (ro_RO) |  |
|
| Romanian (Română) (ro_RO) |  |
|
||||||
| Russian (Русский) (ru_RU) |  |
|
| Russian (Русский) (ru_RU) |  |
|
||||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||||
| Slovakian (Slovensky) (sk_SK) |  |
|
| Slovakian (Slovensky) (sk_SK) |  |
|
||||||
| Spanish (Español) (es_ES) |  |
|
| Spanish (Español) (es_ES) |  |
|
||||||
| Swedish (Svenska) (sv_SE) |  |
|
| Swedish (Svenska) (sv_SE) |  |
|
||||||
| Thai (ไทย) (th_TH) |  |
|
| Thai (ไทย) (th_TH) |  |
|
||||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||||
| Turkish (Türkçe) (tr_TR) |  |
|
| Turkish (Türkçe) (tr_TR) |  |
|
||||||
| Ukrainian (Українська) (uk_UA) |  |
|
| Ukrainian (Українська) (uk_UA) |  |
|
||||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||||
|
|
||||||
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)
|
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "stirling.software"
|
group = "stirling.software"
|
||||||
version = "0.35.1"
|
version = "0.36.0"
|
||||||
|
|
||||||
|
|
||||||
java {
|
java {
|
||||||
|
|||||||
@@ -14,14 +14,17 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/tessdata:rw
|
- ./stirling/latest/data:/usr/share/tessdata:rw
|
||||||
- /stirling/latest/config:/configs:rw
|
- ./stirling/latest/config:/configs:rw
|
||||||
- /stirling/latest/logs:/logs:rw
|
- ./stirling/latest/logs:/logs:rw
|
||||||
|
user: "stirlingpdfuser"
|
||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "false"
|
SECURITY_ENABLELOGIN: "false"
|
||||||
PUID: 1002
|
PUID: 1002
|
||||||
PGID: 1002
|
PGID: 1002
|
||||||
|
LANGS: "ALL"
|
||||||
|
TESSERACT_LANGS: "eng,fra,deu,spa,ita"
|
||||||
UMASK: "022"
|
UMASK: "022"
|
||||||
SYSTEM_DEFAULTLOCALE: en-US
|
SYSTEM_DEFAULTLOCALE: en-US
|
||||||
UI_APPNAME: Stirling-PDF
|
UI_APPNAME: Stirling-PDF
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/tessdata:rw
|
- ./stirling/latest/data:/usr/share/tessdata:rw
|
||||||
- /stirling/latest/config:/configs:rw
|
- ./stirling/latest/config:/configs:rw
|
||||||
- /stirling/latest/logs:/logs:rw
|
- ./stirling/latest/logs:/logs:rw
|
||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "true"
|
SECURITY_ENABLELOGIN: "true"
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/tessdata:rw
|
- ./stirling/latest/data:/usr/share/tessdata:rw
|
||||||
- /stirling/latest/config:/configs:rw
|
- ./stirling/latest/config:/configs:rw
|
||||||
- /stirling/latest/logs:/logs:rw
|
- ./stirling/latest/logs:/logs:rw
|
||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "true"
|
SECURITY_ENABLELOGIN: "true"
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/tessdata:rw
|
- ./stirling/latest/data:/usr/share/tessdata:rw
|
||||||
- /stirling/latest/config:/configs:rw
|
- ./stirling/latest/config:/configs:rw
|
||||||
- /stirling/latest/logs:/logs:rw
|
- ./stirling/latest/logs:/logs:rw
|
||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "true"
|
SECURITY_ENABLELOGIN: "true"
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/config:/configs:rw
|
- ./stirling/latest/config:/configs:rw
|
||||||
- /stirling/latest/logs:/logs:rw
|
- ./stirling/latest/logs:/logs:rw
|
||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "false"
|
DOCKER_ENABLE_SECURITY: "false"
|
||||||
SECURITY_ENABLELOGIN: "false"
|
SECURITY_ENABLELOGIN: "false"
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- /stirling/latest/data:/usr/share/tessdata:rw
|
- ./stirling/latest/data:/usr/share/tessdata:rw
|
||||||
- /stirling/latest/config:/configs:rw
|
- ./stirling/latest/config:/configs:rw
|
||||||
- /stirling/latest/logs:/logs:rw
|
- ./stirling/latest/logs:/logs:rw
|
||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "false"
|
DOCKER_ENABLE_SECURITY: "false"
|
||||||
SECURITY_ENABLELOGIN: "false"
|
SECURITY_ENABLELOGIN: "false"
|
||||||
|
|||||||
@@ -42,14 +42,19 @@ ignore = [
|
|||||||
'addPageNumbers.selectText.3',
|
'addPageNumbers.selectText.3',
|
||||||
'alphabet',
|
'alphabet',
|
||||||
'certSign.name',
|
'certSign.name',
|
||||||
|
'fileChooser.dragAndDrop',
|
||||||
'home.pipeline.title',
|
'home.pipeline.title',
|
||||||
'language.direction',
|
'language.direction',
|
||||||
|
'legal.impressum',
|
||||||
'licenses.version',
|
'licenses.version',
|
||||||
'pipeline.title',
|
'pipeline.title',
|
||||||
'pipelineOptions.pipelineHeader',
|
'pipelineOptions.pipelineHeader',
|
||||||
'pro',
|
'pro',
|
||||||
'sponsor',
|
'sponsor',
|
||||||
'text',
|
'text',
|
||||||
|
'validateSignature.cert.bits',
|
||||||
|
'validateSignature.cert.version',
|
||||||
|
'validateSignature.status',
|
||||||
'watermark.type.1',
|
'watermark.type.1',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Update the user and group IDs as per environment variables
|
|
||||||
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
|
|
||||||
usermod -o -u "$PUID" stirlingpdfuser || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -f3)" ]; then
|
|
||||||
groupmod -o -g "$PGID" stirlingpdfgroup || true
|
|
||||||
fi
|
|
||||||
umask "$UMASK" || true
|
|
||||||
|
|
||||||
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" && "$FAT_DOCKER" != "true" ]]; then
|
|
||||||
echo "issue with calibre in current version, feature currently disabled on Stirling-PDF"
|
|
||||||
#apk add --no-cache calibre@testing
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$FAT_DOCKER" != "true" ]]; then
|
if [[ "$FAT_DOCKER" != "true" ]]; then
|
||||||
/scripts/download-security-jar.sh
|
/scripts/download-security-jar.sh
|
||||||
fi
|
fi
|
||||||
@@ -24,14 +8,4 @@ if [[ -n "$LANGS" ]]; then
|
|||||||
/scripts/installFonts.sh $LANGS
|
/scripts/installFonts.sh $LANGS
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Setting permissions and ownership for necessary directories..."
|
|
||||||
# Attempt to change ownership of directories and files
|
|
||||||
if chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline /app.jar; then
|
|
||||||
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline /app.jar || true
|
|
||||||
# If chown succeeds, execute the command as stirlingpdfuser
|
|
||||||
exec su-exec stirlingpdfuser "$@"
|
|
||||||
else
|
|
||||||
# If chown fails, execute the command without changing the user context
|
|
||||||
echo "[WARN] Chown failed, running as host user"
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
fi
|
|
||||||
|
|||||||
@@ -1,27 +1,35 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Copy the original tesseract-ocr files to the volume directory without overwriting existing files
|
# Copy the original tesseract-ocr files to the volume directory without overwriting existing files
|
||||||
echo "Copying original files without overwriting existing files"
|
echo "Copying original files without overwriting existing files"
|
||||||
mkdir -p /usr/share/tessdata
|
cp -rn /usr/share/tessdata-original/* /usr/share/tessdata 2>/dev/null || true
|
||||||
cp -rn /usr/share/tessdata-original/* /usr/share/tessdata
|
|
||||||
|
|
||||||
|
# Copy additional tessdata if available
|
||||||
if [ -d /usr/share/tesseract-ocr/4.00/tessdata ]; then
|
if [ -d /usr/share/tesseract-ocr/4.00/tessdata ]; then
|
||||||
cp -r /usr/share/tesseract-ocr/4.00/tessdata/* /usr/share/tessdata || true;
|
cp -rn /usr/share/tesseract-ocr/4.00/tessdata/* /usr/share/tessdata 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -d /usr/share/tesseract-ocr/5/tessdata ]; then
|
if [ -d /usr/share/tesseract-ocr/5/tessdata ]; then
|
||||||
cp -r /usr/share/tesseract-ocr/5/tessdata/* /usr/share/tessdata || true;
|
cp -rn /usr/share/tesseract-ocr/5/tessdata/* /usr/share/tessdata 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if TESSERACT_LANGS environment variable is set and is not empty
|
# Check if TESSERACT_LANGS environment variable is set and is not empty
|
||||||
if [[ -n "$TESSERACT_LANGS" ]]; then
|
if [[ -n "$TESSERACT_LANGS" ]]; then
|
||||||
# Convert comma-separated values to a space-separated list
|
# Convert comma-separated values to a space-separated list
|
||||||
LANGS=$(echo $TESSERACT_LANGS | tr ',' ' ')
|
TES_LANGS=$(echo $TESSERACT_LANGS | tr ',' ' ')
|
||||||
pattern='^[a-zA-Z]{2,4}(_[a-zA-Z]{2,4})?$'
|
pattern='^[a-zA-Z]{2,4}(_[a-zA-Z]{2,4})?$'
|
||||||
# Install each language pack
|
|
||||||
for LANG in $LANGS; do
|
# Log available languages
|
||||||
|
echo "Currently installed languages:"
|
||||||
|
tesseract --list-langs
|
||||||
|
|
||||||
|
echo "Requested additional languages: $TES_LANGS"
|
||||||
|
|
||||||
|
# Instead of apk add, download language files from a known source
|
||||||
|
for LANG in $TES_LANGS; do
|
||||||
if [[ $LANG =~ $pattern ]]; then
|
if [[ $LANG =~ $pattern ]]; then
|
||||||
apk add --no-cache "tesseract-ocr-data-$LANG"
|
# Download to user-writable directory
|
||||||
|
wget -P /usr/share/tessdata/ "https://github.com/tesseract-ocr/tessdata/raw/main/${LANG}.traineddata" || \
|
||||||
|
echo "Failed to download language pack for ${LANG}"
|
||||||
else
|
else
|
||||||
echo "Skipping invalid language code"
|
echo "Skipping invalid language code"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,67 +1,156 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
LANGS=$1
|
LANGS=$1
|
||||||
|
FONT_DIR="$HOME/.local/share/fonts"
|
||||||
|
TEMP_DIR=$(mktemp -d)
|
||||||
|
|
||||||
# Function to install a font package
|
# Create fonts directory if it doesn't exist
|
||||||
install_font() {
|
mkdir -p "$FONT_DIR"
|
||||||
echo "Installing font package: $1"
|
|
||||||
if ! apk add "$1" --no-cache; then
|
# Function to get latest GitHub release
|
||||||
echo "Failed to install $1"
|
get_latest_release() {
|
||||||
fi
|
local repo=$1
|
||||||
|
local api_url="https://api.github.com/repos/$repo/releases/latest"
|
||||||
|
curl --silent "$api_url" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Install common fonts used across many languages
|
# Function to download and install a font
|
||||||
#common_fonts=(
|
install_font() {
|
||||||
# font-terminus
|
local font_name=$1
|
||||||
# font-dejavu
|
echo "Installing font package: $font_name"
|
||||||
# font-noto
|
|
||||||
# font-noto-cjk
|
|
||||||
# font-awesome
|
|
||||||
# font-noto-extra
|
|
||||||
#)
|
|
||||||
#
|
|
||||||
#for font in "${common_fonts[@]}"; do
|
|
||||||
# install_font $font
|
|
||||||
#done
|
|
||||||
|
|
||||||
# Map languages to specific font packages
|
# Map font package names to actual font URLs and installation methods
|
||||||
|
case $font_name in
|
||||||
|
"font-dejavu")
|
||||||
|
local version=$(get_latest_release "dejavu-fonts/dejavu-fonts")
|
||||||
|
version=${version#version_} # Remove 'version_' prefix
|
||||||
|
local url="https://github.com/dejavu-fonts/dejavu-fonts/releases/download/version_${version}/dejavu-fonts-ttf-${version}.tar.bz2"
|
||||||
|
wget -q "$url" -P "$TEMP_DIR" && \
|
||||||
|
tar xjf "$TEMP_DIR/dejavu-fonts-ttf-${version}.tar.bz2" -C "$TEMP_DIR" && \
|
||||||
|
find "$TEMP_DIR" -name "*.ttf" -exec cp {} "$FONT_DIR/" \;
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto")
|
||||||
|
# Base Noto Sans and Serif
|
||||||
|
wget -q "https://noto-website-2.storage.googleapis.com/pkgs/NotoSans-hinted.zip" -P "$TEMP_DIR" && \
|
||||||
|
wget -q "https://noto-website-2.storage.googleapis.com/pkgs/NotoSerif-hinted.zip" -P "$TEMP_DIR" && \
|
||||||
|
unzip -q "$TEMP_DIR/NotoSans-hinted.zip" -d "$TEMP_DIR/noto-sans" && \
|
||||||
|
unzip -q "$TEMP_DIR/NotoSerif-hinted.zip" -d "$TEMP_DIR/noto-serif" && \
|
||||||
|
cp "$TEMP_DIR/noto-sans"/*.ttf "$FONT_DIR/" && \
|
||||||
|
cp "$TEMP_DIR/noto-serif"/*.ttf "$FONT_DIR/"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto-cjk")
|
||||||
|
# Noto CJK
|
||||||
|
wget -q "https://github.com/notofonts/noto-cjk/raw/main/Sans/OTF/Japanese/NotoSansCJKjp-Regular.otf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-cjk/raw/main/Sans/OTF/Korean/NotoSansCJKkr-Regular.otf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-cjk/raw/main/Sans/OTF/SimplifiedChinese/NotoSansCJKsc-Regular.otf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-cjk/raw/main/Sans/OTF/TraditionalChinese/NotoSansCJKtc-Regular.otf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto-arabic")
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoNaskhArabic/NotoNaskhArabic-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoKufiArabic/NotoKufiArabic-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto-devanagari")
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSansDevanagari/NotoSansDevanagari-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSerifDevanagari/NotoSerifDevanagari-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto-thai")
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSansThai/NotoSansThai-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSerifThai/NotoSerifThai-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-noto-hebrew")
|
||||||
|
wget -q "https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSansHebrew/NotoSansHebrew-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-awesome")
|
||||||
|
local version=$(get_latest_release "FortAwesome/Font-Awesome")
|
||||||
|
wget -q "https://use.fontawesome.com/releases/v${version}/fontawesome-free-${version}-desktop.zip" -P "$TEMP_DIR" && \
|
||||||
|
unzip -q "$TEMP_DIR/fontawesome-free-${version}-desktop.zip" -d "$TEMP_DIR" && \
|
||||||
|
cp "$TEMP_DIR/fontawesome-free-${version}-desktop/otfs"/*.otf "$FONT_DIR/"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-source-code-pro")
|
||||||
|
local version=$(get_latest_release "adobe-fonts/source-code-pro")
|
||||||
|
wget -q "https://github.com/adobe-fonts/source-code-pro/releases/download/${version}/TTF-source-code-pro-${version}.zip" -P "$TEMP_DIR" && \
|
||||||
|
unzip -q "$TEMP_DIR/TTF-source-code-pro-${version}.zip" -d "$TEMP_DIR/source-code-pro" && \
|
||||||
|
cp "$TEMP_DIR/source-code-pro"/*.ttf "$FONT_DIR/"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-vollkorn")
|
||||||
|
wget -q "https://github.com/FAlthausen/Vollkorn-Typeface/raw/main/fonts/TTF/Vollkorn-Regular.ttf" -P "$FONT_DIR"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"font-liberation")
|
||||||
|
wget -q "https://github.com/liberationfonts/liberation-fonts/files/7261482/liberation-fonts-ttf-2.1.5.tar.gz" -P "$TEMP_DIR" && \
|
||||||
|
tar xzf "$TEMP_DIR/liberation-fonts-ttf-2.1.5.tar.gz" -C "$TEMP_DIR" && \
|
||||||
|
cp "$TEMP_DIR/liberation-fonts-ttf-2.1.5"/*.ttf "$FONT_DIR/"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "Completed installation attempt for $font_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Enhanced language-specific font mappings
|
||||||
declare -A language_fonts=(
|
declare -A language_fonts=(
|
||||||
["ar_AR"]="font-noto-arabic"
|
["ar_AR"]="font-noto-arabic"
|
||||||
["zh_CN"]="font-isas-misc"
|
["zh_CN"]="font-noto-cjk"
|
||||||
["zh_TW"]="font-isas-misc"
|
["zh_TW"]="font-noto-cjk"
|
||||||
["ja_JP"]="font-noto font-noto-thai font-noto-tibetan font-ipa font-sony-misc font-jis-misc"
|
["ja_JP"]="font-noto font-noto-cjk"
|
||||||
["ru_RU"]="font-vollkorn font-misc-cyrillic font-mutt-misc font-screen-cyrillic font-winitzki-cyrillic font-cronyx-cyrillic"
|
["ru_RU"]="font-noto font-liberation font-vollkorn"
|
||||||
["sr_LATN_RS"]="font-vollkorn font-misc-cyrillic font-mutt-misc font-screen-cyrillic font-winitzki-cyrillic font-cronyx-cyrillic"
|
["sr_LATN_RS"]="font-noto font-liberation"
|
||||||
["uk_UA"]="font-vollkorn font-misc-cyrillic font-mutt-misc font-screen-cyrillic font-winitzki-cyrillic font-cronyx-cyrillic"
|
["uk_UA"]="font-noto font-liberation"
|
||||||
["ko_KR"]="font-noto font-noto-thai font-noto-tibetan"
|
["ko_KR"]="font-noto font-noto-cjk"
|
||||||
["el_GR"]="font-noto"
|
["el_GR"]="font-noto"
|
||||||
["hi_IN"]="font-noto-devanagari"
|
["hi_IN"]="font-noto-devanagari"
|
||||||
["bg_BG"]="font-vollkorn font-misc-cyrillic"
|
["bg_BG"]="font-noto font-liberation"
|
||||||
["GENERAL"]="font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra"
|
["th_TH"]="font-noto-thai"
|
||||||
|
["he_IL"]="font-noto-hebrew"
|
||||||
|
["GENERAL"]="font-noto font-dejavu font-liberation font-source-code-pro font-awesome"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Install fonts for other languages which generally do not need special packages beyond 'font-noto'
|
# Install fonts based on specified languages
|
||||||
other_langs=("en_GB" "en_US" "de_DE" "fr_FR" "es_ES" "ca_CA" "it_IT" "pt_BR" "nl_NL" "sv_SE" "pl_PL" "ro_RO" "hu_HU" "tr_TR" "id_ID" "eu_ES")
|
|
||||||
if [[ $LANGS == "ALL" ]]; then
|
if [[ $LANGS == "ALL" ]]; then
|
||||||
# Install all fonts from the language_fonts map
|
# Install all fonts from the language_fonts map
|
||||||
|
declare -A installed_fonts
|
||||||
for fonts in "${language_fonts[@]}"; do
|
for fonts in "${language_fonts[@]}"; do
|
||||||
for font in $fonts; do
|
for font in $fonts; do
|
||||||
install_font $font
|
if [[ -z "${installed_fonts[$font]}" ]]; then
|
||||||
|
install_font "$font"
|
||||||
|
installed_fonts[$font]=1
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
# Split comma-separated languages and install necessary fonts
|
# Split comma-separated languages and install necessary fonts
|
||||||
|
declare -A installed_fonts
|
||||||
IFS=',' read -ra LANG_CODES <<< "$LANGS"
|
IFS=',' read -ra LANG_CODES <<< "$LANGS"
|
||||||
for code in "${LANG_CODES[@]}"; do
|
for code in "${LANG_CODES[@]}"; do
|
||||||
if [[ " ${other_langs[@]} " =~ " ${code} " ]]; then
|
|
||||||
install_font font-noto
|
|
||||||
else
|
|
||||||
fonts_to_install=${language_fonts[$code]}
|
fonts_to_install=${language_fonts[$code]}
|
||||||
if [ ! -z "$fonts_to_install" ]; then
|
if [ ! -z "$fonts_to_install" ]; then
|
||||||
for font in $fonts_to_install; do
|
for font in $fonts_to_install; do
|
||||||
install_font $font
|
if [[ -z "${installed_fonts[$font]}" ]]; then
|
||||||
done
|
install_font "$font"
|
||||||
fi
|
installed_fonts[$font]=1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
rm -rf "$TEMP_DIR"
|
||||||
|
|
||||||
|
# Update font cache
|
||||||
|
if command -v fc-cache >/dev/null; then
|
||||||
|
fc-cache -f "$FONT_DIR"
|
||||||
|
echo "Font cache updated"
|
||||||
|
else
|
||||||
|
echo "Warning: fc-cache not found. You may need to manually update your font cache"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Font installation completed. Fonts installed in: $FONT_DIR"
|
||||||
@@ -28,7 +28,7 @@ public class LicenseKeyChecker {
|
|||||||
this.checkLicense();
|
this.checkLicense();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(fixedRate = 604800000) // 7 days in milliseconds
|
@Scheduled(initialDelay = 604800000, fixedRate = 604800000) // 7 days in milliseconds
|
||||||
public void checkLicensePeriodically() {
|
public void checkLicensePeriodically() {
|
||||||
checkLicense();
|
checkLicense();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package stirling.software.SPDF.config.security;
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -13,7 +12,6 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.context.annotation.DependsOn;
|
import org.springframework.context.annotation.DependsOn;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.authentication.ProviderManager;
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
@@ -32,35 +30,21 @@ import org.springframework.security.oauth2.client.registration.InMemoryClientReg
|
|||||||
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
|
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
|
||||||
import org.springframework.security.saml2.core.Saml2X509Credential;
|
import org.springframework.security.saml2.core.Saml2X509Credential;
|
||||||
import org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType;
|
import org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
|
|
||||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
|
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
|
||||||
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
|
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
|
||||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||||
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
|
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
|
||||||
import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository;
|
|
||||||
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
|
|
||||||
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
|
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||||
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
|
|
||||||
import org.springframework.security.web.context.SecurityContextHolderFilter;
|
|
||||||
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
||||||
import org.springframework.security.web.savedrequest.NullRequestCache;
|
import org.springframework.security.web.savedrequest.NullRequestCache;
|
||||||
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
|
|
||||||
import org.springframework.security.web.session.HttpSessionEventPublisher;
|
|
||||||
import org.springframework.security.web.session.SessionManagementFilter;
|
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
import org.springframework.session.web.http.CookieSerializer;
|
|
||||||
import org.springframework.session.web.http.DefaultCookieSerializer;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
import jakarta.servlet.FilterChain;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
|
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
|
||||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
|
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
|
||||||
@@ -287,7 +271,6 @@ public class SecurityConfiguration {
|
|||||||
relyingPartyRegistrations())
|
relyingPartyRegistrations())
|
||||||
.authenticationManager(
|
.authenticationManager(
|
||||||
new ProviderManager(authenticationProvider))
|
new ProviderManager(authenticationProvider))
|
||||||
|
|
||||||
.successHandler(
|
.successHandler(
|
||||||
new CustomSaml2AuthenticationSuccessHandler(
|
new CustomSaml2AuthenticationSuccessHandler(
|
||||||
loginAttemptService,
|
loginAttemptService,
|
||||||
|
|||||||
@@ -322,27 +322,14 @@ public class GetInfoOnPDF {
|
|||||||
PDEncryption pdfEncryption = pdfBoxDoc.getEncryption();
|
PDEncryption pdfEncryption = pdfBoxDoc.getEncryption();
|
||||||
encryption.put("EncryptionAlgorithm", pdfEncryption.getFilter());
|
encryption.put("EncryptionAlgorithm", pdfEncryption.getFilter());
|
||||||
encryption.put("KeyLength", pdfEncryption.getLength());
|
encryption.put("KeyLength", pdfEncryption.getLength());
|
||||||
AccessPermission ap = pdfBoxDoc.getCurrentAccessPermission();
|
|
||||||
if (ap != null) {
|
|
||||||
ObjectNode permissionsNode = objectMapper.createObjectNode();
|
|
||||||
|
|
||||||
permissionsNode.put("CanAssembleDocument", ap.canAssembleDocument());
|
|
||||||
permissionsNode.put("CanExtractContent", ap.canExtractContent());
|
|
||||||
permissionsNode.put(
|
|
||||||
"CanExtractForAccessibility", ap.canExtractForAccessibility());
|
|
||||||
permissionsNode.put("CanFillInForm", ap.canFillInForm());
|
|
||||||
permissionsNode.put("CanModify", ap.canModify());
|
|
||||||
permissionsNode.put("CanModifyAnnotations", ap.canModifyAnnotations());
|
|
||||||
permissionsNode.put("CanPrint", ap.canPrint());
|
|
||||||
|
|
||||||
encryption.set(
|
|
||||||
"Permissions", permissionsNode); // set the node under "Permissions"
|
|
||||||
}
|
|
||||||
// Add other encryption-related properties as needed
|
// Add other encryption-related properties as needed
|
||||||
} else {
|
} else {
|
||||||
encryption.put("IsEncrypted", false);
|
encryption.put("IsEncrypted", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjectNode permissionsNode = objectMapper.createObjectNode();
|
||||||
|
setNodePermissions(pdfBoxDoc, permissionsNode);
|
||||||
|
|
||||||
ObjectNode pageInfoParent = objectMapper.createObjectNode();
|
ObjectNode pageInfoParent = objectMapper.createObjectNode();
|
||||||
for (int pageNum = 0; pageNum < pdfBoxDoc.getNumberOfPages(); pageNum++) {
|
for (int pageNum = 0; pageNum < pdfBoxDoc.getNumberOfPages(); pageNum++) {
|
||||||
ObjectNode pageInfo = objectMapper.createObjectNode();
|
ObjectNode pageInfo = objectMapper.createObjectNode();
|
||||||
@@ -584,6 +571,7 @@ public class GetInfoOnPDF {
|
|||||||
jsonOutput.set("DocumentInfo", docInfoNode);
|
jsonOutput.set("DocumentInfo", docInfoNode);
|
||||||
jsonOutput.set("Compliancy", compliancy);
|
jsonOutput.set("Compliancy", compliancy);
|
||||||
jsonOutput.set("Encryption", encryption);
|
jsonOutput.set("Encryption", encryption);
|
||||||
|
jsonOutput.set("Permissions", permissionsNode); // set the node under "Permissions"
|
||||||
jsonOutput.set("Other", other);
|
jsonOutput.set("Other", other);
|
||||||
jsonOutput.set("PerPageInfo", pageInfoParent);
|
jsonOutput.set("PerPageInfo", pageInfoParent);
|
||||||
|
|
||||||
@@ -602,6 +590,24 @@ public class GetInfoOnPDF {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setNodePermissions(PDDocument pdfBoxDoc, ObjectNode permissionsNode) {
|
||||||
|
AccessPermission ap = pdfBoxDoc.getCurrentAccessPermission();
|
||||||
|
|
||||||
|
permissionsNode.put("Document Assembly", getPermissionState(ap.canAssembleDocument()));
|
||||||
|
permissionsNode.put("Extracting Content", getPermissionState(ap.canExtractContent()));
|
||||||
|
permissionsNode.put(
|
||||||
|
"Extracting for accessibility",
|
||||||
|
getPermissionState(ap.canExtractForAccessibility()));
|
||||||
|
permissionsNode.put("Form Filling", getPermissionState(ap.canFillInForm()));
|
||||||
|
permissionsNode.put("Modifying", getPermissionState(ap.canModify()));
|
||||||
|
permissionsNode.put("Modifying annotations", getPermissionState(ap.canModifyAnnotations()));
|
||||||
|
permissionsNode.put("Printing", getPermissionState(ap.canPrint()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPermissionState(boolean state) {
|
||||||
|
return state ? "Allowed" : "Not Allowed";
|
||||||
|
}
|
||||||
|
|
||||||
private static void addOutlinesToArray(PDOutlineItem outline, ArrayNode arrayNode) {
|
private static void addOutlinesToArray(PDOutlineItem outline, ArrayNode arrayNode) {
|
||||||
if (outline == null) return;
|
if (outline == null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
package stirling.software.SPDF.controller.api.security;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateExpiredException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.CertificateNotYetValidException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
|
||||||
|
import org.bouncycastle.cert.X509CertificateHolder;
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||||
|
import org.bouncycastle.cms.CMSProcessable;
|
||||||
|
import org.bouncycastle.cms.CMSProcessableByteArray;
|
||||||
|
import org.bouncycastle.cms.CMSSignedData;
|
||||||
|
import org.bouncycastle.cms.SignerInformation;
|
||||||
|
import org.bouncycastle.cms.SignerInformationStore;
|
||||||
|
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
|
||||||
|
import org.bouncycastle.util.Store;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.api.security.SignatureValidationRequest;
|
||||||
|
import stirling.software.SPDF.model.api.security.SignatureValidationResult;
|
||||||
|
import stirling.software.SPDF.service.CertificateValidationService;
|
||||||
|
import stirling.software.SPDF.service.CustomPDDocumentFactory;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/security")
|
||||||
|
@Tag(name = "Security", description = "Security APIs")
|
||||||
|
public class ValidateSignatureController {
|
||||||
|
private final CustomPDDocumentFactory pdfDocumentFactory;
|
||||||
|
private final CertificateValidationService certValidationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ValidateSignatureController(
|
||||||
|
CustomPDDocumentFactory pdfDocumentFactory,
|
||||||
|
CertificateValidationService certValidationService) {
|
||||||
|
this.pdfDocumentFactory = pdfDocumentFactory;
|
||||||
|
this.certValidationService = certValidationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Validate PDF Digital Signature",
|
||||||
|
description =
|
||||||
|
"Validates digital signatures in a PDF file against default or custom certificates.")
|
||||||
|
@PostMapping(value = "/validate-signature")
|
||||||
|
public ResponseEntity<List<SignatureValidationResult>> validateSignature(
|
||||||
|
@ModelAttribute SignatureValidationRequest request) throws IOException {
|
||||||
|
List<SignatureValidationResult> results = new ArrayList<>();
|
||||||
|
MultipartFile file = request.getFileInput();
|
||||||
|
|
||||||
|
// Load custom certificate if provided
|
||||||
|
X509Certificate customCert = null;
|
||||||
|
if (request.getCertFile() != null && !request.getCertFile().isEmpty()) {
|
||||||
|
try (ByteArrayInputStream certStream =
|
||||||
|
new ByteArrayInputStream(request.getCertFile().getBytes())) {
|
||||||
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
|
customCert = (X509Certificate) cf.generateCertificate(certStream);
|
||||||
|
} catch (CertificateException e) {
|
||||||
|
throw new RuntimeException("Invalid certificate file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try (PDDocument document = pdfDocumentFactory.load(file.getInputStream())) {
|
||||||
|
List<PDSignature> signatures = document.getSignatureDictionaries();
|
||||||
|
|
||||||
|
for (PDSignature sig : signatures) {
|
||||||
|
SignatureValidationResult result = new SignatureValidationResult();
|
||||||
|
try {
|
||||||
|
byte[] signedContent = sig.getSignedContent(file.getInputStream());
|
||||||
|
byte[] signatureBytes = sig.getContents(file.getInputStream());
|
||||||
|
|
||||||
|
CMSProcessable content = new CMSProcessableByteArray(signedContent);
|
||||||
|
CMSSignedData signedData = new CMSSignedData(content, signatureBytes);
|
||||||
|
|
||||||
|
Store<X509CertificateHolder> certStore = signedData.getCertificates();
|
||||||
|
SignerInformationStore signerStore = signedData.getSignerInfos();
|
||||||
|
|
||||||
|
for (SignerInformation signer : signerStore.getSigners()) {
|
||||||
|
X509CertificateHolder certHolder =
|
||||||
|
(X509CertificateHolder)
|
||||||
|
certStore.getMatches(signer.getSID()).iterator().next();
|
||||||
|
X509Certificate cert =
|
||||||
|
new JcaX509CertificateConverter().getCertificate(certHolder);
|
||||||
|
|
||||||
|
// Basic signature validation
|
||||||
|
result.setValid(
|
||||||
|
signer.verify(
|
||||||
|
new JcaSimpleSignerInfoVerifierBuilder().build(cert)));
|
||||||
|
|
||||||
|
// Perform chain validation
|
||||||
|
CertificateValidationService.ValidationResult chainResult;
|
||||||
|
if (customCert != null) {
|
||||||
|
chainResult =
|
||||||
|
certValidationService.validateWithCustomCert(cert, customCert);
|
||||||
|
} else {
|
||||||
|
chainResult = certValidationService.validateCertificateChain(cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setChainValid(chainResult.isValid());
|
||||||
|
result.setTrustValid(chainResult.isValid());
|
||||||
|
result.setNotExpired(!chainResult.isExpired());
|
||||||
|
|
||||||
|
// Check if signature was valid at the time of signing
|
||||||
|
if (sig.getSignDate() != null) {
|
||||||
|
try {
|
||||||
|
cert.checkValidity(sig.getSignDate().getTime());
|
||||||
|
result.setValidAtTimeOfSigning(true);
|
||||||
|
} catch (CertificateExpiredException
|
||||||
|
| CertificateNotYetValidException e) {
|
||||||
|
result.setValidAtTimeOfSigning(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set signature info
|
||||||
|
populateSignatureInfo(result, sig, cert);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.setValid(false);
|
||||||
|
result.setErrorMessage("Signature validation failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
results.add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateSignatureInfo(
|
||||||
|
SignatureValidationResult result, PDSignature sig, X509Certificate cert) {
|
||||||
|
result.setSignerName(sig.getName());
|
||||||
|
result.setSignatureDate(sig.getSignDate().getTime().toString());
|
||||||
|
result.setReason(sig.getReason());
|
||||||
|
result.setLocation(sig.getLocation());
|
||||||
|
result.setIssuerDN(cert.getIssuerX500Principal().getName());
|
||||||
|
result.setSubjectDN(cert.getSubjectX500Principal().getName());
|
||||||
|
result.setSerialNumber(cert.getSerialNumber().toString(16));
|
||||||
|
result.setValidFrom(cert.getNotBefore().toString());
|
||||||
|
result.setValidUntil(cert.getNotAfter().toString());
|
||||||
|
result.setSignatureAlgorithm(cert.getSigAlgName());
|
||||||
|
|
||||||
|
try {
|
||||||
|
result.setKeySize(((RSAPublicKey) cert.getPublicKey()).getModulus().bitLength());
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.setKeySize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setVersion(String.valueOf(cert.getVersion()));
|
||||||
|
|
||||||
|
List<String> keyUsages = new ArrayList<>();
|
||||||
|
boolean[] keyUsageFlags = cert.getKeyUsage();
|
||||||
|
if (keyUsageFlags != null) {
|
||||||
|
String[] keyUsageLabels = {
|
||||||
|
"Digital Signature", "Non-Repudiation", "Key Encipherment",
|
||||||
|
"Data Encipherment", "Key Agreement", "Certificate Signing",
|
||||||
|
"CRL Signing", "Encipher Only", "Decipher Only"
|
||||||
|
};
|
||||||
|
for (int i = 0; i < keyUsageFlags.length; i++) {
|
||||||
|
if (keyUsageFlags[i]) {
|
||||||
|
keyUsages.add(keyUsageLabels[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.setKeyUsages(keyUsages);
|
||||||
|
result.setSelfSigned(cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,6 +53,13 @@ public class SecurityWebController {
|
|||||||
return "security/cert-sign";
|
return "security/cert-sign";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/validate-signature")
|
||||||
|
@Hidden
|
||||||
|
public String certSignVerifyForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "validate-signature");
|
||||||
|
return "security/validate-signature";
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/remove-cert-sign")
|
@GetMapping("/remove-cert-sign")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String certUnSignForm(Model model) {
|
public String certUnSignForm(Model model) {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package stirling.software.SPDF.model.api.security;
|
||||||
|
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import stirling.software.SPDF.model.api.PDFFile;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class SignatureValidationRequest extends PDFFile {
|
||||||
|
|
||||||
|
@Schema(description = "(Optional) file to compare PDF cert signatures against x.509 format")
|
||||||
|
private MultipartFile certFile;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package stirling.software.SPDF.model.api.security;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class SignatureValidationResult {
|
||||||
|
private boolean valid;
|
||||||
|
private String signerName;
|
||||||
|
private String signatureDate;
|
||||||
|
private String reason;
|
||||||
|
private String location;
|
||||||
|
private String errorMessage;
|
||||||
|
private boolean chainValid;
|
||||||
|
private boolean trustValid;
|
||||||
|
private boolean notExpired;
|
||||||
|
private boolean notRevoked;
|
||||||
|
private boolean validAtTimeOfSigning;
|
||||||
|
|
||||||
|
private String issuerDN; // Certificate issuer's Distinguished Name
|
||||||
|
private String subjectDN; // Certificate subject's Distinguished Name
|
||||||
|
private String serialNumber; // Certificate serial number
|
||||||
|
private String validFrom; // Certificate validity start date
|
||||||
|
private String validUntil; // Certificate validity end date
|
||||||
|
private String signatureAlgorithm; // Algorithm used for signing
|
||||||
|
private int keySize; // Key size in bits
|
||||||
|
private String version; // Certificate version
|
||||||
|
private List<String> keyUsages; // List of key usage purposes
|
||||||
|
private boolean isSelfSigned; // Whether the certificate is self-signed
|
||||||
|
}
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
package stirling.software.SPDF.service;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.cert.*;
|
||||||
|
import java.security.cert.CertPath;
|
||||||
|
import java.security.cert.CertPathValidator;
|
||||||
|
import java.security.cert.CertificateExpiredException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.CertificateNotYetValidException;
|
||||||
|
import java.security.cert.PKIXParameters;
|
||||||
|
import java.security.cert.TrustAnchor;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
||||||
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class CertificateValidationService {
|
||||||
|
private KeyStore trustStore;
|
||||||
|
private static final String AATL_RESOURCE = "/tl12.acrobatsecuritysettings";
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void initializeTrustStore() throws Exception {
|
||||||
|
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
|
trustStore.load(null, null);
|
||||||
|
loadAATLCertificatesFromPDF();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadAATLCertificatesFromPDF() throws Exception {
|
||||||
|
log.debug("Starting AATL certificate loading from PDF...");
|
||||||
|
|
||||||
|
try (InputStream pdfStream = new ClassPathResource(AATL_RESOURCE).getInputStream()) {
|
||||||
|
PDDocument document = Loader.loadPDF(pdfStream.readAllBytes());
|
||||||
|
|
||||||
|
PDEmbeddedFilesNameTreeNode embeddedFiles =
|
||||||
|
document.getDocumentCatalog().getNames().getEmbeddedFiles();
|
||||||
|
Map<String, PDComplexFileSpecification> files = embeddedFiles.getNames();
|
||||||
|
|
||||||
|
for (Map.Entry<String, PDComplexFileSpecification> entry : files.entrySet()) {
|
||||||
|
log.debug(entry.getKey());
|
||||||
|
if (entry.getKey().equals("SecuritySettings.xml")) {
|
||||||
|
byte[] xmlContent = entry.getValue().getEmbeddedFile().toByteArray();
|
||||||
|
processSecuritySettingsXML(xmlContent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processSecuritySettingsXML(byte[] xmlContent) throws Exception {
|
||||||
|
// Simple XML parsing using String operations
|
||||||
|
String xmlString = new String(xmlContent, "UTF-8");
|
||||||
|
int certCount = 0;
|
||||||
|
int failedCerts = 0;
|
||||||
|
|
||||||
|
// Find all Certificate tags
|
||||||
|
String startTag = "<Certificate>";
|
||||||
|
String endTag = "</Certificate>";
|
||||||
|
int startIndex = 0;
|
||||||
|
|
||||||
|
while ((startIndex = xmlString.indexOf(startTag, startIndex)) != -1) {
|
||||||
|
int endIndex = xmlString.indexOf(endTag, startIndex);
|
||||||
|
if (endIndex == -1) break;
|
||||||
|
|
||||||
|
// Extract certificate data
|
||||||
|
String certData = xmlString.substring(startIndex + startTag.length(), endIndex).trim();
|
||||||
|
startIndex = endIndex + endTag.length();
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] certBytes = Base64.getDecoder().decode(certData);
|
||||||
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
|
X509Certificate cert =
|
||||||
|
(X509Certificate)
|
||||||
|
cf.generateCertificate(new ByteArrayInputStream(certBytes));
|
||||||
|
|
||||||
|
// Only store root certificates (self-signed)
|
||||||
|
if (cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal())) {
|
||||||
|
trustStore.setCertificateEntry("aatl-cert-" + certCount, cert);
|
||||||
|
log.trace(
|
||||||
|
"Successfully loaded AATL root certificate #"
|
||||||
|
+ certCount
|
||||||
|
+ "\n Subject: "
|
||||||
|
+ cert.getSubjectX500Principal().getName()
|
||||||
|
+ "\n Valid until: "
|
||||||
|
+ cert.getNotAfter());
|
||||||
|
certCount++;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
failedCerts++;
|
||||||
|
log.error("Failed to process AATL certificate: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("AATL Certificate loading completed:");
|
||||||
|
log.debug(" Total root certificates successfully loaded: " + certCount);
|
||||||
|
log.debug(" Failed certificates: " + failedCerts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ValidationResult {
|
||||||
|
private boolean valid;
|
||||||
|
private boolean expired;
|
||||||
|
private boolean validAtSigningTime;
|
||||||
|
private String errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValidationResult validateCertificateChain(X509Certificate signerCert) {
|
||||||
|
ValidationResult result = new ValidationResult();
|
||||||
|
try {
|
||||||
|
// Build the certificate chain
|
||||||
|
List<X509Certificate> certChain = buildCertificateChain(signerCert);
|
||||||
|
|
||||||
|
// Create certificate path
|
||||||
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
|
CertPath certPath = cf.generateCertPath(certChain);
|
||||||
|
|
||||||
|
// Set up trust anchors
|
||||||
|
Set<TrustAnchor> anchors = new HashSet<>();
|
||||||
|
Enumeration<String> aliases = trustStore.aliases();
|
||||||
|
while (aliases.hasMoreElements()) {
|
||||||
|
Object trustCert = trustStore.getCertificate(aliases.nextElement());
|
||||||
|
if (trustCert instanceof X509Certificate) {
|
||||||
|
anchors.add(new TrustAnchor((X509Certificate) trustCert, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up validation parameters
|
||||||
|
PKIXParameters params = new PKIXParameters(anchors);
|
||||||
|
params.setRevocationEnabled(false);
|
||||||
|
|
||||||
|
// Validate the path
|
||||||
|
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
|
||||||
|
validator.validate(certPath, params);
|
||||||
|
|
||||||
|
result.setValid(true);
|
||||||
|
result.setExpired(isExpired(signerCert));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.setValid(false);
|
||||||
|
result.setErrorMessage(e.getMessage());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValidationResult validateWithCustomCert(
|
||||||
|
X509Certificate signerCert, X509Certificate customCert) {
|
||||||
|
ValidationResult result = new ValidationResult();
|
||||||
|
try {
|
||||||
|
// Build the complete chain from signer cert
|
||||||
|
List<X509Certificate> certChain = buildCertificateChain(signerCert);
|
||||||
|
|
||||||
|
// Check if custom cert matches any cert in the chain
|
||||||
|
boolean matchFound = false;
|
||||||
|
for (X509Certificate chainCert : certChain) {
|
||||||
|
if (chainCert.equals(customCert)) {
|
||||||
|
matchFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matchFound) {
|
||||||
|
// Check if custom cert is a valid issuer for any cert in the chain
|
||||||
|
for (X509Certificate chainCert : certChain) {
|
||||||
|
try {
|
||||||
|
chainCert.verify(customCert.getPublicKey());
|
||||||
|
matchFound = true;
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Continue checking next cert
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setValid(matchFound);
|
||||||
|
if (!matchFound) {
|
||||||
|
result.setErrorMessage(
|
||||||
|
"Custom certificate is not part of the chain and is not a valid issuer");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.setValid(false);
|
||||||
|
result.setErrorMessage(e.getMessage());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<X509Certificate> buildCertificateChain(X509Certificate signerCert)
|
||||||
|
throws CertificateException {
|
||||||
|
List<X509Certificate> chain = new ArrayList<>();
|
||||||
|
chain.add(signerCert);
|
||||||
|
|
||||||
|
X509Certificate current = signerCert;
|
||||||
|
while (!isSelfSigned(current)) {
|
||||||
|
X509Certificate issuer = findIssuer(current);
|
||||||
|
if (issuer == null) break;
|
||||||
|
chain.add(issuer);
|
||||||
|
current = issuer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSelfSigned(X509Certificate cert) {
|
||||||
|
return cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal());
|
||||||
|
}
|
||||||
|
|
||||||
|
private X509Certificate findIssuer(X509Certificate cert) throws CertificateException {
|
||||||
|
try {
|
||||||
|
Enumeration<String> aliases = trustStore.aliases();
|
||||||
|
while (aliases.hasMoreElements()) {
|
||||||
|
Certificate trustCert = trustStore.getCertificate(aliases.nextElement());
|
||||||
|
if (trustCert instanceof X509Certificate) {
|
||||||
|
X509Certificate x509TrustCert = (X509Certificate) trustCert;
|
||||||
|
if (cert.getIssuerX500Principal()
|
||||||
|
.equals(x509TrustCert.getSubjectX500Principal())) {
|
||||||
|
try {
|
||||||
|
cert.verify(x509TrustCert.getPublicKey());
|
||||||
|
return x509TrustCert;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Continue searching if verification fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new CertificateException("Error accessing trust store", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isExpired(X509Certificate cert) {
|
||||||
|
try {
|
||||||
|
cert.checkValidity();
|
||||||
|
return false;
|
||||||
|
} catch (CertificateExpiredException | CertificateNotYetValidException e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ public class MetricsAggregatorService {
|
|||||||
this.postHogService = postHogService;
|
this.postHogService = postHogService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(fixedRate = 1800000) // Run every 30 minutes
|
@Scheduled(fixedRate = 7200000) // Run every 2 hours
|
||||||
public void aggregateAndSendMetrics() {
|
public void aggregateAndSendMetrics() {
|
||||||
Map<String, Object> metrics = new HashMap<>();
|
Map<String, Object> metrics = new HashMap<>();
|
||||||
Search.in(meterRegistry)
|
Search.in(meterRegistry)
|
||||||
|
|||||||
25972
src/main/resources/certdata.txt
Normal file
25972
src/main/resources/certdata.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=تجزئة المستندات PDF حسب الفص
|
|||||||
home.splitPdfByChapters.desc=قسم مستند PDF إلى ملفات متعددة بناءً على هيكل فصوله.
|
home.splitPdfByChapters.desc=قسم مستند PDF إلى ملفات متعددة بناءً على هيكل فصوله.
|
||||||
splitPdfByChapters.tags=تجزئة، فصول، علامات تبويب، تنظيم
|
splitPdfByChapters.tags=تجزئة، فصول، علامات تبويب، تنظيم
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=إستبدال-عكس اللون
|
replace-color.title=إستبدال-عكس اللون
|
||||||
replace-color.header=استبدال-عكس لون PDF
|
replace-color.header=استبدال-عكس لون PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=PDF-i Fəsillərə Əsasən Böl
|
|||||||
home.splitPdfByChapters.desc=Fəsil strukturuna əsasən PDF-i bir neçə fayla böl.
|
home.splitPdfByChapters.desc=Fəsil strukturuna əsasən PDF-i bir neçə fayla böl.
|
||||||
splitPdfByChapters.tags=böl,fəsillər,əlfəcinlər,nizamla
|
splitPdfByChapters.tags=böl,fəsillər,əlfəcinlər,nizamla
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Qabaqcıl Rəng Seçimləri
|
replace-color.title=Qabaqcıl Rəng Seçimləri
|
||||||
replace-color.header=PDF-də Rəngləri Dəyiş-Tərsinə Çevir
|
replace-color.header=PDF-də Rəngləri Dəyiş-Tərsinə Çevir
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Buraxılış Qeydləri
|
|||||||
releases.header=Buraxılış Qeydləri
|
releases.header=Buraxılış Qeydləri
|
||||||
releases.current.version=Hazırki Buraxılış
|
releases.current.version=Hazırki Buraxılış
|
||||||
releases.note=Buraxılış Qeydləri yalnız ingiliscə mövcuddur
|
releases.note=Buraxılış Qeydləri yalnız ingiliscə mövcuddur
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Разделете PDF по глави
|
|||||||
home.splitPdfByChapters.desc=Разделете PDF на множество файлове въз основа на неговата структура на глави.
|
home.splitPdfByChapters.desc=Разделете PDF на множество файлове въз основа на неговата структура на глави.
|
||||||
splitPdfByChapters.tags=разделяне, глави, отметки, организиране
|
splitPdfByChapters.tags=разделяне, глави, отметки, организиране
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Замени-инвертиране-на-цвят
|
replace-color.title=Замени-инвертиране-на-цвят
|
||||||
replace-color.header=Замяна-инвертиране на цвят PDF
|
replace-color.header=Замяна-инвертиране на цвят PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Divideix PDF per Capítols
|
|||||||
home.splitPdfByChapters.desc=Divideix un PDF en múltiples fitxers segons la seva estructura de capítols.
|
home.splitPdfByChapters.desc=Divideix un PDF en múltiples fitxers segons la seva estructura de capítols.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Reemplaça-Inverteix-Color
|
replace-color.title=Reemplaça-Inverteix-Color
|
||||||
replace-color.header=Reemplaça-Inverteix Color en PDF
|
replace-color.header=Reemplaça-Inverteix Color en PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Rozdělit PDF podle kapitol
|
|||||||
home.splitPdfByChapters.desc=Rozdělit PDF do více souborů na základě jeho struktury kapitol.
|
home.splitPdfByChapters.desc=Rozdělit PDF do více souborů na základě jeho struktury kapitol.
|
||||||
splitPdfByChapters.tags=rozdělení, kapitoly, zápisky, organizace
|
splitPdfByChapters.tags=rozdělení, kapitoly, zápisky, organizace
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Nahradit inverzní barvu PDF
|
replace-color.header=Nahradit inverzní barvu PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Partitioner PDF efter kapitler
|
|||||||
home.splitPdfByChapters.desc=Partitioner en PDF i flere filer baseret på dens kapitelstruktur.
|
home.splitPdfByChapters.desc=Partitioner en PDF i flere filer baseret på dens kapitelstruktur.
|
||||||
splitPdfByChapters.tags=partitionering,kapitler,merker,organisering
|
splitPdfByChapters.tags=partitionering,kapitler,merker,organisering
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Erstat-omgivende Farve PDF
|
replace-color.header=Erstat-omgivende Farve PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ database.fileNullOrEmpty=Datei darf nicht null oder leer sein
|
|||||||
database.failedImportFile=Dateiimport fehlgeschlagen
|
database.failedImportFile=Dateiimport fehlgeschlagen
|
||||||
|
|
||||||
session.expired=Ihre Sitzung ist abgelaufen. Bitte laden Sie die Seite neu und versuchen Sie es erneut.
|
session.expired=Ihre Sitzung ist abgelaufen. Bitte laden Sie die Seite neu und versuchen Sie es erneut.
|
||||||
session.refreshPage=Refresh Page
|
session.refreshPage=Seite aktualisieren
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=PDF-Datei nach Kapiteln aufteilen
|
|||||||
home.splitPdfByChapters.desc=Aufteilung einer PDF-Datei in mehrere Dateien auf Basis der Kapitelstruktur.
|
home.splitPdfByChapters.desc=Aufteilung einer PDF-Datei in mehrere Dateien auf Basis der Kapitelstruktur.
|
||||||
splitPdfByChapters.tags=aufteilen,kapitel,lesezeichen,organisieren
|
splitPdfByChapters.tags=aufteilen,kapitel,lesezeichen,organisieren
|
||||||
|
|
||||||
|
home.validateSignature.title=PDF-Signatur überprüfen
|
||||||
|
home.validateSignature.desc=Digitale Signaturen und Zertifikate in PDF-Dokumenten überprüfen
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,digitale signatur,signatur validieren,überprüfen,Zertifikat,cert
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Farbe Ersetzen-Invertieren
|
replace-color.title=Farbe Ersetzen-Invertieren
|
||||||
replace-color.header=Farb-PDF Ersetzen-Invertieren
|
replace-color.header=Farb-PDF Ersetzen-Invertieren
|
||||||
@@ -818,12 +822,12 @@ sign.save=Signature speichern
|
|||||||
sign.personalSigs=Persönliche Signaturen
|
sign.personalSigs=Persönliche Signaturen
|
||||||
sign.sharedSigs=Geteilte Signaturen
|
sign.sharedSigs=Geteilte Signaturen
|
||||||
sign.noSavedSigs=Es wurden keine gespeicherten Signaturen gefunden
|
sign.noSavedSigs=Es wurden keine gespeicherten Signaturen gefunden
|
||||||
sign.addToAll=Add to all pages
|
sign.addToAll=Zu allen Seiten hinzufügen
|
||||||
sign.delete=Delete
|
sign.delete=Löschen
|
||||||
sign.first=First page
|
sign.first=Erste Seite
|
||||||
sign.last=Last page
|
sign.last=Letzte Seite
|
||||||
sign.next=Next page
|
sign.next=Nächste Seite
|
||||||
sign.previous=Previous page
|
sign.previous=Vorherige Seite
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Reparieren
|
repair.title=Reparieren
|
||||||
@@ -949,17 +953,17 @@ multiTool.deleteSelected=Auswahl löschen
|
|||||||
multiTool.downloadAll=Downloaden
|
multiTool.downloadAll=Downloaden
|
||||||
multiTool.downloadSelected=Auswahl downloaden
|
multiTool.downloadSelected=Auswahl downloaden
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insert Page Break
|
multiTool.insertPageBreak=Seitenumbruch einfügen
|
||||||
multiTool.addFile=Add File
|
multiTool.addFile=Datei hinzufügen
|
||||||
multiTool.rotateLeft=Rotate Left
|
multiTool.rotateLeft=Nach links drehen
|
||||||
multiTool.rotateRight=Rotate Right
|
multiTool.rotateRight=Nach rechts drehen
|
||||||
multiTool.split=Split
|
multiTool.split=Teilen
|
||||||
multiTool.moveLeft=Move Left
|
multiTool.moveLeft=Nach links verschieben
|
||||||
multiTool.moveRight=Move Right
|
multiTool.moveRight=Nach rechts verschieben
|
||||||
multiTool.delete=Delete
|
multiTool.delete=Löschen
|
||||||
multiTool.dragDropMessage=Page(s) Selected
|
multiTool.dragDropMessage=Ausgewählte Seite(n)
|
||||||
multiTool.undo=Undo
|
multiTool.undo=Rückgängig machen
|
||||||
multiTool.redo=Redo
|
multiTool.redo=Wiederherstellen
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=Diese Funktion ist auch auf unserer <a href="{0}">PDF-Multitool-Seite</a> verfügbar. Probieren Sie sie aus, denn sie bietet eine verbesserte Benutzeroberfläche und zusätzliche Funktionen!
|
multiTool-advert.message=Diese Funktion ist auch auf unserer <a href="{0}">PDF-Multitool-Seite</a> verfügbar. Probieren Sie sie aus, denn sie bietet eine verbesserte Benutzeroberfläche und zusätzliche Funktionen!
|
||||||
@@ -1264,14 +1268,49 @@ splitByChapters.desc.4=Duplikate erlauben: Wenn diese Option aktiviert ist, kön
|
|||||||
splitByChapters.submit=PDF teilen
|
splitByChapters.submit=PDF teilen
|
||||||
|
|
||||||
#File Chooser
|
#File Chooser
|
||||||
fileChooser.click=Click
|
fileChooser.click=Klicken
|
||||||
fileChooser.or=or
|
fileChooser.or=oder
|
||||||
fileChooser.dragAndDrop=Drag & Drop
|
fileChooser.dragAndDrop=Drag & Drop
|
||||||
fileChooser.hoveredDragAndDrop=Drag & Drop file(s) here
|
fileChooser.hoveredDragAndDrop=Datei(en) hierhin Ziehen & Fallenlassen
|
||||||
|
|
||||||
#release notes
|
#release notes
|
||||||
releases.footer=Releases
|
releases.footer=Veröffentlichungen
|
||||||
releases.title=Release Notes
|
releases.title=Versionshinweise
|
||||||
releases.header=Release Notes
|
releases.header=Versionshinweise
|
||||||
releases.current.version=Current Release
|
releases.current.version=Aktuelle Version
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Versionshinweise sind nur auf Englisch verfügbar
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=PDF-Signaturen überprüfen
|
||||||
|
validateSignature.header=Digitale Signaturen überprüfen
|
||||||
|
validateSignature.selectPDF=Signierte PDF-Datei auswählen
|
||||||
|
validateSignature.submit=Signaturen überprüfen
|
||||||
|
validateSignature.results=Gültigkeitsprüfungsergebnisse
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Unterzeichner
|
||||||
|
validateSignature.date=Datum
|
||||||
|
validateSignature.reason=Grund
|
||||||
|
validateSignature.location=Ort
|
||||||
|
validateSignature.noSignatures=Keine digitalen Signaturen in diesem Dokument gefunden
|
||||||
|
validateSignature.status.valid=Gültig
|
||||||
|
validateSignature.status.invalid=Ungültig
|
||||||
|
validateSignature.chain.invalid=Zertifikatskettenprüfung fehlgeschlagen - kann die Identität des Unterzeichners nicht verifizieren
|
||||||
|
validateSignature.trust.invalid=Zertifikat nicht im Truststore - Quelle kann nicht verifiziert werden
|
||||||
|
validateSignature.cert.expired=Zertifikat ist abgelaufen
|
||||||
|
validateSignature.cert.revoked=Zertifikat wurde widerrufen
|
||||||
|
validateSignature.signature.info=Signaturinformationen
|
||||||
|
validateSignature.signature=Signatur
|
||||||
|
validateSignature.signature.mathValid=Signatur ist mathematisch gültig ABER:
|
||||||
|
validateSignature.selectCustomCert=Benutzerdefinierte Zertifikatsdatei X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Zertifikat Details
|
||||||
|
validateSignature.cert.issuer=Aussteller
|
||||||
|
validateSignature.cert.subject=Betreff
|
||||||
|
validateSignature.cert.serialNumber=Seriennummer
|
||||||
|
validateSignature.cert.validFrom=Gültig von
|
||||||
|
validateSignature.cert.validUntil=Gültig bis
|
||||||
|
validateSignature.cert.algorithm=Algorithmus
|
||||||
|
validateSignature.cert.keySize=Schlüsselgröße
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Schlüsselverwendung
|
||||||
|
validateSignature.cert.selfSigned=Selbstsigniert
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Διχοτομία PDF ανά Περιγραφές
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=διχοτομία,περιγραφές,κεφάλαια,συνορία
|
splitPdfByChapters.tags=διχοτομία,περιγραφές,κεφάλαια,συνορία
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Αντικατάσταση-Αντίστροφη Παθωμένη Πίντσουρ
|
replace-color.header=Αντικατάσταση-Αντίστροφη Παθωμένη Πίντσουρ
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ joinDiscord=Join our Discord server
|
|||||||
seeDockerHub=See Docker Hub
|
seeDockerHub=See Docker Hub
|
||||||
visitGithub=Visit Github Repository
|
visitGithub=Visit Github Repository
|
||||||
donate=Donate
|
donate=Donate
|
||||||
color=Color
|
color=Colour
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
pro=Pro
|
pro=Pro
|
||||||
@@ -419,9 +419,9 @@ home.auto-rename.title=Auto Rename PDF File
|
|||||||
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
home.auto-rename.desc=Auto renames a PDF file based on its detected header
|
||||||
auto-rename.tags=auto-detect,header-based,organize,relabel
|
auto-rename.tags=auto-detect,header-based,organize,relabel
|
||||||
|
|
||||||
home.adjust-contrast.title=Adjust Colors/Contrast
|
home.adjust-contrast.title=Adjust Coloors/Contrast
|
||||||
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
home.adjust-contrast.desc=Adjust Contrast, Saturation and Brightness of a PDF
|
||||||
adjust-contrast.tags=color-correction,tune,modify,enhance
|
adjust-contrast.tags=color-correction,tune,modify,enhance,colour-correction
|
||||||
|
|
||||||
home.crop.title=Crop PDF
|
home.crop.title=Crop PDF
|
||||||
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
home.crop.desc=Crop a PDF to reduce its size (maintains text!)
|
||||||
@@ -488,11 +488,11 @@ overlay-pdfs.tags=Overlay
|
|||||||
|
|
||||||
home.split-by-sections.title=Split PDF by Sections
|
home.split-by-sections.title=Split PDF by Sections
|
||||||
home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections
|
home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections
|
||||||
split-by-sections.tags=Section Split, Divide, Customize
|
split-by-sections.tags=Section Split, Divide, Customize,Customise
|
||||||
|
|
||||||
home.AddStampRequest.title=Add Stamp to PDF
|
home.AddStampRequest.title=Add Stamp to PDF
|
||||||
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
home.AddStampRequest.desc=Add text or add image stamps at set locations
|
||||||
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize
|
AddStampRequest.tags=Stamp, Add image, center image, Watermark, PDF, Embed, Customize,Customise
|
||||||
|
|
||||||
|
|
||||||
home.PDFToBook.title=PDF to Book
|
home.PDFToBook.title=PDF to Book
|
||||||
@@ -512,23 +512,27 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Advanced Colour options
|
replace-color.title=Advanced Colour options
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Colour PDF
|
||||||
home.replaceColorPdf.title=Advanced Colour options
|
home.replaceColorPdf.title=Advanced Colour options
|
||||||
home.replaceColorPdf.desc=Replace color for text and background in PDF and invert full color of pdf to reduce file size
|
home.replaceColorPdf.desc=Replace colour for text and background in PDF and invert full colour of pdf to reduce file size
|
||||||
replaceColorPdf.tags=Replace Color,Page operations,Back end,server side
|
replaceColorPdf.tags=Replace Colour,Page operations,Back end,server side
|
||||||
replace-color.selectText.1=Replace or Invert color Options
|
replace-color.selectText.1=Replace or Invert colour Options
|
||||||
replace-color.selectText.2=Default(Default high contrast colors)
|
replace-color.selectText.2=Default(Default high contrast colours)
|
||||||
replace-color.selectText.3=Custom(Customized colors)
|
replace-color.selectText.3=Custom(Customised colours)
|
||||||
replace-color.selectText.4=Full-Invert(Invert all colors)
|
replace-color.selectText.4=Full-Invert(Invert all colours)
|
||||||
replace-color.selectText.5=High contrast color options
|
replace-color.selectText.5=High contrast colour options
|
||||||
replace-color.selectText.6=white text on black background
|
replace-color.selectText.6=white text on black background
|
||||||
replace-color.selectText.7=Black text on white background
|
replace-color.selectText.7=Black text on white background
|
||||||
replace-color.selectText.8=Yellow text on black background
|
replace-color.selectText.8=Yellow text on black background
|
||||||
replace-color.selectText.9=Green text on black background
|
replace-color.selectText.9=Green text on black background
|
||||||
replace-color.selectText.10=Choose text Color
|
replace-color.selectText.10=Choose text Colour
|
||||||
replace-color.selectText.11=Choose background Color
|
replace-color.selectText.11=Choose background Colour
|
||||||
replace-color.submit=Replace
|
replace-color.submit=Replace
|
||||||
|
|
||||||
|
|
||||||
@@ -651,7 +655,7 @@ AddStampRequest.position=Position
|
|||||||
AddStampRequest.overrideX=Override X Coordinate
|
AddStampRequest.overrideX=Override X Coordinate
|
||||||
AddStampRequest.overrideY=Override Y Coordinate
|
AddStampRequest.overrideY=Override Y Coordinate
|
||||||
AddStampRequest.customMargin=Custom Margin
|
AddStampRequest.customMargin=Custom Margin
|
||||||
AddStampRequest.customColor=Custom Text Color
|
AddStampRequest.customColor=Custom Text Colour
|
||||||
AddStampRequest.submit=Submit
|
AddStampRequest.submit=Submit
|
||||||
|
|
||||||
|
|
||||||
@@ -783,8 +787,8 @@ removeAnnotations.submit=Remove
|
|||||||
#compare
|
#compare
|
||||||
compare.title=Compare
|
compare.title=Compare
|
||||||
compare.header=Compare PDFs
|
compare.header=Compare PDFs
|
||||||
compare.highlightColor.1=Highlight Color 1:
|
compare.highlightColor.1=Highlight Colour 1:
|
||||||
compare.highlightColor.2=Highlight Color 2:
|
compare.highlightColor.2=Highlight Colour 2:
|
||||||
compare.document.1=Document 1
|
compare.document.1=Document 1
|
||||||
compare.document.2=Document 2
|
compare.document.2=Document 2
|
||||||
compare.submit=Compare
|
compare.submit=Compare
|
||||||
@@ -842,7 +846,7 @@ flatten.submit=Flatten
|
|||||||
ScannerImageSplit.selectText.1=Angle Threshold:
|
ScannerImageSplit.selectText.1=Angle Threshold:
|
||||||
ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10).
|
ScannerImageSplit.selectText.2=Sets the minimum absolute angle required for the image to be rotated (default: 10).
|
||||||
ScannerImageSplit.selectText.3=Tolerance:
|
ScannerImageSplit.selectText.3=Tolerance:
|
||||||
ScannerImageSplit.selectText.4=Determines the range of color variation around the estimated background color (default: 30).
|
ScannerImageSplit.selectText.4=Determines the range of colour variation around the estimated background colour (default: 30).
|
||||||
ScannerImageSplit.selectText.5=Minimum Area:
|
ScannerImageSplit.selectText.5=Minimum Area:
|
||||||
ScannerImageSplit.selectText.6=Sets the minimum area threshold for a photo (default: 10000).
|
ScannerImageSplit.selectText.6=Sets the minimum area threshold for a photo (default: 10000).
|
||||||
ScannerImageSplit.selectText.7=Minimum Contour Area:
|
ScannerImageSplit.selectText.7=Minimum Contour Area:
|
||||||
@@ -894,7 +898,7 @@ compress.title=Compress
|
|||||||
compress.header=Compress PDF
|
compress.header=Compress PDF
|
||||||
compress.credit=This service uses qpdf for PDF Compress/Optimisation.
|
compress.credit=This service uses qpdf for PDF Compress/Optimisation.
|
||||||
compress.selectText.1=Manual Mode - From 1 to 4
|
compress.selectText.1=Manual Mode - From 1 to 4
|
||||||
compress.selectText.2=Optimization level:
|
compress.selectText.2=Optimisation level:
|
||||||
compress.selectText.3=4 (Terrible for text images)
|
compress.selectText.3=4 (Terrible for text images)
|
||||||
compress.selectText.4=Auto mode - Auto adjusts quality to get PDF to exact size
|
compress.selectText.4=Auto mode - Auto adjusts quality to get PDF to exact size
|
||||||
compress.selectText.5=Expected PDF Size (e.g. 25MB, 10.8MB, 25KB)
|
compress.selectText.5=Expected PDF Size (e.g. 25MB, 10.8MB, 25KB)
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Dividir PDF por capítulos
|
|||||||
home.splitPdfByChapters.desc=Divida un PDF en varios archivos según su estructura de capítulos.
|
home.splitPdfByChapters.desc=Divida un PDF en varios archivos según su estructura de capítulos.
|
||||||
splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar
|
splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Reemplazar-Invertir-Color
|
replace-color.title=Reemplazar-Invertir-Color
|
||||||
replace-color.header=Reemplazar-Invertir Color en PDF
|
replace-color.header=Reemplazar-Invertir Color en PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Séparer un PDF par chapitres
|
|||||||
home.splitPdfByChapters.desc=Séparez un PDF en fichiers multiples en fonction de sa structure par chapitres.
|
home.splitPdfByChapters.desc=Séparez un PDF en fichiers multiples en fonction de sa structure par chapitres.
|
||||||
splitPdfByChapters.tags=séparer,chapitres,split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=séparer,chapitres,split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Remplacer-Inverser-Couleur
|
replace-color.title=Remplacer-Inverser-Couleur
|
||||||
replace-color.header=Remplacer-Inverser Couleur PDF
|
replace-color.header=Remplacer-Inverser Couleur PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=अध्यायों पर अलग-कर
|
|||||||
home.splitPdfByChapters.desc=पुस्तक के अध्याय की संरचना पर आधारित एक PDF को बहिन-भागों में विभाजित करें
|
home.splitPdfByChapters.desc=पुस्तक के अध्याय की संरचना पर आधारित एक PDF को बहिन-भागों में विभाजित करें
|
||||||
splitPdfByChapters.tags=विभाजन,अध्याय,पसंदीदा,रजैत
|
splitPdfByChapters.tags=विभाजन,अध्याय,पसंदीदा,रजैत
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=चित्र रंग परिवर्तन/उलटकर परिवर्तन PDF
|
replace-color.header=चित्र रंग परिवर्तन/उलटकर परिवर्तन PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Podijeli PDF prema glavama
|
|||||||
home.splitPdfByChapters.desc=Podijeli PDF na više datoteka prema njegovom strukturnom obliku glava.
|
home.splitPdfByChapters.desc=Podijeli PDF na više datoteka prema njegovom strukturnom obliku glava.
|
||||||
splitPdfByChapters.tags=podjela, glave, markere, organizacija
|
splitPdfByChapters.tags=podjela, glave, markere, organizacija
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Zameni-inverziranje boja u PDF-u
|
replace-color.header=Zameni-inverziranje boja u PDF-u
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=PDF felosztása fejezetek szerint
|
|||||||
home.splitPdfByChapters.desc=Fejezetei alapján egy PDF fájl több dokumentumba osztás.
|
home.splitPdfByChapters.desc=Fejezetei alapján egy PDF fájl több dokumentumba osztás.
|
||||||
splitPdfByChapters.tags=Osztás, fejezetek, jelezes, organizálás
|
splitPdfByChapters.tags=Osztás, fejezetek, jelezes, organizálás
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Visszaalakítás-összevétel a színekkel PDF-ben
|
replace-color.header=Visszaalakítás-összevétel a színekkel PDF-ben
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Pisahkan PDF berdasarkan Bab
|
|||||||
home.splitPdfByChapters.desc=Memisahkan PDF menjadi beberapa file berdasarkan struktur babnya.
|
home.splitPdfByChapters.desc=Memisahkan PDF menjadi beberapa file berdasarkan struktur babnya.
|
||||||
splitPdfByChapters.tags=pemisahan,bab,bookmark,atur
|
splitPdfByChapters.tags=pemisahan,bab,bookmark,atur
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Ganti-Inversi-Warna
|
replace-color.title=Ganti-Inversi-Warna
|
||||||
replace-color.header=Ganti-Inversi Warna PDF
|
replace-color.header=Ganti-Inversi Warna PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Dividi PDF per capitoli
|
|||||||
home.splitPdfByChapters.desc=Dividi un PDF in più file in base alla struttura dei capitoli.
|
home.splitPdfByChapters.desc=Dividi un PDF in più file in base alla struttura dei capitoli.
|
||||||
splitPdfByChapters.tags=dividi, capitoli, segnalibri, organizza
|
splitPdfByChapters.tags=dividi, capitoli, segnalibri, organizza
|
||||||
|
|
||||||
|
home.validateSignature.title=Convalida la firma PDF
|
||||||
|
home.validateSignature.desc=Verificare le firme digitali e i certificati nei documenti PDF
|
||||||
|
validateSignature.tags=firma,verifica,convalida,pdf,certificato,firma digitale,convalida firma,convalida certificato
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Sostituisci-Inverti-Colore
|
replace-color.title=Sostituisci-Inverti-Colore
|
||||||
replace-color.header=Sostituisci-Inverti colore PDF
|
replace-color.header=Sostituisci-Inverti colore PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Note di rilascio
|
|||||||
releases.header=Note di rilascio
|
releases.header=Note di rilascio
|
||||||
releases.current.version=Rilascio corrente
|
releases.current.version=Rilascio corrente
|
||||||
releases.note=Le note di rilascio sono disponibili solo in inglese
|
releases.note=Le note di rilascio sono disponibili solo in inglese
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validare le firme PDF
|
||||||
|
validateSignature.header=Convalidare le firme digitali
|
||||||
|
validateSignature.selectPDF=Seleziona il file PDF firmato
|
||||||
|
validateSignature.submit=Convalida firme
|
||||||
|
validateSignature.results=Risultati di convalida
|
||||||
|
validateSignature.status=Stato
|
||||||
|
validateSignature.signer=Firmatario
|
||||||
|
validateSignature.date=Data
|
||||||
|
validateSignature.reason=Ragione
|
||||||
|
validateSignature.location=Posizione
|
||||||
|
validateSignature.noSignatures=Nessuna firma digitale trovata in questo documento
|
||||||
|
validateSignature.status.valid=Valida
|
||||||
|
validateSignature.status.invalid=Invalida
|
||||||
|
validateSignature.chain.invalid=Convalida della catena di certificati non riuscita: impossibile verificare l'identità del firmatario
|
||||||
|
validateSignature.trust.invalid=Certificato non presente nell'archivio attendibile: la fonte non può essere verificata
|
||||||
|
validateSignature.cert.expired=Il certificato è scaduto
|
||||||
|
validateSignature.cert.revoked=Il certificato è stato revocato
|
||||||
|
validateSignature.signature.info=Informazioni sulla firma
|
||||||
|
validateSignature.signature=Firma
|
||||||
|
validateSignature.signature.mathValid=La firma è matematicamente valida MA:
|
||||||
|
validateSignature.selectCustomCert=File di certificato personalizzato X.509 (opzionale)
|
||||||
|
validateSignature.cert.info=Dettagli del certificato
|
||||||
|
validateSignature.cert.issuer=Emittente
|
||||||
|
validateSignature.cert.subject=Soggetto
|
||||||
|
validateSignature.cert.serialNumber=Numero di serie
|
||||||
|
validateSignature.cert.validFrom=Valido da
|
||||||
|
validateSignature.cert.validUntil=Valido fino a
|
||||||
|
validateSignature.cert.algorithm=Algoritmo
|
||||||
|
validateSignature.cert.keySize=Dimensione chiave
|
||||||
|
validateSignature.cert.version=Versione
|
||||||
|
validateSignature.cert.keyUsage=Utilizzo della chiave
|
||||||
|
validateSignature.cert.selfSigned=Autofirmato
|
||||||
|
validateSignature.cert.bits=bit
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=챕터별로 PDF 분할
|
|||||||
home.splitPdfByChapters.desc=PDF를 여러 파일로 나눕니다. 각 장의 구조에 따라.
|
home.splitPdfByChapters.desc=PDF를 여러 파일로 나눕니다. 각 장의 구조에 따라.
|
||||||
splitPdfByChapters.tags=분할, 챕터, 북마크, 조직화
|
splitPdfByChapters.tags=분할, 챕터, 북마크, 조직화
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=색상 교체/반전 PDF
|
replace-color.header=색상 교체/반전 PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=PDF op hoofdstukken splitsen
|
|||||||
home.splitPdfByChapters.desc=Splits een PDF op basis van zijn hoofdstukstructuur in meerdere bestanden.
|
home.splitPdfByChapters.desc=Splits een PDF op basis van zijn hoofdstukstructuur in meerdere bestanden.
|
||||||
splitPdfByChapters.tags=splitsen, hoofdstukken, bookmarks, organiseren
|
splitPdfByChapters.tags=splitsen, hoofdstukken, bookmarks, organiseren
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Kleur-instellingen voor PDF's
|
replace-color.header=Kleur-instellingen voor PDF's
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Podziel PDF według rozdziałów
|
|||||||
home.splitPdfByChapters.desc=Podział pliku PDF na wiele plików na podstawie struktury rozdziałów.
|
home.splitPdfByChapters.desc=Podział pliku PDF na wiele plików na podstawie struktury rozdziałów.
|
||||||
splitPdfByChapters.tags=podział, rozdziały, zakładki, porządkowanie, organizacja
|
splitPdfByChapters.tags=podział, rozdziały, zakładki, porządkowanie, organizacja
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Zamień-Odwróć-Kolor
|
replace-color.title=Zamień-Odwróć-Kolor
|
||||||
replace-color.header=Zamień-Odwróć kolor PDF
|
replace-color.header=Zamień-Odwróć kolor PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Divide PDF por Capítulos
|
|||||||
home.splitPdfByChapters.desc=Divide um PDF em vários arquivos baseado na sua estrutura de capítulos.
|
home.splitPdfByChapters.desc=Divide um PDF em vários arquivos baseado na sua estrutura de capítulos.
|
||||||
splitPdfByChapters.tags=dividir,capítulos,favoritos,organizar
|
splitPdfByChapters.tags=dividir,capítulos,favoritos,organizar
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Substituir-Inverter-Cor
|
replace-color.title=Substituir-Inverter-Cor
|
||||||
replace-color.header=Substitui-Inverter Cor PDF
|
replace-color.header=Substitui-Inverter Cor PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Dividir PDF por Capítulos
|
|||||||
home.splitPdfByChapters.desc=Divida um PDF em vários arquivos com base na estrutura dos capítulos.
|
home.splitPdfByChapters.desc=Divida um PDF em vários arquivos com base na estrutura dos capítulos.
|
||||||
splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar
|
splitPdfByChapters.tags=dividir,capítulos,marcadores,organizar
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Substituir-Inverter Cor do PDF
|
replace-color.header=Substituir-Inverter Cor do PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Разделить PDF по разделам
|
|||||||
home.splitPdfByChapters.desc=Разделите PDF на несколько файлов на основе структуры его разделов
|
home.splitPdfByChapters.desc=Разделите PDF на несколько файлов на основе структуры его разделов
|
||||||
splitPdfByChapters.tags=разделение, разделы, закладки, организация
|
splitPdfByChapters.tags=разделение, разделы, закладки, организация
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Заменить-Обратное изменение цвета PDF
|
replace-color.header=Заменить-Обратное изменение цвета PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Dela upp PDF efter kapitel
|
|||||||
home.splitPdfByChapters.desc=Dela upp en PDF till flera filer baserat på dess kapitelstruktur.
|
home.splitPdfByChapters.desc=Dela upp en PDF till flera filer baserat på dess kapitelstruktur.
|
||||||
splitPdfByChapters.tags=dela,kapitel,bokmärken,organisera
|
splitPdfByChapters.tags=dela,kapitel,bokmärken,organisera
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Ersätt-Invertera färg på PDF
|
replace-color.header=Ersätt-Invertera färg på PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=Split PDF by Chapters
|
|||||||
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure.
|
||||||
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
splitPdfByChapters.tags=split,chapters,bookmarks,organize
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=Replace-Invert-Color
|
replace-color.title=Replace-Invert-Color
|
||||||
replace-color.header=Replace-Invert Color PDF
|
replace-color.header=Replace-Invert Color PDF
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -512,6 +512,10 @@ home.splitPdfByChapters.title=依章節分割 PDF
|
|||||||
home.splitPdfByChapters.desc=根據 PDF 的章節結構將其分割成多個檔案。
|
home.splitPdfByChapters.desc=根據 PDF 的章節結構將其分割成多個檔案。
|
||||||
splitPdfByChapters.tags=分割,章節,書籤,整理
|
splitPdfByChapters.tags=分割,章節,書籤,整理
|
||||||
|
|
||||||
|
home.validateSignature.title=Validate PDF Signature
|
||||||
|
home.validateSignature.desc=Verify digital signatures and certificates in PDF documents
|
||||||
|
validateSignature.tags=signature,verify,validate,pdf,certificate,digital signature,Validate Signature,Validate certificate
|
||||||
|
|
||||||
#replace-invert-color
|
#replace-invert-color
|
||||||
replace-color.title=取代-反轉顏色
|
replace-color.title=取代-反轉顏色
|
||||||
replace-color.header=取代-反轉 PDF 顏色
|
replace-color.header=取代-反轉 PDF 顏色
|
||||||
@@ -1275,3 +1279,38 @@ releases.title=Release Notes
|
|||||||
releases.header=Release Notes
|
releases.header=Release Notes
|
||||||
releases.current.version=Current Release
|
releases.current.version=Current Release
|
||||||
releases.note=Release notes are only available in English
|
releases.note=Release notes are only available in English
|
||||||
|
|
||||||
|
#Validate Signature
|
||||||
|
validateSignature.title=Validate PDF Signatures
|
||||||
|
validateSignature.header=Validate Digital Signatures
|
||||||
|
validateSignature.selectPDF=Select signed PDF file
|
||||||
|
validateSignature.submit=Validate Signatures
|
||||||
|
validateSignature.results=Validation Results
|
||||||
|
validateSignature.status=Status
|
||||||
|
validateSignature.signer=Signer
|
||||||
|
validateSignature.date=Date
|
||||||
|
validateSignature.reason=Reason
|
||||||
|
validateSignature.location=Location
|
||||||
|
validateSignature.noSignatures=No digital signatures found in this document
|
||||||
|
validateSignature.status.valid=Valid
|
||||||
|
validateSignature.status.invalid=Invalid
|
||||||
|
validateSignature.chain.invalid=Certificate chain validation failed - cannot verify signer's identity
|
||||||
|
validateSignature.trust.invalid=Certificate not in trust store - source cannot be verified
|
||||||
|
validateSignature.cert.expired=Certificate has expired
|
||||||
|
validateSignature.cert.revoked=Certificate has been revoked
|
||||||
|
validateSignature.signature.info=Signature Information
|
||||||
|
validateSignature.signature=Signature
|
||||||
|
validateSignature.signature.mathValid=Signature is mathematically valid BUT:
|
||||||
|
validateSignature.selectCustomCert=Custom Certificate File X.509 (Optional)
|
||||||
|
validateSignature.cert.info=Certificate Details
|
||||||
|
validateSignature.cert.issuer=Issuer
|
||||||
|
validateSignature.cert.subject=Subject
|
||||||
|
validateSignature.cert.serialNumber=Serial Number
|
||||||
|
validateSignature.cert.validFrom=Valid From
|
||||||
|
validateSignature.cert.validUntil=Valid Until
|
||||||
|
validateSignature.cert.algorithm=Algorithm
|
||||||
|
validateSignature.cert.keySize=Key Size
|
||||||
|
validateSignature.cert.version=Version
|
||||||
|
validateSignature.cert.keyUsage=Key Usage
|
||||||
|
validateSignature.cert.selfSigned=Self-Signed
|
||||||
|
validateSignature.cert.bits=bits
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="file"] {
|
.input-container input[type="file"] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,36 @@
|
|||||||
(function () {
|
(function () {
|
||||||
|
if (window.isDownloadScriptInitialized) return; // Prevent re-execution
|
||||||
|
window.isDownloadScriptInitialized = true;
|
||||||
|
|
||||||
const { pdfPasswordPrompt, multipleInputsForSingleRequest, disableMultipleFiles, remoteCall, sessionExpired, refreshPage, error } = window.stirlingPDF;
|
const {
|
||||||
|
pdfPasswordPrompt,
|
||||||
|
multipleInputsForSingleRequest,
|
||||||
|
disableMultipleFiles,
|
||||||
|
remoteCall,
|
||||||
|
sessionExpired,
|
||||||
|
refreshPage,
|
||||||
|
error,
|
||||||
|
} = window.stirlingPDF;
|
||||||
|
|
||||||
function showErrorBanner(message, stackTrace) {
|
function showErrorBanner(message, stackTrace) {
|
||||||
const errorContainer = document.getElementById("errorContainer");
|
const errorContainer = document.getElementById('errorContainer');
|
||||||
errorContainer.style.display = "block"; // Display the banner
|
errorContainer.style.display = 'block'; // Display the banner
|
||||||
errorContainer.querySelector(".alert-heading").textContent = error;
|
errorContainer.querySelector('.alert-heading').textContent = error;
|
||||||
errorContainer.querySelector("p").textContent = message;
|
errorContainer.querySelector('p').textContent = message;
|
||||||
document.querySelector("#traceContent").textContent = stackTrace;
|
document.querySelector('#traceContent').textContent = stackTrace;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showSessionExpiredPrompt() {
|
function showSessionExpiredPrompt() {
|
||||||
const errorContainer = document.getElementById("errorContainer");
|
const errorContainer = document.getElementById('errorContainer');
|
||||||
errorContainer.style.display = "block";
|
errorContainer.style.display = 'block';
|
||||||
errorContainer.querySelector(".alert-heading").textContent = sessionExpired;
|
errorContainer.querySelector('.alert-heading').textContent = sessionExpired;
|
||||||
errorContainer.querySelector("p").textContent = sessionExpired;
|
errorContainer.querySelector('p').textContent = sessionExpired;
|
||||||
document.querySelector("#traceContent").textContent = "";
|
document.querySelector('#traceContent').textContent = '';
|
||||||
|
|
||||||
// Optional: Add a refresh button
|
// Optional: Add a refresh button
|
||||||
const refreshButton = document.createElement("button");
|
const refreshButton = document.createElement('button');
|
||||||
refreshButton.textContent = refreshPage;
|
refreshButton.textContent = refreshPage;
|
||||||
refreshButton.className = "btn btn-primary mt-3";
|
refreshButton.className = 'btn btn-primary mt-3';
|
||||||
refreshButton.onclick = () => location.reload();
|
refreshButton.onclick = () => location.reload();
|
||||||
errorContainer.appendChild(refreshButton);
|
errorContainer.appendChild(refreshButton);
|
||||||
}
|
}
|
||||||
@@ -28,19 +38,19 @@
|
|||||||
let firstErrorOccurred = false;
|
let firstErrorOccurred = false;
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("form").submit(async function (event) {
|
$('form').submit(async function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
firstErrorOccurred = false;
|
firstErrorOccurred = false;
|
||||||
const url = this.action;
|
const url = this.action;
|
||||||
const files = $("#fileInput-input")[0].files;
|
const files = $('#fileInput-input')[0].files;
|
||||||
const formData = new FormData(this);
|
const formData = new FormData(this);
|
||||||
const submitButton = document.getElementById("submitBtn");
|
const submitButton = document.getElementById('submitBtn');
|
||||||
const showGameBtn = document.getElementById("show-game-btn");
|
const showGameBtn = document.getElementById('show-game-btn');
|
||||||
const originalButtonText = submitButton.textContent;
|
const originalButtonText = submitButton.textContent;
|
||||||
var boredWaiting = localStorage.getItem("boredWaiting") || "disabled";
|
var boredWaiting = localStorage.getItem('boredWaiting') || 'disabled';
|
||||||
|
|
||||||
if (showGameBtn) {
|
if (showGameBtn) {
|
||||||
showGameBtn.style.display = "none";
|
showGameBtn.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove empty file entries
|
// Remove empty file entries
|
||||||
@@ -49,58 +59,60 @@
|
|||||||
formData.delete(key);
|
formData.delete(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const override = $("#override").val() || "";
|
const override = $('#override').val() || '';
|
||||||
console.log(override);
|
console.log(override);
|
||||||
|
|
||||||
// Set a timeout to show the game button if operation takes more than 5 seconds
|
// Set a timeout to show the game button if operation takes more than 5 seconds
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
if (boredWaiting === "enabled" && showGameBtn) {
|
if (boredWaiting === 'enabled' && showGameBtn) {
|
||||||
showGameBtn.style.display = "block";
|
showGameBtn.style.display = 'block';
|
||||||
showGameBtn.parentNode.insertBefore(document.createElement('br'), showGameBtn.nextSibling);
|
showGameBtn.parentNode.insertBefore(document.createElement('br'), showGameBtn.nextSibling);
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
submitButton.textContent = "Processing...";
|
submitButton.textContent = 'Processing...';
|
||||||
submitButton.disabled = true;
|
submitButton.disabled = true;
|
||||||
|
|
||||||
if (remoteCall === true) {
|
if (remoteCall === true) {
|
||||||
if (override === "multi" || (!multipleInputsForSingleRequest && files.length > 1 && override !== "single")) {
|
if (override === 'multi' || (!multipleInputsForSingleRequest && files.length > 1 && override !== 'single')) {
|
||||||
await submitMultiPdfForm(url, files);
|
await submitMultiPdfForm(url, files);
|
||||||
} else {
|
} else {
|
||||||
await handleSingleDownload(url, formData);
|
await handleSingleDownload(url, formData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//clearFileInput();
|
||||||
clearFileInput();
|
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
if (showGameBtn) {
|
if (showGameBtn) {
|
||||||
showGameBtn.style.display = "none";
|
showGameBtn.style.display = 'none';
|
||||||
showGameBtn.style.marginTop = "";
|
showGameBtn.style.marginTop = '';
|
||||||
}
|
}
|
||||||
submitButton.textContent = originalButtonText;
|
submitButton.textContent = originalButtonText;
|
||||||
submitButton.disabled = false;
|
submitButton.disabled = false;
|
||||||
|
|
||||||
// After process finishes, check for boredWaiting and gameDialog open status
|
// After process finishes, check for boredWaiting and gameDialog open status
|
||||||
const gameDialog = document.getElementById('game-container-wrapper');
|
const gameDialog = document.getElementById('game-container-wrapper');
|
||||||
if (boredWaiting === "enabled" && gameDialog && gameDialog.open) {
|
if (boredWaiting === 'enabled' && gameDialog && gameDialog.open) {
|
||||||
// Display a green banner at the bottom of the screen saying "Download complete"
|
// Display a green banner at the bottom of the screen saying "Download complete"
|
||||||
let downloadCompleteText = "Download Complete";
|
let downloadCompleteText = 'Download Complete';
|
||||||
if (window.downloadCompleteText) {
|
if (window.downloadCompleteText) {
|
||||||
downloadCompleteText = window.downloadCompleteText;
|
downloadCompleteText = window.downloadCompleteText;
|
||||||
}
|
}
|
||||||
$("body").append('<div id="download-complete-banner" style="position:fixed;bottom:0;left:0;width:100%;background-color:green;color:white;text-align:center;padding:10px;font-size:16px;z-index:1000;">'+ downloadCompleteText + '</div>');
|
$('body').append(
|
||||||
|
'<div id="download-complete-banner" style="position:fixed;bottom:0;left:0;width:100%;background-color:green;color:white;text-align:center;padding:10px;font-size:16px;z-index:1000;">' +
|
||||||
|
downloadCompleteText +
|
||||||
|
'</div>'
|
||||||
|
);
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
$("#download-complete-banner").fadeOut("slow", function() {
|
$('#download-complete-banner').fadeOut('slow', function () {
|
||||||
$(this).remove(); // Remove the banner after fading out
|
$(this).remove(); // Remove the banner after fading out
|
||||||
});
|
});
|
||||||
}, 5000); // Banner will fade out after 5 seconds
|
}, 5000); // Banner will fade out after 5 seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
showGameBtn.style.display = "none";
|
showGameBtn.style.display = 'none';
|
||||||
submitButton.textContent = originalButtonText;
|
submitButton.textContent = originalButtonText;
|
||||||
submitButton.disabled = false;
|
submitButton.disabled = false;
|
||||||
handleDownloadError(error);
|
handleDownloadError(error);
|
||||||
@@ -112,7 +124,7 @@
|
|||||||
async function getPDFPageCount(file) {
|
async function getPDFPageCount(file) {
|
||||||
try {
|
try {
|
||||||
const arrayBuffer = await file.arrayBuffer();
|
const arrayBuffer = await file.arrayBuffer();
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdfjs-legacy/pdf.worker.mjs'
|
pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdfjs-legacy/pdf.worker.mjs';
|
||||||
const pdf = await pdfjsLib.getDocument({data: arrayBuffer}).promise;
|
const pdf = await pdfjsLib.getDocument({data: arrayBuffer}).promise;
|
||||||
return pdf.numPages;
|
return pdf.numPages;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -128,8 +140,8 @@
|
|||||||
let errorMessage = null;
|
let errorMessage = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, { method: "POST", body: formData });
|
const response = await fetch(url, {method: 'POST', body: formData});
|
||||||
const contentType = response.headers.get("content-type");
|
const contentType = response.headers.get('content-type');
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
errorMessage = response.status;
|
errorMessage = response.status;
|
||||||
@@ -137,31 +149,30 @@
|
|||||||
showSessionExpiredPrompt();
|
showSessionExpiredPrompt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (contentType && contentType.includes("application/json")) {
|
if (contentType && contentType.includes('application/json')) {
|
||||||
console.error("Throwing error banner, response was not okay");
|
console.error('Throwing error banner, response was not okay');
|
||||||
return handleJsonResponse(response);
|
return handleJsonResponse(response);
|
||||||
}
|
}
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentDisposition = response.headers.get("Content-Disposition");
|
const contentDisposition = response.headers.get('Content-Disposition');
|
||||||
let filename = getFilenameFromContentDisposition(contentDisposition);
|
let filename = getFilenameFromContentDisposition(contentDisposition);
|
||||||
|
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
success = true;
|
success = true;
|
||||||
|
|
||||||
if (contentType.includes("application/pdf") || contentType.includes("image/")) {
|
if (contentType.includes('application/pdf') || contentType.includes('image/')) {
|
||||||
clearFileInput();
|
//clearFileInput();
|
||||||
return handleResponse(blob, filename, !isMulti, isZip);
|
return handleResponse(blob, filename, !isMulti, isZip);
|
||||||
} else {
|
} else {
|
||||||
clearFileInput();
|
//clearFileInput();
|
||||||
return handleResponse(blob, filename, false, isZip);
|
return handleResponse(blob, filename, false, isZip);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
success = false;
|
success = false;
|
||||||
errorMessage = error.message;
|
errorMessage = error.message;
|
||||||
console.error("Error in handleSingleDownload:", error);
|
console.error('Error in handleSingleDownload:', error);
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
const processingTime = performance.now() - startTime;
|
const processingTime = performance.now() - startTime;
|
||||||
@@ -175,7 +186,7 @@
|
|||||||
file_size: file ? file.size : 0,
|
file_size: file ? file.size : 0,
|
||||||
processing_time: processingTime,
|
processing_time: processingTime,
|
||||||
error_message: errorMessage,
|
error_message: errorMessage,
|
||||||
pdf_pages: pageCount
|
pdf_pages: pageCount,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,11 +195,11 @@
|
|||||||
function getFilenameFromContentDisposition(contentDisposition) {
|
function getFilenameFromContentDisposition(contentDisposition) {
|
||||||
let filename;
|
let filename;
|
||||||
|
|
||||||
if (contentDisposition && contentDisposition.indexOf("attachment") !== -1) {
|
if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) {
|
||||||
filename = decodeURIComponent(contentDisposition.split("filename=")[1].replace(/"/g, "")).trim();
|
filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim();
|
||||||
} else {
|
} else {
|
||||||
// If the Content-Disposition header is not present or does not contain the filename, use a default filename
|
// If the Content-Disposition header is not present or does not contain the filename, use a default filename
|
||||||
filename = "download";
|
filename = 'download';
|
||||||
}
|
}
|
||||||
|
|
||||||
return filename;
|
return filename;
|
||||||
@@ -198,30 +209,30 @@
|
|||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
const errorMessage = JSON.stringify(json, null, 2);
|
const errorMessage = JSON.stringify(json, null, 2);
|
||||||
if (
|
if (
|
||||||
errorMessage.toLowerCase().includes("the password is incorrect") ||
|
errorMessage.toLowerCase().includes('the password is incorrect') ||
|
||||||
errorMessage.toLowerCase().includes("Password is not provided") ||
|
errorMessage.toLowerCase().includes('Password is not provided') ||
|
||||||
errorMessage.toLowerCase().includes("PDF contains an encryption dictionary")
|
errorMessage.toLowerCase().includes('PDF contains an encryption dictionary')
|
||||||
) {
|
) {
|
||||||
if (!firstErrorOccurred) {
|
if (!firstErrorOccurred) {
|
||||||
firstErrorOccurred = true;
|
firstErrorOccurred = true;
|
||||||
alert(pdfPasswordPrompt);
|
alert(pdfPasswordPrompt);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showErrorBanner(json.error + ":" + json.message, json.trace);
|
showErrorBanner(json.error + ':' + json.message, json.trace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleResponse(blob, filename, considerViewOptions = false, isZip = false) {
|
async function handleResponse(blob, filename, considerViewOptions = false, isZip = false) {
|
||||||
if (!blob) return;
|
if (!blob) return;
|
||||||
const downloadOption = localStorage.getItem("downloadOption");
|
const downloadOption = localStorage.getItem('downloadOption');
|
||||||
if (considerViewOptions) {
|
if (considerViewOptions) {
|
||||||
if (downloadOption === "sameWindow") {
|
if (downloadOption === 'sameWindow') {
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
return;
|
return;
|
||||||
} else if (downloadOption === "newWindow") {
|
} else if (downloadOption === 'newWindow') {
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
window.open(url, "_blank");
|
window.open(url, '_blank');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,11 +251,11 @@
|
|||||||
|
|
||||||
function downloadFile(blob, filename) {
|
function downloadFile(blob, filename) {
|
||||||
if (!(blob instanceof Blob)) {
|
if (!(blob instanceof Blob)) {
|
||||||
console.error("Invalid blob passed to downloadFile function");
|
console.error('Invalid blob passed to downloadFile function');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
const a = document.createElement("a");
|
const a = document.createElement('a');
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = filename;
|
a.download = filename;
|
||||||
a.click();
|
a.click();
|
||||||
@@ -254,18 +265,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function submitMultiPdfForm(url, files) {
|
async function submitMultiPdfForm(url, files) {
|
||||||
const zipThreshold = parseInt(localStorage.getItem("zipThreshold"), 10) || 4;
|
const zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4;
|
||||||
const zipFiles = files.length > zipThreshold;
|
const zipFiles = files.length > zipThreshold;
|
||||||
let jszip = null;
|
let jszip = null;
|
||||||
// Add Space below Progress Bar before Showing
|
// Add Space below Progress Bar before Showing
|
||||||
$('.progressBarContainer').after($('<br>'));
|
$('.progressBarContainer').after($('<br>'));
|
||||||
$(".progressBarContainer").show();
|
$('.progressBarContainer').show();
|
||||||
// Initialize the progress bar
|
// Initialize the progress bar
|
||||||
|
|
||||||
let progressBar = $(".progressBar");
|
let progressBar = $('.progressBar');
|
||||||
progressBar.css("width", "0%");
|
progressBar.css('width', '0%');
|
||||||
progressBar.attr("aria-valuenow", 0);
|
progressBar.attr('aria-valuenow', 0);
|
||||||
progressBar.attr("aria-valuemax", files.length);
|
progressBar.attr('aria-valuemax', files.length);
|
||||||
|
|
||||||
if (zipFiles) {
|
if (zipFiles) {
|
||||||
jszip = new JSZip();
|
jszip = new JSZip();
|
||||||
@@ -279,10 +290,10 @@
|
|||||||
if (postForm) {
|
if (postForm) {
|
||||||
formData = new FormData($(postForm)[0]); // Convert the form to a jQuery object and get the raw DOM element
|
formData = new FormData($(postForm)[0]); // Convert the form to a jQuery object and get the raw DOM element
|
||||||
} else {
|
} else {
|
||||||
console.log("No form with POST method found.");
|
console.log('No form with POST method found.');
|
||||||
}
|
}
|
||||||
//Remove file to reuse parameters for other runs
|
//Remove file to reuse parameters for other runs
|
||||||
formData.delete("fileInput");
|
formData.delete('fileInput');
|
||||||
// Remove empty file entries
|
// Remove empty file entries
|
||||||
for (let [key, value] of formData.entries()) {
|
for (let [key, value] of formData.entries()) {
|
||||||
if (value instanceof File && !value.name) {
|
if (value instanceof File && !value.name) {
|
||||||
@@ -298,12 +309,12 @@
|
|||||||
for (const chunk of chunks) {
|
for (const chunk of chunks) {
|
||||||
const promises = chunk.map(async (file) => {
|
const promises = chunk.map(async (file) => {
|
||||||
let fileFormData = new FormData();
|
let fileFormData = new FormData();
|
||||||
fileFormData.append("fileInput", file);
|
fileFormData.append('fileInput', file);
|
||||||
console.log(fileFormData);
|
console.log(fileFormData);
|
||||||
// Add other form data
|
// Add other form data
|
||||||
for (let pair of formData.entries()) {
|
for (let pair of formData.entries()) {
|
||||||
fileFormData.append(pair[0], pair[1]);
|
fileFormData.append(pair[0], pair[1]);
|
||||||
console.log(pair[0] + ", " + pair[1]);
|
console.log(pair[0] + ', ' + pair[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -325,22 +336,22 @@
|
|||||||
|
|
||||||
if (zipFiles) {
|
if (zipFiles) {
|
||||||
try {
|
try {
|
||||||
const content = await jszip.generateAsync({ type: "blob" });
|
const content = await jszip.generateAsync({type: 'blob'});
|
||||||
downloadFile(content, "files.zip");
|
downloadFile(content, 'files.zip');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error generating ZIP file: " + error);
|
console.error('Error generating ZIP file: ' + error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
progressBar.css("width", "100%");
|
progressBar.css('width', '100%');
|
||||||
progressBar.attr("aria-valuenow", Array.from(files).length);
|
progressBar.attr('aria-valuenow', Array.from(files).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateProgressBar(progressBar, files) {
|
function updateProgressBar(progressBar, files) {
|
||||||
let progress = (progressBar.attr("aria-valuenow") / files.length) * 100 + 100 / files.length;
|
let progress = (progressBar.attr('aria-valuenow') / files.length) * 100 + 100 / files.length;
|
||||||
progressBar.css("width", progress + "%");
|
progressBar.css('width', progress + '%');
|
||||||
progressBar.attr("aria-valuenow", parseInt(progressBar.attr("aria-valuenow")) + 1);
|
progressBar.attr('aria-valuenow', parseInt(progressBar.attr('aria-valuenow')) + 1);
|
||||||
}
|
}
|
||||||
window.addEventListener("unload", () => {
|
window.addEventListener('unload', () => {
|
||||||
for (const url of urls) {
|
for (const url of urls) {
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
}
|
}
|
||||||
@@ -349,15 +360,15 @@
|
|||||||
// Clear file input after job
|
// Clear file input after job
|
||||||
function clearFileInput() {
|
function clearFileInput() {
|
||||||
let pathname = document.location.pathname;
|
let pathname = document.location.pathname;
|
||||||
if(pathname != "/merge-pdfs"){
|
if (pathname != '/merge-pdfs') {
|
||||||
let formElement = document.querySelector("#fileInput-input");
|
let formElement = document.querySelector('#fileInput-input');
|
||||||
formElement.value = '';
|
formElement.value = '';
|
||||||
let editSectionElement = document.querySelector("#editSection");
|
let editSectionElement = document.querySelector('#editSection');
|
||||||
if (editSectionElement) {
|
if (editSectionElement) {
|
||||||
editSectionElement.style.display = "none";
|
editSectionElement.style.display = 'none';
|
||||||
}
|
}
|
||||||
let cropPdfCanvas = document.querySelector("#cropPdfCanvas");
|
let cropPdfCanvas = document.querySelector('#cropPdfCanvas');
|
||||||
let overlayCanvas = document.querySelector("#overlayCanvas");
|
let overlayCanvas = document.querySelector('#overlayCanvas');
|
||||||
if (cropPdfCanvas && overlayCanvas) {
|
if (cropPdfCanvas && overlayCanvas) {
|
||||||
cropPdfCanvas.width = 0;
|
cropPdfCanvas.width = 0;
|
||||||
cropPdfCanvas.height = 0;
|
cropPdfCanvas.height = 0;
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { MovePageUpCommand, MovePageDownCommand } from "./commands/move-page.js";
|
import {MovePageUpCommand, MovePageDownCommand} from './commands/move-page.js';
|
||||||
import { RemoveSelectedCommand } from "./commands/remove.js";
|
import {RemoveSelectedCommand} from './commands/remove.js';
|
||||||
import { RotateAllCommand, RotateElementCommand } from "./commands/rotate.js";
|
import {RotateAllCommand, RotateElementCommand} from './commands/rotate.js';
|
||||||
import { SplitAllCommand } from "./commands/split.js";
|
import {SplitAllCommand} from './commands/split.js';
|
||||||
import { UndoManager } from "./UndoManager.js";
|
import {UndoManager} from './UndoManager.js';
|
||||||
|
import {PageBreakCommand} from './commands/page-break.js';
|
||||||
|
import {AddFilesCommand} from './commands/add-page.js';
|
||||||
|
|
||||||
class PdfContainer {
|
class PdfContainer {
|
||||||
fileName;
|
fileName;
|
||||||
@@ -34,7 +36,7 @@ class PdfContainer {
|
|||||||
this.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay.bind(this);
|
this.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay.bind(this);
|
||||||
this.toggleSelectPageVisibility = this.toggleSelectPageVisibility.bind(this);
|
this.toggleSelectPageVisibility = this.toggleSelectPageVisibility.bind(this);
|
||||||
this.updatePagesFromCSV = this.updatePagesFromCSV.bind(this);
|
this.updatePagesFromCSV = this.updatePagesFromCSV.bind(this);
|
||||||
this.addFilesBlankAll = this.addFilesBlankAll.bind(this)
|
this.addFilesBlankAll = this.addFilesBlankAll.bind(this);
|
||||||
this.removeAllElements = this.removeAllElements.bind(this);
|
this.removeAllElements = this.removeAllElements.bind(this);
|
||||||
this.resetPages = this.resetPages.bind(this);
|
this.resetPages = this.resetPages.bind(this);
|
||||||
|
|
||||||
@@ -63,7 +65,7 @@ class PdfContainer {
|
|||||||
window.updatePagesFromCSV = this.updatePagesFromCSV;
|
window.updatePagesFromCSV = this.updatePagesFromCSV;
|
||||||
window.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay;
|
window.updateSelectedPagesDisplay = this.updateSelectedPagesDisplay;
|
||||||
window.updatePageNumbersAndCheckboxes = this.updatePageNumbersAndCheckboxes;
|
window.updatePageNumbersAndCheckboxes = this.updatePageNumbersAndCheckboxes;
|
||||||
window.addFilesBlankAll = this.addFilesBlankAll
|
window.addFilesBlankAll = this.addFilesBlankAll;
|
||||||
window.removeAllElements = this.removeAllElements;
|
window.removeAllElements = this.removeAllElements;
|
||||||
window.resetPages = this.resetPages;
|
window.resetPages = this.resetPages;
|
||||||
|
|
||||||
@@ -76,7 +78,7 @@ class PdfContainer {
|
|||||||
|
|
||||||
undoBtn.disabled = !canUndo;
|
undoBtn.disabled = !canUndo;
|
||||||
redoBtn.disabled = !canRedo;
|
redoBtn.disabled = !canRedo;
|
||||||
})
|
});
|
||||||
|
|
||||||
window.undo = () => {
|
window.undo = () => {
|
||||||
if (undoManager.canUndo()) undoManager.undo();
|
if (undoManager.canUndo()) undoManager.undo();
|
||||||
@@ -84,7 +86,7 @@ class PdfContainer {
|
|||||||
undoBtn.disabled = !undoManager.canUndo();
|
undoBtn.disabled = !undoManager.canUndo();
|
||||||
redoBtn.disabled = !undoManager.canRedo();
|
redoBtn.disabled = !undoManager.canRedo();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
window.redo = () => {
|
window.redo = () => {
|
||||||
if (undoManager.canRedo()) undoManager.redo();
|
if (undoManager.canRedo()) undoManager.redo();
|
||||||
@@ -92,15 +94,15 @@ class PdfContainer {
|
|||||||
undoBtn.disabled = !undoManager.canUndo();
|
undoBtn.disabled = !undoManager.canUndo();
|
||||||
redoBtn.disabled = !undoManager.canRedo();
|
redoBtn.disabled = !undoManager.canRedo();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const filenameInput = document.getElementById("filename-input");
|
const filenameInput = document.getElementById('filename-input');
|
||||||
const downloadBtn = document.getElementById("export-button");
|
const downloadBtn = document.getElementById('export-button');
|
||||||
|
|
||||||
filenameInput.onkeyup = this.updateFilename;
|
filenameInput.onkeyup = this.updateFilename;
|
||||||
filenameInput.onkeydown = this.preventIllegalChars;
|
filenameInput.onkeydown = this.preventIllegalChars;
|
||||||
filenameInput.disabled = false;
|
filenameInput.disabled = false;
|
||||||
filenameInput.innerText = "";
|
filenameInput.innerText = '';
|
||||||
downloadBtn.disabled = true;
|
downloadBtn.disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,55 +130,71 @@ class PdfContainer {
|
|||||||
return movePageCommand;
|
return movePageCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
addFiles(nextSiblingElement, blank = false) {
|
async addFiles(element) {
|
||||||
if (blank) {
|
let addFilesCommand = new AddFilesCommand(
|
||||||
|
element,
|
||||||
|
window.selectedPages,
|
||||||
|
this.addFilesAction.bind(this),
|
||||||
|
this.pagesContainer
|
||||||
|
);
|
||||||
|
|
||||||
this.addFilesBlank(nextSiblingElement);
|
await addFilesCommand.execute();
|
||||||
|
|
||||||
} else {
|
this.undoManager.pushUndoClearRedo(addFilesCommand);
|
||||||
var input = document.createElement("input");
|
}
|
||||||
input.type = "file";
|
|
||||||
|
async addFilesAction(nextSiblingElement) {
|
||||||
|
let pages = [];
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
input.multiple = true;
|
input.multiple = true;
|
||||||
input.setAttribute("accept", "application/pdf,image/*");
|
input.setAttribute('accept', 'application/pdf,image/*');
|
||||||
|
|
||||||
input.onchange = async (e) => {
|
input.onchange = async (e) => {
|
||||||
const files = e.target.files;
|
const files = e.target.files;
|
||||||
|
if (files.length > 0) {
|
||||||
this.addFilesFromFiles(files, nextSiblingElement);
|
pages = await this.addFilesFromFiles(files, nextSiblingElement, pages);
|
||||||
this.updateFilename(files ? files[0].name : "");
|
this.updateFilename(files[0].name);
|
||||||
const selectAll = document.getElementById("select-pages-container");
|
const selectAll = document.getElementById('select-pages-container');
|
||||||
selectAll.classList.toggle("hidden", false);
|
selectAll.classList.toggle('hidden', false);
|
||||||
|
}
|
||||||
|
resolve(pages);
|
||||||
};
|
};
|
||||||
|
|
||||||
input.click();
|
input.click();
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async addFilesFromFiles(files, nextSiblingElement) {
|
async addFilesFromFiles(files, nextSiblingElement, pages) {
|
||||||
this.fileName = files[0].name;
|
this.fileName = files[0].name;
|
||||||
for (var i = 0; i < files.length; i++) {
|
for (var i = 0; i < files.length; i++) {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
let processingTime, errorMessage = null, pageCount = 0;
|
let processingTime,
|
||||||
|
errorMessage = null,
|
||||||
|
pageCount = 0;
|
||||||
try {
|
try {
|
||||||
const file = files[i];
|
const file = files[i];
|
||||||
if (file.type === "application/pdf") {
|
if (file.type === 'application/pdf') {
|
||||||
const {renderer, pdfDocument} = await this.loadFile(file);
|
const {renderer, pdfDocument} = await this.loadFile(file);
|
||||||
pageCount = renderer.pageCount || 0;
|
pageCount = renderer.pageCount || 0;
|
||||||
await this.addPdfFile(renderer, pdfDocument, nextSiblingElement);
|
pages = await this.addPdfFile(renderer, pdfDocument, nextSiblingElement, pages);
|
||||||
} else if (file.type.startsWith("image/")) {
|
} else if (file.type.startsWith('image/')) {
|
||||||
await this.addImageFile(file, nextSiblingElement);
|
pages = await this.addImageFile(file, nextSiblingElement, pages);
|
||||||
}
|
}
|
||||||
processingTime = Date.now() - startTime;
|
processingTime = Date.now() - startTime;
|
||||||
this.captureFileProcessingEvent(true, file, processingTime, null, pageCount);
|
this.captureFileProcessingEvent(true, file, processingTime, null, pageCount);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
processingTime = Date.now() - startTime;
|
processingTime = Date.now() - startTime;
|
||||||
errorMessage = error.message || "Unknown error";
|
errorMessage = error.message || 'Unknown error';
|
||||||
this.captureFileProcessingEvent(false, files[i], processingTime, errorMessage, pageCount);
|
this.captureFileProcessingEvent(false, files[i], processingTime, errorMessage, pageCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelectorAll(".enable-on-file").forEach((element) => {
|
document.querySelectorAll('.enable-on-file').forEach((element) => {
|
||||||
element.disabled = false;
|
element.disabled = false;
|
||||||
});
|
});
|
||||||
|
return pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
captureFileProcessingEvent(success, file, processingTime, errorMessage, pageCount) {
|
captureFileProcessingEvent(success, file, processingTime, errorMessage, pageCount) {
|
||||||
@@ -191,23 +209,20 @@ class PdfContainer {
|
|||||||
pdf_pages: pageCount,
|
pdf_pages: pageCount,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}catch{
|
} catch {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async addFilesBlank(nextSiblingElement, pages) {
|
||||||
async addFilesBlank(nextSiblingElement) {
|
|
||||||
let doc = await PDFLib.PDFDocument.create();
|
let doc = await PDFLib.PDFDocument.create();
|
||||||
let docBytes = await doc.save();
|
let docBytes = await doc.save();
|
||||||
|
|
||||||
const url = URL.createObjectURL(new Blob([docBytes], {type: 'application/pdf'}));
|
const url = URL.createObjectURL(new Blob([docBytes], {type: 'application/pdf'}));
|
||||||
|
|
||||||
const renderer = await this.toRenderer(url);
|
const renderer = await this.toRenderer(url);
|
||||||
|
pages = await this.addPdfFile(renderer, doc, nextSiblingElement, pages);
|
||||||
await this.addPdfFile(renderer, doc, nextSiblingElement);
|
return pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rotateElement(element, deg) {
|
rotateElement(element, deg) {
|
||||||
let rotateCommand = new RotateElementCommand(element, deg);
|
let rotateCommand = new RotateElementCommand(element, deg);
|
||||||
rotateCommand.execute();
|
rotateCommand.execute();
|
||||||
@@ -215,37 +230,43 @@ class PdfContainer {
|
|||||||
return rotateCommand;
|
return rotateCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
async addPdfFile(renderer, pdfDocument, nextSiblingElement) {
|
async addPdfFile(renderer, pdfDocument, nextSiblingElement, pages) {
|
||||||
for (var i = 0; i < renderer.pageCount; i++) {
|
for (var i = 0; i < renderer.pageCount; i++) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement('div');
|
||||||
|
|
||||||
div.classList.add("page-container");
|
div.classList.add('page-container');
|
||||||
div.id = "page-container-" + (i + 1);
|
div.id = 'page-container-' + (i + 1);
|
||||||
var img = document.createElement("img");
|
var img = document.createElement('img');
|
||||||
img.classList.add("page-image");
|
img.classList.add('page-image');
|
||||||
const imageSrc = await renderer.renderPage(i);
|
const imageSrc = await renderer.renderPage(i);
|
||||||
img.src = imageSrc;
|
img.src = imageSrc;
|
||||||
img.pageIdx = i;
|
img.pageIdx = i;
|
||||||
img.rend = renderer;
|
img.rend = renderer;
|
||||||
img.doc = pdfDocument;
|
img.doc = pdfDocument;
|
||||||
div.appendChild(img);
|
div.appendChild(img);
|
||||||
|
|
||||||
this.pdfAdapters.forEach((adapter) => {
|
this.pdfAdapters.forEach((adapter) => {
|
||||||
adapter.adapt?.(div);
|
adapter.adapt?.(div);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (nextSiblingElement) {
|
if (nextSiblingElement) {
|
||||||
this.pagesContainer.insertBefore(div, nextSiblingElement);
|
this.pagesContainer.insertBefore(div, nextSiblingElement);
|
||||||
} else {
|
} else {
|
||||||
this.pagesContainer.appendChild(div);
|
this.pagesContainer.appendChild(div);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
pages.push(div);
|
||||||
}
|
}
|
||||||
|
|
||||||
async addImageFile(file, nextSiblingElement) {
|
return pages;
|
||||||
const div = document.createElement("div");
|
}
|
||||||
div.classList.add("page-container");
|
|
||||||
|
|
||||||
var img = document.createElement("img");
|
async addImageFile(file, nextSiblingElement, pages) {
|
||||||
img.classList.add("page-image");
|
const div = document.createElement('div');
|
||||||
|
div.classList.add('page-container');
|
||||||
|
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.classList.add('page-image');
|
||||||
img.src = URL.createObjectURL(file);
|
img.src = URL.createObjectURL(file);
|
||||||
div.appendChild(img);
|
div.appendChild(img);
|
||||||
|
|
||||||
@@ -257,6 +278,8 @@ class PdfContainer {
|
|||||||
} else {
|
} else {
|
||||||
this.pagesContainer.appendChild(div);
|
this.pagesContainer.appendChild(div);
|
||||||
}
|
}
|
||||||
|
pages.push(div);
|
||||||
|
return pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadFile(file) {
|
async loadFile(file) {
|
||||||
@@ -267,7 +290,7 @@ class PdfContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async toRenderer(objectUrl) {
|
async toRenderer(objectUrl) {
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc = "./pdfjs-legacy/pdf.worker.mjs";
|
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
|
||||||
const pdf = await pdfjsLib.getDocument(objectUrl).promise;
|
const pdf = await pdfjsLib.getDocument(objectUrl).promise;
|
||||||
return {
|
return {
|
||||||
document: pdf,
|
document: pdf,
|
||||||
@@ -275,7 +298,7 @@ class PdfContainer {
|
|||||||
renderPage: async function (pageIdx) {
|
renderPage: async function (pageIdx) {
|
||||||
const page = await this.document.getPage(pageIdx + 1);
|
const page = await this.document.getPage(pageIdx + 1);
|
||||||
|
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement('canvas');
|
||||||
|
|
||||||
// set the canvas size to the size of the page
|
// set the canvas size to the size of the page
|
||||||
if (page.rotate == 90 || page.rotate == 270) {
|
if (page.rotate == 90 || page.rotate == 270) {
|
||||||
@@ -288,7 +311,7 @@ class PdfContainer {
|
|||||||
|
|
||||||
// render the page onto the canvas
|
// render the page onto the canvas
|
||||||
var renderContext = {
|
var renderContext = {
|
||||||
canvasContext: canvas.getContext("2d"),
|
canvasContext: canvas.getContext('2d'),
|
||||||
viewport: page.getViewport({scale: 1}),
|
viewport: page.getViewport({scale: 1}),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -316,7 +339,7 @@ class PdfContainer {
|
|||||||
//if in page select mode is active rotate only selected pages
|
//if in page select mode is active rotate only selected pages
|
||||||
if (window.selectPage && !window.selectedPages.includes(pageIndex)) continue;
|
if (window.selectPage && !window.selectedPages.includes(pageIndex)) continue;
|
||||||
|
|
||||||
const img = child.querySelector("img");
|
const img = child.querySelector('img');
|
||||||
if (!img) continue;
|
if (!img) continue;
|
||||||
|
|
||||||
elementsToRotate.push(img);
|
elementsToRotate.push(img);
|
||||||
@@ -329,11 +352,11 @@ class PdfContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
removeAllElements() {
|
removeAllElements() {
|
||||||
let pageContainerNodeList = document.querySelectorAll(".page-container");
|
let pageContainerNodeList = document.querySelectorAll('.page-container');
|
||||||
for (var i = 0; i < pageContainerNodeList.length; i++) {
|
for (var i = 0; i < pageContainerNodeList.length; i++) {
|
||||||
pageContainerNodeList[i].remove();
|
pageContainerNodeList[i].remove();
|
||||||
}
|
}
|
||||||
document.querySelectorAll(".enable-on-file").forEach((element) => {
|
document.querySelectorAll('.enable-on-file').forEach((element) => {
|
||||||
element.disabled = true;
|
element.disabled = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -345,25 +368,24 @@ class PdfContainer {
|
|||||||
window.selectedPages,
|
window.selectedPages,
|
||||||
this.updatePageNumbersAndCheckboxes
|
this.updatePageNumbersAndCheckboxes
|
||||||
);
|
);
|
||||||
|
removeSelectedCommand.execute();
|
||||||
this.undoManager.pushUndoClearRedo(removeSelectedCommand);
|
this.undoManager.pushUndoClearRedo(removeSelectedCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSelectAll() {
|
toggleSelectAll() {
|
||||||
const checkboxes = document.querySelectorAll(".pdf-actions_checkbox");
|
const checkboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
||||||
window.selectAll = !window.selectAll;
|
window.selectAll = !window.selectAll;
|
||||||
const selectIcon = document.getElementById("select-All-Container");
|
const selectIcon = document.getElementById('select-All-Container');
|
||||||
const deselectIcon = document.getElementById("deselect-All-Container");
|
const deselectIcon = document.getElementById('deselect-All-Container');
|
||||||
|
|
||||||
if (selectIcon.style.display === "none") {
|
if (selectIcon.style.display === 'none') {
|
||||||
selectIcon.style.display = "inline";
|
selectIcon.style.display = 'inline';
|
||||||
deselectIcon.style.display = "none";
|
deselectIcon.style.display = 'none';
|
||||||
} else {
|
} else {
|
||||||
selectIcon.style.display = "none";
|
selectIcon.style.display = 'none';
|
||||||
deselectIcon.style.display = "inline";
|
deselectIcon.style.display = 'inline';
|
||||||
}
|
}
|
||||||
checkboxes.forEach((checkbox) => {
|
checkboxes.forEach((checkbox) => {
|
||||||
|
|
||||||
checkbox.checked = window.selectAll;
|
checkbox.checked = window.selectAll;
|
||||||
|
|
||||||
const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1;
|
const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1;
|
||||||
@@ -386,18 +408,20 @@ class PdfContainer {
|
|||||||
parseCSVInput(csvInput, maxPageIndex) {
|
parseCSVInput(csvInput, maxPageIndex) {
|
||||||
const pages = new Set();
|
const pages = new Set();
|
||||||
|
|
||||||
csvInput.split(",").forEach((item) => {
|
csvInput.split(',').forEach((item) => {
|
||||||
const range = item.split("-").map((p) => parseInt(p.trim()));
|
const range = item.split('-').map((p) => parseInt(p.trim()));
|
||||||
if (range.length === 2) {
|
if (range.length === 2) {
|
||||||
const [start, end] = range;
|
const [start, end] = range;
|
||||||
for (let i = start; i <= end && i <= maxPageIndex; i++) {
|
for (let i = start; i <= end && i <= maxPageIndex; i++) {
|
||||||
if (i > 0) { // Ensure the page number is greater than 0
|
if (i > 0) {
|
||||||
|
// Ensure the page number is greater than 0
|
||||||
pages.add(i);
|
pages.add(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (range.length === 1 && Number.isInteger(range[0])) {
|
} else if (range.length === 1 && Number.isInteger(range[0])) {
|
||||||
const page = range[0];
|
const page = range[0];
|
||||||
if (page > 0 && page <= maxPageIndex) { // Ensure page is within valid range
|
if (page > 0 && page <= maxPageIndex) {
|
||||||
|
// Ensure page is within valid range
|
||||||
pages.add(page);
|
pages.add(page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -407,24 +431,24 @@ class PdfContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updatePagesFromCSV() {
|
updatePagesFromCSV() {
|
||||||
const csvInput = document.getElementById("csv-input").value;
|
const csvInput = document.getElementById('csv-input').value;
|
||||||
|
|
||||||
const allPages = this.pagesContainer.querySelectorAll(".page-container");
|
const allPages = this.pagesContainer.querySelectorAll('.page-container');
|
||||||
const maxPageIndex = allPages.length;
|
const maxPageIndex = allPages.length;
|
||||||
|
|
||||||
window.selectedPages = this.parseCSVInput(csvInput, maxPageIndex);
|
window.selectedPages = this.parseCSVInput(csvInput, maxPageIndex);
|
||||||
|
|
||||||
this.updateSelectedPagesDisplay();
|
this.updateSelectedPagesDisplay();
|
||||||
|
|
||||||
const allCheckboxes = document.querySelectorAll(".pdf-actions_checkbox");
|
const allCheckboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
||||||
allCheckboxes.forEach((checkbox) => {
|
allCheckboxes.forEach((checkbox) => {
|
||||||
const page = parseInt(checkbox.getAttribute("data-page-number"));
|
const page = parseInt(checkbox.getAttribute('data-page-number'));
|
||||||
checkbox.checked = window.selectedPages.includes(page);
|
checkbox.checked = window.selectedPages.includes(page);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
formatSelectedPages(pages) {
|
formatSelectedPages(pages) {
|
||||||
if (pages.length === 0) return "";
|
if (pages.length === 0) return '';
|
||||||
|
|
||||||
pages.sort((a, b) => a - b); // Sort the page numbers in ascending order
|
pages.sort((a, b) => a - b); // Sort the page numbers in ascending order
|
||||||
const ranges = [];
|
const ranges = [];
|
||||||
@@ -445,27 +469,27 @@ class PdfContainer {
|
|||||||
// Add the last range
|
// Add the last range
|
||||||
ranges.push(start === end ? `${start}` : `${start}-${end}`);
|
ranges.push(start === end ? `${start}` : `${start}-${end}`);
|
||||||
|
|
||||||
return ranges.join(", ");
|
return ranges.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSelectedPagesDisplay() {
|
updateSelectedPagesDisplay() {
|
||||||
const selectedPagesList = document.getElementById("selected-pages-list");
|
const selectedPagesList = document.getElementById('selected-pages-list');
|
||||||
const selectedPagesInput = document.getElementById("csv-input");
|
const selectedPagesInput = document.getElementById('csv-input');
|
||||||
selectedPagesList.innerHTML = ""; // Clear the list
|
selectedPagesList.innerHTML = ''; // Clear the list
|
||||||
window.selectedPages.sort((a, b) => a - b);
|
window.selectedPages.sort((a, b) => a - b);
|
||||||
window.selectedPages.forEach((page) => {
|
window.selectedPages.forEach((page) => {
|
||||||
const pageItem = document.createElement("div");
|
const pageItem = document.createElement('div');
|
||||||
pageItem.className = "page-item";
|
pageItem.className = 'page-item';
|
||||||
|
|
||||||
const pageNumber = document.createElement("span");
|
const pageNumber = document.createElement('span');
|
||||||
const pagelabel = /*[[#{multiTool.page}]]*/ 'Page';
|
const pagelabel = /*[[#{multiTool.page}]]*/ 'Page';
|
||||||
pageNumber.className = "selected-page-number";
|
pageNumber.className = 'selected-page-number';
|
||||||
pageNumber.innerText = `${pagelabel} ${page}`;
|
pageNumber.innerText = `${pagelabel} ${page}`;
|
||||||
pageItem.appendChild(pageNumber);
|
pageItem.appendChild(pageNumber);
|
||||||
|
|
||||||
const removeBtn = document.createElement("span");
|
const removeBtn = document.createElement('span');
|
||||||
removeBtn.className = "remove-btn";
|
removeBtn.className = 'remove-btn';
|
||||||
removeBtn.innerHTML = "✕";
|
removeBtn.innerHTML = '✕';
|
||||||
|
|
||||||
// Remove page from selected pages list and update display and checkbox
|
// Remove page from selected pages list and update display and checkbox
|
||||||
removeBtn.onclick = () => {
|
removeBtn.onclick = () => {
|
||||||
@@ -489,7 +513,7 @@ class PdfContainer {
|
|||||||
parsePageRanges(ranges) {
|
parsePageRanges(ranges) {
|
||||||
const pages = new Set();
|
const pages = new Set();
|
||||||
|
|
||||||
ranges.split(',').forEach(range => {
|
ranges.split(',').forEach((range) => {
|
||||||
const [start, end] = range.split('-').map(Number);
|
const [start, end] = range.split('-').map(Number);
|
||||||
if (end) {
|
if (end) {
|
||||||
for (let i = start; i <= end; i++) {
|
for (let i = start; i <= end; i++) {
|
||||||
@@ -503,23 +527,25 @@ class PdfContainer {
|
|||||||
return Array.from(pages).sort((a, b) => a - b);
|
return Array.from(pages).sort((a, b) => a - b);
|
||||||
}
|
}
|
||||||
|
|
||||||
addFilesBlankAll() {
|
async addFilesBlankAll() {
|
||||||
const allPages = this.pagesContainer.querySelectorAll(".page-container");
|
const allPages = this.pagesContainer.querySelectorAll('.page-container');
|
||||||
allPages.forEach((page, index) => {
|
|
||||||
if (index !== 0) {
|
|
||||||
this.addFiles(page, true)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
splitAll() {
|
let pageBreakCommand = new PageBreakCommand(
|
||||||
const allPages = this.pagesContainer.querySelectorAll(".page-container");
|
|
||||||
let splitAllCommand = new SplitAllCommand(
|
|
||||||
allPages,
|
allPages,
|
||||||
window.selectPage,
|
window.selectPage,
|
||||||
window.selectedPages,
|
window.selectedPages,
|
||||||
"split-before"
|
this.addFilesBlank.bind(this),
|
||||||
|
this.pagesContainer
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await pageBreakCommand.execute();
|
||||||
|
|
||||||
|
this.undoManager.pushUndoClearRedo(pageBreakCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
splitAll() {
|
||||||
|
const allPages = this.pagesContainer.querySelectorAll('.page-container');
|
||||||
|
let splitAllCommand = new SplitAllCommand(allPages, window.selectPage, window.selectedPages, 'split-before');
|
||||||
splitAllCommand.execute();
|
splitAllCommand.execute();
|
||||||
|
|
||||||
this.undoManager.pushUndoClearRedo(splitAllCommand);
|
this.undoManager.pushUndoClearRedo(splitAllCommand);
|
||||||
@@ -529,7 +555,7 @@ class PdfContainer {
|
|||||||
const baseDocument = await PDFLib.PDFDocument.load(baseDocBytes);
|
const baseDocument = await PDFLib.PDFDocument.load(baseDocBytes);
|
||||||
const pageNum = baseDocument.getPages().length;
|
const pageNum = baseDocument.getPages().length;
|
||||||
|
|
||||||
splitters.sort((a, b) => a - b);; // We'll sort the separator indexes just in case querySelectorAll does something funny.
|
splitters.sort((a, b) => a - b); // We'll sort the separator indexes just in case querySelectorAll does something funny.
|
||||||
splitters.push(pageNum); // We'll also add a faux separator at the end in order to get the pages after the last separator.
|
splitters.push(pageNum); // We'll also add a faux separator at the end in order to get the pages after the last separator.
|
||||||
|
|
||||||
const splitDocuments = [];
|
const splitDocuments = [];
|
||||||
@@ -544,14 +570,14 @@ class PdfContainer {
|
|||||||
|
|
||||||
const copiedPages = await subDocument.copyPages(baseDocument, pageIndices);
|
const copiedPages = await subDocument.copyPages(baseDocument, pageIndices);
|
||||||
|
|
||||||
copiedPages.forEach(copiedPage => {
|
copiedPages.forEach((copiedPage) => {
|
||||||
subDocument.addPage(copiedPage);
|
subDocument.addPage(copiedPage);
|
||||||
});
|
});
|
||||||
|
|
||||||
const subDocumentBytes = await subDocument.save();
|
const subDocumentBytes = await subDocument.save();
|
||||||
|
|
||||||
splitDocuments.push(subDocumentBytes);
|
splitDocuments.push(subDocumentBytes);
|
||||||
};
|
}
|
||||||
|
|
||||||
return splitDocuments;
|
return splitDocuments;
|
||||||
}
|
}
|
||||||
@@ -560,8 +586,10 @@ class PdfContainer {
|
|||||||
const zip = new JSZip();
|
const zip = new JSZip();
|
||||||
|
|
||||||
for (let i = 0; i < pdfBytesArray.length; i++) {
|
for (let i = 0; i < pdfBytesArray.length; i++) {
|
||||||
const documentBlob = new Blob([pdfBytesArray[i]], { type: "application/pdf" });
|
const documentBlob = new Blob([pdfBytesArray[i]], {
|
||||||
zip.file(baseNameString + "-" + (i + 1) + ".pdf", documentBlob);
|
type: 'application/pdf',
|
||||||
|
});
|
||||||
|
zip.file(baseNameString + '-' + (i + 1) + '.pdf', documentBlob);
|
||||||
}
|
}
|
||||||
|
|
||||||
return zip;
|
return zip;
|
||||||
@@ -569,10 +597,10 @@ class PdfContainer {
|
|||||||
|
|
||||||
async exportPdf(selected) {
|
async exportPdf(selected) {
|
||||||
const pdfDoc = await PDFLib.PDFDocument.create();
|
const pdfDoc = await PDFLib.PDFDocument.create();
|
||||||
const pageContainers = this.pagesContainer.querySelectorAll(".page-container"); // Select all .page-container elements
|
const pageContainers = this.pagesContainer.querySelectorAll('.page-container'); // Select all .page-container elements
|
||||||
for (var i = 0; i < pageContainers.length; i++) {
|
for (var i = 0; i < pageContainers.length; i++) {
|
||||||
if (!selected || window.selectedPages.includes(i + 1)) {
|
if (!selected || window.selectedPages.includes(i + 1)) {
|
||||||
const img = pageContainers[i].querySelector("img"); // Find the img element within each .page-container
|
const img = pageContainers[i].querySelector('img'); // Find the img element within each .page-container
|
||||||
if (!img) continue;
|
if (!img) continue;
|
||||||
let page;
|
let page;
|
||||||
if (img.doc) {
|
if (img.doc) {
|
||||||
@@ -612,7 +640,7 @@ class PdfContainer {
|
|||||||
}
|
}
|
||||||
const rotation = img.style.rotate;
|
const rotation = img.style.rotate;
|
||||||
if (rotation) {
|
if (rotation) {
|
||||||
const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, ""));
|
const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, ''));
|
||||||
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle));
|
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -621,11 +649,11 @@ class PdfContainer {
|
|||||||
pdfDoc.setProducer(stirlingPDFLabel);
|
pdfDoc.setProducer(stirlingPDFLabel);
|
||||||
|
|
||||||
const pdfBytes = await pdfDoc.save();
|
const pdfBytes = await pdfDoc.save();
|
||||||
const pdfBlob = new Blob([pdfBytes], { type: "application/pdf" });
|
const pdfBlob = new Blob([pdfBytes], {type: 'application/pdf'});
|
||||||
|
|
||||||
const filenameInput = document.getElementById("filename-input");
|
const filenameInput = document.getElementById('filename-input');
|
||||||
|
|
||||||
let inputArr = filenameInput.value.split(".");
|
let inputArr = filenameInput.value.split('.');
|
||||||
|
|
||||||
if (inputArr !== null && inputArr !== undefined && inputArr.length > 0) {
|
if (inputArr !== null && inputArr !== undefined && inputArr.length > 0) {
|
||||||
inputArr = inputArr.filter((n) => n); // remove all empty strings, nulls or undefined
|
inputArr = inputArr.filter((n) => n); // remove all empty strings, nulls or undefined
|
||||||
@@ -634,17 +662,18 @@ class PdfContainer {
|
|||||||
inputArr.pop(); // remove right part after last dot
|
inputArr.pop(); // remove right part after last dot
|
||||||
}
|
}
|
||||||
|
|
||||||
filenameInput.value = inputArr.join("");
|
filenameInput.value = inputArr.join('');
|
||||||
this.fileName = filenameInput.value;
|
this.fileName = filenameInput.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const separators = this.pagesContainer.querySelectorAll(".split-before");
|
const separators = this.pagesContainer.querySelectorAll('.split-before');
|
||||||
if (separators.length !== 0) { // Split the pdf if there are separators.
|
if (separators.length !== 0) {
|
||||||
const baseName = this.fileName ? this.fileName : "managed";
|
// Split the pdf if there are separators.
|
||||||
|
const baseName = this.fileName ? this.fileName : 'managed';
|
||||||
|
|
||||||
const pagesArray = Array.from(this.pagesContainer.children);
|
const pagesArray = Array.from(this.pagesContainer.children);
|
||||||
const splitters = [];
|
const splitters = [];
|
||||||
separators.forEach(page => {
|
separators.forEach((page) => {
|
||||||
const pageIndex = pagesArray.indexOf(page);
|
const pageIndex = pagesArray.indexOf(page);
|
||||||
if (pageIndex !== 0) {
|
if (pageIndex !== 0) {
|
||||||
splitters.push(pageIndex);
|
splitters.push(pageIndex);
|
||||||
@@ -655,40 +684,40 @@ class PdfContainer {
|
|||||||
const archivedDocuments = await this.nameAndArchiveFiles(splitDocuments, baseName);
|
const archivedDocuments = await this.nameAndArchiveFiles(splitDocuments, baseName);
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
archivedDocuments.generateAsync({ type: "base64" }).then(function (base64) {
|
archivedDocuments.generateAsync({type: 'base64'}).then(function (base64) {
|
||||||
const url = "data:application/zip;base64," + base64;
|
const url = 'data:application/zip;base64,' + base64;
|
||||||
self.downloadLink = document.createElement("a");
|
self.downloadLink = document.createElement('a');
|
||||||
self.downloadLink.href = url;
|
self.downloadLink.href = url;
|
||||||
self.downloadLink.setAttribute("download", baseName + ".zip");
|
self.downloadLink.setAttribute('download', baseName + '.zip');
|
||||||
self.downloadLink.setAttribute("target", "_blank");
|
self.downloadLink.setAttribute('target', '_blank');
|
||||||
self.downloadLink.click();
|
self.downloadLink.click();
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
} else { // Continue normally if there are no separators
|
// Continue normally if there are no separators
|
||||||
|
|
||||||
const url = URL.createObjectURL(pdfBlob);
|
const url = URL.createObjectURL(pdfBlob);
|
||||||
const downloadOption = localStorage.getItem("downloadOption");
|
const downloadOption = localStorage.getItem('downloadOption');
|
||||||
|
|
||||||
if (!filenameInput.value.includes(".pdf")) {
|
if (!filenameInput.value.includes('.pdf')) {
|
||||||
filenameInput.value = filenameInput.value + ".pdf";
|
filenameInput.value = filenameInput.value + '.pdf';
|
||||||
this.fileName = filenameInput.value;
|
this.fileName = filenameInput.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downloadOption === "sameWindow") {
|
if (downloadOption === 'sameWindow') {
|
||||||
// Open the file in the same window
|
// Open the file in the same window
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
} else if (downloadOption === "newWindow") {
|
} else if (downloadOption === 'newWindow') {
|
||||||
// Open the file in a new window
|
// Open the file in a new window
|
||||||
window.open(url, "_blank");
|
window.open(url, '_blank');
|
||||||
} else {
|
} else {
|
||||||
// Download the file
|
// Download the file
|
||||||
this.downloadLink = document.createElement("a");
|
this.downloadLink = document.createElement('a');
|
||||||
this.downloadLink.id = "download-link";
|
this.downloadLink.id = 'download-link';
|
||||||
this.downloadLink.href = url;
|
this.downloadLink.href = url;
|
||||||
// downloadLink.download = this.fileName ? this.fileName : 'managed.pdf';
|
// downloadLink.download = this.fileName ? this.fileName : 'managed.pdf';
|
||||||
// downloadLink.download = this.fileName;
|
// downloadLink.download = this.fileName;
|
||||||
this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf");
|
this.downloadLink.setAttribute('download', this.fileName ? this.fileName : 'managed.pdf');
|
||||||
this.downloadLink.setAttribute("target", "_blank");
|
this.downloadLink.setAttribute('target', '_blank');
|
||||||
this.downloadLink.onclick = this.setDownloadAttribute;
|
this.downloadLink.onclick = this.setDownloadAttribute;
|
||||||
this.downloadLink.click();
|
this.downloadLink.click();
|
||||||
}
|
}
|
||||||
@@ -696,19 +725,19 @@ class PdfContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resetPages() {
|
resetPages() {
|
||||||
const pageContainers = this.pagesContainer.querySelectorAll(".page-container");
|
const pageContainers = this.pagesContainer.querySelectorAll('.page-container');
|
||||||
|
|
||||||
pageContainers.forEach((container, index) => {
|
pageContainers.forEach((container, index) => {
|
||||||
container.id = "page-container-" + (index + 1);
|
container.id = 'page-container-' + (index + 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
const checkboxes = document.querySelectorAll(".pdf-actions_checkbox");
|
const checkboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
||||||
window.selectAll = false;
|
window.selectAll = false;
|
||||||
const selectIcon = document.getElementById("select-All-Container");
|
const selectIcon = document.getElementById('select-All-Container');
|
||||||
const deselectIcon = document.getElementById("deselect-All-Container");
|
const deselectIcon = document.getElementById('deselect-All-Container');
|
||||||
|
|
||||||
selectIcon.style.display = "inline";
|
selectIcon.style.display = 'inline';
|
||||||
deselectIcon.style.display = "none";
|
deselectIcon.style.display = 'none';
|
||||||
|
|
||||||
checkboxes.forEach((checkbox) => {
|
checkboxes.forEach((checkbox) => {
|
||||||
const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1;
|
const pageNumber = Array.from(checkbox.parentNode.parentNode.children).indexOf(checkbox.parentNode) + 1;
|
||||||
@@ -722,13 +751,13 @@ class PdfContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setDownloadAttribute() {
|
setDownloadAttribute() {
|
||||||
this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf");
|
this.downloadLink.setAttribute('download', this.fileName ? this.fileName : 'managed.pdf');
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFilename(fileName = "") {
|
updateFilename(fileName = '') {
|
||||||
const filenameInput = document.getElementById("filename-input");
|
const filenameInput = document.getElementById('filename-input');
|
||||||
const pagesContainer = document.getElementById("pages-container");
|
const pagesContainer = document.getElementById('pages-container');
|
||||||
const downloadBtn = document.getElementById("export-button");
|
const downloadBtn = document.getElementById('export-button');
|
||||||
|
|
||||||
downloadBtn.disabled = pagesContainer.childElementCount === 0;
|
downloadBtn.disabled = pagesContainer.childElementCount === 0;
|
||||||
|
|
||||||
@@ -752,38 +781,36 @@ class PdfContainer {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
toggleSelectPageVisibility() {
|
toggleSelectPageVisibility() {
|
||||||
window.selectPage = !window.selectPage;
|
window.selectPage = !window.selectPage;
|
||||||
const checkboxes = document.querySelectorAll(".pdf-actions_checkbox");
|
const checkboxes = document.querySelectorAll('.pdf-actions_checkbox');
|
||||||
checkboxes.forEach(checkbox => {
|
checkboxes.forEach((checkbox) => {
|
||||||
checkbox.classList.toggle("hidden", !window.selectPage);
|
checkbox.classList.toggle('hidden', !window.selectPage);
|
||||||
});
|
});
|
||||||
const deleteButton = document.getElementById("delete-button");
|
const deleteButton = document.getElementById('delete-button');
|
||||||
deleteButton.classList.toggle("hidden", !window.selectPage);
|
deleteButton.classList.toggle('hidden', !window.selectPage);
|
||||||
const selectedPages = document.getElementById("selected-pages-display");
|
const selectedPages = document.getElementById('selected-pages-display');
|
||||||
selectedPages.classList.toggle("hidden", !window.selectPage);
|
selectedPages.classList.toggle('hidden', !window.selectPage);
|
||||||
const selectAll = document.getElementById("select-All-Container");
|
const selectAll = document.getElementById('select-All-Container');
|
||||||
selectAll.classList.toggle("hidden", !window.selectPage);
|
selectAll.classList.toggle('hidden', !window.selectPage);
|
||||||
const exportSelected = document.getElementById("export-selected-button");
|
const exportSelected = document.getElementById('export-selected-button');
|
||||||
exportSelected.classList.toggle("hidden", !window.selectPage);
|
exportSelected.classList.toggle('hidden', !window.selectPage);
|
||||||
const selectPagesButton = document.getElementById("select-pages-button");
|
const selectPagesButton = document.getElementById('select-pages-button');
|
||||||
selectPagesButton.style.opacity = window.selectPage ? "1" : "0.5";
|
selectPagesButton.style.opacity = window.selectPage ? '1' : '0.5';
|
||||||
|
|
||||||
if (window.selectPage) {
|
if (window.selectPage) {
|
||||||
this.updatePageNumbersAndCheckboxes();
|
this.updatePageNumbersAndCheckboxes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
updatePageNumbersAndCheckboxes() {
|
updatePageNumbersAndCheckboxes() {
|
||||||
const pageDivs = document.querySelectorAll(".pdf-actions_container");
|
const pageDivs = document.querySelectorAll('.pdf-actions_container');
|
||||||
|
|
||||||
pageDivs.forEach((div, index) => {
|
pageDivs.forEach((div, index) => {
|
||||||
const pageNumber = index + 1;
|
const pageNumber = index + 1;
|
||||||
const checkbox = div.querySelector(".pdf-actions_checkbox");
|
const checkbox = div.querySelector('.pdf-actions_checkbox');
|
||||||
checkbox.id = `selectPageCheckbox-${pageNumber}`;
|
checkbox.id = `selectPageCheckbox-${pageNumber}`;
|
||||||
checkbox.setAttribute("data-page-number", pageNumber);
|
checkbox.setAttribute('data-page-number', pageNumber);
|
||||||
checkbox.checked = window.selectedPages.includes(pageNumber);
|
checkbox.checked = window.selectedPages.includes(pageNumber);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -801,8 +828,10 @@ function detectImageType(uint8Array) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for TIFF signature (little-endian and big-endian)
|
// Check for TIFF signature (little-endian and big-endian)
|
||||||
if ((uint8Array[0] === 73 && uint8Array[1] === 73 && uint8Array[2] === 42 && uint8Array[3] === 0) ||
|
if (
|
||||||
(uint8Array[0] === 77 && uint8Array[1] === 77 && uint8Array[2] === 0 && uint8Array[3] === 42)) {
|
(uint8Array[0] === 73 && uint8Array[1] === 73 && uint8Array[2] === 42 && uint8Array[3] === 0) ||
|
||||||
|
(uint8Array[0] === 77 && uint8Array[1] === 77 && uint8Array[2] === 0 && uint8Array[3] === 42)
|
||||||
|
) {
|
||||||
return 'TIFF';
|
return 'TIFF';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,6 +843,4 @@ function detectImageType(uint8Array) {
|
|||||||
return 'UNKNOWN';
|
return 'UNKNOWN';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default PdfContainer;
|
export default PdfContainer;
|
||||||
|
|||||||
53
src/main/resources/static/js/multitool/commands/add-page.js
Normal file
53
src/main/resources/static/js/multitool/commands/add-page.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import {Command} from './command.js';
|
||||||
|
|
||||||
|
export class AddFilesCommand extends Command {
|
||||||
|
constructor(element, selectedPages, addFilesAction, pagesContainer) {
|
||||||
|
super();
|
||||||
|
this.element = element;
|
||||||
|
this.selectedPages = selectedPages;
|
||||||
|
this.addFilesAction = addFilesAction;
|
||||||
|
this.pagesContainer = pagesContainer;
|
||||||
|
this.addedElements = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute() {
|
||||||
|
const undoBtn = document.getElementById('undo-btn');
|
||||||
|
undoBtn.disabled = true;
|
||||||
|
if (this.element) {
|
||||||
|
const newElement = await this.addFilesAction(this.element);
|
||||||
|
if (newElement) {
|
||||||
|
this.addedElements = newElement;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const newElement = await this.addFilesAction(false);
|
||||||
|
if (newElement) {
|
||||||
|
this.addedElements = newElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
undoBtn.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
undo() {
|
||||||
|
this.addedElements.forEach((element) => {
|
||||||
|
const nextSibling = element.nextSibling;
|
||||||
|
this.pagesContainer.removeChild(element);
|
||||||
|
|
||||||
|
if (this.pagesContainer.childElementCount === 0) {
|
||||||
|
const filenameInput = document.getElementById('filename-input');
|
||||||
|
const filenameParagraph = document.getElementById('filename');
|
||||||
|
const downloadBtn = document.getElementById('export-button');
|
||||||
|
|
||||||
|
filenameInput.disabled = true;
|
||||||
|
filenameInput.value = '';
|
||||||
|
filenameParagraph.innerText = '';
|
||||||
|
downloadBtn.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
element._nextSibling = nextSibling;
|
||||||
|
});
|
||||||
|
this.addedElements = [];
|
||||||
|
}
|
||||||
|
redo() {
|
||||||
|
this.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,9 @@ export class DeletePageCommand extends Command {
|
|||||||
this.filenameInputValue = document.getElementById("filename-input").value;
|
this.filenameInputValue = document.getElementById("filename-input").value;
|
||||||
|
|
||||||
const filenameParagraph = document.getElementById("filename");
|
const filenameParagraph = document.getElementById("filename");
|
||||||
this.filenameParagraphText = filenameParagraph ? filenameParagraph.innerText : "";
|
this.filenameParagraphText = filenameParagraph
|
||||||
|
? filenameParagraph.innerText
|
||||||
|
: "";
|
||||||
}
|
}
|
||||||
|
|
||||||
execute() {
|
execute() {
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import {Command} from './command.js';
|
||||||
|
|
||||||
|
export class PageBreakCommand extends Command {
|
||||||
|
constructor(elements, isSelectedInWindow, selectedPages, pageBreakCallback, pagesContainer) {
|
||||||
|
super();
|
||||||
|
this.elements = elements;
|
||||||
|
this.isSelectedInWindow = isSelectedInWindow;
|
||||||
|
this.selectedPages = selectedPages;
|
||||||
|
this.pageBreakCallback = pageBreakCallback;
|
||||||
|
this.pagesContainer = pagesContainer;
|
||||||
|
this.addedElements = [];
|
||||||
|
this.originalStates = Array.from(elements, (element) => ({
|
||||||
|
element,
|
||||||
|
hasContent: element.innerHTML.trim() !== '',
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute() {
|
||||||
|
const undoBtn = document.getElementById('undo-btn');
|
||||||
|
undoBtn.disabled = true;
|
||||||
|
for (const [index, element] of this.elements.entries()) {
|
||||||
|
if (!this.isSelectedInWindow || this.selectedPages.includes(index)) {
|
||||||
|
if (index !== 0) {
|
||||||
|
const newElement = await this.pageBreakCallback(element, this.addedElements);
|
||||||
|
|
||||||
|
if (newElement) {
|
||||||
|
this.addedElements = newElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
undoBtn.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
undo() {
|
||||||
|
this.addedElements.forEach((element) => {
|
||||||
|
const nextSibling = element.nextSibling;
|
||||||
|
|
||||||
|
this.pagesContainer.removeChild(element);
|
||||||
|
|
||||||
|
if (this.pagesContainer.childElementCount === 0) {
|
||||||
|
const filenameInput = document.getElementById('filename-input');
|
||||||
|
const filenameParagraph = document.getElementById('filename');
|
||||||
|
const downloadBtn = document.getElementById('export-button');
|
||||||
|
|
||||||
|
filenameInput.disabled = true;
|
||||||
|
filenameInput.value = '';
|
||||||
|
filenameParagraph.innerText = '';
|
||||||
|
downloadBtn.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
element._nextSibling = nextSibling;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
redo() {
|
||||||
|
this.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -154,6 +154,9 @@
|
|||||||
<div
|
<div
|
||||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('cert-sign', 'workspace_premium', 'home.certSign.title', 'home.certSign.desc', 'certSign.tags', 'security')}">
|
th:replace="~{fragments/navbarEntry :: navbarEntry ('cert-sign', 'workspace_premium', 'home.certSign.title', 'home.certSign.desc', 'certSign.tags', 'security')}">
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
th:replace="~{fragments/navbarEntry :: navbarEntry('validate-signature','verified','home.validateSignature.title','home.validateSignature.desc','validateSignature.tags','security')}">
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-cert-sign', 'remove_moderator', 'home.removeCertSign.title', 'home.removeCertSign.desc', 'removeCertSign.tags', 'security')}">
|
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-cert-sign', 'remove_moderator', 'home.removeCertSign.title', 'home.removeCertSign.desc', 'removeCertSign.tags', 'security')}">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -215,6 +215,9 @@
|
|||||||
<div
|
<div
|
||||||
th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', toolIcon='workspace_premium', tags=#{certSign.tags}, toolGroup='security')}">
|
th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', toolIcon='workspace_premium', tags=#{certSign.tags}, toolGroup='security')}">
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
th:replace="~{fragments/card :: card(id='validate-signature', cardTitle=#{home.validateSignature.title}, cardText=#{home.validateSignature.desc}, cardLink='validate-signature', toolIcon='verified', tags=#{validateSignature.tags}, toolGroup='security')}">
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
th:replace="~{fragments/card :: card(id='remove-cert-sign', cardTitle=#{home.removeCertSign.title}, cardText=#{home.removeCertSign.desc}, cardLink='remove-cert-sign', toolIcon='remove_moderator', tags=#{removeCertSign.tags}, toolGroup='security')}">
|
th:replace="~{fragments/card :: card(id='remove-cert-sign', cardTitle=#{home.removeCertSign.title}, cardText=#{home.removeCertSign.desc}, cardLink='remove-cert-sign', toolIcon='remove_moderator', tags=#{removeCertSign.tags}, toolGroup='security')}">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -276,7 +276,8 @@ function formatText(text) {
|
|||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
|
|
||||||
// Split the text into lines
|
// Split the text into lines
|
||||||
const lines = text.split('\n');
|
const textWithoutComments = text.replace(/<!--[\s\S]*?-->/g, '');
|
||||||
|
const lines = textWithoutComments.split('\n');
|
||||||
let currentList = null;
|
let currentList = null;
|
||||||
|
|
||||||
lines.forEach(line => {
|
lines.forEach(line => {
|
||||||
|
|||||||
265
src/main/resources/templates/security/validate-signature.html
Normal file
265
src/main/resources/templates/security/validate-signature.html
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<th:block th:insert="~{fragments/common :: head(title=#{validateSignature.title}, header=#{validateSignature.header})}"></th:block>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="page-container">
|
||||||
|
<div id="content-wrap">
|
||||||
|
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||||
|
<br><br>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6 bg-card">
|
||||||
|
<div class="tool-header">
|
||||||
|
<span class="material-symbols-rounded tool-header-icon security">verified</span>
|
||||||
|
<span class="tool-header-text" th:text="#{validateSignature.header}"></span>
|
||||||
|
</div>
|
||||||
|
<form id="pdfForm" th:action="@{'api/v1/security/validate-signature'}" method="post" enctype="multipart/form-data">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label th:text="#{validateSignature.selectPDF}"></label>
|
||||||
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, remoteCall='false', accept='application/pdf')}"></div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label th:text="#{validateSignature.selectCustomCert}" ></label>
|
||||||
|
<div th:replace="~{fragments/common :: fileSelector(name='certFile', multipleInputsForSingleRequest=false, notRequired=true, remoteCall='false', accept='.cer,.crt,.pem')}"></div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 text-left">
|
||||||
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{validateSignature.submit}"></button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- Results section -->
|
||||||
|
<div id="results" style="display: none;">
|
||||||
|
<h4 th:text="#{validateSignature.results}"></h4>
|
||||||
|
<div id="signatures-list"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script th:inline="javascript">
|
||||||
|
const translations = {
|
||||||
|
signature: /*[[#{validateSignature.signature}]]*/,
|
||||||
|
signatureInfo: /*[[#{validateSignature.signature.info}]]*/,
|
||||||
|
certInfo: /*[[#{validateSignature.cert.info}]]*/,
|
||||||
|
signer: /*[[#{validateSignature.signer}]]*/,
|
||||||
|
date: /*[[#{validateSignature.date}]]*/,
|
||||||
|
reason: /*[[#{validateSignature.reason}]]*/,
|
||||||
|
location: /*[[#{validateSignature.location}]]*/,
|
||||||
|
noSignatures: /*[[#{validateSignature.noSignatures}]]*/,
|
||||||
|
statusValid: /*[[#{validateSignature.status.valid}]]*/,
|
||||||
|
statusInvalid: /*[[#{validateSignature.status.invalid}]]*/,
|
||||||
|
mathValid: /*[[#{validateSignature.signature.mathValid}]]*/,
|
||||||
|
chainInvalid: /*[[#{validateSignature.chain.invalid}]]*/,
|
||||||
|
trustInvalid: /*[[#{validateSignature.trust.invalid}]]*/,
|
||||||
|
certExpired: /*[[#{validateSignature.cert.expired}]]*/,
|
||||||
|
certRevoked: /*[[#{validateSignature.cert.revoked}]]*/,
|
||||||
|
certIssuer: /*[[#{validateSignature.cert.issuer}]]*/,
|
||||||
|
certSubject: /*[[#{validateSignature.cert.subject}]]*/,
|
||||||
|
certSerialNumber: /*[[#{validateSignature.cert.serialNumber}]]*/,
|
||||||
|
certValidFrom: /*[[#{validateSignature.cert.validFrom}]]*/,
|
||||||
|
certValidUntil: /*[[#{validateSignature.cert.validUntil}]]*/,
|
||||||
|
certAlgorithm: /*[[#{validateSignature.cert.algorithm}]]*/,
|
||||||
|
certKeySize: /*[[#{validateSignature.cert.keySize}]]*/,
|
||||||
|
certBits: /*[[#{validateSignature.cert.bits}]]*/,
|
||||||
|
certVersion: /*[[#{validateSignature.cert.version}]]*/,
|
||||||
|
certKeyUsage: /*[[#{validateSignature.cert.keyUsage}]]*/,
|
||||||
|
certSelfSigned: /*[[#{validateSignature.cert.selfSigned}]]*/,
|
||||||
|
yes: /*[[#{yes}]]*/,
|
||||||
|
no: /*[[#{no}]]*/,
|
||||||
|
selectPDF: /*[[#{validateSignature.selectPDF}]]*/
|
||||||
|
};
|
||||||
|
|
||||||
|
function escapeHtml(unsafe) {
|
||||||
|
return unsafe
|
||||||
|
?.toString()
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/'/g, "'") || 'N/A';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector('#pdfForm').addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const fileInput = document.getElementById('fileInput-input');
|
||||||
|
const certInput = document.getElementById('certFile-input');
|
||||||
|
if (!fileInput.files.length) {
|
||||||
|
alert(escapeHtml(translations.selectPDF));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
for (const file of fileInput.files) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('fileInput', file);
|
||||||
|
|
||||||
|
if (certInput.files.length > 0) {
|
||||||
|
formData.append('certFile', certInput.files[0]);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await fetch(e.target.action, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileResults = await response.json();
|
||||||
|
fileResults.forEach(result => {
|
||||||
|
result.fileName = file.name;
|
||||||
|
});
|
||||||
|
results.push(...fileResults);
|
||||||
|
} catch (error) {
|
||||||
|
results.push({
|
||||||
|
fileName: file.name,
|
||||||
|
valid: false,
|
||||||
|
errorMessage: `${escapeHtml(translations.statusInvalid)}: ${escapeHtml(error.message)}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displayResults(results);
|
||||||
|
});
|
||||||
|
|
||||||
|
function displayResults(results) {
|
||||||
|
const resultDiv = document.getElementById('results');
|
||||||
|
const listDiv = document.getElementById('signatures-list');
|
||||||
|
listDiv.innerHTML = '';
|
||||||
|
resultDiv.style.display = 'block';
|
||||||
|
|
||||||
|
if (!results || results.length === 0) {
|
||||||
|
listDiv.innerHTML = `<div class="alert alert-warning">${escapeHtml(translations.noSignatures)}</div>`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
results.forEach((result, index) => {
|
||||||
|
const signatureDiv = document.createElement('div');
|
||||||
|
signatureDiv.className = 'card mb-3';
|
||||||
|
|
||||||
|
let validationClass = 'alert-danger';
|
||||||
|
let validationIssues = [];
|
||||||
|
|
||||||
|
if (!result.valid) {
|
||||||
|
validationIssues.push(`${escapeHtml(translations.statusInvalid)}: ${escapeHtml(result.errorMessage || '')}`);
|
||||||
|
} else {
|
||||||
|
const isFullyValid = result.valid &&
|
||||||
|
result.chainValid &&
|
||||||
|
result.trustValid &&
|
||||||
|
result.notExpired &&
|
||||||
|
result.notRevoked;
|
||||||
|
|
||||||
|
if (isFullyValid) {
|
||||||
|
validationClass = 'alert-success';
|
||||||
|
validationIssues.push(escapeHtml(translations.statusValid));
|
||||||
|
} else {
|
||||||
|
validationClass = 'alert-warning';
|
||||||
|
validationIssues.push(escapeHtml(translations.mathValid));
|
||||||
|
|
||||||
|
if (!result.chainValid) {
|
||||||
|
validationIssues.push(escapeHtml(translations.chainInvalid));
|
||||||
|
}
|
||||||
|
if (!result.trustValid) {
|
||||||
|
validationIssues.push(escapeHtml(translations.trustInvalid));
|
||||||
|
}
|
||||||
|
if (!result.notExpired) {
|
||||||
|
validationIssues.push(escapeHtml(translations.certExpired));
|
||||||
|
}
|
||||||
|
if (result.trustValid && result.chainValid && !result.notRevoked) {
|
||||||
|
validationIssues.push(escapeHtml(translations.certRevoked));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let statusMessage = validationIssues[0];
|
||||||
|
if (validationIssues.length > 1) {
|
||||||
|
statusMessage += '<ul class="mb-0 mt-2">';
|
||||||
|
for (let i = 1; i < validationIssues.length; i++) {
|
||||||
|
statusMessage += `<li>${validationIssues[i]}</li>`;
|
||||||
|
}
|
||||||
|
statusMessage += '</ul>';
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = `
|
||||||
|
<div class="card-body">
|
||||||
|
${results.length > 1 ? `<h4 class="mb-3">${escapeHtml(translations.signature)} ${index + 1}</h4>` : ''}
|
||||||
|
<div class="alert ${validationClass}">
|
||||||
|
${statusMessage}
|
||||||
|
</div>
|
||||||
|
<div class="card-text">
|
||||||
|
<h5>${escapeHtml(translations.signatureInfo)}</h5>
|
||||||
|
<table class="table table-borderless">
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.signer)}:</strong></td>
|
||||||
|
<td>${escapeHtml(result.signerName)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.date)}:</strong></td>
|
||||||
|
<td>${escapeHtml(result.signatureDate)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.reason)}:</strong></td>
|
||||||
|
<td>${escapeHtml(result.reason)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.location)}:</strong></td>
|
||||||
|
<td>${escapeHtml(result.location)}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h5>${escapeHtml(translations.certInfo)}</h5>
|
||||||
|
<table class="table table-borderless">
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.certIssuer)}:</strong></td>
|
||||||
|
<td>${escapeHtml(result.issuerDN)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.certSubject)}:</strong></td>
|
||||||
|
<td>${escapeHtml(result.subjectDN)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.certSerialNumber)}:</strong></td>
|
||||||
|
<td>${escapeHtml(result.serialNumber)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.certValidFrom)}:</strong></td>
|
||||||
|
<td>${escapeHtml(result.validFrom)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.certValidUntil)}:</strong></td>
|
||||||
|
<td>${escapeHtml(result.validUntil)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.certAlgorithm)}:</strong></td>
|
||||||
|
<td>${escapeHtml(result.signatureAlgorithm)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.certKeySize)}:</strong></td>
|
||||||
|
<td>${result.keySize ? escapeHtml(result.keySize) + ' ' + escapeHtml(translations.certBits) : 'N/A'}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.certVersion)}:</strong></td>
|
||||||
|
<td>${escapeHtml(result.version)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.certKeyUsage)}:</strong></td>
|
||||||
|
<td>${result.keyUsages ? result.keyUsages.map(usage => escapeHtml(usage)).join(', ') : 'N/A'}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>${escapeHtml(translations.certSelfSigned)}:</strong></td>
|
||||||
|
<td>${result.selfSigned ? escapeHtml(translations.yes) : escapeHtml(translations.no)}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
signatureDiv.innerHTML = content;
|
||||||
|
listDiv.appendChild(signatureDiv);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
src/main/resources/tl12.acrobatsecuritysettings
Normal file
BIN
src/main/resources/tl12.acrobatsecuritysettings
Normal file
Binary file not shown.
Reference in New Issue
Block a user