Co-authored-by: ConnorYoh <40631091+ConnorYoh@users.noreply.github.com>
Co-authored-by: Connor Yoh <con.yoh13@gmail.com>
Co-authored-by: EthanHealy01 <80844253+EthanHealy01@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
This commit is contained in:
Anthony Stirling
2026-03-25 11:00:40 +00:00
committed by GitHub
parent 47cad0a131
commit 28613caf8a
181 changed files with 25715 additions and 124 deletions

View File

@@ -204,6 +204,27 @@ public class ConfigController {
boolean invitesEnabled = applicationProperties.getMail().isEnableInvites();
configData.put("enableEmailInvites", smtpEnabled && invitesEnabled);
// Storage settings
boolean storageEnabled = enableLogin && applicationProperties.getStorage().isEnabled();
boolean sharingEnabled =
storageEnabled && applicationProperties.getStorage().getSharing().isEnabled();
boolean frontendUrlConfigured = frontendUrl != null && !frontendUrl.trim().isEmpty();
boolean shareLinksEnabled =
sharingEnabled
&& applicationProperties.getStorage().getSharing().isLinkEnabled()
&& frontendUrlConfigured;
boolean shareEmailEnabled =
sharingEnabled
&& applicationProperties.getStorage().getSharing().isEmailEnabled()
&& applicationProperties.getMail().isEnabled();
boolean groupSigningEnabled =
storageEnabled && applicationProperties.getStorage().getSigning().isEnabled();
configData.put("storageEnabled", storageEnabled);
configData.put("storageSharingEnabled", sharingEnabled);
configData.put("storageShareLinksEnabled", shareLinksEnabled);
configData.put("storageShareEmailEnabled", shareEmailEnabled);
configData.put("storageGroupSigningEnabled", groupSigningEnabled);
// Check if user is admin using UserServiceInterface
boolean isAdmin = false;
if (userService != null) {

View File

@@ -113,7 +113,7 @@ public class CertSignController {
this.serverCertificateService = serverCertificateService;
}
private static void sign(
public static void sign(
CustomPDFDocumentFactory pdfDocumentFactory,
MultipartFile input,
OutputStream output,
@@ -304,7 +304,7 @@ public class CertSignController {
}
}
class CreateSignature extends CreateSignatureBase {
public static class CreateSignature extends CreateSignatureBase {
File logoFile;
public CreateSignature(KeyStore keystore, char[] pin)

View File

@@ -0,0 +1,111 @@
package stirling.software.SPDF.service;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.KeyStore;
import org.springframework.stereotype.Service;
import stirling.software.SPDF.controller.api.security.CertSignController;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.service.PdfSigningService;
/** Core implementation of {@link PdfSigningService} backed by {@link CertSignController}. */
@Service
public class PdfSigningServiceImpl implements PdfSigningService {
private final CustomPDFDocumentFactory pdfDocumentFactory;
public PdfSigningServiceImpl(CustomPDFDocumentFactory pdfDocumentFactory) {
this.pdfDocumentFactory = pdfDocumentFactory;
}
@Override
public byte[] signWithKeystore(
byte[] pdfBytes,
KeyStore keystore,
char[] password,
boolean showSignature,
Integer pageNumber,
String name,
String location,
String reason,
boolean showLogo)
throws Exception {
CertSignController.CreateSignature createSignature =
new CertSignController.CreateSignature(keystore, password);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayMultipartFile inputFile =
new ByteArrayMultipartFile(pdfBytes, "document.pdf", "application/pdf");
CertSignController.sign(
pdfDocumentFactory,
inputFile,
outputStream,
createSignature,
showSignature,
pageNumber,
name,
location,
reason,
showLogo);
return outputStream.toByteArray();
}
/** Minimal MultipartFile wrapper for passing raw PDF bytes to CertSignController.sign(). */
private static class ByteArrayMultipartFile
implements org.springframework.web.multipart.MultipartFile {
private final byte[] content;
private final String filename;
private final String contentType;
ByteArrayMultipartFile(byte[] content, String filename, String contentType) {
this.content = content;
this.filename = filename;
this.contentType = contentType;
}
@Override
public String getName() {
return "file";
}
@Override
public String getOriginalFilename() {
return filename;
}
@Override
public String getContentType() {
return contentType;
}
@Override
public boolean isEmpty() {
return content == null || content.length == 0;
}
@Override
public long getSize() {
return content == null ? 0 : content.length;
}
@Override
public byte[] getBytes() {
return content;
}
@Override
public java.io.InputStream getInputStream() {
return new ByteArrayInputStream(content);
}
@Override
public void transferTo(java.io.File dest) throws java.io.IOException {
java.nio.file.Files.write(dest.toPath(), content);
}
}
}

View File

@@ -50,6 +50,8 @@ spring.mvc.problemdetails.enabled=false
# Or via SYSTEMFILEUPLOADLIMIT/SYSTEM_MAXFILESIZE which will also set fileUploadLimit in settings.yml
spring.servlet.multipart.max-file-size=${SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE:2000MB}
spring.servlet.multipart.max-request-size=${SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE:2000MB}
# Jetty max form content size (default 200KB is too small for signature images)
server.jetty.max-http-form-post-size=10MB
server.servlet.session.tracking-modes=cookie
server.servlet.context-path=${SYSTEM_ROOTURIPATH:/}
spring.devtools.restart.enabled=true

View File

@@ -240,6 +240,22 @@ system:
databaseBackup:
cron: "0 0 0 * * ?" # Cron expression for automatic database backups "0 0 0 * * ?" daily at midnight
storage:
enabled: false # set to 'true' to allow users to store files on the server (requires security.enableLogin) [ALPHA]
provider: local # storage provider: 'local' for filesystem storage, 'database' for DB-backed storage
local:
basePath: './storage' # base directory for stored files
quotas:
maxStorageMbPerUser: -1 # Max storage per user in MB; -1 disables per-user cap
maxStorageMbTotal: -1 # Max storage across all users in MB; -1 disables total cap
maxFileMb: -1 # Max size per stored file (including history/audit) in MB; -1 disables limit
sharing:
enabled: false # set to 'true' to enable file sharing features [ALPHA]
linkEnabled: true # set to 'false' to disable share links (requires system.frontendUrl)
emailEnabled: false # set to 'true' to allow sharing by email (requires mail.enabled)
linkExpirationDays: 3 # Number of days before share links expire
signing:
enabled: false # set to 'true' to enable group signing workflow (requires storage.enabled) [ALPHA]
autoPipeline:
outputFolder: "" # Output folder for processed pipeline files (leave empty for default)
fileReadiness:

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB