This commit is contained in:
Carpe-Wang 2025-04-19 16:58:51 -04:00
parent ae9a0c5125
commit b9a2918b27
545 changed files with 31422 additions and 97 deletions

View File

@ -10,6 +10,7 @@ plugins {
//id "nebula.lint" version "19.0.3"
id("org.panteleyev.jpackageplugin") version "1.6.1"
id "org.sonarqube" version "6.1.0.5360"
id "jacoco"
}
import com.github.jk1.license.render.*
@ -363,7 +364,7 @@ launch4j {
spotless {
java {
target project.fileTree('src').include('**/*.java')
target project.fileTree('src').include('**/*.java').exclude('**/test/**')
googleJavaFormat("1.25.2").aosp().reorderImports(false)
@ -588,19 +589,36 @@ task printMacVersion {
tasks.named('generateOpenApiDocs') {
doNotTrackState("Tracking state is not supported for this task")
}
tasks.register('convertersTest', Test) {
group = 'verification'
description = 'Run only converter integration tests under controller/api/converters'
// test classpath
testClassesDirs = sourceSets.test.get().output.classesDirs
classpath = sourceSets.test.get().runtimeClasspath
// controller/api/converters
include '**/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdfIntegrationTest.java'
}
// test JUnit Platform
tasks.named('test') {
useJUnitPlatform()
}
tasks.register('convertersTest', Test) {
group = 'verification'
description = 'Run only markdown/pdf converter unit tests'
useJUnitPlatform()
// markdown/pdf
include '**/ConvertMarkdownToPdfTest.class'
include '**/ConvertPDFToMarkdownTest.class'
testClassesDirs = sourceSets.test.output.classesDirs
classpath = sourceSets.test.runtimeClasspath
}
jacocoTestReport {
dependsOn convertersTest //
reports {
html.required = true
xml.required = true
csv.required = false
}
executionData fileTree(buildDir).include(
"/jacoco/convertersTest.exec"
)
}

View File

@ -3,7 +3,6 @@ package stirling.software.SPDF.utils;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import net.bytebuddy.implementation.bytecode.Throw;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@ -13,8 +12,6 @@ import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;
import java.io.IOException;
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = {

View File

@ -1,82 +0,0 @@
package stirling.software.SPDF.utils;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
public class FileToPdfTest {
/**
* Test the HTML to PDF conversion. This test expects an IOException when an empty HTML input is
* provided.
*/
@Test
public void testConvertHtmlToPdf() {
HTMLToPdfRequest request = new HTMLToPdfRequest();
byte[] fileBytes = new byte[0]; // Sample file bytes (empty input)
String fileName = "test.html"; // Sample file name indicating an HTML file
boolean disableSanitize = false; // Flag to control sanitization
// Expect an IOException to be thrown due to empty input
Throwable thrown =
assertThrows(
IOException.class,
() ->
FileToPdf.convertHtmlToPdf(
"/path/", request, fileBytes, fileName, disableSanitize));
assertNotNull(thrown);
}
/**
* Test sanitizeZipFilename with null or empty input. It should return an empty string in these
* cases.
*/
@Test
public void testSanitizeZipFilename_NullOrEmpty() {
assertEquals("", FileToPdf.sanitizeZipFilename(null));
assertEquals("", FileToPdf.sanitizeZipFilename(" "));
}
/**
* Test sanitizeZipFilename to ensure it removes path traversal sequences. This includes
* removing both forward and backward slash sequences.
*/
@Test
public void testSanitizeZipFilename_RemovesTraversalSequences() {
String input = "../some/../path/..\\to\\file.txt";
String expected = "some/path/to/file.txt";
// Print output for debugging purposes
System.out.println("sanitizeZipFilename " + FileToPdf.sanitizeZipFilename(input));
System.out.flush();
// Expect that the method replaces backslashes with forward slashes
// and removes path traversal sequences
assertEquals(expected, FileToPdf.sanitizeZipFilename(input));
}
/** Test sanitizeZipFilename to ensure that it removes leading drive letters and slashes. */
@Test
public void testSanitizeZipFilename_RemovesLeadingDriveAndSlashes() {
String input = "C:\\folder\\file.txt";
String expected = "folder/file.txt";
assertEquals(expected, FileToPdf.sanitizeZipFilename(input));
input = "/folder/file.txt";
expected = "folder/file.txt";
assertEquals(expected, FileToPdf.sanitizeZipFilename(input));
}
/** Test sanitizeZipFilename to verify that safe filenames remain unchanged. */
@Test
public void testSanitizeZipFilename_NoChangeForSafeNames() {
String input = "folder/subfolder/file.txt";
assertEquals(input, FileToPdf.sanitizeZipFilename(input));
}
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

View File

@ -0,0 +1,13 @@
/* Pretty printing styles. Used with prettify.js. */
.str { color: #2A00FF; }
.kwd { color: #7F0055; font-weight:bold; }
.com { color: #3F5FBF; }
.typ { color: #606; }
.lit { color: #066; }
.pun { color: #660; }
.pln { color: #000; }
.tag { color: #008; }
.atn { color: #606; }
.atv { color: #080; }
.dec { color: #606; }

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

View File

@ -0,0 +1,243 @@
body, td {
font-family:sans-serif;
font-size:10pt;
}
h1 {
font-weight:bold;
font-size:18pt;
}
.breadcrumb {
border:#d6d3ce 1px solid;
padding:2px 4px 2px 4px;
}
.breadcrumb .info {
float:right;
}
.breadcrumb .info a {
margin-left:8px;
}
.el_report {
padding-left:18px;
background-image:url(report.gif);
background-position:left center;
background-repeat:no-repeat;
}
.el_group {
padding-left:18px;
background-image:url(group.gif);
background-position:left center;
background-repeat:no-repeat;
}
.el_bundle {
padding-left:18px;
background-image:url(bundle.gif);
background-position:left center;
background-repeat:no-repeat;
}
.el_package {
padding-left:18px;
background-image:url(package.gif);
background-position:left center;
background-repeat:no-repeat;
}
.el_class {
padding-left:18px;
background-image:url(class.gif);
background-position:left center;
background-repeat:no-repeat;
}
.el_source {
padding-left:18px;
background-image:url(source.gif);
background-position:left center;
background-repeat:no-repeat;
}
.el_method {
padding-left:18px;
background-image:url(method.gif);
background-position:left center;
background-repeat:no-repeat;
}
.el_session {
padding-left:18px;
background-image:url(session.gif);
background-position:left center;
background-repeat:no-repeat;
}
pre.source {
border:#d6d3ce 1px solid;
font-family:monospace;
}
pre.source ol {
margin-bottom: 0px;
margin-top: 0px;
}
pre.source li {
border-left: 1px solid #D6D3CE;
color: #A0A0A0;
padding-left: 0px;
}
pre.source span.fc {
background-color:#ccffcc;
}
pre.source span.nc {
background-color:#ffaaaa;
}
pre.source span.pc {
background-color:#ffffcc;
}
pre.source span.bfc {
background-image: url(branchfc.gif);
background-repeat: no-repeat;
background-position: 2px center;
}
pre.source span.bfc:hover {
background-color:#80ff80;
}
pre.source span.bnc {
background-image: url(branchnc.gif);
background-repeat: no-repeat;
background-position: 2px center;
}
pre.source span.bnc:hover {
background-color:#ff8080;
}
pre.source span.bpc {
background-image: url(branchpc.gif);
background-repeat: no-repeat;
background-position: 2px center;
}
pre.source span.bpc:hover {
background-color:#ffff80;
}
table.coverage {
empty-cells:show;
border-collapse:collapse;
}
table.coverage thead {
background-color:#e0e0e0;
}
table.coverage thead td {
white-space:nowrap;
padding:2px 14px 0px 6px;
border-bottom:#b0b0b0 1px solid;
}
table.coverage thead td.bar {
border-left:#cccccc 1px solid;
}
table.coverage thead td.ctr1 {
text-align:right;
border-left:#cccccc 1px solid;
}
table.coverage thead td.ctr2 {
text-align:right;
padding-left:2px;
}
table.coverage thead td.sortable {
cursor:pointer;
background-image:url(sort.gif);
background-position:right center;
background-repeat:no-repeat;
}
table.coverage thead td.up {
background-image:url(up.gif);
}
table.coverage thead td.down {
background-image:url(down.gif);
}
table.coverage tbody td {
white-space:nowrap;
padding:2px 6px 2px 6px;
border-bottom:#d6d3ce 1px solid;
}
table.coverage tbody tr:hover {
background: #f0f0d0 !important;
}
table.coverage tbody td.bar {
border-left:#e8e8e8 1px solid;
}
table.coverage tbody td.ctr1 {
text-align:right;
padding-right:14px;
border-left:#e8e8e8 1px solid;
}
table.coverage tbody td.ctr2 {
text-align:right;
padding-right:14px;
padding-left:2px;
}
table.coverage tfoot td {
white-space:nowrap;
padding:2px 6px 2px 6px;
}
table.coverage tfoot td.bar {
border-left:#e8e8e8 1px solid;
}
table.coverage tfoot td.ctr1 {
text-align:right;
padding-right:14px;
border-left:#e8e8e8 1px solid;
}
table.coverage tfoot td.ctr2 {
text-align:right;
padding-right:14px;
padding-left:2px;
}
.footer {
margin-top:20px;
border-top:#d6d3ce 1px solid;
padding-top:2px;
font-size:8pt;
color:#a0a0a0;
}
.footer a {
color:#a0a0a0;
}
.right {
float:right;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 B

View File

@ -0,0 +1,148 @@
/*******************************************************************************
* Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Marc R. Hoffmann - initial API and implementation
*
*******************************************************************************/
(function () {
/**
* Sets the initial sorting derived from the hash.
*
* @param linkelementids
* list of element ids to search for links to add sort inidcator
* hash links
*/
function initialSort(linkelementids) {
window.linkelementids = linkelementids;
var hash = window.location.hash;
if (hash) {
var m = hash.match(/up-./);
if (m) {
var header = window.document.getElementById(m[0].charAt(3));
if (header) {
sortColumn(header, true);
}
return;
}
var m = hash.match(/dn-./);
if (m) {
var header = window.document.getElementById(m[0].charAt(3));
if (header) {
sortColumn(header, false);
}
return
}
}
}
/**
* Sorts the columns with the given header dependening on the current sort state.
*/
function toggleSort(header) {
var sortup = header.className.indexOf('down ') == 0;
sortColumn(header, sortup);
}
/**
* Sorts the columns with the given header in the given direction.
*/
function sortColumn(header, sortup) {
var table = header.parentNode.parentNode.parentNode;
var body = table.tBodies[0];
var colidx = getNodePosition(header);
resetSortedStyle(table);
var rows = body.rows;
var sortedrows = [];
for (var i = 0; i < rows.length; i++) {
r = rows[i];
sortedrows[parseInt(r.childNodes[colidx].id.slice(1))] = r;
}
var hash;
if (sortup) {
for (var i = sortedrows.length - 1; i >= 0; i--) {
body.appendChild(sortedrows[i]);
}
header.className = 'up ' + header.className;
hash = 'up-' + header.id;
} else {
for (var i = 0; i < sortedrows.length; i++) {
body.appendChild(sortedrows[i]);
}
header.className = 'down ' + header.className;
hash = 'dn-' + header.id;
}
setHash(hash);
}
/**
* Adds the sort indicator as a hash to the document URL and all links.
*/
function setHash(hash) {
window.document.location.hash = hash;
ids = window.linkelementids;
for (var i = 0; i < ids.length; i++) {
setHashOnAllLinks(document.getElementById(ids[i]), hash);
}
}
/**
* Extend all links within the given tag with the given hash.
*/
function setHashOnAllLinks(tag, hash) {
links = tag.getElementsByTagName("a");
for (var i = 0; i < links.length; i++) {
var a = links[i];
var href = a.href;
var hashpos = href.indexOf("#");
if (hashpos != -1) {
href = href.substring(0, hashpos);
}
a.href = href + "#" + hash;
}
}
/**
* Calculates the position of a element within its parent.
*/
function getNodePosition(element) {
var pos = -1;
while (element) {
element = element.previousSibling;
pos++;
}
return pos;
}
/**
* Remove the sorting indicator style from all headers.
*/
function resetSortedStyle(table) {
for (var c = table.tHead.firstChild.firstChild; c; c = c.nextSibling) {
if (c.className) {
if (c.className.indexOf('down ') == 0) {
c.className = c.className.slice(5);
}
if (c.className.indexOf('up ') == 0) {
c.className = c.className.slice(3);
}
}
}
}
window['initialSort'] = initialSort;
window['toggleSort'] = toggleSort;
})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CMSProcessableInputStream</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">org.apache.pdfbox.examples.signature</a> &gt; <span class="el_class">CMSProcessableInputStream</span></div><h1>CMSProcessableInputStream</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">33 of 33</td><td class="ctr2">0%</td><td class="bar">0 of 0</td><td class="ctr2">n/a</td><td class="ctr1">5</td><td class="ctr2">5</td><td class="ctr1">11</td><td class="ctr2">11</td><td class="ctr1">5</td><td class="ctr2">5</td></tr></tfoot><tbody><tr><td id="a1"><a href="CMSProcessableInputStream.java.html#L40" class="el_method">CMSProcessableInputStream(InputStream)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="9" alt="9"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"/><td class="ctr2" id="e0">n/a</td><td class="ctr1" id="f0">1</td><td class="ctr2" id="g0">1</td><td class="ctr1" id="h2">2</td><td class="ctr2" id="i2">2</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a0"><a href="CMSProcessableInputStream.java.html#L43" class="el_method">CMSProcessableInputStream(ASN1ObjectIdentifier, InputStream)</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="9" alt="9"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h0">4</td><td class="ctr2" id="i0">4</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a4"><a href="CMSProcessableInputStream.java.html#L56" class="el_method">write(OutputStream)</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="9" alt="9"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">1</td><td class="ctr2" id="g2">1</td><td class="ctr1" id="h1">3</td><td class="ctr2" id="i1">3</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr><tr><td id="a2"><a href="CMSProcessableInputStream.java.html#L50" class="el_method">getContent()</a></td><td class="bar" id="b3"><img src="../jacoco-resources/redbar.gif" width="40" height="10" title="3" alt="3"/></td><td class="ctr2" id="c3">0%</td><td class="bar" id="d3"/><td class="ctr2" id="e3">n/a</td><td class="ctr1" id="f3">1</td><td class="ctr2" id="g3">1</td><td class="ctr1" id="h3">1</td><td class="ctr2" id="i3">1</td><td class="ctr1" id="j3">1</td><td class="ctr2" id="k3">1</td></tr><tr><td id="a3"><a href="CMSProcessableInputStream.java.html#L62" class="el_method">getContentType()</a></td><td class="bar" id="b4"><img src="../jacoco-resources/redbar.gif" width="40" height="10" title="3" alt="3"/></td><td class="ctr2" id="c4">0%</td><td class="bar" id="d4"/><td class="ctr2" id="e4">n/a</td><td class="ctr1" id="f4">1</td><td class="ctr2" id="g4">1</td><td class="ctr1" id="h4">1</td><td class="ctr2" id="i4">1</td><td class="ctr1" id="j4">1</td><td class="ctr2" id="k4">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CMSProcessableInputStream.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">org.apache.pdfbox.examples.signature</a> &gt; <span class="el_source">CMSProcessableInputStream.java</span></div><h1>CMSProcessableInputStream.java</h1><pre class="source lang-java linenums">/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the &quot;License&quot;); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.examples.signature;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSTypedData;
/**
* Wraps a InputStream into a CMSProcessable object for bouncy castle. It's a memory saving
* alternative to the {@link org.bouncycastle.cms.CMSProcessableByteArray CMSProcessableByteArray}
* class.
*
* @author Thomas Chojecki
*/
class CMSProcessableInputStream implements CMSTypedData {
private final InputStream in;
private final ASN1ObjectIdentifier contentType;
CMSProcessableInputStream(InputStream is) {
<span class="nc" id="L40"> this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), is);</span>
<span class="nc" id="L41"> }</span>
<span class="nc" id="L43"> CMSProcessableInputStream(ASN1ObjectIdentifier type, InputStream is) {</span>
<span class="nc" id="L44"> contentType = type;</span>
<span class="nc" id="L45"> in = is;</span>
<span class="nc" id="L46"> }</span>
@Override
public Object getContent() {
<span class="nc" id="L50"> return in;</span>
}
@Override
public void write(OutputStream out) throws IOException, CMSException {
// read the content only one time
<span class="nc" id="L56"> in.transferTo(out);</span>
<span class="nc" id="L57"> in.close();</span>
<span class="nc" id="L58"> }</span>
@Override
public ASN1ObjectIdentifier getContentType() {
<span class="nc" id="L62"> return contentType;</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CreateSignatureBase.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">org.apache.pdfbox.examples.signature</a> &gt; <span class="el_source">CreateSignatureBase.java</span></div><h1>CreateSignatureBase.java</h1><pre class="source lang-java linenums">/*
* Copyright 2015 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.examples.signature;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Enumeration;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
public abstract class CreateSignatureBase implements SignatureInterface {
private PrivateKey privateKey;
private Certificate[] certificateChain;
private String tsaUrl;
private boolean externalSigning;
/**
* Initialize the signature creator with a keystore (pkcs12) and pin that should be used for the
* signature.
*
* @param keystore is a pkcs12 keystore.
* @param pin is the pin for the keystore / private key
* @throws KeyStoreException if the keystore has not been initialized (loaded)
* @throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found
* @throws UnrecoverableKeyException if the given password is wrong
* @throws CertificateException if the certificate is not valid as signing time
* @throws IOException if no certificate could be found
*/
public CreateSignatureBase(KeyStore keystore, char[] pin)
throws KeyStoreException,
UnrecoverableKeyException,
NoSuchAlgorithmException,
IOException,
<span class="nc" id="L68"> CertificateException {</span>
// grabs the first alias from the keystore and get the private key. An
// alternative method or constructor could be used for setting a specific
// alias that should be used.
<span class="nc" id="L72"> Enumeration&lt;String&gt; aliases = keystore.aliases();</span>
String alias;
<span class="nc" id="L74"> Certificate cert = null;</span>
<span class="nc bnc" id="L75" title="All 4 branches missed."> while (cert == null &amp;&amp; aliases.hasMoreElements()) {</span>
<span class="nc" id="L76"> alias = aliases.nextElement();</span>
<span class="nc" id="L77"> setPrivateKey((PrivateKey) keystore.getKey(alias, pin));</span>
<span class="nc" id="L78"> Certificate[] certChain = keystore.getCertificateChain(alias);</span>
<span class="nc bnc" id="L79" title="All 2 branches missed."> if (certChain != null) {</span>
<span class="nc" id="L80"> setCertificateChain(certChain);</span>
<span class="nc" id="L81"> cert = certChain[0];</span>
<span class="nc bnc" id="L82" title="All 2 branches missed."> if (cert instanceof X509Certificate) {</span>
// avoid expired certificate
<span class="nc" id="L84"> ((X509Certificate) cert).checkValidity();</span>
//// SigUtils.checkCertificateUsage((X509Certificate) cert);
}
}
<span class="nc" id="L89"> }</span>
<span class="nc bnc" id="L91" title="All 2 branches missed."> if (cert == null) {</span>
<span class="nc" id="L92"> throw new IOException(&quot;Could not find certificate&quot;);</span>
}
<span class="nc" id="L94"> }</span>
public final void setPrivateKey(PrivateKey privateKey) {
<span class="nc" id="L97"> this.privateKey = privateKey;</span>
<span class="nc" id="L98"> }</span>
public Certificate[] getCertificateChain() {
<span class="nc" id="L101"> return certificateChain;</span>
}
public final void setCertificateChain(final Certificate[] certificateChain) {
<span class="nc" id="L105"> this.certificateChain = certificateChain;</span>
<span class="nc" id="L106"> }</span>
public void setTsaUrl(String tsaUrl) {
<span class="nc" id="L109"> this.tsaUrl = tsaUrl;</span>
<span class="nc" id="L110"> }</span>
/**
* SignatureInterface sample implementation.
*
* &lt;p&gt;This method will be called from inside of the pdfbox and create the PKCS #7 signature. The
* given InputStream contains the bytes that are given by the byte range.
*
* &lt;p&gt;This method is for internal use only.
*
* &lt;p&gt;Use your favorite cryptographic library to implement PKCS #7 signature creation. If you
* want to create the hash and the signature separately (e.g. to transfer only the hash to an
* external application), read &lt;a href=&quot;https://stackoverflow.com/questions/41767351&quot;&gt;this
* answer&lt;/a&gt; or &lt;a href=&quot;https://stackoverflow.com/questions/56867465&quot;&gt;this answer&lt;/a&gt;.
*
* @throws IOException
*/
@Override
public byte[] sign(InputStream content) throws IOException {
// cannot be done private (interface)
try {
<span class="nc" id="L131"> CMSSignedDataGenerator gen = new CMSSignedDataGenerator();</span>
<span class="nc" id="L132"> X509Certificate cert = (X509Certificate) certificateChain[0];</span>
<span class="nc" id="L133"> ContentSigner sha1Signer =</span>
<span class="nc" id="L134"> new JcaContentSignerBuilder(&quot;SHA256WithRSA&quot;).build(privateKey);</span>
<span class="nc" id="L135"> gen.addSignerInfoGenerator(</span>
new JcaSignerInfoGeneratorBuilder(
<span class="nc" id="L137"> new JcaDigestCalculatorProviderBuilder().build())</span>
<span class="nc" id="L138"> .build(sha1Signer, cert));</span>
<span class="nc" id="L139"> gen.addCertificates(new JcaCertStore(Arrays.asList(certificateChain)));</span>
<span class="nc" id="L140"> CMSProcessableInputStream msg = new CMSProcessableInputStream(content);</span>
<span class="nc" id="L141"> CMSSignedData signedData = gen.generate(msg, false);</span>
<span class="nc bnc" id="L142" title="All 4 branches missed."> if (tsaUrl != null &amp;&amp; !tsaUrl.isEmpty()) {</span>
<span class="nc" id="L143"> ValidationTimeStamp validation = new ValidationTimeStamp(tsaUrl);</span>
<span class="nc" id="L144"> signedData = validation.addSignedTimeStamp(signedData);</span>
}
<span class="nc" id="L146"> return signedData.getEncoded();</span>
<span class="nc" id="L147"> } catch (GeneralSecurityException</span>
| CMSException
| OperatorCreationException
| URISyntaxException e) {
<span class="nc" id="L151"> throw new IOException(e);</span>
}
}
public boolean isExternalSigning() {
<span class="nc" id="L156"> return externalSigning;</span>
}
/**
* Set if external signing scenario should be used. If {@code false}, SignatureInterface would
* be used for signing.
*
* &lt;p&gt;Default: {@code false}
*
* @param externalSigning {@code true} if external signing should be performed
*/
public void setExternalSigning(boolean externalSigning) {
<span class="nc" id="L168"> this.externalSigning = externalSigning;</span>
<span class="nc" id="L169"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>TSAClient</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">org.apache.pdfbox.examples.signature</a> &gt; <span class="el_class">TSAClient</span></div><h1>TSAClient</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">208 of 208</td><td class="ctr2">0%</td><td class="bar">14 of 14</td><td class="ctr2">0%</td><td class="ctr1">11</td><td class="ctr2">11</td><td class="ctr1">59</td><td class="ctr2">59</td><td class="ctr1">4</td><td class="ctr2">4</td></tr></tfoot><tbody><tr><td id="a1"><a href="TSAClient.java.html#L127" class="el_method">getTSAResponse(byte[])</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="98" alt="98"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="10" alt="10"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">6</td><td class="ctr2" id="g0">6</td><td class="ctr1" id="h0">29</td><td class="ctr2" id="i0">29</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a0"><a href="TSAClient.java.html#L81" class="el_method">getTimeStampToken(InputStream)</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="101" height="10" title="83" alt="83"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"><img src="../jacoco-resources/redbar.gif" width="48" height="10" title="4" alt="4"/></td><td class="ctr2" id="e1">0%</td><td class="ctr1" id="f1">3</td><td class="ctr2" id="g1">3</td><td class="ctr1" id="h1">21</td><td class="ctr2" id="i1">21</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a3"><a href="TSAClient.java.html#L67" class="el_method">TSAClient(URL, String, String, MessageDigest)</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="18" height="10" title="15" alt="15"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">1</td><td class="ctr2" id="g2">1</td><td class="ctr1" id="h2">6</td><td class="ctr2" id="i2">6</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr><tr><td id="a2"><a href="TSAClient.java.html#L50" class="el_method">static {...}</a></td><td class="bar" id="b3"><img src="../jacoco-resources/redbar.gif" width="14" height="10" title="12" alt="12"/></td><td class="ctr2" id="c3">0%</td><td class="bar" id="d3"/><td class="ctr2" id="e3">n/a</td><td class="ctr1" id="f3">1</td><td class="ctr2" id="g3">1</td><td class="ctr1" id="h3">3</td><td class="ctr2" id="i3">3</td><td class="ctr1" id="j3">1</td><td class="ctr2" id="k3">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>TSAClient.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">org.apache.pdfbox.examples.signature</a> &gt; <span class="el_source">TSAClient.java</span></div><h1>TSAClient.java</h1><pre class="source lang-java linenums">/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the &quot;License&quot;); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.examples.signature;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Random;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder;
import org.bouncycastle.tsp.TSPException;
import org.bouncycastle.tsp.TimeStampRequest;
import org.bouncycastle.tsp.TimeStampRequestGenerator;
import org.bouncycastle.tsp.TimeStampResponse;
import org.bouncycastle.tsp.TimeStampToken;
/**
* Time Stamping Authority (TSA) Client [RFC 3161].
*
* @author Vakhtang Koroghlishvili
* @author John Hewson
*/
public class TSAClient {
<span class="nc" id="L50"> private static final Logger LOG = LogManager.getLogger(TSAClient.class);</span>
<span class="nc" id="L52"> private static final DigestAlgorithmIdentifierFinder ALGORITHM_OID_FINDER =</span>
new DefaultDigestAlgorithmIdentifierFinder();
// SecureRandom.getInstanceStrong() would be better, but sometimes blocks on Linux
<span class="nc" id="L55"> private static final Random RANDOM = new SecureRandom();</span>
private final URL url;
private final String username;
private final String password;
private final MessageDigest digest;
/**
* @param url the URL of the TSA service
* @param username user name of TSA
* @param password password of TSA
* @param digest the message digest to use
*/
<span class="nc" id="L67"> public TSAClient(URL url, String username, String password, MessageDigest digest) {</span>
<span class="nc" id="L68"> this.url = url;</span>
<span class="nc" id="L69"> this.username = username;</span>
<span class="nc" id="L70"> this.password = password;</span>
<span class="nc" id="L71"> this.digest = digest;</span>
<span class="nc" id="L72"> }</span>
/**
* @param content
* @return the time stamp token
* @throws IOException if there was an error with the connection or data from the TSA server, or
* if the time stamp response could not be validated
*/
public TimeStampToken getTimeStampToken(InputStream content) throws IOException {
<span class="nc" id="L81"> digest.reset();</span>
<span class="nc" id="L82"> DigestInputStream dis = new DigestInputStream(content, digest);</span>
<span class="nc bnc" id="L83" title="All 2 branches missed."> while (dis.read() != -1) {</span>
// do nothing
}
<span class="nc" id="L86"> byte[] hash = digest.digest();</span>
// 32-bit cryptographic nonce
<span class="nc" id="L89"> int nonce = RANDOM.nextInt();</span>
// generate TSA request
<span class="nc" id="L92"> TimeStampRequestGenerator tsaGenerator = new TimeStampRequestGenerator();</span>
<span class="nc" id="L93"> tsaGenerator.setCertReq(true);</span>
<span class="nc" id="L94"> ASN1ObjectIdentifier oid = ALGORITHM_OID_FINDER.find(digest.getAlgorithm()).getAlgorithm();</span>
<span class="nc" id="L95"> TimeStampRequest request = tsaGenerator.generate(oid, hash, BigInteger.valueOf(nonce));</span>
// get TSA response
<span class="nc" id="L98"> byte[] tsaResponse = getTSAResponse(request.getEncoded());</span>
TimeStampResponse response;
try {
<span class="nc" id="L102"> response = new TimeStampResponse(tsaResponse);</span>
<span class="nc" id="L103"> response.validate(request);</span>
<span class="nc" id="L104"> } catch (TSPException e) {</span>
<span class="nc" id="L105"> throw new IOException(e);</span>
<span class="nc" id="L106"> }</span>
<span class="nc" id="L108"> TimeStampToken timeStampToken = response.getTimeStampToken();</span>
<span class="nc bnc" id="L109" title="All 2 branches missed."> if (timeStampToken == null) {</span>
// https://www.ietf.org/rfc/rfc3161.html#section-2.4.2
<span class="nc" id="L111"> throw new IOException(</span>
&quot;Response from &quot;
+ url
+ &quot; does not have a time stamp token, status: &quot;
<span class="nc" id="L115"> + response.getStatus()</span>
+ &quot; (&quot;
<span class="nc" id="L117"> + response.getStatusString()</span>
+ &quot;)&quot;);
}
<span class="nc" id="L121"> return timeStampToken;</span>
}
// gets response data for the given encoded TimeStampRequest data
// throws IOException if a connection to the TSA cannot be established
private byte[] getTSAResponse(byte[] request) throws IOException {
<span class="nc" id="L127"> LOG.debug(&quot;Opening connection to TSA server&quot;);</span>
// todo: support proxy servers
<span class="nc" id="L130"> URLConnection connection = url.openConnection();</span>
<span class="nc" id="L131"> connection.setDoOutput(true);</span>
<span class="nc" id="L132"> connection.setDoInput(true);</span>
<span class="nc" id="L133"> connection.setRequestProperty(&quot;Content-Type&quot;, &quot;application/timestamp-query&quot;);</span>
<span class="nc" id="L135"> LOG.debug(&quot;Established connection to TSA server&quot;);</span>
<span class="nc bnc" id="L137" title="All 8 branches missed."> if (username != null &amp;&amp; password != null &amp;&amp; !username.isEmpty() &amp;&amp; !password.isEmpty()) {</span>
<span class="nc" id="L138"> String contentEncoding = connection.getContentEncoding();</span>
<span class="nc bnc" id="L139" title="All 2 branches missed."> if (contentEncoding == null) {</span>
<span class="nc" id="L140"> contentEncoding = StandardCharsets.UTF_8.name();</span>
}
<span class="nc" id="L142"> connection.setRequestProperty(</span>
&quot;Authorization&quot;,
&quot;Basic &quot;
+ new String(
<span class="nc" id="L146"> Base64.getEncoder()</span>
<span class="nc" id="L147"> .encode(</span>
(username + &quot;:&quot; + password)
<span class="nc" id="L149"> .getBytes(contentEncoding))));</span>
}
// read response
<span class="nc" id="L153"> try (OutputStream output = connection.getOutputStream()) {</span>
<span class="nc" id="L154"> output.write(request);</span>
<span class="nc" id="L155"> } catch (IOException ex) {</span>
<span class="nc" id="L156"> LOG.error(&quot;Exception when writing to {}&quot;, this.url, ex);</span>
<span class="nc" id="L157"> throw ex;</span>
<span class="nc" id="L158"> }</span>
<span class="nc" id="L160"> LOG.debug(&quot;Waiting for response from TSA server&quot;);</span>
byte[] response;
<span class="nc" id="L163"> try (InputStream input = connection.getInputStream()) {</span>
<span class="nc" id="L164"> response = input.readAllBytes();</span>
<span class="nc" id="L165"> } catch (IOException ex) {</span>
<span class="nc" id="L166"> LOG.error(&quot;Exception when reading from {}&quot;, this.url, ex);</span>
<span class="nc" id="L167"> throw ex;</span>
<span class="nc" id="L168"> }</span>
<span class="nc" id="L170"> LOG.debug(&quot;Received response from TSA server&quot;);</span>
<span class="nc" id="L172"> return response;</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>ValidationTimeStamp</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">org.apache.pdfbox.examples.signature</a> &gt; <span class="el_class">ValidationTimeStamp</span></div><h1>ValidationTimeStamp</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">112 of 112</td><td class="ctr2">0%</td><td class="bar">6 of 6</td><td class="ctr2">0%</td><td class="ctr1">7</td><td class="ctr2">7</td><td class="ctr1">26</td><td class="ctr2">26</td><td class="ctr1">4</td><td class="ctr2">4</td></tr></tfoot><tbody><tr><td id="a2"><a href="ValidationTimeStamp.java.html#L111" class="el_method">signTimeStamp(SignerInformation)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="51" alt="51"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="2" alt="2"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">2</td><td class="ctr2" id="g0">2</td><td class="ctr1" id="h0">13</td><td class="ctr2" id="i0">13</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a0"><a href="ValidationTimeStamp.java.html#L89" class="el_method">addSignedTimeStamp(CMSSignedData)</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="75" height="10" title="32" alt="32"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="2" alt="2"/></td><td class="ctr2" id="e1">0%</td><td class="ctr1" id="f1">2</td><td class="ctr2" id="g1">2</td><td class="ctr1" id="h1">6</td><td class="ctr2" id="i1">6</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a3"><a href="ValidationTimeStamp.java.html#L62" class="el_method">ValidationTimeStamp(String)</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="49" height="10" title="21" alt="21"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="2" alt="2"/></td><td class="ctr2" id="e2">0%</td><td class="ctr1" id="f2">2</td><td class="ctr2" id="g2">2</td><td class="ctr1" id="h2">5</td><td class="ctr2" id="i2">5</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr><tr><td id="a1"><a href="ValidationTimeStamp.java.html#L77" class="el_method">getTimeStampToken(InputStream)</a></td><td class="bar" id="b3"><img src="../jacoco-resources/redbar.gif" width="18" height="10" title="8" alt="8"/></td><td class="ctr2" id="c3">0%</td><td class="bar" id="d3"/><td class="ctr2" id="e3">n/a</td><td class="ctr1" id="f3">1</td><td class="ctr2" id="g3">1</td><td class="ctr1" id="h3">2</td><td class="ctr2" id="i3">2</td><td class="ctr1" id="j3">1</td><td class="ctr2" id="k3">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>ValidationTimeStamp.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">org.apache.pdfbox.examples.signature</a> &gt; <span class="el_source">ValidationTimeStamp.java</span></div><h1>ValidationTimeStamp.java</h1><pre class="source lang-java linenums">/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the &quot;License&quot;); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.examples.signature;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.Attributes;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.tsp.TimeStampToken;
/**
* This class wraps the TSAClient and the work that has to be done with it. Like Adding Signed
* TimeStamps to a signature, or creating a CMS timestamp attribute (with a signed timestamp)
*
* @author Others
* @author Alexis Suter
*/
public class ValidationTimeStamp {
private TSAClient tsaClient;
/**
* @param tsaUrl The url where TS-Request will be done.
* @throws NoSuchAlgorithmException
* @throws MalformedURLException
* @throws java.net.URISyntaxException
*/
public ValidationTimeStamp(String tsaUrl)
<span class="nc" id="L62"> throws NoSuchAlgorithmException, MalformedURLException, URISyntaxException {</span>
<span class="nc bnc" id="L63" title="All 2 branches missed."> if (tsaUrl != null) {</span>
<span class="nc" id="L64"> MessageDigest digest = MessageDigest.getInstance(&quot;SHA-256&quot;);</span>
<span class="nc" id="L65"> this.tsaClient = new TSAClient(new URI(tsaUrl).toURL(), null, null, digest);</span>
}
<span class="nc" id="L67"> }</span>
/**
* Creates a signed timestamp token by the given input stream.
*
* @param content InputStream of the content to sign
* @return the byte[] of the timestamp token
* @throws IOException
*/
public byte[] getTimeStampToken(InputStream content) throws IOException {
<span class="nc" id="L77"> TimeStampToken timeStampToken = tsaClient.getTimeStampToken(content);</span>
<span class="nc" id="L78"> return timeStampToken.getEncoded();</span>
}
/**
* Extend cms signed data with TimeStamp first or to all signers
*
* @param signedData Generated CMS signed data
* @return CMSSignedData Extended CMS signed data
* @throws IOException
*/
public CMSSignedData addSignedTimeStamp(CMSSignedData signedData) throws IOException {
<span class="nc" id="L89"> SignerInformationStore signerStore = signedData.getSignerInfos();</span>
<span class="nc" id="L90"> List&lt;SignerInformation&gt; newSigners = new ArrayList&lt;&gt;();</span>
<span class="nc bnc" id="L92" title="All 2 branches missed."> for (SignerInformation signer : signerStore.getSigners()) {</span>
// This adds a timestamp to every signer (into his unsigned attributes) in the
// signature.
<span class="nc" id="L95"> newSigners.add(signTimeStamp(signer));</span>
<span class="nc" id="L96"> }</span>
// Because new SignerInformation is created, new SignerInfoStore has to be created
// and also be replaced in signedData. Which creates a new signedData object.
<span class="nc" id="L100"> return CMSSignedData.replaceSigners(signedData, new SignerInformationStore(newSigners));</span>
}
/**
* Extend CMS Signer Information with the TimeStampToken into the unsigned Attributes.
*
* @param signer information about signer
* @return information about SignerInformation
* @throws IOException
*/
private SignerInformation signTimeStamp(SignerInformation signer) throws IOException {
<span class="nc" id="L111"> AttributeTable unsignedAttributes = signer.getUnsignedAttributes();</span>
<span class="nc" id="L113"> ASN1EncodableVector vector = new ASN1EncodableVector();</span>
<span class="nc bnc" id="L114" title="All 2 branches missed."> if (unsignedAttributes != null) {</span>
<span class="nc" id="L115"> vector = unsignedAttributes.toASN1EncodableVector();</span>
}
<span class="nc" id="L118"> TimeStampToken timeStampToken =</span>
<span class="nc" id="L119"> tsaClient.getTimeStampToken(new ByteArrayInputStream(signer.getSignature()));</span>
<span class="nc" id="L120"> byte[] token = timeStampToken.getEncoded();</span>
<span class="nc" id="L121"> ASN1ObjectIdentifier oid = PKCSObjectIdentifiers.id_aa_signatureTimeStampToken;</span>
<span class="nc" id="L122"> ASN1Encodable signatureTimeStamp =</span>
<span class="nc" id="L123"> new Attribute(oid, new DERSet(ASN1Primitive.fromByteArray(token)));</span>
<span class="nc" id="L125"> vector.add(signatureTimeStamp);</span>
<span class="nc" id="L126"> Attributes signedAttributes = new Attributes(vector);</span>
// There is no other way changing the unsigned attributes of the signer information.
// result is never null, new SignerInformation always returned,
// see source code of replaceUnsignedAttributes
<span class="nc" id="L131"> return SignerInformation.replaceUnsignedAttributes(</span>
signer, new AttributeTable(signedAttributes));
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>ConnectedInputStream.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">org.apache.pdfbox.examples.util</a> &gt; <span class="el_source">ConnectedInputStream.java</span></div><h1>ConnectedInputStream.java</h1><pre class="source lang-java linenums">/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the &quot;License&quot;); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.examples.util;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
/**
* Delegate class to close the connection when the class gets closed.
*
* @author Tilman Hausherr
*/
public class ConnectedInputStream extends InputStream {
HttpURLConnection con;
InputStream is;
<span class="nc" id="L32"> public ConnectedInputStream(HttpURLConnection con, InputStream is) {</span>
<span class="nc" id="L33"> this.con = con;</span>
<span class="nc" id="L34"> this.is = is;</span>
<span class="nc" id="L35"> }</span>
@Override
public int read() throws IOException {
<span class="nc" id="L39"> return is.read();</span>
}
@Override
public int read(byte[] b) throws IOException {
<span class="nc" id="L44"> return is.read(b);</span>
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
<span class="nc" id="L49"> return is.read(b, off, len);</span>
}
@Override
public long skip(long n) throws IOException {
<span class="nc" id="L54"> return is.skip(n);</span>
}
@Override
public int available() throws IOException {
<span class="nc" id="L59"> return is.available();</span>
}
@Override
public synchronized void mark(int readlimit) {
<span class="nc" id="L64"> is.mark(readlimit);</span>
<span class="nc" id="L65"> }</span>
@Override
public synchronized void reset() throws IOException {
<span class="nc" id="L69"> is.reset();</span>
<span class="nc" id="L70"> }</span>
@Override
public boolean markSupported() {
<span class="nc" id="L74"> return is.markSupported();</span>
}
@Override
public void close() throws IOException {
<span class="nc" id="L79"> is.close();</span>
<span class="nc" id="L80"> con.disconnect();</span>
<span class="nc" id="L81"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DeletingRandomAccessFile</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">org.apache.pdfbox.examples.util</a> &gt; <span class="el_class">DeletingRandomAccessFile</span></div><h1>DeletingRandomAccessFile</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">40 of 40</td><td class="ctr2">0%</td><td class="bar">2 of 2</td><td class="ctr2">0%</td><td class="ctr1">4</td><td class="ctr2">4</td><td class="ctr1">13</td><td class="ctr2">13</td><td class="ctr1">3</td><td class="ctr2">3</td></tr></tfoot><tbody><tr><td id="a0"><a href="DeletingRandomAccessFile.java.html#L25" class="el_method">close()</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="28" alt="28"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="2" alt="2"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">2</td><td class="ctr2" id="g0">2</td><td class="ctr1" id="h0">9</td><td class="ctr2" id="i0">9</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a1"><a href="DeletingRandomAccessFile.java.html#L18" class="el_method">DeletingRandomAccessFile(File)</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="34" height="10" title="8" alt="8"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">3</td><td class="ctr2" id="i1">3</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a2"><a href="DeletingRandomAccessFile.java.html#L13" class="el_method">static {...}</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="17" height="10" title="4" alt="4"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">1</td><td class="ctr2" id="g2">1</td><td class="ctr1" id="h2">1</td><td class="ctr2" id="i2">1</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DeletingRandomAccessFile.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">org.apache.pdfbox.examples.util</a> &gt; <span class="el_source">DeletingRandomAccessFile.java</span></div><h1>DeletingRandomAccessFile.java</h1><pre class="source lang-java linenums">package org.apache.pdfbox.examples.util;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
import lombok.extern.slf4j.Slf4j;
/** A custom RandomAccessRead implementation that deletes the file when closed */
<span class="nc" id="L13">@Slf4j</span>
public class DeletingRandomAccessFile extends RandomAccessReadBufferedFile {
private final Path tempFilePath;
public DeletingRandomAccessFile(File file) throws IOException {
<span class="nc" id="L18"> super(file);</span>
<span class="nc" id="L19"> this.tempFilePath = file.toPath();</span>
<span class="nc" id="L20"> }</span>
@Override
public void close() throws IOException {
try {
<span class="nc" id="L25"> super.close();</span>
} finally {
try {
<span class="nc" id="L28"> boolean deleted = Files.deleteIfExists(tempFilePath);</span>
<span class="nc bnc" id="L29" title="All 2 branches missed."> if (deleted) {</span>
<span class="nc" id="L30"> log.info(&quot;Successfully deleted temp file: {}&quot;, tempFilePath);</span>
} else {
<span class="nc" id="L32"> log.warn(&quot;Failed to delete temp file (may not exist): {}&quot;, tempFilePath);</span>
}
<span class="nc" id="L34"> } catch (IOException e) {</span>
<span class="nc" id="L35"> log.error(&quot;Error deleting temp file: {}&quot;, tempFilePath, e);</span>
<span class="nc" id="L36"> }</span>
}
<span class="nc" id="L38"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>org.apache.pdfbox.examples.util</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb', 'coveragetable'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="index.source.html" class="el_source">Source Files</a><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <span class="el_package">org.apache.pdfbox.examples.util</span></div><h1>org.apache.pdfbox.examples.util</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td><td class="sortable ctr1" id="l" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="m" onclick="toggleSort(this)">Classes</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">94 of 94</td><td class="ctr2">0%</td><td class="bar">2 of 2</td><td class="ctr2">0%</td><td class="ctr1">14</td><td class="ctr2">14</td><td class="ctr1">30</td><td class="ctr2">30</td><td class="ctr1">13</td><td class="ctr2">13</td><td class="ctr1">2</td><td class="ctr2">2</td></tr></tfoot><tbody><tr><td id="a0"><a href="ConnectedInputStream.html" class="el_class">ConnectedInputStream</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="54" alt="54"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f0">10</td><td class="ctr2" id="g0">10</td><td class="ctr1" id="h0">17</td><td class="ctr2" id="i0">17</td><td class="ctr1" id="j0">10</td><td class="ctr2" id="k0">10</td><td class="ctr1" id="l0">1</td><td class="ctr2" id="m0">1</td></tr><tr><td id="a1"><a href="DeletingRandomAccessFile.html" class="el_class">DeletingRandomAccessFile</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="88" height="10" title="40" alt="40"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="2" alt="2"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f1">4</td><td class="ctr2" id="g1">4</td><td class="ctr1" id="h1">13</td><td class="ctr2" id="i1">13</td><td class="ctr1" id="j1">3</td><td class="ctr2" id="k1">3</td><td class="ctr1" id="l1">1</td><td class="ctr2" id="m1">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>org.apache.pdfbox.examples.util</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb', 'coveragetable'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="index.html" class="el_class">Classes</a><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <span class="el_package">org.apache.pdfbox.examples.util</span></div><h1>org.apache.pdfbox.examples.util</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td><td class="sortable ctr1" id="l" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="m" onclick="toggleSort(this)">Classes</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">94 of 94</td><td class="ctr2">0%</td><td class="bar">2 of 2</td><td class="ctr2">0%</td><td class="ctr1">14</td><td class="ctr2">14</td><td class="ctr1">30</td><td class="ctr2">30</td><td class="ctr1">13</td><td class="ctr2">13</td><td class="ctr1">2</td><td class="ctr2">2</td></tr></tfoot><tbody><tr><td id="a0"><a href="ConnectedInputStream.java.html" class="el_source">ConnectedInputStream.java</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="54" alt="54"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f0">10</td><td class="ctr2" id="g0">10</td><td class="ctr1" id="h0">17</td><td class="ctr2" id="i0">17</td><td class="ctr1" id="j0">10</td><td class="ctr2" id="k0">10</td><td class="ctr1" id="l0">1</td><td class="ctr2" id="m0">1</td></tr><tr><td id="a1"><a href="DeletingRandomAccessFile.java.html" class="el_source">DeletingRandomAccessFile.java</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="88" height="10" title="40" alt="40"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="2" alt="2"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f1">4</td><td class="ctr2" id="g1">4</td><td class="ctr1" id="h1">13</td><td class="ctr2" id="i1">13</td><td class="ctr1" id="j1">3</td><td class="ctr2" id="k1">3</td><td class="ctr1" id="l1">1</td><td class="ctr2" id="m1">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>EEAppConfig.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.EE</a> &gt; <span class="el_source">EEAppConfig.java</span></div><h1>EEAppConfig.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.EE;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.EnterpriseEdition;
import stirling.software.SPDF.model.ApplicationProperties.Premium;
import stirling.software.SPDF.model.ApplicationProperties.Premium.ProFeatures.GoogleDrive;
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
<span class="nc" id="L18">@Slf4j</span>
public class EEAppConfig {
private final ApplicationProperties applicationProperties;
private final LicenseKeyChecker licenseKeyChecker;
public EEAppConfig(
<span class="nc" id="L26"> ApplicationProperties applicationProperties, LicenseKeyChecker licenseKeyChecker) {</span>
<span class="nc" id="L27"> this.applicationProperties = applicationProperties;</span>
<span class="nc" id="L28"> this.licenseKeyChecker = licenseKeyChecker;</span>
<span class="nc" id="L29"> migrateEnterpriseSettingsToPremium(this.applicationProperties);</span>
<span class="nc" id="L30"> }</span>
@Bean(name = &quot;runningProOrHigher&quot;)
public boolean runningProOrHigher() {
<span class="nc bnc" id="L34" title="All 2 branches missed."> return licenseKeyChecker.getPremiumLicenseEnabledResult() != License.NORMAL;</span>
}
@Bean(name = &quot;runningEE&quot;)
public boolean runningEnterprise() {
<span class="nc bnc" id="L39" title="All 2 branches missed."> return licenseKeyChecker.getPremiumLicenseEnabledResult() == License.ENTERPRISE;</span>
}
@Bean(name = &quot;SSOAutoLogin&quot;)
public boolean ssoAutoLogin() {
<span class="nc" id="L44"> return applicationProperties.getPremium().getProFeatures().isSsoAutoLogin();</span>
}
@Bean(name = &quot;GoogleDriveEnabled&quot;)
public boolean googleDriveEnabled() {
<span class="nc bnc" id="L49" title="All 2 branches missed."> return runningProOrHigher()</span>
<span class="nc bnc" id="L50" title="All 2 branches missed."> &amp;&amp; applicationProperties.getPremium().getProFeatures().getGoogleDrive().isEnabled();</span>
}
@Bean(name = &quot;GoogleDriveConfig&quot;)
public GoogleDrive googleDriveConfig() {
<span class="nc" id="L55"> return applicationProperties.getPremium().getProFeatures().getGoogleDrive();</span>
}
// TODO: Remove post migration
public void migrateEnterpriseSettingsToPremium(ApplicationProperties applicationProperties) {
<span class="nc" id="L60"> EnterpriseEdition enterpriseEdition = applicationProperties.getEnterpriseEdition();</span>
<span class="nc" id="L61"> Premium premium = applicationProperties.getPremium();</span>
// Only proceed if both objects exist
<span class="nc bnc" id="L64" title="All 4 branches missed."> if (enterpriseEdition == null || premium == null) {</span>
<span class="nc" id="L65"> return;</span>
}
// Copy the license key if it's set in enterprise but not in premium
<span class="nc bnc" id="L69" title="All 2 branches missed."> if (premium.getKey() == null</span>
<span class="nc bnc" id="L70" title="All 2 branches missed."> || premium.getKey().equals(&quot;00000000-0000-0000-0000-000000000000&quot;)) {</span>
<span class="nc bnc" id="L71" title="All 2 branches missed."> if (enterpriseEdition.getKey() != null</span>
<span class="nc bnc" id="L72" title="All 2 branches missed."> &amp;&amp; !enterpriseEdition.getKey().equals(&quot;00000000-0000-0000-0000-000000000000&quot;)) {</span>
<span class="nc" id="L73"> premium.setKey(enterpriseEdition.getKey());</span>
}
}
// Copy enabled state if enterprise is enabled but premium is not
<span class="nc bnc" id="L78" title="All 4 branches missed."> if (!premium.isEnabled() &amp;&amp; enterpriseEdition.isEnabled()) {</span>
<span class="nc" id="L79"> premium.setEnabled(true);</span>
}
// Copy SSO auto login setting
<span class="nc bnc" id="L83" title="All 4 branches missed."> if (!premium.getProFeatures().isSsoAutoLogin() &amp;&amp; enterpriseEdition.isSsoAutoLogin()) {</span>
<span class="nc" id="L84"> premium.getProFeatures().setSsoAutoLogin(true);</span>
}
// Copy CustomMetadata settings
<span class="nc" id="L88"> Premium.ProFeatures.CustomMetadata premiumMetadata =</span>
<span class="nc" id="L89"> premium.getProFeatures().getCustomMetadata();</span>
<span class="nc" id="L90"> EnterpriseEdition.CustomMetadata enterpriseMetadata = enterpriseEdition.getCustomMetadata();</span>
<span class="nc bnc" id="L92" title="All 4 branches missed."> if (enterpriseMetadata != null &amp;&amp; premiumMetadata != null) {</span>
// Copy autoUpdateMetadata setting
<span class="nc bnc" id="L94" title="All 2 branches missed."> if (!premiumMetadata.isAutoUpdateMetadata()</span>
<span class="nc bnc" id="L95" title="All 2 branches missed."> &amp;&amp; enterpriseMetadata.isAutoUpdateMetadata()) {</span>
<span class="nc" id="L96"> premiumMetadata.setAutoUpdateMetadata(true);</span>
}
// Copy author if not set in premium but set in enterprise
<span class="nc bnc" id="L100" title="All 2 branches missed."> if ((premiumMetadata.getAuthor() == null</span>
<span class="nc bnc" id="L101" title="All 2 branches missed."> || premiumMetadata.getAuthor().trim().isEmpty()</span>
<span class="nc bnc" id="L102" title="All 2 branches missed."> || &quot;username&quot;.equals(premiumMetadata.getAuthor()))</span>
<span class="nc bnc" id="L103" title="All 2 branches missed."> &amp;&amp; enterpriseMetadata.getAuthor() != null</span>
<span class="nc bnc" id="L104" title="All 2 branches missed."> &amp;&amp; !enterpriseMetadata.getAuthor().trim().isEmpty()) {</span>
<span class="nc" id="L105"> premiumMetadata.setAuthor(enterpriseMetadata.getAuthor());</span>
}
// Copy creator if not set in premium but set in enterprise and different from default
<span class="nc bnc" id="L109" title="All 2 branches missed."> if ((premiumMetadata.getCreator() == null</span>
<span class="nc bnc" id="L110" title="All 2 branches missed."> || &quot;Stirling-PDF&quot;.equals(premiumMetadata.getCreator()))</span>
<span class="nc bnc" id="L111" title="All 2 branches missed."> &amp;&amp; enterpriseMetadata.getCreator() != null</span>
<span class="nc bnc" id="L112" title="All 2 branches missed."> &amp;&amp; !&quot;Stirling-PDF&quot;.equals(enterpriseMetadata.getCreator())) {</span>
<span class="nc" id="L113"> premiumMetadata.setCreator(enterpriseMetadata.getCreator());</span>
}
// Copy producer if not set in premium but set in enterprise and different from default
<span class="nc bnc" id="L117" title="All 2 branches missed."> if ((premiumMetadata.getProducer() == null</span>
<span class="nc bnc" id="L118" title="All 2 branches missed."> || &quot;Stirling-PDF&quot;.equals(premiumMetadata.getProducer()))</span>
<span class="nc bnc" id="L119" title="All 2 branches missed."> &amp;&amp; enterpriseMetadata.getProducer() != null</span>
<span class="nc bnc" id="L120" title="All 2 branches missed."> &amp;&amp; !&quot;Stirling-PDF&quot;.equals(enterpriseMetadata.getProducer())) {</span>
<span class="nc" id="L121"> premiumMetadata.setProducer(enterpriseMetadata.getProducer());</span>
}
}
<span class="nc" id="L124"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>KeygenLicenseVerifier.License</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.EE</a> &gt; <span class="el_class">KeygenLicenseVerifier.License</span></div><h1>KeygenLicenseVerifier.License</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">21 of 21</td><td class="ctr2">0%</td><td class="bar">0 of 0</td><td class="ctr2">n/a</td><td class="ctr1">1</td><td class="ctr2">1</td><td class="ctr1">4</td><td class="ctr2">4</td><td class="ctr1">1</td><td class="ctr2">1</td></tr></tfoot><tbody><tr><td id="a0"><a href="KeygenLicenseVerifier.java.html#L29" class="el_method">static {...}</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="21" alt="21"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"/><td class="ctr2" id="e0">n/a</td><td class="ctr1" id="f0">1</td><td class="ctr2" id="g0">1</td><td class="ctr1" id="h0">4</td><td class="ctr2" id="i0">4</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,582 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>KeygenLicenseVerifier.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.EE</a> &gt; <span class="el_source">KeygenLicenseVerifier.java</span></div><h1>KeygenLicenseVerifier.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.EE;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Base64;
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
import org.bouncycastle.crypto.signers.Ed25519Signer;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.posthog.java.shaded.org.json.JSONException;
import com.posthog.java.shaded.org.json.JSONObject;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.utils.GeneralUtils;
@Service
<span class="nc" id="L26">@Slf4j</span>
public class KeygenLicenseVerifier {
<span class="nc" id="L29"> enum License {</span>
<span class="nc" id="L30"> NORMAL,</span>
<span class="nc" id="L31"> PRO,</span>
<span class="nc" id="L32"> ENTERPRISE</span>
}
// License verification configuration
private static final String ACCOUNT_ID = &quot;e5430f69-e834-4ae4-befd-b602aae5f372&quot;;
private static final String BASE_URL = &quot;https://api.keygen.sh/v1/accounts&quot;;
private static final String PUBLIC_KEY =
&quot;9fbc0d78593dcfcf03c945146edd60083bf5fae77dbc08aaa3935f03ce94a58d&quot;;
private static final String CERT_PREFIX = &quot;-----BEGIN LICENSE FILE-----&quot;;
private static final String CERT_SUFFIX = &quot;-----END LICENSE FILE-----&quot;;
private static final String JWT_PREFIX = &quot;key/&quot;;
<span class="nc" id="L47"> private static final ObjectMapper objectMapper = new ObjectMapper();</span>
private final ApplicationProperties applicationProperties;
@Autowired
<span class="nc" id="L51"> public KeygenLicenseVerifier(ApplicationProperties applicationProperties) {</span>
<span class="nc" id="L52"> this.applicationProperties = applicationProperties;</span>
<span class="nc" id="L53"> }</span>
public License verifyLicense(String licenseKeyOrCert) {
<span class="nc bnc" id="L56" title="All 2 branches missed."> if (isCertificateLicense(licenseKeyOrCert)) {</span>
<span class="nc" id="L57"> log.info(&quot;Detected certificate-based license. Processing...&quot;);</span>
<span class="nc" id="L58"> return resultToEnum(verifyCertificateLicense(licenseKeyOrCert), License.ENTERPRISE);</span>
<span class="nc bnc" id="L59" title="All 2 branches missed."> } else if (isJWTLicense(licenseKeyOrCert)) {</span>
<span class="nc" id="L60"> log.info(&quot;Detected JWT-style license key. Processing...&quot;);</span>
<span class="nc" id="L61"> return resultToEnum(verifyJWTLicense(licenseKeyOrCert), License.ENTERPRISE);</span>
} else {
<span class="nc" id="L63"> log.info(&quot;Detected standard license key. Processing...&quot;);</span>
<span class="nc" id="L64"> return resultToEnum(verifyStandardLicense(licenseKeyOrCert), License.PRO);</span>
}
}
private License resultToEnum(boolean result, License option) {
<span class="nc bnc" id="L69" title="All 2 branches missed."> if (result) {</span>
<span class="nc" id="L70"> return option;</span>
}
<span class="nc" id="L72"> return License.NORMAL;</span>
}
private boolean isCertificateLicense(String license) {
<span class="nc bnc" id="L76" title="All 4 branches missed."> return license != null &amp;&amp; license.trim().startsWith(CERT_PREFIX);</span>
}
private boolean isJWTLicense(String license) {
<span class="nc bnc" id="L80" title="All 4 branches missed."> return license != null &amp;&amp; license.trim().startsWith(JWT_PREFIX);</span>
}
private boolean verifyCertificateLicense(String licenseFile) {
try {
<span class="nc" id="L85"> log.info(&quot;Verifying certificate-based license&quot;);</span>
<span class="nc" id="L87"> String encodedPayload = licenseFile;</span>
// Remove the header
<span class="nc" id="L89"> encodedPayload = encodedPayload.replace(CERT_PREFIX, &quot;&quot;);</span>
// Remove the footer
<span class="nc" id="L91"> encodedPayload = encodedPayload.replace(CERT_SUFFIX, &quot;&quot;);</span>
// Remove all newlines
<span class="nc" id="L93"> encodedPayload = encodedPayload.replaceAll(&quot;\\r?\\n&quot;, &quot;&quot;);</span>
<span class="nc" id="L95"> byte[] payloadBytes = Base64.getDecoder().decode(encodedPayload);</span>
<span class="nc" id="L96"> String payload = new String(payloadBytes);</span>
<span class="nc" id="L98"> log.info(&quot;Decoded certificate payload: {}&quot;, payload);</span>
<span class="nc" id="L100"> String encryptedData = &quot;&quot;;</span>
<span class="nc" id="L101"> String encodedSignature = &quot;&quot;;</span>
<span class="nc" id="L102"> String algorithm = &quot;&quot;;</span>
try {
<span class="nc" id="L105"> JSONObject attrs = new JSONObject(payload);</span>
<span class="nc" id="L106"> encryptedData = (String) attrs.get(&quot;enc&quot;);</span>
<span class="nc" id="L107"> encodedSignature = (String) attrs.get(&quot;sig&quot;);</span>
<span class="nc" id="L108"> algorithm = (String) attrs.get(&quot;alg&quot;);</span>
<span class="nc" id="L110"> log.info(&quot;Certificate algorithm: {}&quot;, algorithm);</span>
<span class="nc" id="L111"> } catch (JSONException e) {</span>
<span class="nc" id="L112"> log.error(&quot;Failed to parse license file: {}&quot;, e.getMessage());</span>
<span class="nc" id="L113"> return false;</span>
<span class="nc" id="L114"> }</span>
// Verify license file algorithm
<span class="nc bnc" id="L117" title="All 2 branches missed."> if (!algorithm.equals(&quot;base64+ed25519&quot;)) {</span>
<span class="nc" id="L118"> log.error(</span>
&quot;Unsupported algorithm: {}. Only base64+ed25519 is supported.&quot;, algorithm);
<span class="nc" id="L120"> return false;</span>
}
// Verify signature
<span class="nc" id="L124"> boolean isSignatureValid = verifyEd25519Signature(encryptedData, encodedSignature);</span>
<span class="nc bnc" id="L125" title="All 2 branches missed."> if (!isSignatureValid) {</span>
<span class="nc" id="L126"> log.error(&quot;License file signature is invalid&quot;);</span>
<span class="nc" id="L127"> return false;</span>
}
<span class="nc" id="L130"> log.info(&quot;License file signature is valid&quot;);</span>
// Decode the base64 data
String decodedData;
try {
<span class="nc" id="L135"> decodedData = new String(Base64.getDecoder().decode(encryptedData));</span>
<span class="nc" id="L136"> } catch (IllegalArgumentException e) {</span>
<span class="nc" id="L137"> log.error(&quot;Failed to decode license data: {}&quot;, e.getMessage());</span>
<span class="nc" id="L138"> return false;</span>
<span class="nc" id="L139"> }</span>
// Process the certificate data
<span class="nc" id="L142"> boolean isValid = processCertificateData(decodedData);</span>
<span class="nc" id="L144"> return isValid;</span>
<span class="nc" id="L145"> } catch (Exception e) {</span>
<span class="nc" id="L146"> log.error(&quot;Error verifying certificate license: {}&quot;, e.getMessage(), e);</span>
<span class="nc" id="L147"> return false;</span>
}
}
private boolean verifyEd25519Signature(String encryptedData, String encodedSignature) {
try {
<span class="nc" id="L153"> log.info(&quot;Signature to verify: {}&quot;, encodedSignature);</span>
<span class="nc" id="L154"> log.info(&quot;Public key being used: {}&quot;, PUBLIC_KEY);</span>
<span class="nc" id="L156"> byte[] signatureBytes = Base64.getDecoder().decode(encodedSignature);</span>
// Create the signing data format - prefix with &quot;license/&quot;
<span class="nc" id="L159"> String signingData = String.format(&quot;license/%s&quot;, encryptedData);</span>
<span class="nc" id="L160"> byte[] signingDataBytes = signingData.getBytes();</span>
<span class="nc" id="L162"> log.info(&quot;Signing data length: {} bytes&quot;, signingDataBytes.length);</span>
<span class="nc" id="L164"> byte[] publicKeyBytes = Hex.decode(PUBLIC_KEY);</span>
<span class="nc" id="L166"> Ed25519PublicKeyParameters verifierParams =</span>
new Ed25519PublicKeyParameters(publicKeyBytes, 0);
<span class="nc" id="L168"> Ed25519Signer verifier = new Ed25519Signer();</span>
<span class="nc" id="L170"> verifier.init(false, verifierParams);</span>
<span class="nc" id="L171"> verifier.update(signingDataBytes, 0, signingDataBytes.length);</span>
// Verify the signature
<span class="nc" id="L174"> boolean result = verifier.verifySignature(signatureBytes);</span>
<span class="nc bnc" id="L175" title="All 2 branches missed."> if (!result) {</span>
<span class="nc" id="L176"> log.error(&quot;Signature verification failed with standard public key&quot;);</span>
}
<span class="nc" id="L179"> return result;</span>
<span class="nc" id="L180"> } catch (Exception e) {</span>
<span class="nc" id="L181"> log.error(&quot;Error verifying Ed25519 signature: {}&quot;, e.getMessage(), e);</span>
<span class="nc" id="L182"> return false;</span>
}
}
private boolean processCertificateData(String certData) {
try {
<span class="nc" id="L188"> log.info(&quot;Processing certificate data: {}&quot;, certData);</span>
<span class="nc" id="L190"> JSONObject licenseData = new JSONObject(certData);</span>
<span class="nc" id="L191"> JSONObject metaObj = licenseData.optJSONObject(&quot;meta&quot;);</span>
<span class="nc bnc" id="L192" title="All 2 branches missed."> if (metaObj != null) {</span>
<span class="nc" id="L193"> String issuedStr = metaObj.optString(&quot;issued&quot;, null);</span>
<span class="nc" id="L194"> String expiryStr = metaObj.optString(&quot;expiry&quot;, null);</span>
<span class="nc bnc" id="L196" title="All 4 branches missed."> if (issuedStr != null &amp;&amp; expiryStr != null) {</span>
<span class="nc" id="L197"> java.time.Instant issued = java.time.Instant.parse(issuedStr);</span>
<span class="nc" id="L198"> java.time.Instant expiry = java.time.Instant.parse(expiryStr);</span>
<span class="nc" id="L199"> java.time.Instant now = java.time.Instant.now();</span>
<span class="nc bnc" id="L201" title="All 2 branches missed."> if (issued.isAfter(now)) {</span>
<span class="nc" id="L202"> log.error(</span>
&quot;License file issued date is in the future. Please adjust system time or request a new license&quot;);
<span class="nc" id="L204"> return false;</span>
}
// Check if the license file has expired
<span class="nc bnc" id="L208" title="All 2 branches missed."> if (expiry.isBefore(now)) {</span>
<span class="nc" id="L209"> log.error(&quot;License file has expired on {}&quot;, expiryStr);</span>
<span class="nc" id="L210"> return false;</span>
}
<span class="nc" id="L213"> log.info(&quot;License file valid until {}&quot;, expiryStr);</span>
}
}
// Get the main license data
<span class="nc" id="L218"> JSONObject dataObj = licenseData.optJSONObject(&quot;data&quot;);</span>
<span class="nc bnc" id="L219" title="All 2 branches missed."> if (dataObj == null) {</span>
<span class="nc" id="L220"> log.error(&quot;No data object found in certificate&quot;);</span>
<span class="nc" id="L221"> return false;</span>
}
// Extract license or machine information
<span class="nc" id="L225"> JSONObject attributesObj = dataObj.optJSONObject(&quot;attributes&quot;);</span>
<span class="nc bnc" id="L226" title="All 2 branches missed."> if (attributesObj != null) {</span>
<span class="nc" id="L227"> log.info(&quot;Found attributes in certificate data&quot;);</span>
// Extract metadata
<span class="nc" id="L230"> JSONObject metadataObj = attributesObj.optJSONObject(&quot;metadata&quot;);</span>
<span class="nc bnc" id="L231" title="All 2 branches missed."> if (metadataObj != null) {</span>
<span class="nc" id="L232"> int users = metadataObj.optInt(&quot;users&quot;, 0);</span>
<span class="nc bnc" id="L233" title="All 2 branches missed."> if (users &gt; 0) {</span>
<span class="nc" id="L234"> applicationProperties.getPremium().setMaxUsers(users);</span>
<span class="nc" id="L235"> log.info(&quot;License allows for {} users&quot;, users);</span>
}
}
// Check maxUsers directly in attributes if present from policy definition
// if (attributesObj.has(&quot;maxUsers&quot;)) {
// int maxUsers = attributesObj.optInt(&quot;maxUsers&quot;, 0);
// if (maxUsers &gt; 0) {
// applicationProperties.getPremium().setMaxUsers(maxUsers);
// log.info(&quot;License directly specifies {} max users&quot;,
// maxUsers);
// }
// }
// Check license status if available
<span class="nc" id="L250"> String status = attributesObj.optString(&quot;status&quot;, null);</span>
<span class="nc bnc" id="L251" title="All 2 branches missed."> if (status != null</span>
<span class="nc bnc" id="L252" title="All 2 branches missed."> &amp;&amp; !status.equals(&quot;ACTIVE&quot;)</span>
<span class="nc bnc" id="L253" title="All 2 branches missed."> &amp;&amp; !status.equals(&quot;EXPIRING&quot;)) { // Accept &quot;EXPIRING&quot; status as valid</span>
<span class="nc" id="L254"> log.error(&quot;License status is not active: {}&quot;, status);</span>
<span class="nc" id="L255"> return false;</span>
}
}
<span class="nc" id="L259"> return true;</span>
<span class="nc" id="L260"> } catch (Exception e) {</span>
<span class="nc" id="L261"> log.error(&quot;Error processing certificate data: {}&quot;, e.getMessage(), e);</span>
<span class="nc" id="L262"> return false;</span>
}
}
private boolean verifyJWTLicense(String licenseKey) {
try {
<span class="nc" id="L268"> log.info(&quot;Verifying ED25519_SIGN format license key&quot;);</span>
// Remove the &quot;key/&quot; prefix
<span class="nc" id="L271"> String licenseData = licenseKey.substring(JWT_PREFIX.length());</span>
// Split into payload and signature
<span class="nc" id="L274"> String[] parts = licenseData.split(&quot;\\.&quot;, 2);</span>
<span class="nc bnc" id="L275" title="All 2 branches missed."> if (parts.length != 2) {</span>
<span class="nc" id="L276"> log.error(</span>
&quot;Invalid ED25519_SIGN license format. Expected format: key/payload.signature&quot;);
<span class="nc" id="L278"> return false;</span>
}
<span class="nc" id="L281"> String encodedPayload = parts[0];</span>
<span class="nc" id="L282"> String encodedSignature = parts[1];</span>
// Verify signature
<span class="nc" id="L285"> boolean isSignatureValid = verifyJWTSignature(encodedPayload, encodedSignature);</span>
<span class="nc bnc" id="L286" title="All 2 branches missed."> if (!isSignatureValid) {</span>
<span class="nc" id="L287"> log.error(&quot;ED25519_SIGN license signature is invalid&quot;);</span>
<span class="nc" id="L288"> return false;</span>
}
<span class="nc" id="L291"> log.info(&quot;ED25519_SIGN license signature is valid&quot;);</span>
// Decode and process payload - first convert from URL-safe base64 if needed
<span class="nc" id="L294"> String base64Payload = encodedPayload.replace('-', '+').replace('_', '/');</span>
<span class="nc" id="L295"> byte[] payloadBytes = Base64.getDecoder().decode(base64Payload);</span>
<span class="nc" id="L296"> String payload = new String(payloadBytes);</span>
// Process the license payload
<span class="nc" id="L299"> boolean isValid = processJWTLicensePayload(payload);</span>
<span class="nc" id="L301"> return isValid;</span>
<span class="nc" id="L302"> } catch (Exception e) {</span>
<span class="nc" id="L303"> log.error(&quot;Error verifying ED25519_SIGN license: {}&quot;, e.getMessage());</span>
<span class="nc" id="L304"> return false;</span>
}
}
private boolean verifyJWTSignature(String encodedPayload, String encodedSignature) {
try {
// Decode base64 signature
byte[] signatureBytes =
<span class="nc" id="L312"> Base64.getDecoder()</span>
<span class="nc" id="L313"> .decode(encodedSignature.replace('-', '+').replace('_', '/'));</span>
// For ED25519_SIGN format, the signing data is &quot;key/&quot; + encodedPayload
<span class="nc" id="L316"> String signingData = String.format(&quot;key/%s&quot;, encodedPayload);</span>
<span class="nc" id="L317"> byte[] dataBytes = signingData.getBytes();</span>
<span class="nc" id="L319"> byte[] publicKeyBytes = Hex.decode(PUBLIC_KEY);</span>
<span class="nc" id="L320"> Ed25519PublicKeyParameters verifierParams =</span>
new Ed25519PublicKeyParameters(publicKeyBytes, 0);
<span class="nc" id="L322"> Ed25519Signer verifier = new Ed25519Signer();</span>
<span class="nc" id="L324"> verifier.init(false, verifierParams);</span>
<span class="nc" id="L325"> verifier.update(dataBytes, 0, dataBytes.length);</span>
// Verify the signature
<span class="nc" id="L328"> return verifier.verifySignature(signatureBytes);</span>
<span class="nc" id="L329"> } catch (Exception e) {</span>
<span class="nc" id="L330"> log.error(&quot;Error verifying JWT signature: {}&quot;, e.getMessage());</span>
<span class="nc" id="L331"> return false;</span>
}
}
private boolean processJWTLicensePayload(String payload) {
try {
<span class="nc" id="L337"> log.info(&quot;Processing license payload: {}&quot;, payload);</span>
<span class="nc" id="L339"> JSONObject licenseData = new JSONObject(payload);</span>
<span class="nc" id="L341"> JSONObject licenseObj = licenseData.optJSONObject(&quot;license&quot;);</span>
<span class="nc bnc" id="L342" title="All 2 branches missed."> if (licenseObj == null) {</span>
<span class="nc" id="L343"> String id = licenseData.optString(&quot;id&quot;, null);</span>
<span class="nc bnc" id="L344" title="All 2 branches missed."> if (id != null) {</span>
<span class="nc" id="L345"> log.info(&quot;Found license ID: {}&quot;, id);</span>
<span class="nc" id="L346"> licenseObj = licenseData; // Use the root object as the license object</span>
} else {
<span class="nc" id="L348"> log.error(&quot;License data not found in payload&quot;);</span>
<span class="nc" id="L349"> return false;</span>
}
}
<span class="nc" id="L353"> String licenseId = licenseObj.optString(&quot;id&quot;, &quot;unknown&quot;);</span>
<span class="nc" id="L354"> log.info(&quot;Processing license with ID: {}&quot;, licenseId);</span>
// Check expiry date
<span class="nc" id="L357"> String expiryStr = licenseObj.optString(&quot;expiry&quot;, null);</span>
<span class="nc bnc" id="L358" title="All 4 branches missed."> if (expiryStr != null &amp;&amp; !expiryStr.equals(&quot;null&quot;)) {</span>
<span class="nc" id="L359"> java.time.Instant expiry = java.time.Instant.parse(expiryStr);</span>
<span class="nc" id="L360"> java.time.Instant now = java.time.Instant.now();</span>
<span class="nc bnc" id="L362" title="All 2 branches missed."> if (now.isAfter(expiry)) {</span>
<span class="nc" id="L363"> log.error(&quot;License has expired on {}&quot;, expiryStr);</span>
<span class="nc" id="L364"> return false;</span>
}
<span class="nc" id="L367"> log.info(&quot;License valid until {}&quot;, expiryStr);</span>
<span class="nc" id="L368"> } else {</span>
<span class="nc" id="L369"> log.info(&quot;License has no expiration date&quot;);</span>
}
// Extract account, product, policy info
<span class="nc" id="L373"> JSONObject accountObj = licenseData.optJSONObject(&quot;account&quot;);</span>
<span class="nc bnc" id="L374" title="All 2 branches missed."> if (accountObj != null) {</span>
<span class="nc" id="L375"> String accountId = accountObj.optString(&quot;id&quot;, &quot;unknown&quot;);</span>
<span class="nc" id="L376"> log.info(&quot;License belongs to account: {}&quot;, accountId);</span>
// Verify this matches your expected account ID
<span class="nc bnc" id="L379" title="All 2 branches missed."> if (!ACCOUNT_ID.equals(accountId)) {</span>
<span class="nc" id="L380"> log.warn(&quot;License account ID does not match expected account ID&quot;);</span>
// You might want to fail verification here depending on your requirements
}
}
// Extract policy information if available
<span class="nc" id="L386"> JSONObject policyObj = licenseData.optJSONObject(&quot;policy&quot;);</span>
<span class="nc bnc" id="L387" title="All 2 branches missed."> if (policyObj != null) {</span>
<span class="nc" id="L388"> String policyId = policyObj.optString(&quot;id&quot;, &quot;unknown&quot;);</span>
<span class="nc" id="L389"> log.info(&quot;License uses policy: {}&quot;, policyId);</span>
// Extract max users from policy if available (customize based on your policy
// structure)
<span class="nc" id="L393"> int users = policyObj.optInt(&quot;users&quot;, 0);</span>
<span class="nc bnc" id="L394" title="All 2 branches missed."> if (users &gt; 0) {</span>
<span class="nc" id="L395"> applicationProperties.getPremium().setMaxUsers(users);</span>
<span class="nc" id="L396"> log.info(&quot;License allows for {} users&quot;, users);</span>
} else {
// Try to get users from metadata if present
<span class="nc" id="L399"> Object metadataObj = policyObj.opt(&quot;metadata&quot;);</span>
<span class="nc bnc" id="L400" title="All 2 branches missed."> if (metadataObj instanceof JSONObject) {</span>
<span class="nc" id="L401"> JSONObject metadata = (JSONObject) metadataObj;</span>
<span class="nc" id="L402"> users = metadata.optInt(&quot;users&quot;, 1);</span>
<span class="nc" id="L403"> applicationProperties.getPremium().setMaxUsers(users);</span>
<span class="nc" id="L404"> log.info(&quot;License allows for {} users (from metadata)&quot;, users);</span>
<span class="nc" id="L405"> } else {</span>
// Default value
<span class="nc" id="L407"> applicationProperties.getPremium().setMaxUsers(1);</span>
<span class="nc" id="L408"> log.info(&quot;Using default of 1 user for license&quot;);</span>
}
}
}
<span class="nc" id="L413"> return true;</span>
<span class="nc" id="L414"> } catch (Exception e) {</span>
<span class="nc" id="L415"> log.error(&quot;Error processing license payload: {}&quot;, e.getMessage(), e);</span>
<span class="nc" id="L416"> return false;</span>
}
}
private boolean verifyStandardLicense(String licenseKey) {
try {
<span class="nc" id="L422"> log.info(&quot;Checking standard license key&quot;);</span>
<span class="nc" id="L423"> String machineFingerprint = generateMachineFingerprint();</span>
// First, try to validate the license
<span class="nc" id="L426"> JsonNode validationResponse = validateLicense(licenseKey, machineFingerprint);</span>
<span class="nc bnc" id="L427" title="All 2 branches missed."> if (validationResponse != null) {</span>
<span class="nc" id="L428"> boolean isValid = validationResponse.path(&quot;meta&quot;).path(&quot;valid&quot;).asBoolean();</span>
<span class="nc" id="L429"> String licenseId = validationResponse.path(&quot;data&quot;).path(&quot;id&quot;).asText();</span>
<span class="nc bnc" id="L430" title="All 2 branches missed."> if (!isValid) {</span>
<span class="nc" id="L431"> String code = validationResponse.path(&quot;meta&quot;).path(&quot;code&quot;).asText();</span>
<span class="nc" id="L432"> log.info(code);</span>
<span class="nc bnc" id="L433" title="All 2 branches missed."> if (&quot;NO_MACHINE&quot;.equals(code)</span>
<span class="nc bnc" id="L434" title="All 2 branches missed."> || &quot;NO_MACHINES&quot;.equals(code)</span>
<span class="nc bnc" id="L435" title="All 2 branches missed."> || &quot;FINGERPRINT_SCOPE_MISMATCH&quot;.equals(code)) {</span>
<span class="nc" id="L436"> log.info(</span>
&quot;License not activated for this machine. Attempting to activate...&quot;);
<span class="nc" id="L438"> boolean activated =</span>
<span class="nc" id="L439"> activateMachine(licenseKey, licenseId, machineFingerprint);</span>
<span class="nc bnc" id="L440" title="All 2 branches missed."> if (activated) {</span>
// Revalidate after activation
<span class="nc" id="L442"> validationResponse = validateLicense(licenseKey, machineFingerprint);</span>
<span class="nc bnc" id="L443" title="All 2 branches missed."> isValid =</span>
validationResponse != null
&amp;&amp; validationResponse
<span class="nc" id="L446"> .path(&quot;meta&quot;)</span>
<span class="nc" id="L447"> .path(&quot;valid&quot;)</span>
<span class="nc bnc" id="L448" title="All 2 branches missed."> .asBoolean();</span>
}
}
}
<span class="nc" id="L452"> return isValid;</span>
}
<span class="nc" id="L455"> return false;</span>
<span class="nc" id="L456"> } catch (Exception e) {</span>
<span class="nc" id="L457"> log.error(&quot;Error verifying standard license: {}&quot;, e.getMessage());</span>
<span class="nc" id="L458"> return false;</span>
}
}
private JsonNode validateLicense(String licenseKey, String machineFingerprint)
throws Exception {
<span class="nc" id="L464"> HttpClient client = HttpClient.newHttpClient();</span>
<span class="nc" id="L465"> String requestBody =</span>
<span class="nc" id="L466"> String.format(</span>
&quot;{\&quot;meta\&quot;:{\&quot;key\&quot;:\&quot;%s\&quot;,\&quot;scope\&quot;:{\&quot;fingerprint\&quot;:\&quot;%s\&quot;}}}&quot;,
licenseKey, machineFingerprint);
HttpRequest request =
<span class="nc" id="L470"> HttpRequest.newBuilder()</span>
<span class="nc" id="L471"> .uri(</span>
<span class="nc" id="L472"> URI.create(</span>
BASE_URL
+ &quot;/&quot;
+ ACCOUNT_ID
+ &quot;/licenses/actions/validate-key&quot;))
<span class="nc" id="L477"> .header(&quot;Content-Type&quot;, &quot;application/vnd.api+json&quot;)</span>
<span class="nc" id="L478"> .header(&quot;Accept&quot;, &quot;application/vnd.api+json&quot;)</span>
// .header(&quot;Authorization&quot;, &quot;License &quot; + licenseKey)
<span class="nc" id="L480"> .POST(HttpRequest.BodyPublishers.ofString(requestBody))</span>
<span class="nc" id="L481"> .build();</span>
<span class="nc" id="L483"> HttpResponse&lt;String&gt; response = client.send(request, HttpResponse.BodyHandlers.ofString());</span>
<span class="nc" id="L484"> log.info(&quot;ValidateLicenseResponse body: {}&quot;, response.body());</span>
<span class="nc" id="L485"> JsonNode jsonResponse = objectMapper.readTree(response.body());</span>
<span class="nc bnc" id="L486" title="All 2 branches missed."> if (response.statusCode() == 200) {</span>
<span class="nc" id="L487"> JsonNode metaNode = jsonResponse.path(&quot;meta&quot;);</span>
<span class="nc" id="L488"> boolean isValid = metaNode.path(&quot;valid&quot;).asBoolean();</span>
<span class="nc" id="L490"> String detail = metaNode.path(&quot;detail&quot;).asText();</span>
<span class="nc" id="L491"> String code = metaNode.path(&quot;code&quot;).asText();</span>
<span class="nc" id="L493"> log.info(&quot;License validity: &quot; + isValid);</span>
<span class="nc" id="L494"> log.info(&quot;Validation detail: &quot; + detail);</span>
<span class="nc" id="L495"> log.info(&quot;Validation code: &quot; + code);</span>
<span class="nc" id="L497"> int users =</span>
jsonResponse
<span class="nc" id="L499"> .path(&quot;data&quot;)</span>
<span class="nc" id="L500"> .path(&quot;attributes&quot;)</span>
<span class="nc" id="L501"> .path(&quot;metadata&quot;)</span>
<span class="nc" id="L502"> .path(&quot;users&quot;)</span>
<span class="nc" id="L503"> .asInt(0);</span>
<span class="nc" id="L504"> applicationProperties.getPremium().setMaxUsers(users);</span>
<span class="nc" id="L505"> log.info(applicationProperties.toString());</span>
<span class="nc" id="L507"> } else {</span>
<span class="nc" id="L508"> log.error(&quot;Error validating license. Status code: {}&quot;, response.statusCode());</span>
}
<span class="nc" id="L510"> return jsonResponse;</span>
}
private boolean activateMachine(String licenseKey, String licenseId, String machineFingerprint)
throws Exception {
<span class="nc" id="L515"> HttpClient client = HttpClient.newHttpClient();</span>
String hostname;
try {
<span class="nc" id="L519"> hostname = java.net.InetAddress.getLocalHost().getHostName();</span>
<span class="nc" id="L520"> } catch (Exception e) {</span>
<span class="nc" id="L521"> hostname = &quot;Unknown&quot;;</span>
<span class="nc" id="L522"> }</span>
<span class="nc" id="L524"> JSONObject body =</span>
new JSONObject()
<span class="nc" id="L526"> .put(</span>
&quot;data&quot;,
new JSONObject()
<span class="nc" id="L529"> .put(&quot;type&quot;, &quot;machines&quot;)</span>
<span class="nc" id="L530"> .put(</span>
&quot;attributes&quot;,
new JSONObject()
<span class="nc" id="L533"> .put(&quot;fingerprint&quot;, machineFingerprint)</span>
<span class="nc" id="L534"> .put(</span>
&quot;platform&quot;,
<span class="nc" id="L536"> System.getProperty(&quot;os.name&quot;))</span>
<span class="nc" id="L537"> .put(&quot;name&quot;, hostname))</span>
<span class="nc" id="L538"> .put(</span>
&quot;relationships&quot;,
new JSONObject()
<span class="nc" id="L541"> .put(</span>
&quot;license&quot;,
new JSONObject()
<span class="nc" id="L544"> .put(</span>
&quot;data&quot;,
new JSONObject()
<span class="nc" id="L547"> .put(</span>
&quot;type&quot;,
&quot;licenses&quot;)
<span class="nc" id="L550"> .put(</span>
&quot;id&quot;,
licenseId)))));
HttpRequest request =
<span class="nc" id="L555"> HttpRequest.newBuilder()</span>
<span class="nc" id="L556"> .uri(URI.create(BASE_URL + &quot;/&quot; + ACCOUNT_ID + &quot;/machines&quot;))</span>
<span class="nc" id="L557"> .header(&quot;Content-Type&quot;, &quot;application/vnd.api+json&quot;)</span>
<span class="nc" id="L558"> .header(&quot;Accept&quot;, &quot;application/vnd.api+json&quot;)</span>
<span class="nc" id="L559"> .header(&quot;Authorization&quot;, &quot;License &quot; + licenseKey)</span>
<span class="nc" id="L560"> .POST(HttpRequest.BodyPublishers.ofString(body.toString()))</span>
<span class="nc" id="L561"> .build();</span>
<span class="nc" id="L563"> HttpResponse&lt;String&gt; response = client.send(request, HttpResponse.BodyHandlers.ofString());</span>
<span class="nc" id="L564"> log.info(&quot;activateMachine Response body: &quot; + response.body());</span>
<span class="nc bnc" id="L565" title="All 2 branches missed."> if (response.statusCode() == 201) {</span>
<span class="nc" id="L566"> log.info(&quot;Machine activated successfully&quot;);</span>
<span class="nc" id="L567"> return true;</span>
} else {
<span class="nc" id="L569"> log.error(</span>
&quot;Error activating machine. Status code: {}, error: {}&quot;,
<span class="nc" id="L571"> response.statusCode(),</span>
<span class="nc" id="L572"> response.body());</span>
<span class="nc" id="L574"> return false;</span>
}
}
private String generateMachineFingerprint() {
<span class="nc" id="L579"> return GeneralUtils.generateMachineFingerprint();</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>LicenseKeyChecker.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.EE</a> &gt; <span class="el_source">LicenseKeyChecker.java</span></div><h1>LicenseKeyChecker.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.EE;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.utils.GeneralUtils;
@Component
<span class="nc" id="L19">@Slf4j</span>
public class LicenseKeyChecker {
private static final String FILE_PREFIX = &quot;file:&quot;;
private final KeygenLicenseVerifier licenseService;
private final ApplicationProperties applicationProperties;
<span class="nc" id="L28"> private License premiumEnabledResult = License.NORMAL;</span>
@Autowired
public LicenseKeyChecker(
<span class="nc" id="L32"> KeygenLicenseVerifier licenseService, ApplicationProperties applicationProperties) {</span>
<span class="nc" id="L33"> this.licenseService = licenseService;</span>
<span class="nc" id="L34"> this.applicationProperties = applicationProperties;</span>
<span class="nc" id="L35"> this.checkLicense();</span>
<span class="nc" id="L36"> }</span>
@Scheduled(initialDelay = 604800000, fixedRate = 604800000) // 7 days in milliseconds
public void checkLicensePeriodically() {
<span class="nc" id="L40"> checkLicense();</span>
<span class="nc" id="L41"> }</span>
private void checkLicense() {
<span class="nc bnc" id="L44" title="All 2 branches missed."> if (!applicationProperties.getPremium().isEnabled()) {</span>
<span class="nc" id="L45"> premiumEnabledResult = License.NORMAL;</span>
} else {
<span class="nc" id="L47"> String licenseKey = getLicenseKeyContent(applicationProperties.getPremium().getKey());</span>
<span class="nc bnc" id="L48" title="All 2 branches missed."> if (licenseKey != null) {</span>
<span class="nc" id="L49"> premiumEnabledResult = licenseService.verifyLicense(licenseKey);</span>
<span class="nc bnc" id="L50" title="All 2 branches missed."> if (License.ENTERPRISE == premiumEnabledResult) {</span>
<span class="nc" id="L51"> log.info(&quot;License key is Enterprise.&quot;);</span>
<span class="nc bnc" id="L52" title="All 2 branches missed."> } else if (License.PRO == premiumEnabledResult) {</span>
<span class="nc" id="L53"> log.info(&quot;License key is Pro.&quot;);</span>
} else {
<span class="nc" id="L55"> log.info(&quot;License key is invalid, defaulting to non pro license.&quot;);</span>
}
} else {
<span class="nc" id="L58"> log.error(&quot;Failed to obtain license key content.&quot;);</span>
<span class="nc" id="L59"> premiumEnabledResult = License.NORMAL;</span>
}
}
<span class="nc" id="L62"> }</span>
private String getLicenseKeyContent(String keyOrFilePath) {
<span class="nc bnc" id="L65" title="All 4 branches missed."> if (keyOrFilePath == null || keyOrFilePath.trim().isEmpty()) {</span>
<span class="nc" id="L66"> log.error(&quot;License key is not specified&quot;);</span>
<span class="nc" id="L67"> return null;</span>
}
// Check if it's a file reference
<span class="nc bnc" id="L71" title="All 2 branches missed."> if (keyOrFilePath.startsWith(FILE_PREFIX)) {</span>
<span class="nc" id="L72"> String filePath = keyOrFilePath.substring(FILE_PREFIX.length());</span>
try {
<span class="nc" id="L74"> Path path = Paths.get(filePath);</span>
<span class="nc bnc" id="L75" title="All 2 branches missed."> if (!Files.exists(path)) {</span>
<span class="nc" id="L76"> log.error(&quot;License file does not exist: {}&quot;, filePath);</span>
<span class="nc" id="L77"> return null;</span>
}
<span class="nc" id="L79"> log.info(&quot;Reading license from file: {}&quot;, filePath);</span>
<span class="nc" id="L80"> return Files.readString(path);</span>
<span class="nc" id="L81"> } catch (IOException e) {</span>
<span class="nc" id="L82"> log.error(&quot;Failed to read license file: {}&quot;, e.getMessage());</span>
<span class="nc" id="L83"> return null;</span>
}
}
// It's a direct license key
<span class="nc" id="L88"> return keyOrFilePath;</span>
}
public void updateLicenseKey(String newKey) throws IOException {
<span class="nc" id="L92"> applicationProperties.getPremium().setKey(newKey);</span>
<span class="nc" id="L93"> GeneralUtils.saveKeyToSettings(&quot;EnterpriseEdition.key&quot;, newKey);</span>
<span class="nc" id="L94"> checkLicense();</span>
<span class="nc" id="L95"> }</span>
public License getPremiumLicenseEnabledResult() {
<span class="nc" id="L98"> return premiumEnabledResult;</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>stirling.software.SPDF.EE</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb', 'coveragetable'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="index.html" class="el_class">Classes</a><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <span class="el_package">stirling.software.SPDF.EE</span></div><h1>stirling.software.SPDF.EE</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td><td class="sortable ctr1" id="l" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="m" onclick="toggleSort(this)">Classes</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">1,397 of 1,397</td><td class="ctr2">0%</td><td class="bar">166 of 166</td><td class="ctr2">0%</td><td class="ctr1">115</td><td class="ctr2">115</td><td class="ctr1">385</td><td class="ctr2">385</td><td class="ctr1">32</td><td class="ctr2">32</td><td class="ctr1">4</td><td class="ctr2">4</td></tr></tfoot><tbody><tr><td id="a1"><a href="KeygenLicenseVerifier.java.html" class="el_source">KeygenLicenseVerifier.java</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="1,060" alt="1,060"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="88" alt="88"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">61</td><td class="ctr2" id="g0">61</td><td class="ctr1" id="h0">294</td><td class="ctr2" id="i0">294</td><td class="ctr1" id="j0">17</td><td class="ctr2" id="k0">17</td><td class="ctr1" id="l0">2</td><td class="ctr2" id="m0">2</td></tr><tr><td id="a0"><a href="EEAppConfig.java.html" class="el_source">EEAppConfig.java</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="22" height="10" title="198" alt="198"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"><img src="../jacoco-resources/redbar.gif" width="84" height="10" title="62" alt="62"/></td><td class="ctr2" id="e1">0%</td><td class="ctr1" id="f1">39</td><td class="ctr2" id="g1">39</td><td class="ctr1" id="h1">49</td><td class="ctr2" id="i1">49</td><td class="ctr1" id="j1">8</td><td class="ctr2" id="k1">8</td><td class="ctr1" id="l1">1</td><td class="ctr2" id="m1">1</td></tr><tr><td id="a2"><a href="LicenseKeyChecker.java.html" class="el_source">LicenseKeyChecker.java</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="15" height="10" title="139" alt="139"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"><img src="../jacoco-resources/redbar.gif" width="21" height="10" title="16" alt="16"/></td><td class="ctr2" id="e2">0%</td><td class="ctr1" id="f2">15</td><td class="ctr2" id="g2">15</td><td class="ctr1" id="h2">42</td><td class="ctr2" id="i2">42</td><td class="ctr1" id="j2">7</td><td class="ctr2" id="k2">7</td><td class="ctr1" id="l2">1</td><td class="ctr2" id="m2">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>ReplaceAndInvertColorFactory</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.Factories</a> &gt; <span class="el_class">ReplaceAndInvertColorFactory</span></div><h1>ReplaceAndInvertColorFactory</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">29 of 29</td><td class="ctr2">0%</td><td class="bar">6 of 6</td><td class="ctr2">0%</td><td class="ctr1">5</td><td class="ctr2">5</td><td class="ctr1">6</td><td class="ctr2">6</td><td class="ctr1">2</td><td class="ctr2">2</td></tr></tfoot><tbody><tr><td id="a0"><a href="ReplaceAndInvertColorFactory.java.html#L22" class="el_method">replaceAndInvert(MultipartFile, ReplaceAndInvert, HighContrastColorCombination, String, String)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="26" alt="26"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="6" alt="6"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">4</td><td class="ctr2" id="g0">4</td><td class="ctr1" id="h0">5</td><td class="ctr2" id="i0">5</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a1"><a href="ReplaceAndInvertColorFactory.java.html#L13" class="el_method">ReplaceAndInvertColorFactory()</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="13" height="10" title="3" alt="3"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">1</td><td class="ctr2" id="i1">1</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>ReplaceAndInvertColorFactory.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.Factories</a> &gt; <span class="el_source">ReplaceAndInvertColorFactory.java</span></div><h1>ReplaceAndInvertColorFactory.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.Factories;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
import stirling.software.SPDF.utils.misc.CustomColorReplaceStrategy;
import stirling.software.SPDF.utils.misc.InvertFullColorStrategy;
import stirling.software.SPDF.utils.misc.ReplaceAndInvertColorStrategy;
@Component
<span class="nc" id="L13">public class ReplaceAndInvertColorFactory {</span>
public ReplaceAndInvertColorStrategy replaceAndInvert(
MultipartFile file,
ReplaceAndInvert replaceAndInvertOption,
HighContrastColorCombination highContrastColorCombination,
String backGroundColor,
String textColor) {
<span class="nc bnc" id="L22" title="All 4 branches missed."> if (replaceAndInvertOption == ReplaceAndInvert.CUSTOM_COLOR</span>
|| replaceAndInvertOption == ReplaceAndInvert.HIGH_CONTRAST_COLOR) {
<span class="nc" id="L25"> return new CustomColorReplaceStrategy(</span>
file,
replaceAndInvertOption,
textColor,
backGroundColor,
highContrastColorCombination);
<span class="nc bnc" id="L32" title="All 2 branches missed."> } else if (replaceAndInvertOption == ReplaceAndInvert.FULL_INVERSION) {</span>
<span class="nc" id="L34"> return new InvertFullColorStrategy(file, replaceAndInvertOption);</span>
}
<span class="nc" id="L37"> return null;</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>stirling.software.SPDF.Factories</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb', 'coveragetable'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="index.source.html" class="el_source">Source Files</a><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <span class="el_package">stirling.software.SPDF.Factories</span></div><h1>stirling.software.SPDF.Factories</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td><td class="sortable ctr1" id="l" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="m" onclick="toggleSort(this)">Classes</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">29 of 29</td><td class="ctr2">0%</td><td class="bar">6 of 6</td><td class="ctr2">0%</td><td class="ctr1">5</td><td class="ctr2">5</td><td class="ctr1">6</td><td class="ctr2">6</td><td class="ctr1">2</td><td class="ctr2">2</td><td class="ctr1">1</td><td class="ctr2">1</td></tr></tfoot><tbody><tr><td id="a0"><a href="ReplaceAndInvertColorFactory.html" class="el_class">ReplaceAndInvertColorFactory</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="29" alt="29"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="6" alt="6"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">5</td><td class="ctr2" id="g0">5</td><td class="ctr1" id="h0">6</td><td class="ctr2" id="i0">6</td><td class="ctr1" id="j0">2</td><td class="ctr2" id="k0">2</td><td class="ctr1" id="l0">1</td><td class="ctr2" id="m0">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>stirling.software.SPDF.Factories</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb', 'coveragetable'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="index.html" class="el_class">Classes</a><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <span class="el_package">stirling.software.SPDF.Factories</span></div><h1>stirling.software.SPDF.Factories</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td><td class="sortable ctr1" id="l" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="m" onclick="toggleSort(this)">Classes</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">29 of 29</td><td class="ctr2">0%</td><td class="bar">6 of 6</td><td class="ctr2">0%</td><td class="ctr1">5</td><td class="ctr2">5</td><td class="ctr1">6</td><td class="ctr2">6</td><td class="ctr1">2</td><td class="ctr2">2</td><td class="ctr1">1</td><td class="ctr2">1</td></tr></tfoot><tbody><tr><td id="a0"><a href="ReplaceAndInvertColorFactory.java.html" class="el_source">ReplaceAndInvertColorFactory.java</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="29" alt="29"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="6" alt="6"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">5</td><td class="ctr2" id="g0">5</td><td class="ctr1" id="h0">6</td><td class="ctr2" id="i0">6</td><td class="ctr1" id="j0">2</td><td class="ctr2" id="k0">2</td><td class="ctr1" id="l0">1</td><td class="ctr2" id="m0">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DesktopBrowser.new MavenCefAppHandlerAdapter() {...}</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.UI.impl</a> &gt; <span class="el_class">DesktopBrowser.new MavenCefAppHandlerAdapter() {...}</span></div><h1>DesktopBrowser.new MavenCefAppHandlerAdapter() {...}</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">17 of 17</td><td class="ctr2">0%</td><td class="bar">2 of 2</td><td class="ctr2">0%</td><td class="ctr1">3</td><td class="ctr2">3</td><td class="ctr1">5</td><td class="ctr2">5</td><td class="ctr1">2</td><td class="ctr2">2</td></tr></tfoot><tbody><tr><td id="a0"><a href="DesktopBrowser.java.html#L139" class="el_method">stateHasChanged(CefApp.CefAppState)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="11" alt="11"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="2" alt="2"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">2</td><td class="ctr2" id="g0">2</td><td class="ctr1" id="h0">4</td><td class="ctr2" id="i0">4</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a1"><a href="DesktopBrowser.java.html#L136" class="el_method">{...}</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="65" height="10" title="6" alt="6"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">1</td><td class="ctr2" id="i1">1</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DesktopBrowser.new CefDownloadHandlerAdapter() {...}</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.UI.impl</a> &gt; <span class="el_class">DesktopBrowser.new CefDownloadHandlerAdapter() {...}</span></div><h1>DesktopBrowser.new CefDownloadHandlerAdapter() {...}</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">30 of 30</td><td class="ctr2">0%</td><td class="bar">4 of 4</td><td class="ctr2">0%</td><td class="ctr1">5</td><td class="ctr2">5</td><td class="ctr1">8</td><td class="ctr2">8</td><td class="ctr1">3</td><td class="ctr2">3</td></tr></tfoot><tbody><tr><td id="a1"><a href="DesktopBrowser.java.html#L165" class="el_method">onDownloadUpdated(CefBrowser, CefDownloadItem, CefDownloadItemCallback)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="18" alt="18"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="4" alt="4"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">3</td><td class="ctr2" id="g0">3</td><td class="ctr1" id="h0">5</td><td class="ctr2" id="i0">5</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a2"><a href="DesktopBrowser.java.html#L149" class="el_method">{...}</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="40" height="10" title="6" alt="6"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h2">1</td><td class="ctr2" id="i2">1</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a0"><a href="DesktopBrowser.java.html#L156" class="el_method">onBeforeDownload(CefBrowser, CefDownloadItem, String, CefBeforeDownloadCallback)</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="40" height="10" title="6" alt="6"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">1</td><td class="ctr2" id="g2">1</td><td class="ctr1" id="h1">2</td><td class="ctr2" id="i1">2</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DesktopBrowser.new ConsoleProgressHandler() {...}</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.UI.impl</a> &gt; <span class="el_class">DesktopBrowser.new ConsoleProgressHandler() {...}</span></div><h1>DesktopBrowser.new ConsoleProgressHandler() {...}</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">70 of 70</td><td class="ctr2">0%</td><td class="bar">10 of 10</td><td class="ctr2">0%</td><td class="ctr1">10</td><td class="ctr2">10</td><td class="ctr1">23</td><td class="ctr2">23</td><td class="ctr1">3</td><td class="ctr2">3</td></tr></tfoot><tbody><tr><td id="a1"><a href="DesktopBrowser.java.html#L181" class="el_method">lambda$handleProgress$0(EnumProgress, float)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="55" alt="55"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="10" alt="10"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">8</td><td class="ctr2" id="g0">8</td><td class="ctr1" id="h0">19</td><td class="ctr2" id="i0">19</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a0"><a href="DesktopBrowser.java.html#L178" class="el_method">handleProgress(EnumProgress, float)</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="19" height="10" title="9" alt="9"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">3</td><td class="ctr2" id="i1">3</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a2"><a href="DesktopBrowser.java.html#L175" class="el_method">{...}</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="13" height="10" title="6" alt="6"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">1</td><td class="ctr2" id="g2">1</td><td class="ctr1" id="h2">1</td><td class="ctr2" id="i2">1</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DesktopBrowser.new WindowAdapter() {...}</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.UI.impl</a> &gt; <span class="el_class">DesktopBrowser.new WindowAdapter() {...}</span></div><h1>DesktopBrowser.new WindowAdapter() {...}</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">12 of 12</td><td class="ctr2">0%</td><td class="bar">0 of 0</td><td class="ctr2">n/a</td><td class="ctr1">2</td><td class="ctr2">2</td><td class="ctr1">4</td><td class="ctr2">4</td><td class="ctr1">2</td><td class="ctr2">2</td></tr></tfoot><tbody><tr><td id="a1"><a href="DesktopBrowser.java.html#L227" class="el_method">{...}</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="6" alt="6"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"/><td class="ctr2" id="e0">n/a</td><td class="ctr1" id="f0">1</td><td class="ctr2" id="g0">1</td><td class="ctr1" id="h1">1</td><td class="ctr2" id="i1">1</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a0"><a href="DesktopBrowser.java.html#L230" class="el_method">windowClosing(WindowEvent)</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="6" alt="6"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h0">3</td><td class="ctr2" id="i0">3</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DesktopBrowser.new CefLoadHandlerAdapter() {...}</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.UI.impl</a> &gt; <span class="el_class">DesktopBrowser.new CefLoadHandlerAdapter() {...}</span></div><h1>DesktopBrowser.new CefLoadHandlerAdapter() {...}</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">150 of 150</td><td class="ctr2">0%</td><td class="bar">10 of 10</td><td class="ctr2">0%</td><td class="ctr1">9</td><td class="ctr2">9</td><td class="ctr1">52</td><td class="ctr2">52</td><td class="ctr1">4</td><td class="ctr2">4</td></tr></tfoot><tbody><tr><td id="a1"><a href="DesktopBrowser.java.html#L270" class="el_method">lambda$onLoadingStateChange$1(CefBrowser)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="82" alt="82"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="6" alt="6"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">4</td><td class="ctr2" id="g0">4</td><td class="ctr1" id="h0">33</td><td class="ctr2" id="i0">33</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a2"><a href="DesktopBrowser.java.html#L253" class="el_method">onLoadingStateChange(CefBrowser, boolean, boolean, boolean)</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="67" height="10" title="46" alt="46"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"><img src="../jacoco-resources/redbar.gif" width="80" height="10" title="4" alt="4"/></td><td class="ctr2" id="e1">0%</td><td class="ctr1" id="f1">3</td><td class="ctr2" id="g1">3</td><td class="ctr1" id="h1">11</td><td class="ctr2" id="i1">11</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a0"><a href="DesktopBrowser.java.html#L303" class="el_method">lambda$onLoadingStateChange$0(CefBrowser, ActionEvent)</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="19" height="10" title="13" alt="13"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">1</td><td class="ctr2" id="g2">1</td><td class="ctr1" id="h2">7</td><td class="ctr2" id="i2">7</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr><tr><td id="a3"><a href="DesktopBrowser.java.html#L246" class="el_method">{...}</a></td><td class="bar" id="b3"><img src="../jacoco-resources/redbar.gif" width="13" height="10" title="9" alt="9"/></td><td class="ctr2" id="c3">0%</td><td class="bar" id="d3"/><td class="ctr2" id="e3">n/a</td><td class="ctr1" id="f3">1</td><td class="ctr2" id="g3">1</td><td class="ctr1" id="h3">1</td><td class="ctr2" id="i3">1</td><td class="ctr1" id="j3">1</td><td class="ctr2" id="k3">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DesktopBrowser.new WindowStateListener() {...}</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.UI.impl</a> &gt; <span class="el_class">DesktopBrowser.new WindowStateListener() {...}</span></div><h1>DesktopBrowser.new WindowStateListener() {...}</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">14 of 14</td><td class="ctr2">0%</td><td class="bar">2 of 2</td><td class="ctr2">0%</td><td class="ctr1">3</td><td class="ctr2">3</td><td class="ctr1">4</td><td class="ctr2">4</td><td class="ctr1">2</td><td class="ctr2">2</td></tr></tfoot><tbody><tr><td id="a0"><a href="DesktopBrowser.java.html#L386" class="el_method">windowStateChanged(WindowEvent)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="8" alt="8"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="2" alt="2"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">2</td><td class="ctr2" id="g0">2</td><td class="ctr1" id="h0">3</td><td class="ctr2" id="i0">3</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a1"><a href="DesktopBrowser.java.html#L384" class="el_method">{...}</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="90" height="10" title="6" alt="6"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">1</td><td class="ctr2" id="i1">1</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,498 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DesktopBrowser.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.UI.impl</a> &gt; <span class="el_source">DesktopBrowser.java</span></div><h1>DesktopBrowser.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.UI.impl;
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.WindowEvent;
import java.awt.event.WindowStateListener;
import java.io.File;
import java.io.InputStream;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import org.cef.CefApp;
import org.cef.CefClient;
import org.cef.CefSettings;
import org.cef.browser.CefBrowser;
import org.cef.callback.CefBeforeDownloadCallback;
import org.cef.callback.CefDownloadItem;
import org.cef.callback.CefDownloadItemCallback;
import org.cef.handler.CefDownloadHandlerAdapter;
import org.cef.handler.CefLoadHandlerAdapter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import me.friwi.jcefmaven.CefAppBuilder;
import me.friwi.jcefmaven.EnumProgress;
import me.friwi.jcefmaven.MavenCefAppHandlerAdapter;
import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler;
import stirling.software.SPDF.UI.WebBrowser;
import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.utils.UIScaling;
@Component
<span class="nc" id="L50">@Slf4j</span>
@ConditionalOnProperty(
name = &quot;STIRLING_PDF_DESKTOP_UI&quot;,
havingValue = &quot;true&quot;,
matchIfMissing = false)
public class DesktopBrowser implements WebBrowser {
private static CefApp cefApp;
private static CefClient client;
private static CefBrowser browser;
private static JFrame frame;
private static LoadingWindow loadingWindow;
<span class="nc" id="L61"> private static volatile boolean browserInitialized = false;</span>
private static TrayIcon trayIcon;
private static SystemTray systemTray;
<span class="nc" id="L65"> public DesktopBrowser() {</span>
<span class="nc" id="L66"> SwingUtilities.invokeLater(</span>
() -&gt; {
<span class="nc" id="L68"> loadingWindow = new LoadingWindow(null, &quot;Initializing...&quot;);</span>
<span class="nc" id="L69"> loadingWindow.setVisible(true);</span>
<span class="nc" id="L70"> });</span>
<span class="nc" id="L71"> }</span>
public void initWebUI(String url) {
<span class="nc" id="L74"> CompletableFuture.runAsync(</span>
() -&gt; {
try {
<span class="nc" id="L77"> CefAppBuilder builder = new CefAppBuilder();</span>
<span class="nc" id="L78"> configureCefSettings(builder);</span>
<span class="nc" id="L79"> builder.setProgressHandler(createProgressHandler());</span>
<span class="nc" id="L80"> builder.setInstallDir(</span>
<span class="nc" id="L81"> new File(InstallationPathConfig.getClientWebUIPath()));</span>
// Build and initialize CEF
<span class="nc" id="L83"> cefApp = builder.build();</span>
<span class="nc" id="L84"> client = cefApp.createClient();</span>
// Set up download handler
<span class="nc" id="L87"> setupDownloadHandler();</span>
// Create browser and frame on EDT
<span class="nc" id="L90"> SwingUtilities.invokeAndWait(</span>
() -&gt; {
<span class="nc" id="L92"> browser = client.createBrowser(url, false, false);</span>
<span class="nc" id="L93"> setupMainFrame();</span>
<span class="nc" id="L94"> setupLoadHandler();</span>
// Force initialize UI after 7 seconds if not already done
<span class="nc" id="L97"> Timer timeoutTimer =</span>
new Timer(
2500,
e -&gt; {
<span class="nc" id="L101"> log.warn(</span>
&quot;Loading timeout reached. Forcing&quot;
+ &quot; UI transition.&quot;);
<span class="nc bnc" id="L104" title="All 2 branches missed."> if (!browserInitialized) {</span>
// Force UI initialization
<span class="nc" id="L106"> forceInitializeUI();</span>
}
<span class="nc" id="L108"> });</span>
<span class="nc" id="L109"> timeoutTimer.setRepeats(false);</span>
<span class="nc" id="L110"> timeoutTimer.start();</span>
<span class="nc" id="L111"> });</span>
<span class="nc" id="L112"> } catch (Exception e) {</span>
<span class="nc" id="L113"> log.error(&quot;Error initializing JCEF browser: &quot;, e);</span>
<span class="nc" id="L114"> cleanup();</span>
<span class="nc" id="L115"> }</span>
<span class="nc" id="L116"> });</span>
<span class="nc" id="L117"> }</span>
private void configureCefSettings(CefAppBuilder builder) {
<span class="nc" id="L120"> CefSettings settings = builder.getCefSettings();</span>
<span class="nc" id="L121"> String basePath = InstallationPathConfig.getClientWebUIPath();</span>
<span class="nc" id="L122"> log.info(&quot;basePath &quot; + basePath);</span>
<span class="nc" id="L123"> settings.cache_path = new File(basePath + &quot;cache&quot;).getAbsolutePath();</span>
<span class="nc" id="L124"> settings.root_cache_path = new File(basePath + &quot;root_cache&quot;).getAbsolutePath();</span>
// settings.browser_subprocess_path = new File(basePath +
// &quot;subprocess&quot;).getAbsolutePath();
// settings.resources_dir_path = new File(basePath + &quot;resources&quot;).getAbsolutePath();
// settings.locales_dir_path = new File(basePath + &quot;locales&quot;).getAbsolutePath();
<span class="nc" id="L129"> settings.log_file = new File(basePath, &quot;debug.log&quot;).getAbsolutePath();</span>
<span class="nc" id="L131"> settings.persist_session_cookies = true;</span>
<span class="nc" id="L132"> settings.windowless_rendering_enabled = false;</span>
<span class="nc" id="L133"> settings.log_severity = CefSettings.LogSeverity.LOGSEVERITY_INFO;</span>
<span class="nc" id="L135"> builder.setAppHandler(</span>
<span class="nc" id="L136"> new MavenCefAppHandlerAdapter() {</span>
@Override
public void stateHasChanged(org.cef.CefApp.CefAppState state) {
<span class="nc" id="L139"> log.info(&quot;CEF state changed: &quot; + state);</span>
<span class="nc bnc" id="L140" title="All 2 branches missed."> if (state == CefApp.CefAppState.TERMINATED) {</span>
<span class="nc" id="L141"> System.exit(0);</span>
}
<span class="nc" id="L143"> }</span>
});
<span class="nc" id="L145"> }</span>
private void setupDownloadHandler() {
<span class="nc" id="L148"> client.addDownloadHandler(</span>
<span class="nc" id="L149"> new CefDownloadHandlerAdapter() {</span>
@Override
public boolean onBeforeDownload(
CefBrowser browser,
CefDownloadItem downloadItem,
String suggestedName,
CefBeforeDownloadCallback callback) {
<span class="nc" id="L156"> callback.Continue(&quot;&quot;, true);</span>
<span class="nc" id="L157"> return true;</span>
}
@Override
public void onDownloadUpdated(
CefBrowser browser,
CefDownloadItem downloadItem,
CefDownloadItemCallback callback) {
<span class="nc bnc" id="L165" title="All 2 branches missed."> if (downloadItem.isComplete()) {</span>
<span class="nc" id="L166"> log.info(&quot;Download completed: &quot; + downloadItem.getFullPath());</span>
<span class="nc bnc" id="L167" title="All 2 branches missed."> } else if (downloadItem.isCanceled()) {</span>
<span class="nc" id="L168"> log.info(&quot;Download canceled: &quot; + downloadItem.getFullPath());</span>
}
<span class="nc" id="L170"> }</span>
});
<span class="nc" id="L172"> }</span>
private ConsoleProgressHandler createProgressHandler() {
<span class="nc" id="L175"> return new ConsoleProgressHandler() {</span>
@Override
public void handleProgress(EnumProgress state, float percent) {
<span class="nc" id="L178"> Objects.requireNonNull(state, &quot;state cannot be null&quot;);</span>
<span class="nc" id="L179"> SwingUtilities.invokeLater(</span>
() -&gt; {
<span class="nc bnc" id="L181" title="All 2 branches missed."> if (loadingWindow != null) {</span>
<span class="nc bnc" id="L182" title="All 6 branches missed."> switch (state) {</span>
case LOCATING:
<span class="nc" id="L184"> loadingWindow.setStatus(&quot;Locating Files...&quot;);</span>
<span class="nc" id="L185"> loadingWindow.setProgress(0);</span>
<span class="nc" id="L186"> break;</span>
case DOWNLOADING:
<span class="nc bnc" id="L188" title="All 2 branches missed."> if (percent &gt;= 0) {</span>
<span class="nc" id="L189"> loadingWindow.setStatus(</span>
<span class="nc" id="L190"> String.format(</span>
&quot;Downloading additional files: %.0f%%&quot;,
<span class="nc" id="L192"> percent));</span>
<span class="nc" id="L193"> loadingWindow.setProgress((int) percent);</span>
}
break;
case EXTRACTING:
<span class="nc" id="L197"> loadingWindow.setStatus(&quot;Extracting files...&quot;);</span>
<span class="nc" id="L198"> loadingWindow.setProgress(60);</span>
<span class="nc" id="L199"> break;</span>
case INITIALIZING:
<span class="nc" id="L201"> loadingWindow.setStatus(&quot;Initializing UI...&quot;);</span>
<span class="nc" id="L202"> loadingWindow.setProgress(80);</span>
<span class="nc" id="L203"> break;</span>
case INITIALIZED:
<span class="nc" id="L205"> loadingWindow.setStatus(&quot;Finalising startup...&quot;);</span>
<span class="nc" id="L206"> loadingWindow.setProgress(90);</span>
break;
}
}
<span class="nc" id="L210"> });</span>
<span class="nc" id="L211"> }</span>
};
}
private void setupMainFrame() {
<span class="nc" id="L216"> frame = new JFrame(&quot;Stirling-PDF&quot;);</span>
<span class="nc" id="L217"> frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);</span>
<span class="nc" id="L218"> frame.setUndecorated(true);</span>
<span class="nc" id="L219"> frame.setOpacity(0.0f);</span>
<span class="nc" id="L221"> JPanel contentPane = new JPanel(new BorderLayout());</span>
<span class="nc" id="L222"> contentPane.setDoubleBuffered(true);</span>
<span class="nc" id="L223"> contentPane.add(browser.getUIComponent(), BorderLayout.CENTER);</span>
<span class="nc" id="L224"> frame.setContentPane(contentPane);</span>
<span class="nc" id="L226"> frame.addWindowListener(</span>
<span class="nc" id="L227"> new java.awt.event.WindowAdapter() {</span>
@Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
<span class="nc" id="L230"> cleanup();</span>
<span class="nc" id="L231"> System.exit(0);</span>
<span class="nc" id="L232"> }</span>
});
<span class="nc" id="L235"> frame.setSize(UIScaling.scaleWidth(1280), UIScaling.scaleHeight(800));</span>
<span class="nc" id="L236"> frame.setLocationRelativeTo(null);</span>
<span class="nc" id="L238"> loadIcon();</span>
<span class="nc" id="L239"> }</span>
private void setupLoadHandler() {
<span class="nc" id="L242"> final long initStartTime = System.currentTimeMillis();</span>
<span class="nc" id="L243"> log.info(&quot;Setting up load handler at: {}&quot;, initStartTime);</span>
<span class="nc" id="L245"> client.addLoadHandler(</span>
<span class="nc" id="L246"> new CefLoadHandlerAdapter() {</span>
@Override
public void onLoadingStateChange(
CefBrowser browser,
boolean isLoading,
boolean canGoBack,
boolean canGoForward) {
<span class="nc" id="L253"> log.debug(</span>
&quot;Loading state change - isLoading: {}, canGoBack: {}, canGoForward:&quot;
+ &quot; {}, browserInitialized: {}, Time elapsed: {}ms&quot;,
<span class="nc" id="L256"> isLoading,</span>
<span class="nc" id="L257"> canGoBack,</span>
<span class="nc" id="L258"> canGoForward,</span>
<span class="nc" id="L259"> browserInitialized,</span>
<span class="nc" id="L260"> System.currentTimeMillis() - initStartTime);</span>
<span class="nc bnc" id="L262" title="All 4 branches missed."> if (!isLoading &amp;&amp; !browserInitialized) {</span>
<span class="nc" id="L263"> log.info(</span>
&quot;Browser finished loading, preparing to initialize UI&quot;
+ &quot; components&quot;);
<span class="nc" id="L266"> browserInitialized = true;</span>
<span class="nc" id="L267"> SwingUtilities.invokeLater(</span>
() -&gt; {
try {
<span class="nc bnc" id="L270" title="All 2 branches missed."> if (loadingWindow != null) {</span>
<span class="nc" id="L271"> log.info(&quot;Starting UI initialization sequence&quot;);</span>
// Close loading window first
<span class="nc" id="L274"> loadingWindow.setVisible(false);</span>
<span class="nc" id="L275"> loadingWindow.dispose();</span>
<span class="nc" id="L276"> loadingWindow = null;</span>
<span class="nc" id="L277"> log.info(&quot;Loading window disposed&quot;);</span>
// Then setup the main frame
<span class="nc" id="L280"> frame.setVisible(false);</span>
<span class="nc" id="L281"> frame.dispose();</span>
<span class="nc" id="L282"> frame.setOpacity(1.0f);</span>
<span class="nc" id="L283"> frame.setUndecorated(false);</span>
<span class="nc" id="L284"> frame.pack();</span>
<span class="nc" id="L285"> frame.setSize(</span>
<span class="nc" id="L286"> UIScaling.scaleWidth(1280),</span>
<span class="nc" id="L287"> UIScaling.scaleHeight(800));</span>
<span class="nc" id="L288"> frame.setLocationRelativeTo(null);</span>
<span class="nc" id="L289"> log.debug(&quot;Frame reconfigured&quot;);</span>
// Show the main frame
<span class="nc" id="L292"> frame.setVisible(true);</span>
<span class="nc" id="L293"> frame.requestFocus();</span>
<span class="nc" id="L294"> frame.toFront();</span>
<span class="nc" id="L295"> log.info(&quot;Main frame displayed and focused&quot;);</span>
// Focus the browser component
<span class="nc" id="L298"> Timer focusTimer =</span>
new Timer(
100,
e -&gt; {
try {
<span class="nc" id="L303"> browser.getUIComponent()</span>
<span class="nc" id="L304"> .requestFocus();</span>
<span class="nc" id="L305"> log.info(</span>
&quot;Browser component&quot;
+ &quot; focused&quot;);
<span class="nc" id="L308"> } catch (Exception ex) {</span>
<span class="nc" id="L309"> log.error(</span>
&quot;Error focusing&quot;
+ &quot; browser&quot;,
ex);
<span class="nc" id="L313"> }</span>
<span class="nc" id="L314"> });</span>
<span class="nc" id="L315"> focusTimer.setRepeats(false);</span>
<span class="nc" id="L316"> focusTimer.start();</span>
}
<span class="nc" id="L318"> } catch (Exception e) {</span>
<span class="nc" id="L319"> log.error(&quot;Error during UI initialization&quot;, e);</span>
// Attempt cleanup on error
<span class="nc bnc" id="L321" title="All 2 branches missed."> if (loadingWindow != null) {</span>
<span class="nc" id="L322"> loadingWindow.dispose();</span>
<span class="nc" id="L323"> loadingWindow = null;</span>
}
<span class="nc bnc" id="L325" title="All 2 branches missed."> if (frame != null) {</span>
<span class="nc" id="L326"> frame.setVisible(true);</span>
<span class="nc" id="L327"> frame.requestFocus();</span>
}
<span class="nc" id="L329"> }</span>
<span class="nc" id="L330"> });</span>
}
<span class="nc" id="L332"> }</span>
});
<span class="nc" id="L334"> }</span>
private void setupTrayIcon(Image icon) {
<span class="nc bnc" id="L337" title="All 2 branches missed."> if (!SystemTray.isSupported()) {</span>
<span class="nc" id="L338"> log.warn(&quot;System tray is not supported&quot;);</span>
<span class="nc" id="L339"> return;</span>
}
try {
<span class="nc" id="L343"> systemTray = SystemTray.getSystemTray();</span>
// Create popup menu
<span class="nc" id="L346"> PopupMenu popup = new PopupMenu();</span>
// Create menu items
<span class="nc" id="L349"> MenuItem showItem = new MenuItem(&quot;Show&quot;);</span>
<span class="nc" id="L350"> showItem.addActionListener(</span>
e -&gt; {
<span class="nc" id="L352"> frame.setVisible(true);</span>
<span class="nc" id="L353"> frame.setState(Frame.NORMAL);</span>
<span class="nc" id="L354"> });</span>
<span class="nc" id="L356"> MenuItem exitItem = new MenuItem(&quot;Exit&quot;);</span>
<span class="nc" id="L357"> exitItem.addActionListener(</span>
e -&gt; {
<span class="nc" id="L359"> cleanup();</span>
<span class="nc" id="L360"> System.exit(0);</span>
<span class="nc" id="L361"> });</span>
// Add menu items to popup menu
<span class="nc" id="L364"> popup.add(showItem);</span>
<span class="nc" id="L365"> popup.addSeparator();</span>
<span class="nc" id="L366"> popup.add(exitItem);</span>
// Create tray icon
<span class="nc" id="L369"> trayIcon = new TrayIcon(icon, &quot;Stirling-PDF&quot;, popup);</span>
<span class="nc" id="L370"> trayIcon.setImageAutoSize(true);</span>
// Add double-click behavior
<span class="nc" id="L373"> trayIcon.addActionListener(</span>
e -&gt; {
<span class="nc" id="L375"> frame.setVisible(true);</span>
<span class="nc" id="L376"> frame.setState(Frame.NORMAL);</span>
<span class="nc" id="L377"> });</span>
// Add tray icon to system tray
<span class="nc" id="L380"> systemTray.add(trayIcon);</span>
// Modify frame behavior to minimize to tray
<span class="nc" id="L383"> frame.addWindowStateListener(</span>
<span class="nc" id="L384"> new WindowStateListener() {</span>
public void windowStateChanged(WindowEvent e) {
<span class="nc bnc" id="L386" title="All 2 branches missed."> if (e.getNewState() == Frame.ICONIFIED) {</span>
<span class="nc" id="L387"> frame.setVisible(false);</span>
}
<span class="nc" id="L389"> }</span>
});
<span class="nc" id="L392"> } catch (AWTException e) {</span>
<span class="nc" id="L393"> log.error(&quot;Error setting up system tray icon&quot;, e);</span>
<span class="nc" id="L394"> }</span>
<span class="nc" id="L395"> }</span>
private void loadIcon() {
try {
<span class="nc" id="L399"> Image icon = null;</span>
<span class="nc" id="L400"> String[] iconPaths = {&quot;/static/favicon.ico&quot;};</span>
<span class="nc bnc" id="L402" title="All 2 branches missed."> for (String path : iconPaths) {</span>
<span class="nc bnc" id="L403" title="All 2 branches missed."> if (icon != null) break;</span>
try {
<span class="nc" id="L405"> try (InputStream is = getClass().getResourceAsStream(path)) {</span>
<span class="nc bnc" id="L406" title="All 2 branches missed."> if (is != null) {</span>
<span class="nc" id="L407"> icon = ImageIO.read(is);</span>
<span class="nc" id="L408"> break;</span>
}
<span class="nc bnc" id="L410" title="All 2 branches missed."> }</span>
<span class="nc" id="L411"> } catch (Exception e) {</span>
<span class="nc" id="L412"> log.debug(&quot;Could not load icon from &quot; + path, e);</span>
<span class="nc" id="L413"> }</span>
}
<span class="nc bnc" id="L416" title="All 2 branches missed."> if (icon != null) {</span>
<span class="nc" id="L417"> frame.setIconImage(icon);</span>
<span class="nc" id="L418"> setupTrayIcon(icon);</span>
} else {
<span class="nc" id="L420"> log.warn(&quot;Could not load icon from any source&quot;);</span>
}
<span class="nc" id="L422"> } catch (Exception e) {</span>
<span class="nc" id="L423"> log.error(&quot;Error loading icon&quot;, e);</span>
<span class="nc" id="L424"> }</span>
<span class="nc" id="L425"> }</span>
@PreDestroy
public void cleanup() {
<span class="nc bnc" id="L429" title="All 2 branches missed."> if (browser != null) browser.close(true);</span>
<span class="nc bnc" id="L430" title="All 2 branches missed."> if (client != null) client.dispose();</span>
<span class="nc bnc" id="L431" title="All 2 branches missed."> if (cefApp != null) cefApp.dispose();</span>
<span class="nc bnc" id="L432" title="All 2 branches missed."> if (loadingWindow != null) loadingWindow.dispose();</span>
<span class="nc" id="L433"> }</span>
public static void forceInitializeUI() {
try {
<span class="nc bnc" id="L437" title="All 2 branches missed."> if (loadingWindow != null) {</span>
<span class="nc" id="L438"> log.info(&quot;Forcing start of UI initialization sequence&quot;);</span>
// Close loading window first
<span class="nc" id="L441"> loadingWindow.setVisible(false);</span>
<span class="nc" id="L442"> loadingWindow.dispose();</span>
<span class="nc" id="L443"> loadingWindow = null;</span>
<span class="nc" id="L444"> log.info(&quot;Loading window disposed&quot;);</span>
// Then setup the main frame
<span class="nc" id="L447"> frame.setVisible(false);</span>
<span class="nc" id="L448"> frame.dispose();</span>
<span class="nc" id="L449"> frame.setOpacity(1.0f);</span>
<span class="nc" id="L450"> frame.setUndecorated(false);</span>
<span class="nc" id="L451"> frame.pack();</span>
<span class="nc" id="L452"> frame.setSize(UIScaling.scaleWidth(1280), UIScaling.scaleHeight(800));</span>
<span class="nc" id="L453"> frame.setLocationRelativeTo(null);</span>
<span class="nc" id="L454"> log.debug(&quot;Frame reconfigured&quot;);</span>
// Show the main frame
<span class="nc" id="L457"> frame.setVisible(true);</span>
<span class="nc" id="L458"> frame.requestFocus();</span>
<span class="nc" id="L459"> frame.toFront();</span>
<span class="nc" id="L460"> log.info(&quot;Main frame displayed and focused&quot;);</span>
// Focus the browser component if available
<span class="nc bnc" id="L463" title="All 2 branches missed."> if (browser != null) {</span>
<span class="nc" id="L464"> Timer focusTimer =</span>
new Timer(
100,
e -&gt; {
try {
<span class="nc" id="L469"> browser.getUIComponent().requestFocus();</span>
<span class="nc" id="L470"> log.info(&quot;Browser component focused&quot;);</span>
<span class="nc" id="L471"> } catch (Exception ex) {</span>
<span class="nc" id="L472"> log.error(</span>
&quot;Error focusing browser during force ui&quot;
+ &quot; initialization.&quot;,
ex);
<span class="nc" id="L476"> }</span>
<span class="nc" id="L477"> });</span>
<span class="nc" id="L478"> focusTimer.setRepeats(false);</span>
<span class="nc" id="L479"> focusTimer.start();</span>
}
}
<span class="nc" id="L482"> } catch (Exception e) {</span>
<span class="nc" id="L483"> log.error(&quot;Error during Forced UI initialization.&quot;, e);</span>
// Attempt cleanup on error
<span class="nc bnc" id="L485" title="All 2 branches missed."> if (loadingWindow != null) {</span>
<span class="nc" id="L486"> loadingWindow.dispose();</span>
<span class="nc" id="L487"> loadingWindow = null;</span>
}
<span class="nc bnc" id="L489" title="All 2 branches missed."> if (frame != null) {</span>
<span class="nc" id="L490"> frame.setVisible(true);</span>
<span class="nc" id="L491"> frame.setOpacity(1.0f);</span>
<span class="nc" id="L492"> frame.setUndecorated(false);</span>
<span class="nc" id="L493"> frame.requestFocus();</span>
}
<span class="nc" id="L495"> }</span>
<span class="nc" id="L496"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,352 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>LoadingWindow.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.UI.impl</a> &gt; <span class="el_source">LoadingWindow.java</span></div><h1>LoadingWindow.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.UI.impl;
import java.awt.*;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import javax.swing.*;
import io.github.pixee.security.BoundedLineReader;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.utils.UIScaling;
<span class="nc" id="L20">@Slf4j</span>
public class LoadingWindow extends JDialog {
private final JProgressBar progressBar;
private final JLabel statusLabel;
private final JPanel mainPanel;
private final JLabel brandLabel;
private long startTime;
private Timer stuckTimer;
<span class="nc" id="L29"> private long stuckThreshold = 4000;</span>
<span class="nc" id="L30"> private long timeAt90Percent = -1;</span>
private volatile Process explorerProcess;
<span class="nc" id="L32"> private static final boolean IS_WINDOWS =</span>
<span class="nc" id="L33"> System.getProperty(&quot;os.name&quot;).toLowerCase().contains(&quot;win&quot;);</span>
public LoadingWindow(Frame parent, String initialUrl) {
<span class="nc" id="L36"> super(parent, &quot;Initializing Stirling-PDF&quot;, true);</span>
<span class="nc" id="L37"> startTime = System.currentTimeMillis();</span>
<span class="nc" id="L38"> log.info(&quot;Creating LoadingWindow - initialization started at: {}&quot;, startTime);</span>
// Initialize components
<span class="nc" id="L41"> mainPanel = new JPanel();</span>
<span class="nc" id="L42"> mainPanel.setBackground(Color.WHITE);</span>
<span class="nc" id="L43"> mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 30, 20, 30));</span>
<span class="nc" id="L44"> mainPanel.setLayout(new GridBagLayout());</span>
<span class="nc" id="L45"> GridBagConstraints gbc = new GridBagConstraints();</span>
// Configure GridBagConstraints
<span class="nc" id="L48"> gbc.gridwidth = GridBagConstraints.REMAINDER;</span>
<span class="nc" id="L49"> gbc.fill = GridBagConstraints.HORIZONTAL;</span>
<span class="nc" id="L50"> gbc.insets = new Insets(5, 5, 5, 5);</span>
<span class="nc" id="L51"> gbc.weightx = 1.0;</span>
<span class="nc" id="L52"> gbc.weighty = 0.0;</span>
// Add icon
try {
<span class="nc" id="L56"> try (InputStream is = getClass().getResourceAsStream(&quot;/static/favicon.ico&quot;)) {</span>
<span class="nc bnc" id="L57" title="All 2 branches missed."> if (is != null) {</span>
<span class="nc" id="L58"> Image img = ImageIO.read(is);</span>
<span class="nc bnc" id="L59" title="All 2 branches missed."> if (img != null) {</span>
<span class="nc" id="L60"> Image scaledImg = UIScaling.scaleIcon(img, 48, 48);</span>
<span class="nc" id="L61"> JLabel iconLabel = new JLabel(new ImageIcon(scaledImg));</span>
<span class="nc" id="L62"> iconLabel.setHorizontalAlignment(SwingConstants.CENTER);</span>
<span class="nc" id="L63"> gbc.gridy = 0;</span>
<span class="nc" id="L64"> mainPanel.add(iconLabel, gbc);</span>
<span class="nc" id="L65"> log.info(&quot;Icon loaded and scaled successfully&quot;);</span>
}
}
}
<span class="nc" id="L69"> } catch (Exception e) {</span>
<span class="nc" id="L70"> log.error(&quot;Failed to load icon&quot;, e);</span>
<span class="nc" id="L71"> }</span>
// URL Label with explicit size
<span class="nc" id="L74"> brandLabel = new JLabel(initialUrl);</span>
<span class="nc" id="L75"> brandLabel.setHorizontalAlignment(SwingConstants.CENTER);</span>
<span class="nc" id="L76"> brandLabel.setPreferredSize(new Dimension(300, 25));</span>
<span class="nc" id="L77"> brandLabel.setText(&quot;Stirling-PDF&quot;);</span>
<span class="nc" id="L78"> gbc.gridy = 1;</span>
<span class="nc" id="L79"> mainPanel.add(brandLabel, gbc);</span>
// Status label with explicit size
<span class="nc" id="L82"> statusLabel = new JLabel(&quot;Initializing...&quot;);</span>
<span class="nc" id="L83"> statusLabel.setHorizontalAlignment(SwingConstants.CENTER);</span>
<span class="nc" id="L84"> statusLabel.setPreferredSize(new Dimension(300, 25));</span>
<span class="nc" id="L85"> gbc.gridy = 2;</span>
<span class="nc" id="L86"> mainPanel.add(statusLabel, gbc);</span>
// Progress bar with explicit size
<span class="nc" id="L89"> progressBar = new JProgressBar(0, 100);</span>
<span class="nc" id="L90"> progressBar.setStringPainted(true);</span>
<span class="nc" id="L91"> progressBar.setPreferredSize(new Dimension(300, 25));</span>
<span class="nc" id="L92"> gbc.gridy = 3;</span>
<span class="nc" id="L93"> mainPanel.add(progressBar, gbc);</span>
// Set dialog properties
<span class="nc" id="L96"> setContentPane(mainPanel);</span>
<span class="nc" id="L97"> setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);</span>
<span class="nc" id="L98"> setResizable(false);</span>
<span class="nc" id="L99"> setUndecorated(false);</span>
// Set size and position
<span class="nc" id="L102"> setSize(UIScaling.scaleWidth(400), UIScaling.scaleHeight(200));</span>
<span class="nc" id="L104"> setLocationRelativeTo(parent);</span>
<span class="nc" id="L105"> setAlwaysOnTop(true);</span>
<span class="nc" id="L106"> setProgress(0);</span>
<span class="nc" id="L107"> setStatus(&quot;Starting...&quot;);</span>
<span class="nc" id="L109"> log.info(</span>
&quot;LoadingWindow initialization completed in {}ms&quot;,
<span class="nc" id="L111"> System.currentTimeMillis() - startTime);</span>
<span class="nc" id="L112"> }</span>
private void checkAndRefreshExplorer() {
<span class="nc bnc" id="L115" title="All 2 branches missed."> if (!IS_WINDOWS) {</span>
<span class="nc" id="L116"> return;</span>
}
<span class="nc bnc" id="L118" title="All 2 branches missed."> if (timeAt90Percent == -1) {</span>
<span class="nc" id="L119"> timeAt90Percent = System.currentTimeMillis();</span>
<span class="nc" id="L120"> stuckTimer =</span>
new Timer(
1000,
e -&gt; {
<span class="nc" id="L124"> long currentTime = System.currentTimeMillis();</span>
<span class="nc bnc" id="L125" title="All 2 branches missed."> if (currentTime - timeAt90Percent &gt; stuckThreshold) {</span>
try {
<span class="nc" id="L127"> log.debug(</span>
&quot;Attempting Windows explorer refresh due to 90% stuck state&quot;);
<span class="nc" id="L129"> String currentDir = System.getProperty(&quot;user.dir&quot;);</span>
// Store current explorer PIDs before we start new one
<span class="nc" id="L132"> Set&lt;String&gt; existingPids = new HashSet&lt;&gt;();</span>
<span class="nc" id="L133"> ProcessBuilder listExplorer =</span>
new ProcessBuilder(
&quot;cmd&quot;,
&quot;/c&quot;,
&quot;wmic&quot;,
&quot;process&quot;,
&quot;where&quot;,
&quot;name='explorer.exe'&quot;,
&quot;get&quot;,
&quot;ProcessId&quot;,
&quot;/format:csv&quot;);
<span class="nc" id="L144"> Process process = listExplorer.start();</span>
<span class="nc" id="L145"> BufferedReader reader =</span>
new BufferedReader(
new InputStreamReader(
<span class="nc" id="L148"> process.getInputStream()));</span>
String line;
<span class="nc" id="L150"> while ((line =</span>
<span class="nc bnc" id="L151" title="All 2 branches missed."> BoundedLineReader.readLine(</span>
reader, 5_000_000))
!= null) {
<span class="nc bnc" id="L154" title="All 2 branches missed."> if (line.matches(&quot;.*\\d+.*&quot;)) { // Contains numbers</span>
<span class="nc" id="L155"> String[] parts = line.trim().split(&quot;,&quot;);</span>
<span class="nc bnc" id="L156" title="All 2 branches missed."> if (parts.length &gt;= 2) {</span>
<span class="nc" id="L157"> existingPids.add(</span>
<span class="nc" id="L158"> parts[parts.length - 1].trim());</span>
}
<span class="nc" id="L160"> }</span>
}
<span class="nc" id="L162"> process.waitFor(2, TimeUnit.SECONDS);</span>
// Start new explorer
<span class="nc" id="L165"> ProcessBuilder pb =</span>
new ProcessBuilder(
&quot;cmd&quot;,
&quot;/c&quot;,
&quot;start&quot;,
&quot;/min&quot;,
&quot;/b&quot;,
&quot;explorer.exe&quot;,
currentDir);
<span class="nc" id="L174"> pb.redirectErrorStream(true);</span>
<span class="nc" id="L175"> explorerProcess = pb.start();</span>
// Schedule cleanup
<span class="nc" id="L178"> Timer cleanupTimer =</span>
new Timer(
2000,
cleanup -&gt; {
try {
// Find new explorer processes
<span class="nc" id="L184"> ProcessBuilder findNewExplorer =</span>
new ProcessBuilder(
&quot;cmd&quot;,
&quot;/c&quot;,
&quot;wmic&quot;,
&quot;process&quot;,
&quot;where&quot;,
&quot;name='explorer.exe'&quot;,
&quot;get&quot;,
&quot;ProcessId&quot;,
&quot;/format:csv&quot;);
<span class="nc" id="L195"> Process newProcess =</span>
<span class="nc" id="L196"> findNewExplorer.start();</span>
<span class="nc" id="L197"> BufferedReader newReader =</span>
new BufferedReader(
new InputStreamReader(
newProcess
<span class="nc" id="L201"> .getInputStream()));</span>
String newLine;
<span class="nc" id="L203"> while ((newLine =</span>
BoundedLineReader
<span class="nc bnc" id="L205" title="All 2 branches missed."> .readLine(</span>
newReader,
5_000_000))
!= null) {
<span class="nc bnc" id="L209" title="All 2 branches missed."> if (newLine.matches(</span>
&quot;.*\\d+.*&quot;)) {
<span class="nc" id="L211"> String[] parts =</span>
<span class="nc" id="L212"> newLine.trim()</span>
<span class="nc" id="L213"> .split(&quot;,&quot;);</span>
<span class="nc bnc" id="L214" title="All 2 branches missed."> if (parts.length &gt;= 2) {</span>
<span class="nc" id="L215"> String pid =</span>
parts[
parts.length
- 1]
<span class="nc" id="L219"> .trim();</span>
<span class="nc" id="L220"> if (!existingPids</span>
<span class="nc bnc" id="L221" title="All 2 branches missed."> .contains(</span>
pid)) {
<span class="nc" id="L223"> log.debug(</span>
&quot;Found new explorer.exe with PID: &quot;
+ pid);
ProcessBuilder
<span class="nc" id="L227"> killProcess =</span>
new ProcessBuilder(
&quot;taskkill&quot;,
&quot;/PID&quot;,
pid,
&quot;/F&quot;);
<span class="nc" id="L233"> killProcess</span>
<span class="nc" id="L234"> .redirectErrorStream(</span>
true);
<span class="nc" id="L236"> Process killResult =</span>
killProcess
<span class="nc" id="L238"> .start();</span>
<span class="nc" id="L239"> killResult.waitFor(</span>
2,
TimeUnit
.SECONDS);
<span class="nc" id="L243"> log.debug(</span>
&quot;Explorer process terminated: &quot;
+ pid);
}
}
<span class="nc" id="L248"> }</span>
}
<span class="nc" id="L250"> newProcess.waitFor(</span>
2, TimeUnit.SECONDS);
<span class="nc" id="L252"> } catch (Exception ex) {</span>
<span class="nc" id="L253"> log.error(</span>
&quot;Error cleaning up Windows explorer process&quot;,
ex);
<span class="nc" id="L256"> }</span>
<span class="nc" id="L257"> });</span>
<span class="nc" id="L258"> cleanupTimer.setRepeats(false);</span>
<span class="nc" id="L259"> cleanupTimer.start();</span>
<span class="nc" id="L260"> stuckTimer.stop();</span>
<span class="nc" id="L261"> } catch (Exception ex) {</span>
<span class="nc" id="L262"> log.error(&quot;Error refreshing Windows explorer&quot;, ex);</span>
<span class="nc" id="L263"> }</span>
}
<span class="nc" id="L265"> });</span>
<span class="nc" id="L266"> stuckTimer.setRepeats(true);</span>
<span class="nc" id="L267"> stuckTimer.start();</span>
}
<span class="nc" id="L269"> }</span>
public void setProgress(final int progress) {
<span class="nc" id="L272"> SwingUtilities.invokeLater(</span>
() -&gt; {
try {
<span class="nc" id="L275"> int validProgress = Math.min(Math.max(progress, 0), 100);</span>
<span class="nc" id="L276"> log.info(</span>
&quot;Setting progress to {}% at {}ms since start&quot;,
<span class="nc" id="L278"> validProgress, System.currentTimeMillis() - startTime);</span>
// Log additional details when near 90%
<span class="nc bnc" id="L281" title="All 4 branches missed."> if (validProgress &gt;= 85 &amp;&amp; validProgress &lt;= 95) {</span>
<span class="nc" id="L282"> log.info(</span>
&quot;Near 90% progress - Current status: {}, Window visible: {}, &quot;
+ &quot;Progress bar responding: {}, Memory usage: {}MB&quot;,
<span class="nc" id="L285"> statusLabel.getText(),</span>
<span class="nc" id="L286"> isVisible(),</span>
<span class="nc" id="L287"> progressBar.isEnabled(),</span>
<span class="nc" id="L288"> Runtime.getRuntime().totalMemory() / (1024 * 1024));</span>
// Add thread state logging
<span class="nc" id="L291"> Thread currentThread = Thread.currentThread();</span>
<span class="nc" id="L292"> log.info(</span>
&quot;Current thread state - Name: {}, State: {}, Priority: {}&quot;,
<span class="nc" id="L294"> currentThread.getName(),</span>
<span class="nc" id="L295"> currentThread.getState(),</span>
<span class="nc" id="L296"> currentThread.getPriority());</span>
<span class="nc bnc" id="L298" title="All 4 branches missed."> if (validProgress &gt;= 90 &amp;&amp; validProgress &lt; 95) {</span>
<span class="nc" id="L299"> checkAndRefreshExplorer();</span>
} else {
// Reset the timer if we move past 95%
<span class="nc bnc" id="L302" title="All 2 branches missed."> if (validProgress &gt;= 95) {</span>
<span class="nc bnc" id="L303" title="All 2 branches missed."> if (stuckTimer != null) {</span>
<span class="nc" id="L304"> stuckTimer.stop();</span>
}
<span class="nc" id="L306"> timeAt90Percent = -1;</span>
}
}
}
<span class="nc" id="L311"> progressBar.setValue(validProgress);</span>
<span class="nc" id="L312"> progressBar.setString(validProgress + &quot;%&quot;);</span>
<span class="nc" id="L313"> mainPanel.revalidate();</span>
<span class="nc" id="L314"> mainPanel.repaint();</span>
<span class="nc" id="L315"> } catch (Exception e) {</span>
<span class="nc" id="L316"> log.error(&quot;Error updating progress to &quot; + progress, e);</span>
<span class="nc" id="L317"> }</span>
<span class="nc" id="L318"> });</span>
<span class="nc" id="L319"> }</span>
public void setStatus(final String status) {
<span class="nc" id="L322"> log.info(</span>
&quot;Status update at {}ms - Setting status to: {}&quot;,
<span class="nc" id="L324"> System.currentTimeMillis() - startTime,</span>
status);
<span class="nc" id="L327"> SwingUtilities.invokeLater(</span>
() -&gt; {
try {
<span class="nc bnc" id="L330" title="All 2 branches missed."> String validStatus = status != null ? status : &quot;&quot;;</span>
<span class="nc" id="L331"> statusLabel.setText(validStatus);</span>
// Log UI state when status changes
<span class="nc" id="L334"> log.info(</span>
&quot;UI State - Window visible: {}, Progress: {}%, Status: {}&quot;,
<span class="nc" id="L336"> isVisible(), progressBar.getValue(), validStatus);</span>
<span class="nc" id="L338"> mainPanel.revalidate();</span>
<span class="nc" id="L339"> mainPanel.repaint();</span>
<span class="nc" id="L340"> } catch (Exception e) {</span>
<span class="nc" id="L341"> log.error(&quot;Error updating status to: &quot; + status, e);</span>
<span class="nc" id="L342"> }</span>
<span class="nc" id="L343"> });</span>
<span class="nc" id="L344"> }</span>
@Override
public void dispose() {
<span class="nc" id="L348"> log.info(&quot;LoadingWindow disposing after {}ms&quot;, System.currentTimeMillis() - startTime);</span>
<span class="nc" id="L349"> super.dispose();</span>
<span class="nc" id="L350"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>stirling.software.SPDF.UI.impl</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb', 'coveragetable'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="index.html" class="el_class">Classes</a><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <span class="el_package">stirling.software.SPDF.UI.impl</span></div><h1>stirling.software.SPDF.UI.impl</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td><td class="sortable ctr1" id="l" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="m" onclick="toggleSort(this)">Classes</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">1,577 of 1,577</td><td class="ctr2">0%</td><td class="bar">96 of 96</td><td class="ctr2">0%</td><td class="ctr1">96</td><td class="ctr2">96</td><td class="ctr1">429</td><td class="ctr2">429</td><td class="ctr1">46</td><td class="ctr2">46</td><td class="ctr1">8</td><td class="ctr2">8</td></tr></tfoot><tbody><tr><td id="a0"><a href="DesktopBrowser.java.html" class="el_source">DesktopBrowser.java</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="791" alt="791"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="58" alt="58"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">67</td><td class="ctr2" id="g0">67</td><td class="ctr1" id="h0">256</td><td class="ctr2" id="i0">256</td><td class="ctr1" id="j0">36</td><td class="ctr2" id="k0">36</td><td class="ctr1" id="l0">7</td><td class="ctr2" id="m0">7</td></tr><tr><td id="a1"><a href="LoadingWindow.java.html" class="el_source">LoadingWindow.java</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="119" height="10" title="786" alt="786"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"><img src="../jacoco-resources/redbar.gif" width="78" height="10" title="38" alt="38"/></td><td class="ctr2" id="e1">0%</td><td class="ctr1" id="f1">29</td><td class="ctr2" id="g1">29</td><td class="ctr1" id="h1">173</td><td class="ctr2" id="i1">173</td><td class="ctr1" id="j1">10</td><td class="ctr2" id="k1">10</td><td class="ctr1" id="l1">1</td><td class="ctr2" id="m1">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>ShowAdminInterface</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.config.interfaces</a> &gt; <span class="el_class">ShowAdminInterface</span></div><h1>ShowAdminInterface</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">2 of 2</td><td class="ctr2">0%</td><td class="bar">0 of 0</td><td class="ctr2">n/a</td><td class="ctr1">1</td><td class="ctr2">1</td><td class="ctr1">1</td><td class="ctr2">1</td><td class="ctr1">1</td><td class="ctr2">1</td></tr></tfoot><tbody><tr><td id="a0"><a href="ShowAdminInterface.java.html#L5" class="el_method">getShowUpdateOnlyAdmins()</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="2" alt="2"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"/><td class="ctr2" id="e0">n/a</td><td class="ctr1" id="f0">1</td><td class="ctr2" id="g0">1</td><td class="ctr1" id="h0">1</td><td class="ctr2" id="i0">1</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>ShowAdminInterface.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.interfaces</a> &gt; <span class="el_source">ShowAdminInterface.java</span></div><h1>ShowAdminInterface.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.interfaces;
public interface ShowAdminInterface {
default boolean getShowUpdateOnlyAdmins() {
<span class="nc" id="L5"> return true;</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>stirling.software.SPDF.config.interfaces</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb', 'coveragetable'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="index.source.html" class="el_source">Source Files</a><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <span class="el_package">stirling.software.SPDF.config.interfaces</span></div><h1>stirling.software.SPDF.config.interfaces</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td><td class="sortable ctr1" id="l" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="m" onclick="toggleSort(this)">Classes</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">2 of 2</td><td class="ctr2">0%</td><td class="bar">0 of 0</td><td class="ctr2">n/a</td><td class="ctr1">1</td><td class="ctr2">1</td><td class="ctr1">1</td><td class="ctr2">1</td><td class="ctr1">1</td><td class="ctr2">1</td><td class="ctr1">1</td><td class="ctr2">1</td></tr></tfoot><tbody><tr><td id="a0"><a href="ShowAdminInterface.html" class="el_class">ShowAdminInterface</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="2" alt="2"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"/><td class="ctr2" id="e0">n/a</td><td class="ctr1" id="f0">1</td><td class="ctr2" id="g0">1</td><td class="ctr1" id="h0">1</td><td class="ctr2" id="i0">1</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td><td class="ctr1" id="l0">1</td><td class="ctr2" id="m0">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>stirling.software.SPDF.config.interfaces</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb', 'coveragetable'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="index.html" class="el_class">Classes</a><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <span class="el_package">stirling.software.SPDF.config.interfaces</span></div><h1>stirling.software.SPDF.config.interfaces</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td><td class="sortable ctr1" id="l" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="m" onclick="toggleSort(this)">Classes</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">2 of 2</td><td class="ctr2">0%</td><td class="bar">0 of 0</td><td class="ctr2">n/a</td><td class="ctr1">1</td><td class="ctr2">1</td><td class="ctr1">1</td><td class="ctr2">1</td><td class="ctr1">1</td><td class="ctr2">1</td><td class="ctr1">1</td><td class="ctr2">1</td></tr></tfoot><tbody><tr><td id="a0"><a href="ShowAdminInterface.java.html" class="el_source">ShowAdminInterface.java</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="2" alt="2"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"/><td class="ctr2" id="e0">n/a</td><td class="ctr1" id="f0">1</td><td class="ctr2" id="g0">1</td><td class="ctr1" id="h0">1</td><td class="ctr2" id="i0">1</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td><td class="ctr1" id="l0">1</td><td class="ctr2" id="m0">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DatabaseConfig.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.database</a> &gt; <span class="el_source">DatabaseConfig.java</span></div><h1>DatabaseConfig.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.database;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
<span class="nc" id="L17">@Slf4j</span>
@Getter
@Configuration
public class DatabaseConfig {
public final String DATASOURCE_DEFAULT_URL;
public static final String DATASOURCE_URL_TEMPLATE = &quot;jdbc:%s://%s:%4d/%s&quot;;
public static final String DEFAULT_DRIVER = &quot;org.h2.Driver&quot;;
public static final String DEFAULT_USERNAME = &quot;sa&quot;;
public static final String POSTGRES_DRIVER = &quot;org.postgresql.Driver&quot;;
private final ApplicationProperties applicationProperties;
private final boolean runningProOrHigher;
public DatabaseConfig(
ApplicationProperties applicationProperties,
<span class="nc" id="L34"> @Qualifier(&quot;runningProOrHigher&quot;) boolean runningProOrHigher) {</span>
<span class="nc" id="L35"> DATASOURCE_DEFAULT_URL =</span>
&quot;jdbc:h2:file:&quot;
<span class="nc" id="L37"> + InstallationPathConfig.getConfigPath()</span>
+ &quot;stirling-pdf-DB-2.3.232;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE&quot;;
<span class="nc" id="L39"> log.debug(&quot;Database URL: {}&quot;, DATASOURCE_DEFAULT_URL);</span>
<span class="nc" id="L40"> this.applicationProperties = applicationProperties;</span>
<span class="nc" id="L41"> this.runningProOrHigher = runningProOrHigher;</span>
<span class="nc" id="L42"> }</span>
/**
* Creates the &lt;code&gt;DataSource&lt;/code&gt; for the connection to the DB. If &lt;code&gt;useDefault&lt;/code&gt;
* is set to &lt;code&gt;true&lt;/code&gt;, it will use the default H2 DB. If it is set to &lt;code&gt;false
* &lt;/code&gt;, it will use the user's custom configuration set in the settings.yml.
*
* @return a &lt;code&gt;DataSource&lt;/code&gt; using the configuration settings in the settings.yml
* @throws UnsupportedProviderException if the type of database selected is not supported
*/
@Bean
@Qualifier(&quot;dataSource&quot;)
public DataSource dataSource() throws UnsupportedProviderException {
<span class="nc" id="L55"> DataSourceBuilder&lt;?&gt; dataSourceBuilder = DataSourceBuilder.create();</span>
<span class="nc bnc" id="L57" title="All 2 branches missed."> if (!runningProOrHigher) {</span>
<span class="nc" id="L58"> return useDefaultDataSource(dataSourceBuilder);</span>
}
<span class="nc" id="L61"> ApplicationProperties.System system = applicationProperties.getSystem();</span>
<span class="nc" id="L62"> ApplicationProperties.Datasource datasource = system.getDatasource();</span>
<span class="nc bnc" id="L64" title="All 2 branches missed."> if (!datasource.isEnableCustomDatabase()) {</span>
<span class="nc" id="L65"> return useDefaultDataSource(dataSourceBuilder);</span>
}
<span class="nc" id="L68"> log.info(&quot;Using custom database configuration&quot;);</span>
<span class="nc bnc" id="L70" title="All 2 branches missed."> if (!datasource.getCustomDatabaseUrl().isBlank()) {</span>
<span class="nc bnc" id="L71" title="All 2 branches missed."> if (datasource.getCustomDatabaseUrl().contains(&quot;postgresql&quot;)) {</span>
<span class="nc" id="L72"> dataSourceBuilder.driverClassName(POSTGRES_DRIVER);</span>
}
<span class="nc" id="L75"> dataSourceBuilder.url(datasource.getCustomDatabaseUrl());</span>
} else {
<span class="nc" id="L77"> dataSourceBuilder.driverClassName(getDriverClassName(datasource.getType()));</span>
<span class="nc" id="L78"> dataSourceBuilder.url(</span>
<span class="nc" id="L79"> generateCustomDataSourceUrl(</span>
<span class="nc" id="L80"> datasource.getType(),</span>
<span class="nc" id="L81"> datasource.getHostName(),</span>
<span class="nc" id="L82"> datasource.getPort(),</span>
<span class="nc" id="L83"> datasource.getName()));</span>
}
<span class="nc" id="L85"> dataSourceBuilder.username(datasource.getUsername());</span>
<span class="nc" id="L86"> dataSourceBuilder.password(datasource.getPassword());</span>
<span class="nc" id="L88"> return dataSourceBuilder.build();</span>
}
private DataSource useDefaultDataSource(DataSourceBuilder&lt;?&gt; dataSourceBuilder) {
<span class="nc" id="L92"> log.info(&quot;Using default H2 database&quot;);</span>
<span class="nc" id="L94"> dataSourceBuilder.url(DATASOURCE_DEFAULT_URL);</span>
<span class="nc" id="L95"> dataSourceBuilder.username(DEFAULT_USERNAME);</span>
<span class="nc" id="L97"> return dataSourceBuilder.build();</span>
}
/**
* Generate the URL the &lt;code&gt;DataSource&lt;/code&gt; will use to connect to the database
*
* @param dataSourceType the type of the database
* @param hostname the host name
* @param port the port number to use for the database
* @param dataSourceName the name the database to connect to
* @return the &lt;code&gt;DataSource&lt;/code&gt; URL
*/
private String generateCustomDataSourceUrl(
String dataSourceType, String hostname, Integer port, String dataSourceName) {
<span class="nc" id="L111"> return DATASOURCE_URL_TEMPLATE.formatted(dataSourceType, hostname, port, dataSourceName);</span>
}
/**
* Selects the database driver based on the type of database chosen.
*
* @param driverName the type of the driver (e.g. 'h2', 'postgresql')
* @return the fully qualified driver for the database chosen
* @throws UnsupportedProviderException when an unsupported database is selected
*/
private String getDriverClassName(String driverName) throws UnsupportedProviderException {
try {
<span class="nc" id="L123"> ApplicationProperties.Driver driver =</span>
<span class="nc" id="L124"> ApplicationProperties.Driver.valueOf(driverName.toUpperCase());</span>
<span class="nc bnc" id="L126" title="All 3 branches missed."> switch (driver) {</span>
case H2 -&gt; {
<span class="nc" id="L128"> log.debug(&quot;H2 driver selected&quot;);</span>
<span class="nc" id="L129"> return DEFAULT_DRIVER;</span>
}
case POSTGRESQL -&gt; {
<span class="nc" id="L132"> log.debug(&quot;Postgres driver selected&quot;);</span>
<span class="nc" id="L133"> return POSTGRES_DRIVER;</span>
}
default -&gt; {
<span class="nc" id="L136"> log.warn(&quot;{} driver selected&quot;, driverName);</span>
<span class="nc" id="L137"> throw new UnsupportedProviderException(</span>
driverName + &quot; is not currently supported&quot;);
}
}
<span class="nc" id="L141"> } catch (IllegalArgumentException e) {</span>
<span class="nc" id="L142"> log.warn(&quot;Unknown driver: {}&quot;, driverName);</span>
<span class="nc" id="L143"> throw new UnsupportedProviderException(driverName + &quot; is not currently supported&quot;);</span>
}
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,318 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DatabaseService.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.database</a> &gt; <span class="el_source">DatabaseService.java</span></div><h1>DatabaseService.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.database;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.init.CannotReadScriptException;
import org.springframework.jdbc.datasource.init.ScriptException;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.exception.BackupNotFoundException;
import stirling.software.SPDF.utils.FileInfo;
<span class="nc" id="L36">@Slf4j</span>
@Service
public class DatabaseService implements DatabaseInterface {
public static final String BACKUP_PREFIX = &quot;backup_&quot;;
public static final String SQL_SUFFIX = &quot;.sql&quot;;
private final Path BACKUP_DIR;
private final ApplicationProperties applicationProperties;
private final DataSource dataSource;
<span class="nc" id="L47"> public DatabaseService(ApplicationProperties applicationProperties, DataSource dataSource) {</span>
<span class="nc" id="L48"> this.BACKUP_DIR =</span>
<span class="nc" id="L49"> Paths.get(InstallationPathConfig.getConfigPath(), &quot;db&quot;, &quot;backup&quot;).normalize();</span>
<span class="nc" id="L50"> this.applicationProperties = applicationProperties;</span>
<span class="nc" id="L51"> this.dataSource = dataSource;</span>
<span class="nc" id="L52"> }</span>
/**
* Checks if there is at least one backup. First checks if the directory exists, then checks if
* there are backup scripts within the directory
*
* @return true if there are backup scripts, false if there are not
*/
@Override
public boolean hasBackup() {
<span class="nc" id="L62"> createBackupDirectory();</span>
<span class="nc bnc" id="L64" title="All 2 branches missed."> if (Files.exists(BACKUP_DIR)) {</span>
<span class="nc bnc" id="L65" title="All 2 branches missed."> return !getBackupList().isEmpty();</span>
}
<span class="nc" id="L68"> return false;</span>
}
/**
* Read the backup directory and filter for files with the prefix &quot;backup_&quot; and suffix &quot;.sql&quot;
*
* @return a &lt;code&gt;List&lt;/code&gt; of backup files
*/
@Override
public List&lt;FileInfo&gt; getBackupList() {
<span class="nc" id="L78"> List&lt;FileInfo&gt; backupFiles = new ArrayList&lt;&gt;();</span>
<span class="nc bnc" id="L80" title="All 2 branches missed."> if (isH2Database()) {</span>
<span class="nc" id="L81"> createBackupDirectory();</span>
<span class="nc" id="L83"> try (DirectoryStream&lt;Path&gt; stream =</span>
<span class="nc" id="L84"> Files.newDirectoryStream(</span>
BACKUP_DIR,
path -&gt;
<span class="nc bnc" id="L87" title="All 2 branches missed."> path.getFileName().toString().startsWith(BACKUP_PREFIX)</span>
<span class="nc" id="L88"> &amp;&amp; path.getFileName()</span>
<span class="nc" id="L89"> .toString()</span>
<span class="nc bnc" id="L90" title="All 2 branches missed."> .endsWith(SQL_SUFFIX))) {</span>
<span class="nc bnc" id="L91" title="All 2 branches missed."> for (Path entry : stream) {</span>
<span class="nc" id="L92"> BasicFileAttributes attrs =</span>
<span class="nc" id="L93"> Files.readAttributes(entry, BasicFileAttributes.class);</span>
<span class="nc" id="L94"> LocalDateTime modificationDate =</span>
<span class="nc" id="L95"> LocalDateTime.ofInstant(</span>
<span class="nc" id="L96"> attrs.lastModifiedTime().toInstant(), ZoneId.systemDefault());</span>
<span class="nc" id="L97"> LocalDateTime creationDate =</span>
<span class="nc" id="L98"> LocalDateTime.ofInstant(</span>
<span class="nc" id="L99"> attrs.creationTime().toInstant(), ZoneId.systemDefault());</span>
<span class="nc" id="L100"> long fileSize = attrs.size();</span>
<span class="nc" id="L101"> backupFiles.add(</span>
new FileInfo(
<span class="nc" id="L103"> entry.getFileName().toString(),</span>
<span class="nc" id="L104"> entry.toString(),</span>
modificationDate,
fileSize,
creationDate));
<span class="nc" id="L108"> }</span>
<span class="nc" id="L109"> } catch (IOException e) {</span>
<span class="nc" id="L110"> log.error(&quot;Error reading backup directory: {}&quot;, e.getMessage(), e);</span>
<span class="nc" id="L111"> }</span>
}
<span class="nc" id="L114"> return backupFiles;</span>
}
private void createBackupDirectory() {
<span class="nc bnc" id="L118" title="All 2 branches missed."> if (!Files.exists(BACKUP_DIR)) {</span>
try {
<span class="nc" id="L120"> Files.createDirectories(BACKUP_DIR);</span>
<span class="nc" id="L121"> log.debug(&quot;create backup directory: {}&quot;, BACKUP_DIR);</span>
<span class="nc" id="L122"> } catch (IOException e) {</span>
<span class="nc" id="L123"> log.error(&quot;Error create backup directory: {}&quot;, e.getMessage(), e);</span>
<span class="nc" id="L124"> }</span>
}
<span class="nc" id="L126"> }</span>
@Override
public void importDatabase() {
<span class="nc bnc" id="L130" title="All 2 branches missed."> if (!hasBackup()) throw new BackupNotFoundException(&quot;No backup scripts were found.&quot;);</span>
<span class="nc" id="L132"> List&lt;FileInfo&gt; backupList = this.getBackupList();</span>
<span class="nc" id="L133"> backupList.sort(Comparator.comparing(FileInfo::getModificationDate).reversed());</span>
<span class="nc" id="L135"> Path latestExport = Paths.get(backupList.get(0).getFilePath());</span>
<span class="nc" id="L137"> executeDatabaseScript(latestExport);</span>
<span class="nc" id="L138"> }</span>
/** Imports a database backup from the specified file. */
public boolean importDatabaseFromUI(String fileName) {
try {
<span class="nc" id="L143"> importDatabaseFromUI(getBackupFilePath(fileName));</span>
<span class="nc" id="L144"> return true;</span>
<span class="nc" id="L145"> } catch (IOException e) {</span>
<span class="nc" id="L146"> log.error(</span>
&quot;Error importing database from file: {}, message: {}&quot;,
fileName,
<span class="nc" id="L149"> e.getMessage(),</span>
<span class="nc" id="L150"> e.getCause());</span>
<span class="nc" id="L151"> return false;</span>
}
}
/** Imports a database backup from the specified path. */
public boolean importDatabaseFromUI(Path tempTemplatePath) throws IOException {
<span class="nc" id="L157"> executeDatabaseScript(tempTemplatePath);</span>
<span class="nc" id="L158"> LocalDateTime dateNow = LocalDateTime.now();</span>
<span class="nc" id="L159"> DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern(&quot;yyyyMMddHHmm&quot;);</span>
<span class="nc" id="L160"> Path insertOutputFilePath =</span>
<span class="nc" id="L161"> this.getBackupFilePath(</span>
<span class="nc" id="L162"> BACKUP_PREFIX + &quot;user_&quot; + dateNow.format(myFormatObj) + SQL_SUFFIX);</span>
<span class="nc" id="L163"> Files.copy(tempTemplatePath, insertOutputFilePath);</span>
<span class="nc" id="L164"> Files.deleteIfExists(tempTemplatePath);</span>
<span class="nc" id="L165"> return true;</span>
}
@Override
public void exportDatabase() {
<span class="nc" id="L170"> List&lt;FileInfo&gt; filteredBackupList =</span>
<span class="nc" id="L171"> this.getBackupList().stream()</span>
<span class="nc bnc" id="L172" title="All 2 branches missed."> .filter(backup -&gt; !backup.getFileName().startsWith(BACKUP_PREFIX + &quot;user_&quot;))</span>
<span class="nc" id="L173"> .collect(Collectors.toList());</span>
<span class="nc bnc" id="L175" title="All 2 branches missed."> if (filteredBackupList.size() &gt; 5) {</span>
<span class="nc" id="L176"> deleteOldestBackup(filteredBackupList);</span>
}
<span class="nc" id="L179"> LocalDateTime dateNow = LocalDateTime.now();</span>
<span class="nc" id="L180"> DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern(&quot;yyyyMMddHHmm&quot;);</span>
<span class="nc" id="L181"> Path insertOutputFilePath =</span>
<span class="nc" id="L182"> this.getBackupFilePath(BACKUP_PREFIX + dateNow.format(myFormatObj) + SQL_SUFFIX);</span>
<span class="nc bnc" id="L184" title="All 2 branches missed."> if (isH2Database()) {</span>
<span class="nc" id="L185"> String query = &quot;SCRIPT SIMPLE COLUMNS DROP to ?;&quot;;</span>
<span class="nc" id="L187"> try (Connection conn = dataSource.getConnection();</span>
<span class="nc" id="L188"> PreparedStatement stmt = conn.prepareStatement(query)) {</span>
<span class="nc" id="L189"> stmt.setString(1, insertOutputFilePath.toString());</span>
<span class="nc" id="L190"> stmt.execute();</span>
<span class="nc" id="L191"> } catch (SQLException e) {</span>
<span class="nc" id="L192"> log.error(&quot;Error during database export: {}&quot;, e.getMessage(), e);</span>
<span class="nc" id="L193"> } catch (CannotReadScriptException e) {</span>
<span class="nc" id="L194"> log.error(&quot;Error during database export: File {} not found&quot;, insertOutputFilePath);</span>
<span class="nc" id="L195"> }</span>
<span class="nc" id="L197"> log.info(&quot;Database export completed: {}&quot;, insertOutputFilePath);</span>
}
<span class="nc" id="L199"> }</span>
private static void deleteOldestBackup(List&lt;FileInfo&gt; filteredBackupList) {
try {
<span class="nc" id="L203"> filteredBackupList.sort(</span>
<span class="nc" id="L204"> Comparator.comparing(</span>
<span class="nc" id="L205"> p -&gt; p.getFileName().substring(7, p.getFileName().length() - 4)));</span>
<span class="nc" id="L207"> FileInfo oldestFile = filteredBackupList.get(0);</span>
<span class="nc" id="L208"> Files.deleteIfExists(Paths.get(oldestFile.getFilePath()));</span>
<span class="nc" id="L209"> log.info(&quot;Deleted oldest backup: {}&quot;, oldestFile.getFileName());</span>
<span class="nc" id="L210"> } catch (IOException e) {</span>
<span class="nc" id="L211"> log.error(&quot;Unable to delete oldest backup, message: {}&quot;, e.getMessage(), e);</span>
<span class="nc" id="L212"> }</span>
<span class="nc" id="L213"> }</span>
/**
* Retrieves the H2 database version.
*
* @return &lt;code&gt;String&lt;/code&gt; of the H2 version
*/
public String getH2Version() {
<span class="nc" id="L221"> String version = &quot;Unknown&quot;;</span>
<span class="nc bnc" id="L223" title="All 2 branches missed."> if (isH2Database()) {</span>
<span class="nc" id="L224"> try (Connection conn = dataSource.getConnection()) {</span>
<span class="nc" id="L225"> try (Statement stmt = conn.createStatement();</span>
<span class="nc" id="L226"> ResultSet rs = stmt.executeQuery(&quot;SELECT H2VERSION() AS version&quot;)) {</span>
<span class="nc bnc" id="L227" title="All 2 branches missed."> if (rs.next()) {</span>
<span class="nc" id="L228"> version = rs.getString(&quot;version&quot;);</span>
<span class="nc" id="L229"> log.info(&quot;H2 Database Version: {}&quot;, version);</span>
}
}
<span class="nc" id="L232"> } catch (SQLException e) {</span>
<span class="nc" id="L233"> log.error(&quot;Error retrieving H2 version: {}&quot;, e.getMessage(), e);</span>
<span class="nc" id="L234"> }</span>
}
<span class="nc" id="L237"> return version;</span>
}
private boolean isH2Database() {
<span class="nc" id="L241"> ApplicationProperties.Datasource datasource =</span>
<span class="nc" id="L242"> applicationProperties.getSystem().getDatasource();</span>
<span class="nc bnc" id="L243" title="All 2 branches missed."> return !datasource.isEnableCustomDatabase()</span>
<span class="nc bnc" id="L244" title="All 2 branches missed."> || datasource.getType().equalsIgnoreCase(ApplicationProperties.Driver.H2.name());</span>
}
/**
* Deletes a backup file.
*
* @return true if successful, false if not
*/
public boolean deleteBackupFile(String fileName) throws IOException {
<span class="nc bnc" id="L253" title="All 2 branches missed."> if (!isValidFileName(fileName)) {</span>
<span class="nc" id="L254"> log.error(&quot;Invalid file name: {}&quot;, fileName);</span>
<span class="nc" id="L255"> return false;</span>
}
<span class="nc" id="L257"> Path filePath = this.getBackupFilePath(fileName);</span>
<span class="nc bnc" id="L258" title="All 2 branches missed."> if (Files.deleteIfExists(filePath)) {</span>
<span class="nc" id="L259"> log.info(&quot;Deleted backup file: {}&quot;, fileName);</span>
<span class="nc" id="L260"> return true;</span>
} else {
<span class="nc" id="L262"> log.error(&quot;File not found or could not be deleted: {}&quot;, fileName);</span>
<span class="nc" id="L263"> return false;</span>
}
}
/**
* Gets the Path for a given backup file name.
*
* @return the &lt;code&gt;Path&lt;/code&gt; object for the given file name
*/
public Path getBackupFilePath(String fileName) {
<span class="nc" id="L273"> createBackupDirectory();</span>
<span class="nc" id="L274"> Path filePath = BACKUP_DIR.resolve(fileName).normalize();</span>
<span class="nc bnc" id="L275" title="All 2 branches missed."> if (!filePath.startsWith(BACKUP_DIR)) {</span>
<span class="nc" id="L276"> throw new SecurityException(&quot;Path traversal detected&quot;);</span>
}
<span class="nc" id="L278"> return filePath;</span>
}
private void executeDatabaseScript(Path scriptPath) {
<span class="nc bnc" id="L282" title="All 2 branches missed."> if (isH2Database()) {</span>
<span class="nc" id="L283"> String query = &quot;RUNSCRIPT from ?;&quot;;</span>
<span class="nc" id="L285"> try (Connection conn = dataSource.getConnection();</span>
<span class="nc" id="L286"> PreparedStatement stmt = conn.prepareStatement(query)) {</span>
<span class="nc" id="L287"> stmt.setString(1, scriptPath.toString());</span>
<span class="nc" id="L288"> stmt.execute();</span>
<span class="nc" id="L289"> } catch (SQLException e) {</span>
<span class="nc" id="L290"> log.error(&quot;Error during database import: {}&quot;, e.getMessage(), e);</span>
<span class="nc" id="L291"> } catch (ScriptException e) {</span>
<span class="nc" id="L292"> log.error(&quot;Error: File {} not found&quot;, scriptPath.toString(), e);</span>
<span class="nc" id="L293"> }</span>
}
<span class="nc" id="L296"> log.info(&quot;Database import completed: {}&quot;, scriptPath);</span>
<span class="nc" id="L297"> }</span>
/**
* Checks for invalid characters or sequences
*
* @return true if it contains no invalid characters, false if it does
*/
private boolean isValidFileName(String fileName) {
<span class="nc bnc" id="L305" title="All 2 branches missed."> return fileName != null</span>
<span class="nc bnc" id="L306" title="All 2 branches missed."> &amp;&amp; !fileName.contains(&quot;..&quot;)</span>
<span class="nc bnc" id="L307" title="All 2 branches missed."> &amp;&amp; !fileName.contains(&quot;/&quot;)</span>
<span class="nc bnc" id="L308" title="All 2 branches missed."> &amp;&amp; !fileName.contains(&quot;\\&quot;)</span>
<span class="nc bnc" id="L309" title="All 2 branches missed."> &amp;&amp; !fileName.contains(&quot;:&quot;)</span>
<span class="nc bnc" id="L310" title="All 2 branches missed."> &amp;&amp; !fileName.contains(&quot;*&quot;)</span>
<span class="nc bnc" id="L311" title="All 2 branches missed."> &amp;&amp; !fileName.contains(&quot;?&quot;)</span>
<span class="nc bnc" id="L312" title="All 2 branches missed."> &amp;&amp; !fileName.contains(&quot;\&quot;&quot;)</span>
<span class="nc bnc" id="L313" title="All 2 branches missed."> &amp;&amp; !fileName.contains(&quot;&lt;&quot;)</span>
<span class="nc bnc" id="L314" title="All 2 branches missed."> &amp;&amp; !fileName.contains(&quot;&gt;&quot;)</span>
<span class="nc bnc" id="L315" title="All 2 branches missed."> &amp;&amp; !fileName.contains(&quot;|&quot;);</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>ScheduledTasks</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.config.security.database</a> &gt; <span class="el_class">ScheduledTasks</span></div><h1>ScheduledTasks</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">10 of 10</td><td class="ctr2">0%</td><td class="bar">0 of 0</td><td class="ctr2">n/a</td><td class="ctr1">2</td><td class="ctr2">2</td><td class="ctr1">5</td><td class="ctr2">5</td><td class="ctr1">2</td><td class="ctr2">2</td></tr></tfoot><tbody><tr><td id="a1"><a href="ScheduledTasks.java.html#L19" class="el_method">ScheduledTasks(DatabaseInterface)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="6" alt="6"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"/><td class="ctr2" id="e0">n/a</td><td class="ctr1" id="f0">1</td><td class="ctr2" id="g0">1</td><td class="ctr1" id="h0">3</td><td class="ctr2" id="i0">3</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a0"><a href="ScheduledTasks.java.html#L25" class="el_method">performBackup()</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="80" height="10" title="4" alt="4"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">2</td><td class="ctr2" id="i1">2</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>ScheduledTasks.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.database</a> &gt; <span class="el_source">ScheduledTasks.java</span></div><h1>ScheduledTasks.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.database;
import java.sql.SQLException;
import org.springframework.context.annotation.Conditional;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
import stirling.software.SPDF.controller.api.H2SQLCondition;
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
@Component
@Conditional(H2SQLCondition.class)
public class ScheduledTasks {
private final DatabaseInterface databaseService;
<span class="nc" id="L19"> public ScheduledTasks(DatabaseInterface databaseService) {</span>
<span class="nc" id="L20"> this.databaseService = databaseService;</span>
<span class="nc" id="L21"> }</span>
@Scheduled(cron = &quot;0 0 0 * * ?&quot;)
public void performBackup() throws SQLException, UnsupportedProviderException {
<span class="nc" id="L25"> databaseService.exportDatabase();</span>
<span class="nc" id="L26"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>stirling.software.SPDF.config.security.database</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb', 'coveragetable'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="index.source.html" class="el_source">Source Files</a><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <span class="el_package">stirling.software.SPDF.config.security.database</span></div><h1>stirling.software.SPDF.config.security.database</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td><td class="sortable ctr1" id="l" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="m" onclick="toggleSort(this)">Classes</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">737 of 737</td><td class="ctr2">0%</td><td class="bar">71 of 71</td><td class="ctr2">0%</td><td class="ctr1">63</td><td class="ctr2">63</td><td class="ctr1">206</td><td class="ctr2">206</td><td class="ctr1">27</td><td class="ctr2">27</td><td class="ctr1">3</td><td class="ctr2">3</td></tr></tfoot><tbody><tr><td id="a1"><a href="DatabaseService.html" class="el_class">DatabaseService</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="551" alt="551"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="60" alt="60"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">49</td><td class="ctr2" id="g0">49</td><td class="ctr1" id="h0">154</td><td class="ctr2" id="i0">154</td><td class="ctr1" id="j0">19</td><td class="ctr2" id="k0">19</td><td class="ctr1" id="l0">1</td><td class="ctr2" id="m0">1</td></tr><tr><td id="a0"><a href="DatabaseConfig.html" class="el_class">DatabaseConfig</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="38" height="10" title="176" alt="176"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"><img src="../jacoco-resources/redbar.gif" width="22" height="10" title="11" alt="11"/></td><td class="ctr2" id="e1">0%</td><td class="ctr1" id="f1">12</td><td class="ctr2" id="g1">12</td><td class="ctr1" id="h1">47</td><td class="ctr2" id="i1">47</td><td class="ctr1" id="j1">6</td><td class="ctr2" id="k1">6</td><td class="ctr1" id="l1">1</td><td class="ctr2" id="m1">1</td></tr><tr><td id="a2"><a href="ScheduledTasks.html" class="el_class">ScheduledTasks</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="2" height="10" title="10" alt="10"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">2</td><td class="ctr2" id="g2">2</td><td class="ctr1" id="h2">5</td><td class="ctr2" id="i2">5</td><td class="ctr1" id="j2">2</td><td class="ctr2" id="k2">2</td><td class="ctr1" id="l2">1</td><td class="ctr2" id="m2">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>stirling.software.SPDF.config.security.database</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb', 'coveragetable'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="index.html" class="el_class">Classes</a><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <span class="el_package">stirling.software.SPDF.config.security.database</span></div><h1>stirling.software.SPDF.config.security.database</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td><td class="sortable ctr1" id="l" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="m" onclick="toggleSort(this)">Classes</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">737 of 737</td><td class="ctr2">0%</td><td class="bar">71 of 71</td><td class="ctr2">0%</td><td class="ctr1">63</td><td class="ctr2">63</td><td class="ctr1">206</td><td class="ctr2">206</td><td class="ctr1">27</td><td class="ctr2">27</td><td class="ctr1">3</td><td class="ctr2">3</td></tr></tfoot><tbody><tr><td id="a1"><a href="DatabaseService.java.html" class="el_source">DatabaseService.java</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="551" alt="551"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="60" alt="60"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">49</td><td class="ctr2" id="g0">49</td><td class="ctr1" id="h0">154</td><td class="ctr2" id="i0">154</td><td class="ctr1" id="j0">19</td><td class="ctr2" id="k0">19</td><td class="ctr1" id="l0">1</td><td class="ctr2" id="m0">1</td></tr><tr><td id="a0"><a href="DatabaseConfig.java.html" class="el_source">DatabaseConfig.java</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="38" height="10" title="176" alt="176"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"><img src="../jacoco-resources/redbar.gif" width="22" height="10" title="11" alt="11"/></td><td class="ctr2" id="e1">0%</td><td class="ctr1" id="f1">12</td><td class="ctr2" id="g1">12</td><td class="ctr1" id="h1">47</td><td class="ctr2" id="i1">47</td><td class="ctr1" id="j1">6</td><td class="ctr2" id="k1">6</td><td class="ctr1" id="l1">1</td><td class="ctr2" id="m1">1</td></tr><tr><td id="a2"><a href="ScheduledTasks.java.html" class="el_source">ScheduledTasks.java</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="2" height="10" title="10" alt="10"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">2</td><td class="ctr2" id="g2">2</td><td class="ctr1" id="h2">5</td><td class="ctr2" id="i2">5</td><td class="ctr1" id="j2">2</td><td class="ctr2" id="k2">2</td><td class="ctr1" id="l2">1</td><td class="ctr2" id="m2">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomOAuth2AuthenticationFailureHandler</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.config.security.oauth2</a> &gt; <span class="el_class">CustomOAuth2AuthenticationFailureHandler</span></div><h1>CustomOAuth2AuthenticationFailureHandler</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">95 of 95</td><td class="ctr2">0%</td><td class="bar">12 of 12</td><td class="ctr2">0%</td><td class="ctr1">9</td><td class="ctr2">9</td><td class="ctr1">25</td><td class="ctr2">25</td><td class="ctr1">3</td><td class="ctr2">3</td></tr></tfoot><tbody><tr><td id="a1"><a href="CustomOAuth2AuthenticationFailureHandler.java.html#L30" class="el_method">onAuthenticationFailure(HttpServletRequest, HttpServletResponse, AuthenticationException)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="88" alt="88"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="12" alt="12"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">7</td><td class="ctr2" id="g0">7</td><td class="ctr1" id="h0">23</td><td class="ctr2" id="i0">23</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a2"><a href="CustomOAuth2AuthenticationFailureHandler.java.html#L19" class="el_method">static {...}</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="5" height="10" title="4" alt="4"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">1</td><td class="ctr2" id="i1">1</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a0"><a href="CustomOAuth2AuthenticationFailureHandler.java.html#L20" class="el_method">CustomOAuth2AuthenticationFailureHandler()</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="4" height="10" title="3" alt="3"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">1</td><td class="ctr2" id="g2">1</td><td class="ctr1" id="h2">1</td><td class="ctr2" id="i2">1</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomOAuth2AuthenticationFailureHandler.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.oauth2</a> &gt; <span class="el_source">CustomOAuth2AuthenticationFailureHandler.java</span></div><h1>CustomOAuth2AuthenticationFailureHandler.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.oauth2;
import java.io.IOException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
<span class="nc" id="L19">@Slf4j</span>
<span class="nc" id="L20">public class CustomOAuth2AuthenticationFailureHandler</span>
extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception)
throws IOException, ServletException {
<span class="nc bnc" id="L30" title="All 2 branches missed."> if (exception instanceof BadCredentialsException) {</span>
<span class="nc" id="L31"> log.error(&quot;BadCredentialsException&quot;, exception);</span>
<span class="nc" id="L32"> getRedirectStrategy().sendRedirect(request, response, &quot;/login?error=badCredentials&quot;);</span>
<span class="nc" id="L33"> return;</span>
}
<span class="nc bnc" id="L35" title="All 2 branches missed."> if (exception instanceof DisabledException) {</span>
<span class="nc" id="L36"> log.error(&quot;User is deactivated: &quot;, exception);</span>
<span class="nc" id="L37"> getRedirectStrategy().sendRedirect(request, response, &quot;/logout?userIsDisabled=true&quot;);</span>
<span class="nc" id="L38"> return;</span>
}
<span class="nc bnc" id="L40" title="All 2 branches missed."> if (exception instanceof LockedException) {</span>
<span class="nc" id="L41"> log.error(&quot;Account locked: &quot;, exception);</span>
<span class="nc" id="L42"> getRedirectStrategy().sendRedirect(request, response, &quot;/logout?error=locked&quot;);</span>
<span class="nc" id="L43"> return;</span>
}
<span class="nc bnc" id="L45" title="All 2 branches missed."> if (exception instanceof OAuth2AuthenticationException oAuth2Exception) {</span>
<span class="nc" id="L46"> OAuth2Error error = oAuth2Exception.getError();</span>
<span class="nc" id="L48"> String errorCode = error.getErrorCode();</span>
<span class="nc bnc" id="L50" title="All 2 branches missed."> if (&quot;Password must not be null&quot;.equals(error.getErrorCode())) {</span>
<span class="nc" id="L51"> errorCode = &quot;userAlreadyExistsWeb&quot;;</span>
}
<span class="nc" id="L54"> log.error(</span>
&quot;OAuth2 Authentication error: {}&quot;,
<span class="nc bnc" id="L56" title="All 2 branches missed."> errorCode != null ? errorCode : exception.getMessage(),</span>
exception);
<span class="nc" id="L58"> getRedirectStrategy().sendRedirect(request, response, &quot;/login?errorOAuth=&quot; + errorCode);</span>
}
<span class="nc" id="L60"> log.error(&quot;Unhandled authentication exception&quot;, exception);</span>
<span class="nc" id="L61"> super.onAuthenticationFailure(request, response, exception);</span>
<span class="nc" id="L62"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomOAuth2AuthenticationSuccessHandler</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.config.security.oauth2</a> &gt; <span class="el_class">CustomOAuth2AuthenticationSuccessHandler</span></div><h1>CustomOAuth2AuthenticationSuccessHandler</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">157 of 157</td><td class="ctr2">0%</td><td class="bar">30 of 30</td><td class="ctr2">0%</td><td class="ctr1">17</td><td class="ctr2">17</td><td class="ctr1">45</td><td class="ctr2">45</td><td class="ctr1">2</td><td class="ctr2">2</td></tr></tfoot><tbody><tr><td id="a1"><a href="CustomOAuth2AuthenticationSuccessHandler.java.html#L47" class="el_method">onAuthenticationSuccess(HttpServletRequest, HttpServletResponse, Authentication)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="145" alt="145"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="30" alt="30"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">16</td><td class="ctr2" id="g0">16</td><td class="ctr1" id="h0">40</td><td class="ctr2" id="i0">40</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a0"><a href="CustomOAuth2AuthenticationSuccessHandler.java.html#L36" class="el_method">CustomOAuth2AuthenticationSuccessHandler(LoginAttemptService, ApplicationProperties, UserService)</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="9" height="10" title="12" alt="12"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">5</td><td class="ctr2" id="i1">5</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomOAuth2AuthenticationSuccessHandler.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.oauth2</a> &gt; <span class="el_source">CustomOAuth2AuthenticationSuccessHandler.java</span></div><h1>CustomOAuth2AuthenticationSuccessHandler.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.oauth2;
import java.io.IOException;
import java.sql.SQLException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.SPDF.model.AuthenticationType;
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
import stirling.software.SPDF.utils.RequestUriUtils;
public class CustomOAuth2AuthenticationSuccessHandler
extends SavedRequestAwareAuthenticationSuccessHandler {
private final LoginAttemptService loginAttemptService;
private final ApplicationProperties applicationProperties;
private final UserService userService;
public CustomOAuth2AuthenticationSuccessHandler(
LoginAttemptService loginAttemptService,
ApplicationProperties applicationProperties,
<span class="nc" id="L36"> UserService userService) {</span>
<span class="nc" id="L37"> this.applicationProperties = applicationProperties;</span>
<span class="nc" id="L38"> this.userService = userService;</span>
<span class="nc" id="L39"> this.loginAttemptService = loginAttemptService;</span>
<span class="nc" id="L40"> }</span>
@Override
public void onAuthenticationSuccess(
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {
<span class="nc" id="L47"> Object principal = authentication.getPrincipal();</span>
<span class="nc" id="L48"> String username = &quot;&quot;;</span>
<span class="nc bnc" id="L50" title="All 2 branches missed."> if (principal instanceof OAuth2User oAuth2User) {</span>
<span class="nc" id="L51"> username = oAuth2User.getName();</span>
<span class="nc bnc" id="L52" title="All 2 branches missed."> } else if (principal instanceof UserDetails detailsUser) {</span>
<span class="nc" id="L53"> username = detailsUser.getUsername();</span>
}
// Get the saved request
<span class="nc" id="L57"> HttpSession session = request.getSession(false);</span>
<span class="nc" id="L58"> String contextPath = request.getContextPath();</span>
SavedRequest savedRequest =
<span class="nc bnc" id="L60" title="All 2 branches missed."> (session != null)</span>
<span class="nc" id="L61"> ? (SavedRequest) session.getAttribute(&quot;SPRING_SECURITY_SAVED_REQUEST&quot;)</span>
<span class="nc" id="L62"> : null;</span>
<span class="nc bnc" id="L64" title="All 2 branches missed."> if (savedRequest != null</span>
<span class="nc bnc" id="L65" title="All 2 branches missed."> &amp;&amp; !RequestUriUtils.isStaticResource(contextPath, savedRequest.getRedirectUrl())) {</span>
// Redirect to the original destination
<span class="nc" id="L67"> super.onAuthenticationSuccess(request, response, authentication);</span>
} else {
<span class="nc" id="L69"> OAUTH2 oAuth = applicationProperties.getSecurity().getOauth2();</span>
<span class="nc bnc" id="L71" title="All 2 branches missed."> if (loginAttemptService.isBlocked(username)) {</span>
<span class="nc bnc" id="L72" title="All 2 branches missed."> if (session != null) {</span>
<span class="nc" id="L73"> session.removeAttribute(&quot;SPRING_SECURITY_SAVED_REQUEST&quot;);</span>
}
<span class="nc" id="L75"> throw new LockedException(</span>
&quot;Your account has been locked due to too many failed login attempts.&quot;);
}
<span class="nc bnc" id="L79" title="All 2 branches missed."> if (userService.isUserDisabled(username)) {</span>
<span class="nc" id="L80"> getRedirectStrategy()</span>
<span class="nc" id="L81"> .sendRedirect(request, response, &quot;/logout?userIsDisabled=true&quot;);</span>
<span class="nc" id="L82"> return;</span>
}
<span class="nc bnc" id="L84" title="All 2 branches missed."> if (userService.usernameExistsIgnoreCase(username)</span>
<span class="nc bnc" id="L85" title="All 2 branches missed."> &amp;&amp; userService.hasPassword(username)</span>
<span class="nc bnc" id="L86" title="All 2 branches missed."> &amp;&amp; !userService.isAuthenticationTypeByUsername(username, AuthenticationType.SSO)</span>
<span class="nc bnc" id="L87" title="All 2 branches missed."> &amp;&amp; oAuth.getAutoCreateUser()) {</span>
<span class="nc" id="L88"> response.sendRedirect(contextPath + &quot;/logout?oAuth2AuthenticationErrorWeb=true&quot;);</span>
<span class="nc" id="L89"> return;</span>
}
try {
<span class="nc bnc" id="L93" title="All 2 branches missed."> if (oAuth.getBlockRegistration()</span>
<span class="nc bnc" id="L94" title="All 2 branches missed."> &amp;&amp; !userService.usernameExistsIgnoreCase(username)) {</span>
<span class="nc" id="L95"> response.sendRedirect(contextPath + &quot;/logout?oAuth2AdminBlockedUser=true&quot;);</span>
<span class="nc" id="L96"> return;</span>
}
<span class="nc bnc" id="L98" title="All 2 branches missed."> if (principal instanceof OAuth2User) {</span>
<span class="nc" id="L99"> userService.processSSOPostLogin(username, oAuth.getAutoCreateUser());</span>
}
<span class="nc" id="L101"> response.sendRedirect(contextPath + &quot;/&quot;);</span>
<span class="nc" id="L102"> } catch (IllegalArgumentException | SQLException | UnsupportedProviderException e) {</span>
<span class="nc" id="L103"> response.sendRedirect(contextPath + &quot;/logout?invalidUsername=true&quot;);</span>
<span class="nc" id="L104"> }</span>
}
<span class="nc" id="L106"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomOAuth2UserService</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.config.security.oauth2</a> &gt; <span class="el_class">CustomOAuth2UserService</span></div><h1>CustomOAuth2UserService</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">113 of 113</td><td class="ctr2">0%</td><td class="bar">6 of 6</td><td class="ctr2">0%</td><td class="ctr1">6</td><td class="ctr2">6</td><td class="ctr1">30</td><td class="ctr2">30</td><td class="ctr1">3</td><td class="ctr2">3</td></tr></tfoot><tbody><tr><td id="a1"><a href="CustomOAuth2UserService.java.html#L46" class="el_method">loadUser(OidcUserRequest)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="92" alt="92"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="6" alt="6"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">4</td><td class="ctr2" id="g0">4</td><td class="ctr1" id="h0">23</td><td class="ctr2" id="i0">23</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a0"><a href="CustomOAuth2UserService.java.html#L26" class="el_method">CustomOAuth2UserService(ApplicationProperties, UserService, LoginAttemptService)</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="22" height="10" title="17" alt="17"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">6</td><td class="ctr2" id="i1">6</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a2"><a href="CustomOAuth2UserService.java.html#L23" class="el_method">static {...}</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="5" height="10" title="4" alt="4"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">1</td><td class="ctr2" id="g2">1</td><td class="ctr1" id="h2">1</td><td class="ctr2" id="i2">1</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomOAuth2UserService.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.oauth2</a> &gt; <span class="el_source">CustomOAuth2UserService.java</span></div><h1>CustomOAuth2UserService.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.oauth2;
import java.util.Optional;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.model.UsernameAttribute;
<span class="nc" id="L23">@Slf4j</span>
public class CustomOAuth2UserService implements OAuth2UserService&lt;OidcUserRequest, OidcUser&gt; {
<span class="nc" id="L26"> private final OidcUserService delegate = new OidcUserService();</span>
private final UserService userService;
private final LoginAttemptService loginAttemptService;
private final ApplicationProperties applicationProperties;
public CustomOAuth2UserService(
ApplicationProperties applicationProperties,
UserService userService,
<span class="nc" id="L37"> LoginAttemptService loginAttemptService) {</span>
<span class="nc" id="L38"> this.applicationProperties = applicationProperties;</span>
<span class="nc" id="L39"> this.userService = userService;</span>
<span class="nc" id="L40"> this.loginAttemptService = loginAttemptService;</span>
<span class="nc" id="L41"> }</span>
@Override
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
try {
<span class="nc" id="L46"> OidcUser user = delegate.loadUser(userRequest);</span>
<span class="nc" id="L47"> OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2();</span>
<span class="nc" id="L48"> UsernameAttribute usernameAttribute =</span>
<span class="nc" id="L49"> UsernameAttribute.valueOf(oauth2.getUseAsUsername().toUpperCase());</span>
<span class="nc" id="L50"> String usernameAttributeKey = usernameAttribute.getName();</span>
// todo: save user by OIDC ID instead of username
<span class="nc" id="L53"> Optional&lt;User&gt; internalUser =</span>
<span class="nc" id="L54"> userService.findByUsernameIgnoreCase(user.getAttribute(usernameAttributeKey));</span>
<span class="nc bnc" id="L56" title="All 2 branches missed."> if (internalUser.isPresent()) {</span>
<span class="nc" id="L57"> String internalUsername = internalUser.get().getUsername();</span>
<span class="nc bnc" id="L58" title="All 2 branches missed."> if (loginAttemptService.isBlocked(internalUsername)) {</span>
<span class="nc" id="L59"> throw new LockedException(</span>
&quot;The account &quot;
+ internalUsername
+ &quot; has been locked due to too many failed login attempts.&quot;);
}
<span class="nc bnc" id="L64" title="All 2 branches missed."> if (userService.hasPassword(usernameAttributeKey)) {</span>
<span class="nc" id="L65"> throw new IllegalArgumentException(&quot;Password must not be null&quot;);</span>
}
}
// Return a new OidcUser with adjusted attributes
<span class="nc" id="L70"> return new DefaultOidcUser(</span>
<span class="nc" id="L71"> user.getAuthorities(),</span>
<span class="nc" id="L72"> userRequest.getIdToken(),</span>
<span class="nc" id="L73"> user.getUserInfo(),</span>
usernameAttributeKey);
<span class="nc" id="L75"> } catch (IllegalArgumentException e) {</span>
<span class="nc" id="L76"> log.error(&quot;Error loading OIDC user: {}&quot;, e.getMessage());</span>
<span class="nc" id="L77"> throw new OAuth2AuthenticationException(new OAuth2Error(e.getMessage()), e);</span>
<span class="nc" id="L78"> } catch (Exception e) {</span>
<span class="nc" id="L79"> log.error(&quot;Unexpected error loading OIDC user&quot;, e);</span>
<span class="nc" id="L80"> throw new OAuth2AuthenticationException(&quot;Unexpected error during authentication&quot;);</span>
}
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,253 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>OAuth2Configuration.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.oauth2</a> &gt; <span class="el_source">OAuth2Configuration.java</span></div><h1>OAuth2Configuration.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.oauth2;
import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE;
import static stirling.software.SPDF.utils.validation.Validator.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.ClientRegistrations;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.model.UsernameAttribute;
import stirling.software.SPDF.model.exception.NoProviderFoundException;
import stirling.software.SPDF.model.provider.GitHubProvider;
import stirling.software.SPDF.model.provider.GoogleProvider;
import stirling.software.SPDF.model.provider.KeycloakProvider;
import stirling.software.SPDF.model.provider.Provider;
<span class="nc" id="L39">@Slf4j</span>
@Configuration
@ConditionalOnProperty(value = &quot;security.oauth2.enabled&quot;, havingValue = &quot;true&quot;)
public class OAuth2Configuration {
public static final String REDIRECT_URI_PATH = &quot;{baseUrl}/login/oauth2/code/&quot;;
private final ApplicationProperties applicationProperties;
@Lazy private final UserService userService;
public OAuth2Configuration(
<span class="nc" id="L50"> ApplicationProperties applicationProperties, @Lazy UserService userService) {</span>
<span class="nc" id="L51"> this.userService = userService;</span>
<span class="nc" id="L52"> this.applicationProperties = applicationProperties;</span>
<span class="nc" id="L53"> }</span>
@Bean
@ConditionalOnProperty(value = &quot;security.oauth2.enabled&quot;, havingValue = &quot;true&quot;)
public ClientRegistrationRepository clientRegistrationRepository()
throws NoProviderFoundException {
<span class="nc" id="L59"> List&lt;ClientRegistration&gt; registrations = new ArrayList&lt;&gt;();</span>
<span class="nc" id="L60"> githubClientRegistration().ifPresent(registrations::add);</span>
<span class="nc" id="L61"> oidcClientRegistration().ifPresent(registrations::add);</span>
<span class="nc" id="L62"> googleClientRegistration().ifPresent(registrations::add);</span>
<span class="nc" id="L63"> keycloakClientRegistration().ifPresent(registrations::add);</span>
<span class="nc bnc" id="L65" title="All 2 branches missed."> if (registrations.isEmpty()) {</span>
<span class="nc" id="L66"> log.error(&quot;No OAuth2 provider registered&quot;);</span>
<span class="nc" id="L67"> throw new NoProviderFoundException(&quot;At least one OAuth2 provider must be configured.&quot;);</span>
}
<span class="nc" id="L70"> return new InMemoryClientRegistrationRepository(registrations);</span>
}
private Optional&lt;ClientRegistration&gt; keycloakClientRegistration() {
<span class="nc" id="L74"> OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2();</span>
<span class="nc bnc" id="L76" title="All 4 branches missed."> if (isOAuth2Enabled(oauth2) || isClientInitialised(oauth2)) {</span>
<span class="nc" id="L77"> return Optional.empty();</span>
}
<span class="nc" id="L80"> Client client = oauth2.getClient();</span>
<span class="nc" id="L81"> KeycloakProvider keycloakClient = client.getKeycloak();</span>
<span class="nc" id="L82"> Provider keycloak =</span>
new KeycloakProvider(
<span class="nc" id="L84"> keycloakClient.getIssuer(),</span>
<span class="nc" id="L85"> keycloakClient.getClientId(),</span>
<span class="nc" id="L86"> keycloakClient.getClientSecret(),</span>
<span class="nc" id="L87"> keycloakClient.getScopes(),</span>
<span class="nc" id="L88"> keycloakClient.getUseAsUsername());</span>
<span class="nc bnc" id="L90" title="All 2 branches missed."> return validateProvider(keycloak)</span>
<span class="nc" id="L91"> ? Optional.of(</span>
<span class="nc" id="L92"> ClientRegistrations.fromIssuerLocation(keycloak.getIssuer())</span>
<span class="nc" id="L93"> .registrationId(keycloak.getName())</span>
<span class="nc" id="L94"> .clientId(keycloak.getClientId())</span>
<span class="nc" id="L95"> .clientSecret(keycloak.getClientSecret())</span>
<span class="nc" id="L96"> .scope(keycloak.getScopes())</span>
<span class="nc" id="L97"> .userNameAttributeName(keycloak.getUseAsUsername().getName())</span>
<span class="nc" id="L98"> .clientName(keycloak.getClientName())</span>
<span class="nc" id="L99"> .build())</span>
<span class="nc" id="L100"> : Optional.empty();</span>
}
private Optional&lt;ClientRegistration&gt; googleClientRegistration() {
<span class="nc" id="L104"> OAUTH2 oAuth2 = applicationProperties.getSecurity().getOauth2();</span>
<span class="nc bnc" id="L106" title="All 4 branches missed."> if (isOAuth2Enabled(oAuth2) || isClientInitialised(oAuth2)) {</span>
<span class="nc" id="L107"> return Optional.empty();</span>
}
<span class="nc" id="L110"> Client client = oAuth2.getClient();</span>
<span class="nc" id="L111"> GoogleProvider googleClient = client.getGoogle();</span>
<span class="nc" id="L112"> Provider google =</span>
new GoogleProvider(
<span class="nc" id="L114"> googleClient.getClientId(),</span>
<span class="nc" id="L115"> googleClient.getClientSecret(),</span>
<span class="nc" id="L116"> googleClient.getScopes(),</span>
<span class="nc" id="L117"> googleClient.getUseAsUsername());</span>
<span class="nc bnc" id="L119" title="All 2 branches missed."> return validateProvider(google)</span>
<span class="nc" id="L120"> ? Optional.of(</span>
<span class="nc" id="L121"> ClientRegistration.withRegistrationId(google.getName())</span>
<span class="nc" id="L122"> .clientId(google.getClientId())</span>
<span class="nc" id="L123"> .clientSecret(google.getClientSecret())</span>
<span class="nc" id="L124"> .scope(google.getScopes())</span>
<span class="nc" id="L125"> .authorizationUri(google.getAuthorizationUri())</span>
<span class="nc" id="L126"> .tokenUri(google.getTokenUri())</span>
<span class="nc" id="L127"> .userInfoUri(google.getUserInfoUri())</span>
<span class="nc" id="L128"> .userNameAttributeName(google.getUseAsUsername().getName())</span>
<span class="nc" id="L129"> .clientName(google.getClientName())</span>
<span class="nc" id="L130"> .redirectUri(REDIRECT_URI_PATH + google.getName())</span>
<span class="nc" id="L131"> .authorizationGrantType(AUTHORIZATION_CODE)</span>
<span class="nc" id="L132"> .build())</span>
<span class="nc" id="L133"> : Optional.empty();</span>
}
private Optional&lt;ClientRegistration&gt; githubClientRegistration() {
<span class="nc" id="L137"> OAUTH2 oAuth2 = applicationProperties.getSecurity().getOauth2();</span>
<span class="nc bnc" id="L139" title="All 2 branches missed."> if (isOAuth2Enabled(oAuth2)) {</span>
<span class="nc" id="L140"> return Optional.empty();</span>
}
<span class="nc" id="L143"> Client client = oAuth2.getClient();</span>
<span class="nc" id="L144"> GitHubProvider githubClient = client.getGithub();</span>
<span class="nc" id="L145"> Provider github =</span>
new GitHubProvider(
<span class="nc" id="L147"> githubClient.getClientId(),</span>
<span class="nc" id="L148"> githubClient.getClientSecret(),</span>
<span class="nc" id="L149"> githubClient.getScopes(),</span>
<span class="nc" id="L150"> githubClient.getUseAsUsername());</span>
<span class="nc bnc" id="L152" title="All 2 branches missed."> return validateProvider(github)</span>
<span class="nc" id="L153"> ? Optional.of(</span>
<span class="nc" id="L154"> ClientRegistration.withRegistrationId(github.getName())</span>
<span class="nc" id="L155"> .clientId(github.getClientId())</span>
<span class="nc" id="L156"> .clientSecret(github.getClientSecret())</span>
<span class="nc" id="L157"> .scope(github.getScopes())</span>
<span class="nc" id="L158"> .authorizationUri(github.getAuthorizationUri())</span>
<span class="nc" id="L159"> .tokenUri(github.getTokenUri())</span>
<span class="nc" id="L160"> .userInfoUri(github.getUserInfoUri())</span>
<span class="nc" id="L161"> .userNameAttributeName(github.getUseAsUsername().getName())</span>
<span class="nc" id="L162"> .clientName(github.getClientName())</span>
<span class="nc" id="L163"> .redirectUri(REDIRECT_URI_PATH + github.getName())</span>
<span class="nc" id="L164"> .authorizationGrantType(AUTHORIZATION_CODE)</span>
<span class="nc" id="L165"> .build())</span>
<span class="nc" id="L166"> : Optional.empty();</span>
}
private Optional&lt;ClientRegistration&gt; oidcClientRegistration() {
<span class="nc" id="L170"> OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();</span>
<span class="nc bnc" id="L172" title="All 4 branches missed."> if (isOAuth2Enabled(oauth) || isClientInitialised(oauth)) {</span>
<span class="nc" id="L173"> return Optional.empty();</span>
}
<span class="nc" id="L176"> String name = oauth.getProvider();</span>
<span class="nc" id="L177"> String firstChar = String.valueOf(name.charAt(0));</span>
<span class="nc" id="L178"> String clientName = name.replaceFirst(firstChar, firstChar.toUpperCase());</span>
<span class="nc" id="L180"> Provider oidcProvider =</span>
new Provider(
<span class="nc" id="L182"> oauth.getIssuer(),</span>
name,
clientName,
<span class="nc" id="L185"> oauth.getClientId(),</span>
<span class="nc" id="L186"> oauth.getClientSecret(),</span>
<span class="nc" id="L187"> oauth.getScopes(),</span>
<span class="nc" id="L188"> UsernameAttribute.valueOf(oauth.getUseAsUsername().toUpperCase()),</span>
null,
null,
null);
<span class="nc bnc" id="L193" title="All 4 branches missed."> return !isStringEmpty(oidcProvider.getIssuer()) || validateProvider(oidcProvider)</span>
<span class="nc" id="L194"> ? Optional.of(</span>
<span class="nc" id="L195"> ClientRegistrations.fromIssuerLocation(oauth.getIssuer())</span>
<span class="nc" id="L196"> .registrationId(name)</span>
<span class="nc" id="L197"> .clientId(oidcProvider.getClientId())</span>
<span class="nc" id="L198"> .clientSecret(oidcProvider.getClientSecret())</span>
<span class="nc" id="L199"> .scope(oidcProvider.getScopes())</span>
<span class="nc" id="L200"> .userNameAttributeName(oidcProvider.getUseAsUsername().getName())</span>
<span class="nc" id="L201"> .clientName(clientName)</span>
<span class="nc" id="L202"> .redirectUri(REDIRECT_URI_PATH + &quot;oidc&quot;)</span>
<span class="nc" id="L203"> .authorizationGrantType(AUTHORIZATION_CODE)</span>
<span class="nc" id="L204"> .build())</span>
<span class="nc" id="L205"> : Optional.empty();</span>
}
private boolean isOAuth2Enabled(OAUTH2 oAuth2) {
<span class="nc bnc" id="L209" title="All 4 branches missed."> return oAuth2 == null || !oAuth2.getEnabled();</span>
}
private boolean isClientInitialised(OAUTH2 oauth2) {
<span class="nc" id="L213"> Client client = oauth2.getClient();</span>
<span class="nc bnc" id="L214" title="All 2 branches missed."> return client == null;</span>
}
/*
This following function is to grant Authorities to the OAUTH2 user from the values stored in the database.
This is required for the internal; 'hasRole()' function to give out the correct role.
*/
@Bean
@ConditionalOnProperty(value = &quot;security.oauth2.enabled&quot;, havingValue = &quot;true&quot;)
GrantedAuthoritiesMapper userAuthoritiesMapper() {
<span class="nc" id="L225"> return (authorities) -&gt; {</span>
<span class="nc" id="L226"> Set&lt;GrantedAuthority&gt; mappedAuthorities = new HashSet&lt;&gt;();</span>
<span class="nc" id="L227"> authorities.forEach(</span>
authority -&gt; {
// Add existing OAUTH2 Authorities
<span class="nc" id="L230"> mappedAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority()));</span>
// Add Authorities from database for existing user, if user is present.
<span class="nc bnc" id="L232" title="All 2 branches missed."> if (authority instanceof OAuth2UserAuthority oAuth2Auth) {</span>
<span class="nc" id="L233"> String useAsUsername =</span>
applicationProperties
<span class="nc" id="L235"> .getSecurity()</span>
<span class="nc" id="L236"> .getOauth2()</span>
<span class="nc" id="L237"> .getUseAsUsername();</span>
<span class="nc" id="L238"> Optional&lt;User&gt; userOpt =</span>
<span class="nc" id="L239"> userService.findByUsernameIgnoreCase(</span>
<span class="nc" id="L240"> (String) oAuth2Auth.getAttributes().get(useAsUsername));</span>
<span class="nc bnc" id="L241" title="All 2 branches missed."> if (userOpt.isPresent()) {</span>
<span class="nc" id="L242"> User user = userOpt.get();</span>
<span class="nc" id="L243"> mappedAuthorities.add(</span>
new SimpleGrantedAuthority(
<span class="nc" id="L245"> userService.findRole(user).getAuthority()));</span>
}
}
<span class="nc" id="L248"> });</span>
<span class="nc" id="L249"> return mappedAuthorities;</span>
};
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CertificateUtils</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.config.security.saml2</a> &gt; <span class="el_class">CertificateUtils</span></div><h1>CertificateUtils</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">90 of 90</td><td class="ctr2">0%</td><td class="bar">6 of 6</td><td class="ctr2">0%</td><td class="ctr1">6</td><td class="ctr2">6</td><td class="ctr1">18</td><td class="ctr2">18</td><td class="ctr1">3</td><td class="ctr2">3</td></tr></tfoot><tbody><tr><td id="a2"><a href="CertificateUtils.java.html#L35" class="el_method">readPrivateKey(Resource)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="58" alt="58"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="6" alt="6"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">4</td><td class="ctr2" id="g0">4</td><td class="ctr1" id="h0">11</td><td class="ctr2" id="i0">11</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a1"><a href="CertificateUtils.java.html#L23" class="el_method">readCertificate(Resource)</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="60" height="10" title="29" alt="29"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">6</td><td class="ctr2" id="i1">6</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a0"><a href="CertificateUtils.java.html#L20" class="el_method">CertificateUtils()</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="6" height="10" title="3" alt="3"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">1</td><td class="ctr2" id="g2">1</td><td class="ctr1" id="h2">1</td><td class="ctr2" id="i2">1</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CertificateUtils.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.saml2</a> &gt; <span class="el_source">CertificateUtils.java</span></div><h1>CertificateUtils.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.saml2;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.io.Resource;
@ConditionalOnProperty(name = &quot;security.saml2.enabled&quot;, havingValue = &quot;true&quot;)
<span class="nc" id="L20">public class CertificateUtils {</span>
public static X509Certificate readCertificate(Resource certificateResource) throws Exception {
<span class="nc" id="L23"> try (PemReader pemReader =</span>
new PemReader(
new InputStreamReader(
<span class="nc" id="L26"> certificateResource.getInputStream(), StandardCharsets.UTF_8))) {</span>
<span class="nc" id="L27"> PemObject pemObject = pemReader.readPemObject();</span>
<span class="nc" id="L28"> byte[] decodedCert = pemObject.getContent();</span>
<span class="nc" id="L29"> CertificateFactory cf = CertificateFactory.getInstance(&quot;X.509&quot;);</span>
<span class="nc" id="L30"> return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(decodedCert));</span>
}
}
public static RSAPrivateKey readPrivateKey(Resource privateKeyResource) throws Exception {
<span class="nc" id="L35"> try (PEMParser pemParser =</span>
new PEMParser(
new InputStreamReader(
<span class="nc" id="L38"> privateKeyResource.getInputStream(), StandardCharsets.UTF_8))) {</span>
<span class="nc" id="L40"> Object object = pemParser.readObject();</span>
<span class="nc" id="L41"> JcaPEMKeyConverter converter = new JcaPEMKeyConverter();</span>
<span class="nc bnc" id="L43" title="All 2 branches missed."> if (object instanceof PEMKeyPair keypair) {</span>
// Handle traditional RSA private key format
<span class="nc" id="L45"> return (RSAPrivateKey) converter.getPrivateKey(keypair.getPrivateKeyInfo());</span>
<span class="nc bnc" id="L46" title="All 2 branches missed."> } else if (object instanceof PrivateKeyInfo keyInfo) {</span>
// Handle PKCS#8 format
<span class="nc" id="L48"> return (RSAPrivateKey) converter.getPrivateKey(keyInfo);</span>
} else {
<span class="nc" id="L50"> throw new IllegalArgumentException(</span>
&quot;Unsupported key format: &quot;
<span class="nc bnc" id="L52" title="All 2 branches missed."> + (object != null ? object.getClass().getName() : &quot;null&quot;));</span>
}
<span class="nc" id="L54"> }</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomSaml2AuthenticatedPrincipal</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.config.security.saml2</a> &gt; <span class="el_class">CustomSaml2AuthenticatedPrincipal</span></div><h1>CustomSaml2AuthenticatedPrincipal</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">21 of 21</td><td class="ctr2">0%</td><td class="bar">0 of 0</td><td class="ctr2">n/a</td><td class="ctr1">3</td><td class="ctr2">3</td><td class="ctr1">3</td><td class="ctr2">3</td><td class="ctr1">3</td><td class="ctr2">3</td></tr></tfoot><tbody><tr><td id="a0"><a href="CustomSaml2AuthenticatedPrincipal.java.html#L11" class="el_method">CustomSaml2AuthenticatedPrincipal(String, Map, String, List)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="15" alt="15"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"/><td class="ctr2" id="e0">n/a</td><td class="ctr1" id="f0">1</td><td class="ctr2" id="g0">1</td><td class="ctr1" id="h0">1</td><td class="ctr2" id="i0">1</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a2"><a href="CustomSaml2AuthenticatedPrincipal.java.html#L20" class="el_method">getName()</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="24" height="10" title="3" alt="3"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">1</td><td class="ctr2" id="i1">1</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a1"><a href="CustomSaml2AuthenticatedPrincipal.java.html#L25" class="el_method">getAttributes()</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="24" height="10" title="3" alt="3"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">1</td><td class="ctr2" id="g2">1</td><td class="ctr1" id="h2">1</td><td class="ctr2" id="i2">1</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomSaml2AuthenticatedPrincipal.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.saml2</a> &gt; <span class="el_source">CustomSaml2AuthenticatedPrincipal.java</span></div><h1>CustomSaml2AuthenticatedPrincipal.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.saml2;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
@ConditionalOnProperty(name = &quot;security.saml2.enabled&quot;, havingValue = &quot;true&quot;)
<span class="nc" id="L11">public record CustomSaml2AuthenticatedPrincipal(</span>
String name,
Map&lt;String, List&lt;Object&gt;&gt; attributes,
String nameId,
List&lt;String&gt; sessionIndexes)
implements Saml2AuthenticatedPrincipal, Serializable {
@Override
public String getName() {
<span class="nc" id="L20"> return this.name;</span>
}
@Override
public Map&lt;String, List&lt;Object&gt;&gt; getAttributes() {
<span class="nc" id="L25"> return this.attributes;</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomSaml2AuthenticationFailureHandler</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.config.security.saml2</a> &gt; <span class="el_class">CustomSaml2AuthenticationFailureHandler</span></div><h1>CustomSaml2AuthenticationFailureHandler</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">37 of 37</td><td class="ctr2">0%</td><td class="bar">4 of 4</td><td class="ctr2">0%</td><td class="ctr1">5</td><td class="ctr2">5</td><td class="ctr1">11</td><td class="ctr2">11</td><td class="ctr1">3</td><td class="ctr2">3</td></tr></tfoot><tbody><tr><td id="a1"><a href="CustomSaml2AuthenticationFailureHandler.java.html#L27" class="el_method">onAuthenticationFailure(HttpServletRequest, HttpServletResponse, AuthenticationException)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="30" alt="30"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="4" alt="4"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">3</td><td class="ctr2" id="g0">3</td><td class="ctr1" id="h0">9</td><td class="ctr2" id="i0">9</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a2"><a href="CustomSaml2AuthenticationFailureHandler.java.html#L17" class="el_method">static {...}</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="16" height="10" title="4" alt="4"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">1</td><td class="ctr2" id="i1">1</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr><tr><td id="a0"><a href="CustomSaml2AuthenticationFailureHandler.java.html#L19" class="el_method">CustomSaml2AuthenticationFailureHandler()</a></td><td class="bar" id="b2"><img src="../jacoco-resources/redbar.gif" width="12" height="10" title="3" alt="3"/></td><td class="ctr2" id="c2">0%</td><td class="bar" id="d2"/><td class="ctr2" id="e2">n/a</td><td class="ctr1" id="f2">1</td><td class="ctr2" id="g2">1</td><td class="ctr1" id="h2">1</td><td class="ctr2" id="i2">1</td><td class="ctr1" id="j2">1</td><td class="ctr2" id="k2">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomSaml2AuthenticationFailureHandler.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.saml2</a> &gt; <span class="el_source">CustomSaml2AuthenticationFailureHandler.java</span></div><h1>CustomSaml2AuthenticationFailureHandler.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.saml2;
import java.io.IOException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.authentication.ProviderNotFoundException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.saml2.core.Saml2Error;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
<span class="nc" id="L17">@Slf4j</span>
@ConditionalOnProperty(name = &quot;security.saml2.enabled&quot;, havingValue = &quot;true&quot;)
<span class="nc" id="L19">public class CustomSaml2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {</span>
@Override
public void onAuthenticationFailure(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception)
throws IOException {
<span class="nc" id="L27"> log.error(&quot;Authentication error&quot;, exception);</span>
<span class="nc bnc" id="L29" title="All 2 branches missed."> if (exception instanceof Saml2AuthenticationException) {</span>
<span class="nc" id="L30"> Saml2Error error = ((Saml2AuthenticationException) exception).getSaml2Error();</span>
<span class="nc" id="L31"> getRedirectStrategy()</span>
<span class="nc" id="L32"> .sendRedirect(request, response, &quot;/login?errorOAuth=&quot; + error.getErrorCode());</span>
<span class="nc bnc" id="L33" title="All 2 branches missed."> } else if (exception instanceof ProviderNotFoundException) {</span>
<span class="nc" id="L34"> getRedirectStrategy()</span>
<span class="nc" id="L35"> .sendRedirect(</span>
request,
response,
&quot;/login?errorOAuth=not_authentication_provider_found&quot;);
}
<span class="nc" id="L40"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomSaml2AuthenticationSuccessHandler</title><script type="text/javascript" src="../jacoco-resources/sort.js"></script></head><body onload="initialSort(['breadcrumb'])"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.html" class="el_package">stirling.software.SPDF.config.security.saml2</a> &gt; <span class="el_class">CustomSaml2AuthenticationSuccessHandler</span></div><h1>CustomSaml2AuthenticationSuccessHandler</h1><table class="coverage" cellspacing="0" id="coveragetable"><thead><tr><td class="sortable" id="a" onclick="toggleSort(this)">Element</td><td class="down sortable bar" id="b" onclick="toggleSort(this)">Missed Instructions</td><td class="sortable ctr2" id="c" onclick="toggleSort(this)">Cov.</td><td class="sortable bar" id="d" onclick="toggleSort(this)">Missed Branches</td><td class="sortable ctr2" id="e" onclick="toggleSort(this)">Cov.</td><td class="sortable ctr1" id="f" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="g" onclick="toggleSort(this)">Cxty</td><td class="sortable ctr1" id="h" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="i" onclick="toggleSort(this)">Lines</td><td class="sortable ctr1" id="j" onclick="toggleSort(this)">Missed</td><td class="sortable ctr2" id="k" onclick="toggleSort(this)">Methods</td></tr></thead><tfoot><tr><td>Total</td><td class="bar">222 of 222</td><td class="ctr2">0%</td><td class="bar">36 of 36</td><td class="ctr2">0%</td><td class="ctr1">20</td><td class="ctr2">20</td><td class="ctr1">56</td><td class="ctr2">56</td><td class="ctr1">2</td><td class="ctr2">2</td></tr></tfoot><tbody><tr><td id="a0"><a href="CustomSaml2AuthenticationSuccessHandler.java.html#L41" class="el_method">onAuthenticationSuccess(HttpServletRequest, HttpServletResponse, Authentication)</a></td><td class="bar" id="b0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="218" alt="218"/></td><td class="ctr2" id="c0">0%</td><td class="bar" id="d0"><img src="../jacoco-resources/redbar.gif" width="120" height="10" title="36" alt="36"/></td><td class="ctr2" id="e0">0%</td><td class="ctr1" id="f0">19</td><td class="ctr2" id="g0">19</td><td class="ctr1" id="h0">55</td><td class="ctr2" id="i0">55</td><td class="ctr1" id="j0">1</td><td class="ctr2" id="k0">1</td></tr><tr><td id="a1"><a href="CustomSaml2AuthenticationSuccessHandler.java.html#L28" class="el_method">static {...}</a></td><td class="bar" id="b1"><img src="../jacoco-resources/redbar.gif" width="2" height="10" title="4" alt="4"/></td><td class="ctr2" id="c1">0%</td><td class="bar" id="d1"/><td class="ctr2" id="e1">n/a</td><td class="ctr1" id="f1">1</td><td class="ctr2" id="g1">1</td><td class="ctr1" id="h1">1</td><td class="ctr2" id="i1">1</td><td class="ctr1" id="j1">1</td><td class="ctr2" id="k1">1</td></tr></tbody></table><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomSaml2AuthenticationSuccessHandler.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.saml2</a> &gt; <span class="el_source">CustomSaml2AuthenticationSuccessHandler.java</span></div><h1>CustomSaml2AuthenticationSuccessHandler.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.saml2;
import java.io.IOException;
import java.sql.SQLException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
import stirling.software.SPDF.model.AuthenticationType;
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
import stirling.software.SPDF.utils.RequestUriUtils;
@AllArgsConstructor
<span class="nc" id="L28">@Slf4j</span>
public class CustomSaml2AuthenticationSuccessHandler
extends SavedRequestAwareAuthenticationSuccessHandler {
private LoginAttemptService loginAttemptService;
private ApplicationProperties applicationProperties;
private UserService userService;
@Override
public void onAuthenticationSuccess(
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {
<span class="nc" id="L41"> Object principal = authentication.getPrincipal();</span>
<span class="nc" id="L42"> log.debug(&quot;Starting SAML2 authentication success handling&quot;);</span>
<span class="nc bnc" id="L44" title="All 2 branches missed."> if (principal instanceof CustomSaml2AuthenticatedPrincipal saml2Principal) {</span>
<span class="nc" id="L45"> String username = saml2Principal.name();</span>
<span class="nc" id="L46"> log.debug(&quot;Authenticated principal found for user: {}&quot;, username);</span>
<span class="nc" id="L48"> HttpSession session = request.getSession(false);</span>
<span class="nc" id="L49"> String contextPath = request.getContextPath();</span>
SavedRequest savedRequest =
<span class="nc bnc" id="L51" title="All 2 branches missed."> (session != null)</span>
<span class="nc" id="L52"> ? (SavedRequest) session.getAttribute(&quot;SPRING_SECURITY_SAVED_REQUEST&quot;)</span>
<span class="nc" id="L53"> : null;</span>
<span class="nc bnc" id="L55" title="All 2 branches missed."> log.debug(</span>
&quot;Session exists: {}, Saved request exists: {}&quot;,
<span class="nc bnc" id="L57" title="All 2 branches missed."> session != null,</span>
<span class="nc" id="L58"> savedRequest != null);</span>
<span class="nc bnc" id="L60" title="All 2 branches missed."> if (savedRequest != null</span>
<span class="nc bnc" id="L61" title="All 2 branches missed."> &amp;&amp; !RequestUriUtils.isStaticResource(</span>
<span class="nc" id="L62"> contextPath, savedRequest.getRedirectUrl())) {</span>
<span class="nc" id="L63"> log.debug(</span>
&quot;Valid saved request found, redirecting to original destination: {}&quot;,
<span class="nc" id="L65"> savedRequest.getRedirectUrl());</span>
<span class="nc" id="L66"> super.onAuthenticationSuccess(request, response, authentication);</span>
} else {
<span class="nc" id="L68"> SAML2 saml2 = applicationProperties.getSecurity().getSaml2();</span>
<span class="nc" id="L69"> log.debug(</span>
&quot;Processing SAML2 authentication with autoCreateUser: {}&quot;,
<span class="nc" id="L71"> saml2.getAutoCreateUser());</span>
<span class="nc bnc" id="L73" title="All 2 branches missed."> if (loginAttemptService.isBlocked(username)) {</span>
<span class="nc" id="L74"> log.debug(&quot;User {} is blocked due to too many login attempts&quot;, username);</span>
<span class="nc bnc" id="L75" title="All 2 branches missed."> if (session != null) {</span>
<span class="nc" id="L76"> session.removeAttribute(&quot;SPRING_SECURITY_SAVED_REQUEST&quot;);</span>
}
<span class="nc" id="L78"> throw new LockedException(</span>
&quot;Your account has been locked due to too many failed login attempts.&quot;);
}
<span class="nc" id="L82"> boolean userExists = userService.usernameExistsIgnoreCase(username);</span>
<span class="nc bnc" id="L83" title="All 4 branches missed."> boolean hasPassword = userExists &amp;&amp; userService.hasPassword(username);</span>
<span class="nc bnc" id="L84" title="All 2 branches missed."> boolean isSSOUser =</span>
userExists
<span class="nc bnc" id="L86" title="All 2 branches missed."> &amp;&amp; userService.isAuthenticationTypeByUsername(</span>
username, AuthenticationType.SSO);
<span class="nc" id="L89"> log.debug(</span>
&quot;User status - Exists: {}, Has password: {}, Is SSO user: {}&quot;,
<span class="nc" id="L91"> userExists,</span>
<span class="nc" id="L92"> hasPassword,</span>
<span class="nc" id="L93"> isSSOUser);</span>
<span class="nc bnc" id="L95" title="All 8 branches missed."> if (userExists &amp;&amp; hasPassword &amp;&amp; !isSSOUser &amp;&amp; saml2.getAutoCreateUser()) {</span>
<span class="nc" id="L96"> log.debug(</span>
&quot;User {} exists with password but is not SSO user, redirecting to logout&quot;,
username);
<span class="nc" id="L99"> response.sendRedirect(</span>
contextPath + &quot;/logout?oAuth2AuthenticationErrorWeb=true&quot;);
<span class="nc" id="L101"> return;</span>
}
try {
<span class="nc bnc" id="L105" title="All 4 branches missed."> if (saml2.getBlockRegistration() &amp;&amp; !userExists) {</span>
<span class="nc" id="L106"> log.debug(&quot;Registration blocked for new user: {}&quot;, username);</span>
<span class="nc" id="L107"> response.sendRedirect(</span>
contextPath + &quot;/login?errorOAuth=oAuth2AdminBlockedUser&quot;);
<span class="nc" id="L109"> return;</span>
}
<span class="nc" id="L111"> log.debug(&quot;Processing SSO post-login for user: {}&quot;, username);</span>
<span class="nc" id="L112"> userService.processSSOPostLogin(username, saml2.getAutoCreateUser());</span>
<span class="nc" id="L113"> log.debug(&quot;Successfully processed authentication for user: {}&quot;, username);</span>
<span class="nc" id="L114"> response.sendRedirect(contextPath + &quot;/&quot;);</span>
<span class="nc" id="L115"> } catch (IllegalArgumentException | SQLException | UnsupportedProviderException e) {</span>
<span class="nc" id="L116"> log.debug(</span>
&quot;Invalid username detected for user: {}, redirecting to logout&quot;,
username);
<span class="nc" id="L119"> response.sendRedirect(contextPath + &quot;/logout?invalidUsername=true&quot;);</span>
<span class="nc" id="L120"> }</span>
}
<span class="nc" id="L122"> } else {</span>
<span class="nc" id="L123"> log.debug(&quot;Non-SAML2 principal detected, delegating to parent handler&quot;);</span>
<span class="nc" id="L124"> super.onAuthenticationSuccess(request, response, authentication);</span>
}
<span class="nc" id="L126"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>CustomSaml2ResponseAuthenticationConverter.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.saml2</a> &gt; <span class="el_source">CustomSaml2ResponseAuthenticationConverter.java</span></div><h1>CustomSaml2ResponseAuthenticationConverter.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.saml2;
import java.util.*;
import org.opensaml.core.xml.XMLObject;
import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.saml.saml2.core.Attribute;
import org.opensaml.saml.saml2.core.AttributeStatement;
import org.opensaml.saml.saml2.core.AuthnStatement;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.ResponseToken;
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.User;
<span class="nc" id="L21">@Slf4j</span>
@ConditionalOnProperty(name = &quot;security.saml2.enabled&quot;, havingValue = &quot;true&quot;)
public class CustomSaml2ResponseAuthenticationConverter
implements Converter&lt;ResponseToken, Saml2Authentication&gt; {
private final UserService userService;
<span class="nc" id="L28"> public CustomSaml2ResponseAuthenticationConverter(UserService userService) {</span>
<span class="nc" id="L29"> this.userService = userService;</span>
<span class="nc" id="L30"> }</span>
private Map&lt;String, List&lt;Object&gt;&gt; extractAttributes(Assertion assertion) {
<span class="nc" id="L33"> Map&lt;String, List&lt;Object&gt;&gt; attributes = new HashMap&lt;&gt;();</span>
<span class="nc bnc" id="L35" title="All 2 branches missed."> for (AttributeStatement attributeStatement : assertion.getAttributeStatements()) {</span>
<span class="nc bnc" id="L36" title="All 2 branches missed."> for (Attribute attribute : attributeStatement.getAttributes()) {</span>
<span class="nc" id="L37"> String attributeName = attribute.getName();</span>
<span class="nc" id="L38"> List&lt;Object&gt; values = new ArrayList&lt;&gt;();</span>
<span class="nc bnc" id="L40" title="All 2 branches missed."> for (XMLObject xmlObject : attribute.getAttributeValues()) {</span>
// Get the text content directly
<span class="nc" id="L42"> String value = xmlObject.getDOM().getTextContent();</span>
<span class="nc bnc" id="L43" title="All 4 branches missed."> if (value != null &amp;&amp; !value.trim().isEmpty()) {</span>
<span class="nc" id="L44"> values.add(value);</span>
}
<span class="nc" id="L46"> }</span>
<span class="nc bnc" id="L48" title="All 2 branches missed."> if (!values.isEmpty()) {</span>
// Store with both full URI and last part of the URI
<span class="nc" id="L50"> attributes.put(attributeName, values);</span>
<span class="nc" id="L51"> String shortName = attributeName.substring(attributeName.lastIndexOf('/') + 1);</span>
<span class="nc" id="L52"> attributes.put(shortName, values);</span>
}
<span class="nc" id="L54"> }</span>
<span class="nc" id="L55"> }</span>
<span class="nc" id="L57"> return attributes;</span>
}
@Override
public Saml2Authentication convert(ResponseToken responseToken) {
<span class="nc" id="L62"> Assertion assertion = responseToken.getResponse().getAssertions().get(0);</span>
<span class="nc" id="L63"> Map&lt;String, List&lt;Object&gt;&gt; attributes = extractAttributes(assertion);</span>
// Debug log with actual values
<span class="nc" id="L66"> log.debug(&quot;Extracted SAML Attributes: {}&quot;, attributes);</span>
// Try to get username/identifier in order of preference
String userIdentifier;
<span class="nc bnc" id="L70" title="All 2 branches missed."> if (hasAttribute(attributes, &quot;username&quot;)) {</span>
<span class="nc" id="L71"> userIdentifier = getFirstAttributeValue(attributes, &quot;username&quot;);</span>
<span class="nc bnc" id="L72" title="All 2 branches missed."> } else if (hasAttribute(attributes, &quot;emailaddress&quot;)) {</span>
<span class="nc" id="L73"> userIdentifier = getFirstAttributeValue(attributes, &quot;emailaddress&quot;);</span>
<span class="nc bnc" id="L74" title="All 2 branches missed."> } else if (hasAttribute(attributes, &quot;name&quot;)) {</span>
<span class="nc" id="L75"> userIdentifier = getFirstAttributeValue(attributes, &quot;name&quot;);</span>
<span class="nc bnc" id="L76" title="All 2 branches missed."> } else if (hasAttribute(attributes, &quot;upn&quot;)) {</span>
<span class="nc" id="L77"> userIdentifier = getFirstAttributeValue(attributes, &quot;upn&quot;);</span>
<span class="nc bnc" id="L78" title="All 2 branches missed."> } else if (hasAttribute(attributes, &quot;uid&quot;)) {</span>
<span class="nc" id="L79"> userIdentifier = getFirstAttributeValue(attributes, &quot;uid&quot;);</span>
} else {
<span class="nc" id="L81"> userIdentifier = assertion.getSubject().getNameID().getValue();</span>
}
// Rest of your existing code...
<span class="nc" id="L85"> Optional&lt;User&gt; userOpt = userService.findByUsernameIgnoreCase(userIdentifier);</span>
<span class="nc" id="L86"> SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(&quot;ROLE_USER&quot;);</span>
<span class="nc bnc" id="L87" title="All 2 branches missed."> if (userOpt.isPresent()) {</span>
<span class="nc" id="L88"> User user = userOpt.get();</span>
<span class="nc" id="L89"> simpleGrantedAuthority =</span>
<span class="nc" id="L90"> new SimpleGrantedAuthority(userService.findRole(user).getAuthority());</span>
}
<span class="nc" id="L93"> List&lt;String&gt; sessionIndexes = new ArrayList&lt;&gt;();</span>
<span class="nc bnc" id="L94" title="All 2 branches missed."> for (AuthnStatement authnStatement : assertion.getAuthnStatements()) {</span>
<span class="nc" id="L95"> sessionIndexes.add(authnStatement.getSessionIndex());</span>
<span class="nc" id="L96"> }</span>
<span class="nc" id="L98"> CustomSaml2AuthenticatedPrincipal principal =</span>
new CustomSaml2AuthenticatedPrincipal(
userIdentifier, attributes, userIdentifier, sessionIndexes);
<span class="nc" id="L102"> return new Saml2Authentication(</span>
principal,
<span class="nc" id="L104"> responseToken.getToken().getSaml2Response(),</span>
<span class="nc" id="L105"> List.of(simpleGrantedAuthority));</span>
}
private boolean hasAttribute(Map&lt;String, List&lt;Object&gt;&gt; attributes, String name) {
<span class="nc bnc" id="L109" title="All 4 branches missed."> return attributes.containsKey(name) &amp;&amp; !attributes.get(name).isEmpty();</span>
}
private String getFirstAttributeValue(Map&lt;String, List&lt;Object&gt;&gt; attributes, String name) {
<span class="nc" id="L113"> List&lt;Object&gt; values = attributes.get(name);</span>
<span class="nc bnc" id="L114" title="All 4 branches missed."> return values != null &amp;&amp; !values.isEmpty() ? values.get(0).toString() : null;</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="zh"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>SAML2Configuration.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Stirling-PDF</a> &gt; <a href="index.source.html" class="el_package">stirling.software.SPDF.config.security.saml2</a> &gt; <span class="el_source">SAML2Configuration.java</span></div><h1>SAML2Configuration.java</h1><pre class="source lang-java linenums">package stirling.software.SPDF.config.security.saml2;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.UUID;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType;
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
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.RelyingPartyRegistrationRepository;
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.authentication.OpenSaml4AuthenticationRequestResolver;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
@Configuration
<span class="nc" id="L30">@Slf4j</span>
@ConditionalOnProperty(value = &quot;security.saml2.enabled&quot;, havingValue = &quot;true&quot;)
public class SAML2Configuration {
private final ApplicationProperties applicationProperties;
<span class="nc" id="L36"> public SAML2Configuration(ApplicationProperties applicationProperties) {</span>
<span class="nc" id="L37"> this.applicationProperties = applicationProperties;</span>
<span class="nc" id="L38"> }</span>
@Bean
@ConditionalOnProperty(name = &quot;security.saml2.enabled&quot;, havingValue = &quot;true&quot;)
public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception {
<span class="nc" id="L43"> SAML2 samlConf = applicationProperties.getSecurity().getSaml2();</span>
<span class="nc" id="L44"> X509Certificate idpCert = CertificateUtils.readCertificate(samlConf.getIdpCert());</span>
<span class="nc" id="L45"> Saml2X509Credential verificationCredential = Saml2X509Credential.verification(idpCert);</span>
<span class="nc" id="L46"> Resource privateKeyResource = samlConf.getPrivateKey();</span>
<span class="nc" id="L47"> Resource certificateResource = samlConf.getSpCert();</span>
<span class="nc" id="L48"> Saml2X509Credential signingCredential =</span>
new Saml2X509Credential(
<span class="nc" id="L50"> CertificateUtils.readPrivateKey(privateKeyResource),</span>
<span class="nc" id="L51"> CertificateUtils.readCertificate(certificateResource),</span>
Saml2X509CredentialType.SIGNING);
<span class="nc" id="L53"> RelyingPartyRegistration rp =</span>
<span class="nc" id="L54"> RelyingPartyRegistration.withRegistrationId(samlConf.getRegistrationId())</span>
<span class="nc" id="L55"> .signingX509Credentials(c -&gt; c.add(signingCredential))</span>
<span class="nc" id="L56"> .entityId(samlConf.getIdpIssuer())</span>
<span class="nc" id="L57"> .singleLogoutServiceBinding(Saml2MessageBinding.POST)</span>
<span class="nc" id="L58"> .singleLogoutServiceLocation(samlConf.getIdpSingleLogoutUrl())</span>
<span class="nc" id="L59"> .singleLogoutServiceResponseLocation(&quot;http://localhost:8080/login&quot;)</span>
<span class="nc" id="L60"> .assertionConsumerServiceBinding(Saml2MessageBinding.POST)</span>
<span class="nc" id="L61"> .assertionConsumerServiceLocation(</span>
&quot;{baseUrl}/login/saml2/sso/{registrationId}&quot;)
<span class="nc" id="L63"> .assertingPartyMetadata(</span>
metadata -&gt;
<span class="nc" id="L65"> metadata.entityId(samlConf.getIdpIssuer())</span>
<span class="nc" id="L66"> .verificationX509Credentials(</span>
<span class="nc" id="L67"> c -&gt; c.add(verificationCredential))</span>
<span class="nc" id="L68"> .singleSignOnServiceBinding(</span>
Saml2MessageBinding.POST)
<span class="nc" id="L70"> .singleSignOnServiceLocation(</span>
<span class="nc" id="L71"> samlConf.getIdpSingleLoginUrl())</span>
<span class="nc" id="L72"> .singleLogoutServiceBinding(</span>
Saml2MessageBinding.POST)
<span class="nc" id="L74"> .singleLogoutServiceLocation(</span>
<span class="nc" id="L75"> samlConf.getIdpSingleLogoutUrl())</span>
<span class="nc" id="L76"> .wantAuthnRequestsSigned(true))</span>
<span class="nc" id="L77"> .build();</span>
<span class="nc" id="L78"> return new InMemoryRelyingPartyRegistrationRepository(rp);</span>
}
@Bean
@ConditionalOnProperty(name = &quot;security.saml2.enabled&quot;, havingValue = &quot;true&quot;)
public OpenSaml4AuthenticationRequestResolver authenticationRequestResolver(
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
<span class="nc" id="L85"> OpenSaml4AuthenticationRequestResolver resolver =</span>
new OpenSaml4AuthenticationRequestResolver(relyingPartyRegistrationRepository);
<span class="nc" id="L88"> resolver.setAuthnRequestCustomizer(</span>
customizer -&gt; {
<span class="nc" id="L90"> HttpServletRequest request = customizer.getRequest();</span>
<span class="nc" id="L91"> AuthnRequest authnRequest = customizer.getAuthnRequest();</span>
<span class="nc" id="L92"> HttpSessionSaml2AuthenticationRequestRepository requestRepository =</span>
new HttpSessionSaml2AuthenticationRequestRepository();
<span class="nc" id="L94"> AbstractSaml2AuthenticationRequest saml2AuthenticationRequest =</span>
<span class="nc" id="L95"> requestRepository.loadAuthenticationRequest(request);</span>
<span class="nc bnc" id="L97" title="All 2 branches missed."> if (saml2AuthenticationRequest != null) {</span>
<span class="nc" id="L98"> String sessionId = request.getSession(false).getId();</span>
<span class="nc" id="L100"> log.debug(</span>
&quot;Retrieving SAML 2 authentication request ID from the current HTTP session {}&quot;,
sessionId);
<span class="nc" id="L104"> String authenticationRequestId = saml2AuthenticationRequest.getId();</span>
<span class="nc bnc" id="L106" title="All 2 branches missed."> if (!authenticationRequestId.isBlank()) {</span>
<span class="nc" id="L107"> authnRequest.setID(authenticationRequestId);</span>
} else {
<span class="nc" id="L109"> log.warn(</span>
&quot;No authentication request found for HTTP session {}. Generating new ID&quot;,
sessionId);
<span class="nc" id="L112"> authnRequest.setID(&quot;ARQ&quot; + UUID.randomUUID().toString().substring(1));</span>
}
<span class="nc" id="L114"> } else {</span>
<span class="nc" id="L115"> log.debug(&quot;Generating new authentication request ID&quot;);</span>
<span class="nc" id="L116"> authnRequest.setID(&quot;ARQ&quot; + UUID.randomUUID().toString().substring(1));</span>
}
<span class="nc" id="L119"> logAuthnRequestDetails(authnRequest);</span>
<span class="nc" id="L120"> logHttpRequestDetails(request);</span>
<span class="nc" id="L121"> });</span>
<span class="nc" id="L122"> return resolver;</span>
}
private static void logAuthnRequestDetails(AuthnRequest authnRequest) {
<span class="nc" id="L126"> String message =</span>
&quot;&quot;&quot;
AuthnRequest:
ID: {}
Issuer: {}
IssueInstant: {}
AssertionConsumerService (ACS) URL: {}
&quot;&quot;&quot;;
<span class="nc" id="L135"> log.debug(</span>
message,
<span class="nc" id="L137"> authnRequest.getID(),</span>
<span class="nc bnc" id="L138" title="All 2 branches missed."> authnRequest.getIssuer() != null ? authnRequest.getIssuer().getValue() : null,</span>
<span class="nc" id="L139"> authnRequest.getIssueInstant(),</span>
<span class="nc" id="L140"> authnRequest.getAssertionConsumerServiceURL());</span>
<span class="nc bnc" id="L142" title="All 2 branches missed."> if (authnRequest.getNameIDPolicy() != null) {</span>
<span class="nc" id="L143"> log.debug(&quot;NameIDPolicy Format: {}&quot;, authnRequest.getNameIDPolicy().getFormat());</span>
}
<span class="nc" id="L145"> }</span>
private static void logHttpRequestDetails(HttpServletRequest request) {
<span class="nc" id="L148"> log.debug(&quot;HTTP Headers: &quot;);</span>
<span class="nc" id="L149"> Collections.list(request.getHeaderNames())</span>
<span class="nc" id="L150"> .forEach(</span>
headerName -&gt;
<span class="nc" id="L152"> log.debug(&quot;{}: {}&quot;, headerName, request.getHeader(headerName)));</span>
<span class="nc" id="L153"> String message =</span>
&quot;&quot;&quot;
HTTP Request Method: {}
Session ID: {}
Request Path: {}
Query String: {}
Remote Address: {}
SAML Request Parameters:
SAMLRequest: {}
RelayState: {}
&quot;&quot;&quot;;
<span class="nc" id="L166"> log.debug(</span>
message,
<span class="nc" id="L168"> request.getMethod(),</span>
<span class="nc" id="L169"> request.getSession().getId(),</span>
<span class="nc" id="L170"> request.getRequestURI(),</span>
<span class="nc" id="L171"> request.getQueryString(),</span>
<span class="nc" id="L172"> request.getRemoteAddr(),</span>
<span class="nc" id="L173"> request.getParameter(&quot;SAMLRequest&quot;),</span>
<span class="nc" id="L174"> request.getParameter(&quot;RelayState&quot;));</span>
<span class="nc" id="L175"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.12.202403310830</span></div></body></html>

Some files were not shown because too many files have changed in this diff Show More