#############################################################################################################
#                                         Welcome to settings file from                                     #
#                      ____ _____ ___ ____  _     ___ _   _  ____       ____  ____  _____                   #
#                     / ___|_   _|_ _|  _ \| |   |_ _| \ | |/ ___|     |  _ \|  _ \|  ___|                  #
#                     \___ \ | |  | || |_) | |    | ||  \| | |  _ _____| |_) | | | | |_                     #
#                      ___) || |  | ||  _ <| |___ | || |\  | |_| |_____|  __/| |_| |  _|                    #
#                     |____/ |_| |___|_| \_\_____|___|_| \_|\____|     |_|   |____/|_|                      #
#                                                                                                           #
# Do not comment out any entry, it will be removed on next startup                                          #
# If you want to override with environment parameter follow parameter naming SECURITY_INITIALLOGIN_USERNAME #
#############################################################################################################

security:
  enableLogin: true # set to 'true' to enable login
  loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1
  loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
  loginMethod: all # Accepts values like 'all' and 'normal'(only Login with Username/Password), 'oauth2'(only Login with OAuth2) or 'saml2'(only Login with SAML2)
  initialLogin:
    username: "" # initial username for the first login
    password: "" # initial password for the first login
  oauth2:
    enabled: false # set to 'true' to enable login (Note: enableLogin must also be 'true' for this to work)
    client:
      keycloak:
        issuer: "" # URL of the Keycloak realm's OpenID Connect Discovery endpoint
        clientId: "" # client ID for Keycloak OAuth2
        clientSecret: "" # client secret for Keycloak OAuth2
        scopes: openid, profile, email # scopes for Keycloak OAuth2
        useAsUsername: preferred_username # field to use as the username for Keycloak OAuth2. Available options are: [email | name | given_name | family_name | preferred_name]
      google:
        clientId: "" # client ID for Google OAuth2
        clientSecret: "" # client secret for Google OAuth2
        scopes: email, profile # scopes for Google OAuth2
        useAsUsername: email # field to use as the username for Google OAuth2. Available options are: [email | name | given_name | family_name]
      github:
        clientId: "" # client ID for GitHub OAuth2
        clientSecret: "" # client secret for GitHub OAuth2
        scopes: read:user # scope for GitHub OAuth2
        useAsUsername: login # field to use as the username for GitHub OAuth2. Available options are: [email | login | name]
    issuer: "" # set to any Provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) endpoint
    clientId: "" # client ID from your Provider
    clientSecret: "" # client secret from your Provider
    autoCreateUser: true # set to 'true' to allow auto-creation of non-existing users
    blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
    useAsUsername: email # default is 'email'; custom fields can be used as the username
    scopes: openid, profile, email # specify the scopes for which the application will request permissions
    provider: google # set this to your OAuth Provider's name, e.g., 'google' or 'keycloak'
  saml2:
    enabled: false # Only enabled for paid enterprise clients (enterpriseEdition.enabled must be true)
    provider: "" # The name of your Provider
    autoCreateUser: true # set to 'true' to allow auto-creation of non-existing users
    blockRegistration: false # set to 'true' to deny login with SSO without prior registration by an admin
    registrationId: stirling # The name of your Service Provider (SP) app name. Should match the name in the path for your SSO & SLO URLs
    idpMetadataUri: https://dev-XXXXXXXX.okta.com/app/externalKey/sso/saml/metadata # The uri for your Provider's metadata
    idpSingleLoginUrl: https://dev-XXXXXXXX.okta.com/app/dev-XXXXXXXX_stirlingpdf_1/externalKey/sso/saml # The URL for initiating SSO. Provided by your Provider
    idpSingleLogoutUrl: https://dev-XXXXXXXX.okta.com/app/dev-XXXXXXXX_stirlingpdf_1/externalKey/slo/saml # The URL for initiating SLO. Provided by your Provider
    idpIssuer: "" # The ID of your Provider
    idpCert: classpath:okta.cert # The certificate your Provider will use to authenticate your app's SAML authentication requests. Provided by your Provider
    privateKey: classpath:saml-private-key.key # Your private key. Generated from your keypair
    spCert: classpath:saml-public-cert.crt # Your signing certificate. Generated from your keypair
  # IMPORTANT: For SAML setup, download your SP metadata from the BACKEND URL: http://localhost:8080/saml2/service-provider-metadata/{registrationId}
  # Do NOT use the frontend dev server URL (localhost:5173) as it will generate incorrect ACS URLs. Always use the backend URL (localhost:8080) for SAML configuration.
  jwt: # This feature is currently under development and not yet fully supported. Do not use in production.
    persistence: true # Set to 'true' to enable JWT key store
    enableKeyRotation: true # Set to 'true' to enable key pair rotation
    enableKeyCleanup: true # Set to 'true' to enable key pair cleanup
    tokenExpiryMinutes: 1440 # JWT access token lifetime in minutes for web clients (1 day).
    desktopTokenExpiryMinutes: 43200 # JWT access token lifetime in minutes for desktop clients (30 days). 
    allowedClockSkewSeconds: 60 # Allowed JWT validation clock skew in seconds to tolerate small client/server time drift.
    refreshGraceMinutes: 15 # Allow refresh using an expired access token only within this many minutes after expiry.
  validation: # PDF signature validation settings
    trust:
      serverAsAnchor: true # Trust server certificate as anchor for PDF signatures (if configured and self-signed or CA)
      useSystemTrust: true # Trust Java/OS system trust store for PDF signature validation
      useMozillaBundle: true # Trust bundled Mozilla CA bundle (~140 CAs) for PDF signature validation
      useAATL: false # Trust Adobe Approved Trust List (AATL) for PDF signature validation - downloads from Adobe on startup if enabled
      useEUTL: false # Trust EU Trusted List (EUTL) for eIDAS qualified certificates - downloads LOTL and national TSLs on startup if enabled
    allowAIA: false # Allow JDK to fetch issuer certificates and revocation information from network (OCSP/CRL/AIA)
    aatl:
      url: https://trustlist.adobe.com/tl.pdf # Adobe Approved Trust List download URL
    eutl:
      lotlUrl: https://ec.europa.eu/tools/lotl/eu-lotl.xml # EU List Of Trusted Lists (LOTL) URL
      acceptTransitional: false # Accept certificates with 'supervisionincessation' status (transitional state)
    revocation:
      mode: none # Revocation checking mode: 'none' (disabled), 'ocsp' (OCSP only), 'crl' (CRL only), 'ocsp+crl' (OCSP with CRL fallback)
      hardFail: false # Fail validation if revocation status cannot be determined (true=strict, false=soft-fail)
  xFrameOptions: DENY # X-Frame-Options header value. Options: 'DENY' (default, prevents all framing), 'SAMEORIGIN' (allows framing from same domain), 'DISABLED' (no X-Frame-Options header sent). Note: automatically set to DISABLED when login is disabled

premium:
  key: 00000000-0000-0000-0000-000000000000
  enabled: false # Enable license key checks for pro/enterprise features
  proFeatures:
    SSOAutoLogin: false
    CustomMetadata:
      autoUpdateMetadata: false
      author: username
      creator: Stirling-PDF
      producer: Stirling-PDF
  enterpriseFeatures:
    audit:
      enabled: true # Enable audit logging
      level: 2 # Audit logging level: 0=OFF, 1=BASIC, 2=STANDARD, 3=VERBOSE
      retentionDays: 90 # Number of days to retain audit logs
    databaseNotifications:
      backups:
        successful: false # set to 'true' to enable email notifications for successful database backups
        failed: false # set to 'true' to enable email notifications for failed database backups
      imports:
        successful: false # set to 'true' to enable email notifications for successful database imports
        failed: false # set to 'true' to enable email notifications for failed database imports

mail:
  enabled: false # set to 'true' to enable sending emails
  enableInvites: false # set to 'true' to enable email invites for user management (requires mail.enabled and security.enableLogin)
  host: smtp.example.com # SMTP server hostname
  port: 587 # SMTP server port
  username: "" # SMTP server username
  password: "" # SMTP server password
  from: "" # sender email address
  startTlsEnable: true # enable STARTTLS (explicit TLS upgrade after connecting) when supported by the SMTP server
  startTlsRequired: false # require STARTTLS; connection fails if the upgrade command is not supported
  sslEnable: false # enable SSL/TLS wrapper for implicit TLS (typically used with port 465)
  sslTrust: "" # optional trusted host override, e.g. "smtp.example.com" or "*"; defaults to "*" (trust all) when empty
  sslCheckServerIdentity: false # enable hostname verification when using SSL/TLS

telegram:
  enabled: false # set to 'true' to enable Telegram bot integration
  botToken: "" # Telegram bot token obtained from BotFather
  botUsername: "" # Telegram bot username (without @)
  pipelineInboxFolder: telegram # Name of the pipeline inbox folder for Telegram uploads
  customFolderSuffix: true # set to 'true' to allow users to specify custom target folders via UserID
  enableAllowUserIDs: true # set to 'true' to restrict access to specific Telegram user IDs
  allowUserIDs: [] # List of allowed Telegram user IDs (e.g. [123456789, 987654321]). Leave empty to allow all users.
  enableAllowChannelIDs: true # set to 'true' to restrict access to specific Telegram channel IDs
  allowChannelIDs: [] # List of allowed Telegram channel IDs (e.g. [-1001234567890, -1009876543210]). Leave empty to allow all channels.
  processingTimeoutSeconds: 180 # Maximum time in seconds to wait for processing a Telegram request
  pollingIntervalMillis: 2000 # Interval in milliseconds between polling for new messages
  feedback:
    channel:
      noValidDocument: true # set to 'false' to hide/suppress feedback messages in channels (to avoid spam)
      errorProcessing: true # set to 'false' to hide/suppress feedback messages in channels (to avoid spam)
      errorMessage: true # set to 'false' to hide/suppress error messages in channels (to avoid spam)
      processing: true # set to 'false' to hide/suppress processing messages in channels (to avoid spam)
    user:
      noValidDocument: true # set to 'false' to hide/suppress feedback messages to users (to avoid spam)
      errorProcessing: true # set to 'false' to hide/suppress feedback messages to users (to avoid spam)
      errorMessage: true # set to 'false' to hide/suppress error messages to users (to avoid spam)
      processing: true # set to 'false' to hide/suppress processing messages to users (to avoid spam)

legal:
  termsAndConditions: https://www.stirling.com/legal/terms-of-service # URL to the terms and conditions of your application (e.g. https://example.com/terms). Empty string to disable or filename to load from local file in static folder
  privacyPolicy: https://www.stirling.com/legal/privacy-policy # URL to the privacy policy of your application (e.g. https://example.com/privacy). Empty string to disable or filename to load from local file in static folder
  accessibilityStatement: "" # URL to the accessibility statement of your application (e.g. https://example.com/accessibility). Empty string to disable or filename to load from local file in static folder
  cookiePolicy: "" # URL to the cookie policy of your application (e.g. https://example.com/cookie). Empty string to disable or filename to load from local file in static folder
  impressum: "" # URL to the impressum of your application (e.g. https://example.com/impressum). Empty string to disable or filename to load from local file in static folder

system:
  defaultLocale: en-US # set the default language (e.g. 'de-DE', 'fr-FR', etc)
  googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
  enableAlphaFunctionality: false # set to enable functionality which might need more testing before it fully goes live (this feature might make no changes)
  showUpdate: false # see when a new update is available
  showUpdateOnlyAdmin: false # only admins can see when a new update is available, depending on showUpdate it must be set to 'true'
  showSettingsWhenNoLogin: true # set to 'false' to hide settings button when login is disabled (enableLogin: false). Only applies when login is disabled.
  customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template HTML files
  tessdataDir: "" # path to the directory containing the Tessdata files. This setting is relevant for Windows systems. For Windows users, this path should be adjusted to point to the appropriate directory where the Tessdata files are stored.
  enableAnalytics: null # Master toggle for analytics: set to 'true' to enable all analytics, 'false' to disable all analytics, or leave as 'null' to prompt admin on first launch
  enableDesktopInstallSlide: true # Set to 'false' to hide the desktop app installation slide in the onboarding flow
  enablePosthog: null # Enable PostHog analytics (open-source product analytics): set to 'true' to enable, 'false' to disable, or 'null' to enable by default when analytics is enabled
  enableScarf: null # Enable Scarf tracking pixel: set to 'true' to enable, 'false' to disable, or 'null' to enable by default when analytics is enabled
  enableUrlToPDF: false # Set to 'true' to enable URL to PDF, INTERNAL ONLY, known security issues, should not be used externally
  disableSanitize: false # set to true to disable Sanitize HTML; (can lead to injections in HTML)
  maxDPI: 500 # Maximum allowed DPI for PDF to image conversion
  corsAllowedOrigins: [] # List of allowed origins for CORS (e.g. ['http://localhost:5173', 'https://app.example.com']). Leave empty to disable CORS. For local development with frontend on port 5173, add 'http://localhost:5173'
  backendUrl: "" # Backend base URL for SAML/OAuth/API callbacks (e.g. 'http://localhost:8080' for dev, 'https://api.example.com' for production). REQUIRED for SSO authentication to work correctly. This is where your IdP will send SAML responses and OAuth callbacks. Leave empty to default to 'http://localhost:8080' in development.
  frontendUrl: "" # Frontend URL for invite email links (e.g. 'https://app.example.com'). Optional - if not set, will use backendUrl. This is the URL users click in invite emails.
  enableMobileScanner: false # Enable mobile phone QR code upload feature. Requires frontendUrl to be configured.
  mobileScannerSettings:
    convertToPdf: true # Automatically convert uploaded images to PDF format. If false, images are kept as-is.
    imageResolution: full # Image resolution for mobile uploads: 'full' (original size) or 'reduced' (max 1200px on longest side). Only applies when convertToPdf is true.
    pageFormat: A4 # Page format for converted PDFs: 'keep' (original image dimensions), 'A4' (A4 page size), or 'letter' (US Letter page size). Only applies when convertToPdf is true.
    stretchToFit: false # Whether to stretch images to fill the entire page (may distort aspect ratio). If false, images are centered with preserved aspect ratio. Only applies when convertToPdf is true.
  serverCertificate:
    enabled: true # Enable server-side certificate for "Sign with Stirling-PDF" option
    organizationName: Stirling-PDF # Organization name for generated certificates
    validity: 365 # Certificate validity in days
    regenerateOnStartup: false # Generate new certificate on each startup
  html:
    urlSecurity:
      enabled: true # Enable URL security restrictions for HTML processing
      level: MEDIUM # Security level: MAX (whitelist only), MEDIUM (block internal networks), OFF (no restrictions)
      allowedDomains: [] # Whitelist of allowed domains (e.g. ['cdn.example.com', 'images.google.com'])
      blockedDomains: [] # Additional domains to block (e.g. ['evil.com', 'malicious.org'])
      internalTlds: [".local", ".internal", ".corp", ".home"] # Block domains with these TLD patterns
      blockPrivateNetworks: true # Block RFC 1918 private networks (10.x.x.x, 192.168.x.x, 172.16-31.x.x)
      blockLocalhost: true # Block localhost and loopback addresses (127.x.x.x, ::1)
      blockLinkLocal: true # Block link-local addresses (169.254.x.x, fe80::/10)
      blockCloudMetadata: true # Block cloud provider metadata endpoints (169.254.169.254)
  datasource:
    enableCustomDatabase: false # Enterprise users ONLY, set this property to 'true' if you would like to use your own custom database configuration
    customDatabaseUrl: "" # eg jdbc:postgresql://localhost:5432/postgres, set the url for your own custom database connection. If provided, the type, hostName, port and name are not necessary and will not be used
    username: postgres # set the database username
    password: postgres # set the database password
    type: postgresql # the type of the database to set (e.g. 'h2', 'postgresql')
    hostName: localhost # the host name to use for the database url. Set to 'localhost' when running the app locally. Set to match the name of the container name of your database container when running the app on a server (Docker configuration)
    port: 5432 # set the port number of the database. Ensure this matches the port the database is listening to
    name: postgres # set the name of your database. Should match the name of the database you create
  customPaths:
    pipeline:
      pipelineDir: "" # Defaults to /pipeline
      watchedFoldersDir: "" # Defaults to /pipeline/watchedFolders
      watchedFoldersDirs: [] # List of watched folder directories. Defaults to watchedFoldersDir or /pipeline/watchedFolders.
      finishedFoldersDir: "" # Defaults to /pipeline/finishedFolders
    operations:
      weasyprint: "" # Defaults to /opt/venv/bin/weasyprint
      unoconvert: "" # Defaults to /opt/venv/bin/unoconvert
      calibre: "" # Defaults to /usr/bin/ebook-convert
      ocrmypdf: "" # Defaults to /usr/bin/ocrmypdf
      soffice: "" # Defaults to /usr/bin/soffice
  fileUploadLimit: "" # Defaults to "". No limit when string is empty. Set a number, between 0 and 999, followed by one of the following strings to set a limit. "KB", "MB", "GB".
  tempFileManagement:
    baseTmpDir: "" # Defaults to java.io.tmpdir/stirling-pdf
    libreofficeDir: "" # Defaults to tempFileManagement.baseTmpDir/libreoffice
    systemTempDir: "" # Only used if cleanupSystemTemp is true
    prefix: stirling-pdf- # Prefix for temp file names
    maxAgeHours: 24 # Maximum age in hours before temp files are cleaned up
    cleanupIntervalMinutes: 30 # How often to run cleanup (in minutes)
    startupCleanup: true # Clean up old temp files on startup
    cleanupSystemTemp: false # Whether to clean broader system temp directory
  databaseBackup:
    cron: "0 0 0 * * ?" # Cron expression for automatic database backups "0 0 0 * * ?" daily at midnight

ui:
  appNameNavbar: "" # name displayed on the navigation bar
  logoStyle: classic # Options: 'classic' (default - classic S icon) or 'modern' (minimalist logo)
  languages: [] # If empty, all languages are enabled. To display only German and Polish ["de_DE", "pl_PL"]. British English is always enabled.
  defaultHideUnavailableTools: false # Default user preference: hide disabled tools instead of greying them out
  defaultHideUnavailableConversions: false # Default user preference: hide disabled conversion options instead of greying them out

endpoints:
  toRemove: [] # list endpoints to disable (e.g. ['img-to-pdf', 'remove-pages'])
  groupsToRemove: [] # list groups to disable (e.g. ['LibreOffice', 'DeveloperTools', 'DeveloperDocs', 'Automation'])

metrics:
  enabled: true # 'true' to enable Info APIs (`/api/*`) endpoints, 'false' to disable

# Automatically Generated Settings (Do Not Edit Directly)
AutomaticallyGenerated:
  key: 98380302-5c34-496a-a18c-ba388fc4275a
  UUID: 66d9eb96-3bb3-4129-82af-e40539b438bb
  appVersion: 2.5.3

processExecutor:
  autoUnoServer: true # true: use local pool based on libreOfficeSessionLimit; false: use unoServerEndpoints
  unoServerEndpoints: [] # Used when autoUnoServer is false
  # Example manual endpoints (uncomment to use):
  # unoServerEndpoints:
  #   - host: "127.0.0.1"
  #     port: 2003
  #     hostLocation: "auto"  # auto|local|remote (use "remote" for port-forwarded servers)
  #     protocol: "http"       # http|https
  #   - host: "remote-server.local"
  #     port: 8080
  #     hostLocation: "remote"
  #     protocol: "https"
  sessionLimit: # Process executor instances limits
    libreOfficeSessionLimit: 1 # Each additional uno server adds ~50MB idle RAM
    pdfToHtmlSessionLimit: 1
    qpdfSessionLimit: 4
    tesseractSessionLimit: 1
    pythonOpenCvSessionLimit: 8
    weasyPrintSessionLimit: 16
    installAppSessionLimit: 1
    calibreSessionLimit: 1
    imageMagickSessionLimit: 4
    ghostscriptSessionLimit: 8
    ocrMyPdfSessionLimit: 2
  timeoutMinutes: # Process executor timeout in minutes
    libreOfficetimeoutMinutes: 30
    pdfToHtmltimeoutMinutes: 20
    pythonOpenCvtimeoutMinutes: 30
    weasyPrinttimeoutMinutes: 30
    installApptimeoutMinutes: 60
    calibretimeoutMinutes: 30
    imageMagickTimeoutMinutes: 30
    tesseractTimeoutMinutes: 30
    qpdfTimeoutMinutes: 30
    ghostscriptTimeoutMinutes: 30
    ocrMyPdfTimeoutMinutes: 30

pdfEditor:
  fallback-font: classpath:/static/fonts/NotoSans-Regular.ttf # Override to point at a custom fallback font
  cache:
    max-bytes: -1 # Max in-memory cache size in bytes; -1 disables byte cap
    max-percent: 20 # Max in-memory cache as % of JVM max; used when max-bytes <= 0
  font-normalization:
    enabled: false # IMPORTANT: Disable to preserve ToUnicode CMaps for correct font rendering. Ghostscript strips Unicode mappings from CID fonts.
  cff-converter:
    enabled: true # Wrap CFF/Type1CFF fonts as OpenType-CFF for browser compatibility
    method: python # Converter method: 'python' (fontTools, recommended - wraps as OTF), 'fontforge' (legacy - converts to TTF, may hang on CID fonts)
    python-command: /opt/venv/bin/python3 # Python interpreter path
    python-script: /scripts/convert_cff_to_ttf.py # Path to font wrapping script
    fontforge-command: fontforge # Override if FontForge is installed under a different name/path
  type3:
    library:
      enabled: true # Match common Type3 fonts against the built-in library of converted programs
      index: classpath:/type3/library/index.json # Override to point at a custom index.json (supports http:, file:, classpath:)
