If you are looking for a production crystal reports server look into SAP Crystal Server.
CrystalCMD is a C#/dotnet and Java program that loads JSON files into Crystal Reports to produce PDFs. Initially an experimental proof of concept, it demonstrates generating Crystal Reports on Linux using Java and .NET framework (wine).
The main focus is the c#/dotnet implementation running within Windows/IIS and Linux/Wine.
Key Features:
- PDF Generation: Converts JSON (with embedded csv) data into PDF reports with Crystal Reports templates.
- Command Line & Server Modes: Supports both modes; server mode is recommended for better performance.
- Cross-Platform: Works on Linux and can run .NET implementations using Wine.
- Provide a path for porting a asp.net framework site from windows and iis to asp.net dotnet core net6.0 or newer on linux
- Provide support for developers to work on projects that use dotnet crystal reports while using a mac
- Provide a way to fence off legacy crystal reports behind a web api
CrystalCMD is developed with the following work flow:
- Nothing happens for months/years
- Someone needs it to do something it doesn't already do
- That person implements that something and submits a pull request
- Repeat if it doesn't have a feature that you want it to have, add it
- If it has a bug you need fixed, fix it
The git history was rewritten with git filter-repo to remove the SAP Crystal Reports
runtime jars (and an old committed build artifact) from all commits. They were removed
because the SAP Crystal runtime is proprietary and must not be redistributed in source
control, and because the binaries bloated the repository (the .git directory shrank from
~165 MB to ~2 MB).
Consequences:
- Every commit SHA before the rewrite changed. If you have an older clone, re-clone or hard-reset to the rewritten history — old branches reference commits that no longer exist.
java/CrystalCmd/lib/no longer contains the jars. Reconstruct it before building withscripts/download-crystal-libs.sh(or.ps1on Windows) — seejava/CrystalCmd/lib/README.md.
Note that, when using the command line option, this is very slow and highly recommended to use the server option.
test server: c.majorsilence.com
Example running from base CrystalCmd folder.
curl https://c.majorsilence.com/status
curl -u "username:password" -F "reportdata=@test.json" -F "reporttemplate=@the_dataset_report.rpt" https://c.majorsilence.com/export --output testout.pdf
# test localhost
curl -u "username:password" -F "reportdata=@test.json" -F "reporttemplate=@the_dataset_report.rpt" http://127.0.0.1:4321/export --output testout.pdf- http://localhost:4321/status
- http://localhost:4321/export
- Returns pdf as bytestream
- Must be passed two post variables as byte arrays
- reporttemplate
- reportdata
CrystalCmd renders whatever Crystal Reports template (.rpt) the caller uploads. That
is by design, but it has important security consequences, because a .rpt can embed its own
database connections, SQL command objects, and references to external/UNC resources. Treat
the rendering service as something that runs untrusted report definitions and harden the
deployment accordingly.
A malicious or compromised client can submit a template that tries to:
- connect to arbitrary databases or hosts reachable from the worker (SSRF / use of any ambient credentials),
- reference a UNC path (
\\attacker\share\...) to make a Windows worker authenticate outbound over SMB and leak NetNTLM hashes, - abuse
RecordSelectionFormula/ formula fields (Crystal formula injection).
Because any .rpt must be accepted, mitigate at the deployment boundary:
- Run the worker as a low-privilege account.
- Place it in an isolated network segment with an egress firewall that denies outbound traffic except to data sources you explicitly allow. Block outbound SMB (445/139).
- Only expose the API to trusted callers (authenticated, ideally also network-restricted).
- Where you control the report set, prefer an allow-list of known-good templates over accepting arbitrary uploads.
- Basic auth credentials come from
Credentials:Username/Credentials:Password. They ship empty — the server rejects all requests until you set them. The server refuses to start if they are set to the well-known defaultsuser/password(setSecurity:AllowDefaultCredentials=trueonly for local testing). - JWT is enabled only when
Jwt:Keyis a real secret of at least 32 bytes; the shipped placeholder is ignored so it cannot be used to forge tokens. Use a unique secret. - Basic credentials and bearer tokens are sent on every request. Always use TLS. Set
Security:RequireHttps=trueto force HSTS + HTTPS redirect when the server is exposed directly, or terminate TLS at a trusted reverse proxy (the server honoursX-Forwarded-Proto/X-Forwarded-For).
The id returned by POST /export/poll and POST /analyzer/poll is an opaque handle. When
a signing key is configured (Security:PollTokenKey, falling back to Jwt:Key) the handle
is bound to the authenticated caller via HMAC, so one principal cannot fetch another's
report by guessing/replaying the id. Set Security:PollTokenKey to a shared secret across
all instances in a multi-instance JWT deployment.
Limits:MaxRequestBodyBytes(default 100 MB) caps a single request body.- GZip request bodies are decompressed with a hard cap (200 MB) to prevent decompression bombs.
The reference Java server requires Basic auth on /export, reading expected credentials
from the CRYSTALCMD_USERNAME / CRYSTALCMD_PASSWORD environment variables (it rejects all
requests when they are unset). It is still a proof of concept — keep it behind an
authenticating, TLS-terminating reverse proxy and do not expose it directly.
Majorsilence.CrystalCMD.postman_collection.json
Use this project to generate test data from c# program
See Crystal Reports, Developer for Visual Studio Downloads.
-
Download the Crystal Reports .net runtime from: https://origin.softwaredownloads.sap.com/public/site/index.html
- CR for Visual Studio SP35 CR Runtime 64-bit
- CR for Visual Studio SP35 CR Runtime 32-bit
-
Majorsilence.CrystalCmd.NetframeworkConsoleServer
- a net48 embedio based console app/webserver
- can be run on Linux using wine
See the dotnet/Readme.md file for more info..
flowchart TD
subgraph "Client Applications"
A[".NET Application"] --> C["Majorsilence.CrystalCMD.Client"]
B["Mac/Linux/Windows/iOS/Android Applications"] --> C
end
subgraph "Server"
D["ASP.NET Core 10 Web Services Majorsilence.CrystalCmd.Server"]
end
subgraph "Worker"
E[".NET 4.8 Worker Process Majorsilence.CrystalCmd.Console"]
end
J["WorkQueue Database"]
C --> D
D -- "Save report / enqueue job" --> J
E -- "Poll / read job" --> J
J -- "Job data" --> E
subgraph "Processing"
E --> G["Crystal Reports Engine"]
G --> H["Generate PDF"]
H -- "Save PDF to workqueue" --> J
end
D -- "Make PDF available to client" --> C
C --> I["Client receives PDF"]
classDef client fill:#d1f0ff,stroke:#333,stroke-width:1px
classDef server fill:#ffe6cc,stroke:#333,stroke-width:1px
classDef process fill:#e6ffcc,stroke:#333,stroke-width:1px
class A,B,C client
class D,E,J server
class G,H,I process
Basic info on the java version.
CrystalCmd upports running as a command line tool. Pass in path to report, data, and output fileand a pdf is generated.
java -jar CrystalCmd.jar -reportpath "/path/to/report.rpt" -datafile "/path/to/data.json" -outpath "/path/to/generated/file.pdf"example 2
java -jar CrystalCmd.jar -reportpath "/home/peter/Projects/CrystalCmd/the_dataset_report.rpt" -datafile "/home/peter/Projects/CrystalCmd/test.json" -outpath "/home/peter/Projects/CrystalCmd/java/CrystalCmd/build/output.pdf"CrystalCmd supports running in server mode. If you run it with no command line arguments it starts a web server listening on port 4321. There are two end points that can be called.
java -jar CrystalCmd.jarCall the server.
curl -u "username:password" -F "reporttemplate=@the_dataset_report.rpt" -F "reportdata=@test.json" http://localhost:4321/export > myoutputfile.pdfdocker run -p 2005:4321 -t majorsilence/crystalcmdOr run it as a daemon.
docker run -p 2005:4321 -d majorsilence/crystalcmdNow check the status in your browser:
install
snap install ./java/CrystalCmd/build/CrystalCmd.snap --force-dangerous --classicrun
crystalcmd -reportpath "/home/peter/Projects/CrystalWrapper/the_dataset_report.rpt" -datafile "/home/peter/Projects/CrystalWrapper/test.json" -outpath "/home/peter/Projects/CrystalWrapper/Java/build/output.pdf"sudo ./build_snap.shsudo apt-get install openjdk-11-jdkDownload eclipse java edition.
Setup eclipse with crystal references.
Import java/CrystalCmd folder as ecplise project (Eclipse -> File -> Open Projects from File System).
Download intelliJ community edition.
sudo apt-get install openjdk-11-jre- Eclipse -> File -> Export -> Java -> Runnable Jar File
Package required libraries into generated JAR
output as "CrystalCmd.jar" in folder ./CrystalCmd/java/CrystalCmd/build
https://origin.softwaredownloads.sap.com/public/site/index.html
After some experimentation, a workaround was to create the fonts folder in the AdoptOpenJDK JRE (jre\lib\fonts) and copy a single font file from the Linux msttcorefonts mentioned above into the newly created fonts folder. My document uses all Arial font, but it doesn't seem to matter what font file is in the fonts folder. I copied Webdings.ttf. The file does have to be a real font file. I tried making a dummy text file and rename it to Webdings.ttf, but the NPE occurred with the dummy font file.
Once a real font is copied to jre\lib\fonts, The PDF is created just fine with the Arial font embedded. It seems that there just has to be a one real font at jre\lib\fonts to get started, and then crjava/AdoptOpenJDK will eventually use fontconfig to find the correct Windows font.
Copy a file from
Copy a file to C:\Users[UserName].jdks\openjdk-16.0.1\lib\fonts from C:\Windows\Fonts.
copy '/System/Library/Fonts' into '/Users/[UserName]]/Library/Java/JavaVirtualMachines/[JavaVersion]/Contents/Home/lib/fonts'
# try the ubuntu or fedora way first
# https://answers.sap.com/questions/676449/nullpointerexception-in-opentypefontmanager.html
apk add --no-cache msttcorefonts-installer && update-ms-fonts && fc-cache -f && ln -s /usr/share/fonts/truetype/msttcorefonts /usr/lib/jvm/default-jvm/jre/lib/fontsapt install fonts-dejavu fontconfig msttcorefonts-installer && update-ms-fonts && fc-cache -f
ln -s /usr/share/fonts/truetype/msttcorefonts /usr/lib/jvm/java-1.11.0-openjdk-amd64/lib/fontsdnf install fontconfig dejavu-sans-fonts dejavu-serif-fonts