mirror of
https://github.com/nsacyber/HIRS.git
synced 2025-04-15 06:56:44 +00:00
v3_issue_811: Got rid of newer bootstrap folder. Will integrate into HIRS in another issue. Figured out where the search issue lies. Need to figure out how to search on columns on the server side.
This commit is contained in:
parent
97204d25db
commit
17802d2b44
@ -111,7 +111,7 @@ jobs:
|
||||
run: |
|
||||
mkdir artifacts
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
|
@ -4,13 +4,15 @@ import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredent
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface PlatformCertificateRepository extends JpaRepository<PlatformCredential, UUID> {
|
||||
public interface PlatformCertificateRepository extends JpaRepository<PlatformCredential, UUID>,
|
||||
JpaSpecificationExecutor<PlatformCredential> {
|
||||
|
||||
/**
|
||||
* Query that retrieves a list of platform credentials using the provided archive flag.
|
||||
@ -30,6 +32,7 @@ public interface PlatformCertificateRepository extends JpaRepository<PlatformCre
|
||||
*/
|
||||
Page<PlatformCredential> findByArchiveFlag(boolean archiveFlag, Pageable pageable);
|
||||
|
||||
|
||||
/**
|
||||
* Query that retrieves a list of platform credentials using the provided device id.
|
||||
*
|
||||
|
@ -30,14 +30,14 @@ public class Column {
|
||||
/**
|
||||
* Column's name.
|
||||
*
|
||||
* @see http://datatables.net/reference/option/columns.name
|
||||
* @see https://datatables.net/reference/option/columns.name
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Flag to indicate if this column is searchable (true) or not (false).
|
||||
*
|
||||
* @see http://datatables.net/reference/option/columns.searchable
|
||||
* @see https://datatables.net/reference/option/columns.searchable
|
||||
*/
|
||||
@NotNull
|
||||
private boolean searchable;
|
||||
@ -45,7 +45,7 @@ public class Column {
|
||||
/**
|
||||
* Flag to indicate if this column is orderable (true) or not (false).
|
||||
*
|
||||
* @see http://datatables.net/reference/option/columns.orderable
|
||||
* @see https://datatables.net/reference/option/columns.orderable
|
||||
*/
|
||||
@NotNull
|
||||
private boolean orderable;
|
||||
|
@ -24,16 +24,19 @@ import java.util.Map;
|
||||
public class DataTableInput {
|
||||
|
||||
private static final int DEFAULT_LENGTH = 10;
|
||||
|
||||
/**
|
||||
* Order parameter.
|
||||
*/
|
||||
@NotEmpty
|
||||
private final List<Order> order = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Per-column search parameter.
|
||||
*/
|
||||
@NotEmpty
|
||||
private final List<Column> columns = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Draw counter. This is used by DataTables to ensure that the Ajax returns from server-side
|
||||
* processing requests are drawn in sequence by DataTables (Ajax requests are asynchronous and
|
||||
@ -44,6 +47,7 @@ public class DataTableInput {
|
||||
@Min(0)
|
||||
@Setter
|
||||
private int draw = 1;
|
||||
|
||||
/**
|
||||
* Paging first record indicator. This is the start point in the current data set
|
||||
* (0 index based - i.e. 0 is the first record).
|
||||
@ -52,6 +56,7 @@ public class DataTableInput {
|
||||
@Min(0)
|
||||
@Setter
|
||||
private int start = 0;
|
||||
|
||||
/**
|
||||
* Number of records that the table can display in the current draw. It is expected that the
|
||||
* number of records returned will be equal to this number,
|
||||
@ -63,6 +68,7 @@ public class DataTableInput {
|
||||
@Min(-1)
|
||||
@Setter
|
||||
private int length = DEFAULT_LENGTH;
|
||||
|
||||
/**
|
||||
* Global search parameter.
|
||||
*/
|
||||
|
@ -1,6 +1,5 @@
|
||||
package hirs.attestationca.portal.page.controllers;
|
||||
|
||||
import hirs.attestationca.persist.CriteriaModifier;
|
||||
import hirs.attestationca.persist.DBManagerException;
|
||||
import hirs.attestationca.persist.DBServiceException;
|
||||
import hirs.attestationca.persist.FilteredRecordsList;
|
||||
@ -21,6 +20,7 @@ import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredent
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
|
||||
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
|
||||
import hirs.attestationca.persist.util.CredentialHelper;
|
||||
import hirs.attestationca.portal.datatables.Column;
|
||||
import hirs.attestationca.portal.datatables.DataTableInput;
|
||||
import hirs.attestationca.portal.datatables.DataTableResponse;
|
||||
import hirs.attestationca.portal.page.Page;
|
||||
@ -29,17 +29,17 @@ import hirs.attestationca.portal.page.PageMessages;
|
||||
import hirs.attestationca.portal.page.params.NoPageParams;
|
||||
import hirs.attestationca.portal.page.utils.CertificateStringMapBuilder;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bouncycastle.util.encoders.DecoderException;
|
||||
import org.hibernate.Session;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
@ -56,13 +56,13 @@ import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.Reference;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
@ -236,6 +236,33 @@ public class CertificatePageController extends PageController<NoPageParams> {
|
||||
return mav;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private String buildSearchQuery(@NotNull String searchTerm, List<Column> columns) {
|
||||
|
||||
StringBuilder searchQuery = new StringBuilder();
|
||||
|
||||
if (!StringUtils.isBlank(searchTerm)) {
|
||||
// Iterate over columns and add search conditions for the ones that are searchable
|
||||
boolean firstCondition = true;
|
||||
|
||||
for (Column column : columns) {
|
||||
if (column.isSearchable()) {
|
||||
if (!firstCondition) {
|
||||
searchQuery.append(" OR ");
|
||||
}
|
||||
|
||||
searchQuery.append(column.getName()).append(" LIKE '%").append(searchTerm).append("%'");
|
||||
|
||||
firstCondition = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return searchQuery.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries for the list of Certificates and returns a data table response
|
||||
* with the records.
|
||||
@ -257,25 +284,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
|
||||
String orderColumnName = input.getOrderColumnName();
|
||||
log.debug("Ordering on column: {}", orderColumnName);
|
||||
|
||||
// check that the alert is not archived and that it is in the specified report
|
||||
CriteriaModifier criteriaModifier = new CriteriaModifier() {
|
||||
@Override
|
||||
public void modify(final CriteriaQuery criteriaQuery) {
|
||||
Session session = entityManager.unwrap(Session.class);
|
||||
CriteriaBuilder cb = session.getCriteriaBuilder();
|
||||
Root<Certificate> rimRoot = criteriaQuery.from(Reference.class);
|
||||
criteriaQuery.select(rimRoot).distinct(true)
|
||||
.where(cb.isNull(rimRoot.get(Certificate.ARCHIVE_FIELD)));
|
||||
|
||||
// add a device alias if this query includes the device table
|
||||
// for getting the device (e.g. device name).
|
||||
// use left join, since device may be null. Query will return all
|
||||
// Certs of this type, whether it has a Device or not (device field may be null)
|
||||
// if (hasDeviceTableToJoin(certificateType)) {
|
||||
// criteria.createAlias("device", "device", JoinType.LEFT_OUTER_JOIN);
|
||||
//}
|
||||
}
|
||||
};
|
||||
//String searchQuery = buildSearchQuery(input.getSearch().getValue(), input.getColumns());
|
||||
|
||||
int currentPage = input.getStart() / input.getLength();
|
||||
Pageable paging = PageRequest.of(currentPage, input.getLength(), Sort.by(orderColumnName));
|
||||
@ -286,8 +295,32 @@ public class CertificatePageController extends PageController<NoPageParams> {
|
||||
switch (certificateType) {
|
||||
case PLATFORMCREDENTIAL -> {
|
||||
FilteredRecordsList<PlatformCredential> records = new FilteredRecordsList<>();
|
||||
org.springframework.data.domain.Page<PlatformCredential> pagedResult =
|
||||
this.platformCertificateRepository.findByArchiveFlag(false, paging);
|
||||
|
||||
org.springframework.data.domain.Page<PlatformCredential> pagedResult = null;
|
||||
|
||||
if (StringUtils.isBlank(input.getSearch().getValue())) {
|
||||
pagedResult =
|
||||
this.platformCertificateRepository.findByArchiveFlag(false, paging);
|
||||
} else {
|
||||
|
||||
Specification<PlatformCredential> spec = (root, query, criteriaBuilder) -> {
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
|
||||
for (Column column : input.getColumns()) {
|
||||
if (column.isSearchable()) {
|
||||
predicates.add(criteriaBuilder.like(
|
||||
criteriaBuilder.lower(root.get(column.getName())),
|
||||
"%" + column.getSearch().getValue().toLowerCase() + "%"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Combine predicates into a single query (AND all conditions)
|
||||
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
|
||||
};
|
||||
|
||||
pagedResult = platformCertificateRepository.findAll(spec, paging);
|
||||
}
|
||||
|
||||
if (pagedResult.hasContent()) {
|
||||
records.addAll(pagedResult.getContent());
|
||||
|
@ -99,7 +99,7 @@ public class DevicePageController extends PageController<NoPageParams> {
|
||||
final DataTableInput input) {
|
||||
log.debug("Handling request for device list");
|
||||
String orderColumnName = input.getOrderColumnName();
|
||||
log.info("Ordering on column: {}", orderColumnName);
|
||||
log.debug("Ordering on column: {}", orderColumnName);
|
||||
|
||||
// get all the devices
|
||||
FilteredRecordsList<Device> deviceList = new FilteredRecordsList<>();
|
||||
|
@ -112,11 +112,11 @@ public class ReferenceManifestPageController extends PageController<NoPageParams
|
||||
method = RequestMethod.GET)
|
||||
public DataTableResponse<ReferenceManifest> getTableData(
|
||||
@Valid final DataTableInput input) {
|
||||
log.debug("Handling request for summary list: " + input);
|
||||
log.debug("Handling request for summary list: {}", input);
|
||||
|
||||
String orderColumnName = input.getOrderColumnName();
|
||||
log.info("Ordering on column: " + orderColumnName);
|
||||
log.info("Querying with the following dataTableInput: " + input);
|
||||
log.debug("Ordering on column: {}", orderColumnName);
|
||||
log.debug("Querying with the following dataTableInput: {}", input);
|
||||
|
||||
FilteredRecordsList<ReferenceManifest> records = new FilteredRecordsList<>();
|
||||
int currentPage = input.getStart() / input.getLength();
|
||||
@ -137,7 +137,7 @@ public class ReferenceManifestPageController extends PageController<NoPageParams
|
||||
|
||||
records.setRecordsFiltered(referenceManifestRepository.findByArchiveFlag(false).size());
|
||||
|
||||
log.debug("Returning list of size: " + records.size());
|
||||
log.debug("Returning list of size: {}", records.size());
|
||||
return new DataTableResponse<>(records, input);
|
||||
}
|
||||
|
||||
@ -282,10 +282,11 @@ public class ReferenceManifestPageController extends PageController<NoPageParams
|
||||
// send a 404 error when invalid Reference Manifest
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
} else {
|
||||
StringBuilder fileName = new StringBuilder("filename=\"");
|
||||
fileName.append(referenceManifest.getFileName());
|
||||
// Set filename for download.
|
||||
response.setHeader("Content-Disposition", "attachment;" + fileName);
|
||||
response.setHeader("Content-Disposition",
|
||||
"attachment;" + "filename=\"" + referenceManifest.getFileName()
|
||||
// Set filename for download.
|
||||
);
|
||||
response.setContentType("application/octet-stream");
|
||||
|
||||
// write cert to output stream
|
||||
|
@ -89,10 +89,10 @@ public class RimDatabasePageController extends PageController<NoPageParams> {
|
||||
method = RequestMethod.GET)
|
||||
public DataTableResponse<ReferenceDigestValue> getTableData(
|
||||
@Valid final DataTableInput input) {
|
||||
log.info("Handling request for summary list: " + input);
|
||||
log.debug("Handling request for summary list: {}", input);
|
||||
|
||||
String orderColumnName = input.getOrderColumnName();
|
||||
log.info("Ordering on column: " + orderColumnName);
|
||||
log.debug("Ordering on column: {}", orderColumnName);
|
||||
|
||||
// check that the alert is not archived and that it is in the specified report
|
||||
CriteriaModifier criteriaModifier = new CriteriaModifier() {
|
||||
@ -106,7 +106,7 @@ public class RimDatabasePageController extends PageController<NoPageParams> {
|
||||
}
|
||||
};
|
||||
|
||||
log.info("Querying with the following dataTableInput: " + input.toString());
|
||||
log.debug("Querying with the following dataTableInput: {}", input);
|
||||
|
||||
FilteredRecordsList<ReferenceDigestValue> referenceDigestValues = new FilteredRecordsList<>();
|
||||
|
||||
@ -139,7 +139,7 @@ public class RimDatabasePageController extends PageController<NoPageParams> {
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("Returning list of size: " + referenceDigestValues.size());
|
||||
log.debug("Returning list of size: {}", referenceDigestValues.size());
|
||||
return new DataTableResponse<>(referenceDigestValues, input);
|
||||
}
|
||||
}
|
||||
|
@ -8,123 +8,151 @@
|
||||
|
||||
<%-- CONTENT --%>
|
||||
<my:page>
|
||||
<jsp:attribute name="script">
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="${lib}/jquery.spring-friendly/jquery.spring-friendly.js"
|
||||
></script>
|
||||
</jsp:attribute>
|
||||
<jsp:attribute name="pageHeaderTitle">Platform Certificates</jsp:attribute>
|
||||
|
||||
<jsp:attribute name="script">
|
||||
<script type="text/javascript" src="${lib}/jquery.spring-friendly/jquery.spring-friendly.js"></script>
|
||||
</jsp:attribute>
|
||||
<jsp:attribute name="pageHeaderTitle">Platform Certificates</jsp:attribute>
|
||||
<jsp:body>
|
||||
<!-- text and icon resource variables -->
|
||||
<c:set var="endorsementIcon" value="${icons}/ic_vpn_key_black_24dp.png" />
|
||||
<div class="aca-input-box-header">
|
||||
<form:form
|
||||
method="POST"
|
||||
action="${portal}/certificate-request/platform-credentials/upload"
|
||||
enctype="multipart/form-data"
|
||||
>
|
||||
Platform Credentials
|
||||
<my:file-chooser
|
||||
id="platformCredentialEditor"
|
||||
label="Import Platform Credentials"
|
||||
>
|
||||
<input id="importFile" type="file" name="file" multiple="multiple" />
|
||||
</my:file-chooser>
|
||||
<a href="${portal}/certificate-request/platform-credentials/bulk">
|
||||
<img src="${icons}/ic_file_download_black_24dp.png" title="Download All Platform Certificates">
|
||||
</a>
|
||||
</form:form>
|
||||
</div>
|
||||
<br />
|
||||
<div class="aca-data-table">
|
||||
<table id="platformTable" class="display" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Device</th>
|
||||
<th>Issuer</th>
|
||||
<th>Type</th>
|
||||
<th>Manufacturer</th>
|
||||
<th>Model</th>
|
||||
<th>Version</th>
|
||||
<th>Board SN</th>
|
||||
<th>Valid (begin)</th>
|
||||
<th>Valid (end)</th>
|
||||
<th>Endorsement</th>
|
||||
<th>Options</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<jsp:body>
|
||||
<!-- text and icon resource variables -->
|
||||
<c:set var="endorsementIcon" value="${icons}/ic_vpn_key_black_24dp.png"/>
|
||||
<div class="aca-input-box-header">
|
||||
<form:form method="POST" action="${portal}/certificate-request/platform-credentials/upload" enctype="multipart/form-data">
|
||||
Platform Credentials
|
||||
<my:file-chooser id="platformCredentialEditor" label="Import Platform Credentials">
|
||||
<input id="importFile" type="file" name="file" multiple="multiple" />
|
||||
</my:file-chooser>
|
||||
<a href="${portal}/certificate-request/platform-credentials/bulk">
|
||||
<img src="${icons}/ic_file_download_black_24dp.png" title="Download All Platform Certificates">
|
||||
</a>
|
||||
</form:form>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="aca-data-table">
|
||||
<table id="platformTable" class="display" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Device</th>
|
||||
<th>Issuer</th>
|
||||
<th>Type</th>
|
||||
<th>Manufacturer</th>
|
||||
<th>Model</th>
|
||||
<th>Version</th>
|
||||
<th>Board SN</th>
|
||||
<th>Valid (begin)</th>
|
||||
<th>Valid (end)</th>
|
||||
<th>Endorsement</th>
|
||||
<th>Options</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
let url = pagePath + "/list";
|
||||
let columns = [
|
||||
{
|
||||
name: "deviceName",
|
||||
data: "deviceName",
|
||||
orderable: true,
|
||||
searchable: true,
|
||||
render: function (data, type, full, meta) {
|
||||
// if there is a device, display its name, otherwise
|
||||
return full.deviceName;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "issuer",
|
||||
data: "issuer",
|
||||
orderable: true,
|
||||
searchable: true,
|
||||
},
|
||||
{
|
||||
name: "credentialType",
|
||||
data: "credentialType",
|
||||
render: function (data, type, full, meta) {
|
||||
if (full.platformChainType !== "") {
|
||||
return full.platformChainType;
|
||||
} else {
|
||||
return full.credentialType;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "manufacturer",
|
||||
data: "manufacturer",
|
||||
orderable: true,
|
||||
searchable: true,
|
||||
},
|
||||
{ name: "model", data: "model", orderable: true, searchable: true },
|
||||
{ name: "version", data: "version", orderable: true, searchable: true },
|
||||
{ name: "platformSerial",data: "platformSerial", orderable: true, searchable: true },
|
||||
{
|
||||
name: "beginValidity",
|
||||
data: "beginValidity",
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return formatCertificateDate(full.beginValidity);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "endValidity",
|
||||
data: "endValidity",
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return formatCertificateDate(full.endValidity);
|
||||
},
|
||||
},
|
||||
{
|
||||
data: "id",
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
//Display endorsement credential
|
||||
if (full.endorsementCredential === null) return "";
|
||||
let html = "";
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
let url = pagePath +'/list';
|
||||
let columns = [
|
||||
{
|
||||
data: 'deviceName',
|
||||
render: function (data, type, full, meta) {
|
||||
// if there's a device, display its name, otherwise
|
||||
return full.deviceName;
|
||||
}
|
||||
},
|
||||
{data: 'issuer'},
|
||||
{
|
||||
data: 'credentialType',
|
||||
render: function (data, type, full, meta) {
|
||||
if (full.platformChainType !== '') {
|
||||
return full.platformChainType;
|
||||
} else {
|
||||
return full.credentialType;
|
||||
}
|
||||
}
|
||||
},
|
||||
{data: 'manufacturer'},
|
||||
{data: 'model'},
|
||||
{data: 'version'},
|
||||
{data: 'platformSerial'},
|
||||
{
|
||||
data: 'beginValidity',
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
return formatCertificateDate(full.beginValidity);
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'endValidity',
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
return formatCertificateDate(full.endValidity);
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
orderable: false,
|
||||
searchable:false,
|
||||
render: function (data, type, full, meta) {
|
||||
//Display endorsement credential
|
||||
if(full.endorsementCredential === null) return '';
|
||||
let html = '';
|
||||
let id = full.endorsementCredential.id;
|
||||
html =
|
||||
certificateDetailsLink("endorsement", id, false) + " ";
|
||||
|
||||
let id = full.endorsementCredential.id;
|
||||
html = certificateDetailsLink('endorsement', id, false) +' ';
|
||||
return html;
|
||||
},
|
||||
},
|
||||
{
|
||||
data: "id",
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
// Set up a delete icon with link to handleDeleteRequest().
|
||||
// sets up a hidden input field containing the ID which is
|
||||
// used as a parameter to the REST POST call to delete
|
||||
let html = "";
|
||||
html += certificateDetailsLink("platform", full.id, true);
|
||||
html += certificateDownloadLink(full.id, pagePath);
|
||||
html += certificateDeleteLink(full.id, pagePath);
|
||||
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
orderable: false,
|
||||
searchable:false,
|
||||
render: function(data, type, full, meta) {
|
||||
// Set up a delete icon with link to handleDeleteRequest().
|
||||
// sets up a hidden input field containing the ID which is
|
||||
// used as a parameter to the REST POST call to delete
|
||||
let html = '';
|
||||
html += certificateDetailsLink('platform', full.id, true);
|
||||
html += certificateDownloadLink(full.id, pagePath);
|
||||
html += certificateDeleteLink(full.id, pagePath);
|
||||
return html;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
//Set data tables
|
||||
setDataTables("#platformTable", url, columns);
|
||||
});
|
||||
</script>
|
||||
</jsp:body>
|
||||
</my:page>
|
||||
//Set data tables
|
||||
setDataTables("#platformTable", url, columns);
|
||||
});
|
||||
</script>
|
||||
</jsp:body>
|
||||
</my:page>
|
||||
|
@ -2,222 +2,265 @@
|
||||
* Converts a byte to HEX.
|
||||
*/
|
||||
function byteToHexString(arr) {
|
||||
let str = "";
|
||||
$.each(arr, function (index, value) {
|
||||
str += ('0' + (value & 0xFF).toString(16)).slice(-2) + ":";
|
||||
});
|
||||
return (str.substring(0, str.length - 2)).toUpperCase();
|
||||
let str = "";
|
||||
$.each(arr, function (index, value) {
|
||||
str += ("0" + (value & 0xff).toString(16)).slice(-2) + ":";
|
||||
});
|
||||
return str.substring(0, str.length - 2).toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
Parses hex string for display.
|
||||
*/
|
||||
function parseHexString(hexString) {
|
||||
let str = hexString.toUpperCase();
|
||||
//Do not parse if there is 2 characters
|
||||
if (str.length === 2) {
|
||||
return str;
|
||||
}
|
||||
return str.match(/.{2}/g).join(':');
|
||||
let str = hexString.toUpperCase();
|
||||
//Do not parse if there is 2 characters
|
||||
if (str.length === 2) {
|
||||
return str;
|
||||
}
|
||||
return str.match(/.{2}/g).join(":");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the HEX string value to display as byte hex string.
|
||||
*/
|
||||
function parseSerialNumber(hexString) {
|
||||
let str = hexString.toUpperCase();
|
||||
if (str.length % 2 !== 0) {
|
||||
str = '0' + hexString;
|
||||
}
|
||||
//Do not parse if there is 2 characters
|
||||
if (str.length === 2) {
|
||||
return str;
|
||||
}
|
||||
//Parse and return
|
||||
return newString = str.match(/.{2}/g).join(':');
|
||||
|
||||
let str = hexString.toUpperCase();
|
||||
if (str.length % 2 !== 0) {
|
||||
str = "0" + hexString;
|
||||
}
|
||||
//Do not parse if there is 2 characters
|
||||
if (str.length === 2) {
|
||||
return str;
|
||||
}
|
||||
//Parse and return
|
||||
return (newString = str.match(/.{2}/g).join(":"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles user request to delete a cert. Prompts user to confirm.
|
||||
* Upon confirmation, submits the delete form which is required to make
|
||||
* a POST call to delete the credential.
|
||||
*/
|
||||
* Handles user request to delete a cert. Prompts user to confirm.
|
||||
* Upon confirmation, submits the delete form which is required to make
|
||||
* a POST call to delete the credential.
|
||||
*/
|
||||
function handleDeleteRequest(id) {
|
||||
if (confirm("Delete certificate?")) {
|
||||
$('#deleteForm' + id).submit();
|
||||
}
|
||||
if (confirm("Delete certificate?")) {
|
||||
$("#deleteForm" + id).submit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles user request to delete a cert. Prompts user to confirm.
|
||||
* Upon confirmation, submits the delete form which is required to make
|
||||
* a POST call to delete the reference integrity manifest.
|
||||
*/
|
||||
* Handles user request to delete a cert. Prompts user to confirm.
|
||||
* Upon confirmation, submits the delete form which is required to make
|
||||
* a POST call to delete the reference integrity manifest.
|
||||
*/
|
||||
function handleRimDeleteRequest(id) {
|
||||
if (confirm("Delete RIM?")) {
|
||||
$('#deleteForm' + id).submit();
|
||||
}
|
||||
if (confirm("Delete RIM?")) {
|
||||
$("#deleteForm" + id).submit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data tables using the columns definition, the ajax URL and
|
||||
* the ID of the table.
|
||||
* @param id of the data table
|
||||
* @param url for the AJAX call
|
||||
* @param columns definition of the table to render
|
||||
*
|
||||
*/
|
||||
* Set the data tables using the columns definition, the ajax URL and
|
||||
* the ID of the table.
|
||||
* @param id of the data table
|
||||
* @param url for the AJAX call
|
||||
* @param columns definition of the table to render
|
||||
*
|
||||
*/
|
||||
function setDataTables(id, url, columns) {
|
||||
let dtable = $(id).DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: {
|
||||
url: url,
|
||||
dataSrc: function (json) {
|
||||
formatElementDates('.date');
|
||||
return json.data;
|
||||
}
|
||||
},
|
||||
columns: columns
|
||||
});
|
||||
|
||||
return dtable;
|
||||
return new DataTable(id,{
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: {
|
||||
url: url,
|
||||
dataSrc: function (json) {
|
||||
formatElementDates(".date");
|
||||
return json.data;
|
||||
}
|
||||
},
|
||||
columns: columns
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a certificate details like for the specified certificate
|
||||
* type and ID with the corresponding icon.
|
||||
* @param type of certificate
|
||||
* @param id of the certificate
|
||||
* @param sameType boolean indicating if the details is the same
|
||||
* certificate type.
|
||||
*/
|
||||
* Create a certificate details like for the specified certificate
|
||||
* type and ID with the corresponding icon.
|
||||
* @param type of certificate
|
||||
* @param id of the certificate
|
||||
* @param sameType boolean indicating if the details is the same
|
||||
* certificate type.
|
||||
*/
|
||||
function certificateDetailsLink(type, id, sameType) {
|
||||
let href = portal + '/certificate-details?id=' + id + '&type=' + type;
|
||||
let title = "";
|
||||
let icon = icons;
|
||||
|
||||
//If the details is the same certificate type use assignment icon,
|
||||
//otherwise use the icon for the certificate type.
|
||||
if (sameType) {
|
||||
title = "Details";
|
||||
icon += '/ic_assignment_black_24dp.png';
|
||||
} else {
|
||||
switch (type) {
|
||||
case "issued":
|
||||
icon += "/ic_library_books_black_24dp.png";
|
||||
title = "View Issued Attestation Certificate Details"
|
||||
break;
|
||||
case "platform":
|
||||
icon += "/ic_important_devices_black_24dp.png";
|
||||
title = "View Platform Certificate Details";
|
||||
break;
|
||||
case "endorsement":
|
||||
icon += "/ic_vpn_key_black_24dp.png";
|
||||
title = "View Endorsement Certificate Details";
|
||||
break;
|
||||
case "idevid":
|
||||
icon += "/ic_vpn_key_black_24dp.png";
|
||||
title = "View IDevID Certificate Details";
|
||||
break;
|
||||
}
|
||||
}
|
||||
let html = '<a href=' + href + '>'
|
||||
+ '<img src="' + icon + '" title="' + title + '"></a>';
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a RIM details like for the specified rim.
|
||||
* type and ID with the corresponding icon.
|
||||
* @param id of the rim
|
||||
*/
|
||||
function rimDetailsLink(id) {
|
||||
let href = portal + '/rim-details?id=' + id;
|
||||
let title = "";
|
||||
let icon = icons;
|
||||
let href = portal + "/certificate-details?id=" + id + "&type=" + type;
|
||||
let title = "";
|
||||
let icon = icons;
|
||||
|
||||
//If the details is the same certificate type use assignment icon,
|
||||
//otherwise use the icon for the certificate type.
|
||||
if (sameType) {
|
||||
title = "Details";
|
||||
icon += '/ic_assignment_black_24dp.png';
|
||||
|
||||
let html = '<a href=' + href + '>'
|
||||
+ '<img src="' + icon + '" title="' + title + '"></a>';
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a certificate delete link for the specified ID
|
||||
* @param id of the certificate
|
||||
* @param pagePath path to the link
|
||||
*/
|
||||
function certificateDeleteLink(id, pagePath) {
|
||||
let icon = icons + '/ic_delete_black_24dp.png';
|
||||
let formURL = pagePath + "/delete";
|
||||
|
||||
let html = '<a href="#!" onclick="handleDeleteRequest(\'' + id + '\')">'
|
||||
+ '<img src="' + icon + '" title="Delete"></a>'
|
||||
+ '<form id="deleteForm' + id + '" action="' + formURL + '" method="post">'
|
||||
+ '<input name="id" type="hidden" value="' + id + '"></form>';
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a RIM delete link for the specified ID
|
||||
* @param id of the RIM
|
||||
* @param pagePath path to the link
|
||||
*/
|
||||
function rimDeleteLink(id, pagePath) {
|
||||
let icon = icons + '/ic_delete_black_24dp.png';
|
||||
let formURL = pagePath + "/delete";
|
||||
|
||||
let html = '<a href="#!" onclick="handleRimDeleteRequest(\'' + id + '\')">'
|
||||
+ '<img src="' + icon + '" title="Delete"></a>'
|
||||
+ '<form id="deleteForm' + id + '" action="' + formURL + '" method="post">'
|
||||
+ '<input name="id" type="hidden" value="' + id + '"></form>';
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a certificate download link for the specified ID
|
||||
* @param id of the certificate
|
||||
* @param pagePath path to the link
|
||||
*/
|
||||
function certificateDownloadLink(id, pagePath) {
|
||||
let icon = icons + '/ic_file_download_black_24dp.png';
|
||||
let href = pagePath + '/download?id=' + id;
|
||||
|
||||
let html = '<a href="' + href + '">'
|
||||
+ '<img src="' + icon + '" title="Download Certificate"></a>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a rim download link for the specified ID
|
||||
* @param id of the rim
|
||||
* @param pagePath path to the link
|
||||
*/
|
||||
function rimDownloadLink(id, pagePath) {
|
||||
let icon = icons + '/ic_file_download_black_24dp.png';
|
||||
let href = pagePath + '/download?id=' + id;
|
||||
|
||||
let html = '<a href="' + href + '">'
|
||||
+ '<img src="' + icon + '" title="Download Reference Integrity Manifest"></a>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a given date to a UTC string, or returns an indefinite icon
|
||||
* @param date to format
|
||||
*/
|
||||
function formatCertificateDate(dateText) {
|
||||
let date = +dateText; // Convert to numeric
|
||||
|
||||
if (date == 253402300799000) {
|
||||
return 'Indefinite';
|
||||
icon += "/ic_assignment_black_24dp.png";
|
||||
} else {
|
||||
switch (type) {
|
||||
case "issued":
|
||||
icon += "/ic_library_books_black_24dp.png";
|
||||
title = "View Issued Attestation Certificate Details";
|
||||
break;
|
||||
case "platform":
|
||||
icon += "/ic_important_devices_black_24dp.png";
|
||||
title = "View Platform Certificate Details";
|
||||
break;
|
||||
case "endorsement":
|
||||
icon += "/ic_vpn_key_black_24dp.png";
|
||||
title = "View Endorsement Certificate Details";
|
||||
break;
|
||||
case "idevid":
|
||||
icon += "/ic_vpn_key_black_24dp.png";
|
||||
title = "View IDevID Certificate Details";
|
||||
break;
|
||||
}
|
||||
}
|
||||
let html =
|
||||
"<a href=" +
|
||||
href +
|
||||
">" +
|
||||
'<img src="' +
|
||||
icon +
|
||||
'" title="' +
|
||||
title +
|
||||
'"></a>';
|
||||
return html;
|
||||
}
|
||||
|
||||
return new Date(date).toUTCString();
|
||||
}
|
||||
/**
|
||||
* Create a RIM details like for the specified rim.
|
||||
* type and ID with the corresponding icon.
|
||||
* @param id of the rim
|
||||
*/
|
||||
function rimDetailsLink(id) {
|
||||
let href = portal + "/rim-details?id=" + id;
|
||||
let title = "";
|
||||
let icon = icons;
|
||||
|
||||
title = "Details";
|
||||
icon += "/ic_assignment_black_24dp.png";
|
||||
|
||||
let html =
|
||||
"<a href=" +
|
||||
href +
|
||||
">" +
|
||||
'<img src="' +
|
||||
icon +
|
||||
'" title="' +
|
||||
title +
|
||||
'"></a>';
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a certificate delete link for the specified ID
|
||||
* @param id of the certificate
|
||||
* @param pagePath path to the link
|
||||
*/
|
||||
function certificateDeleteLink(id, pagePath) {
|
||||
let icon = icons + "/ic_delete_black_24dp.png";
|
||||
let formURL = pagePath + "/delete";
|
||||
|
||||
let html =
|
||||
'<a href="#!" onclick="handleDeleteRequest(\'' +
|
||||
id +
|
||||
"')\">" +
|
||||
'<img src="' +
|
||||
icon +
|
||||
'" title="Delete"></a>' +
|
||||
'<form id="deleteForm' +
|
||||
id +
|
||||
'" action="' +
|
||||
formURL +
|
||||
'" method="post">' +
|
||||
'<input name="id" type="hidden" value="' +
|
||||
id +
|
||||
'"></form>';
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a RIM delete link for the specified ID
|
||||
* @param id of the RIM
|
||||
* @param pagePath path to the link
|
||||
*/
|
||||
function rimDeleteLink(id, pagePath) {
|
||||
let icon = icons + "/ic_delete_black_24dp.png";
|
||||
let formURL = pagePath + "/delete";
|
||||
|
||||
let html =
|
||||
'<a href="#!" onclick="handleRimDeleteRequest(\'' +
|
||||
id +
|
||||
"')\">" +
|
||||
'<img src="' +
|
||||
icon +
|
||||
'" title="Delete"></a>' +
|
||||
'<form id="deleteForm' +
|
||||
id +
|
||||
'" action="' +
|
||||
formURL +
|
||||
'" method="post">' +
|
||||
'<input name="id" type="hidden" value="' +
|
||||
id +
|
||||
'"></form>';
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a certificate download link for the specified ID
|
||||
* @param id of the certificate
|
||||
* @param pagePath path to the link
|
||||
*/
|
||||
function certificateDownloadLink(id, pagePath) {
|
||||
let icon = icons + "/ic_file_download_black_24dp.png";
|
||||
let href = pagePath + "/download?id=" + id;
|
||||
|
||||
let html =
|
||||
'<a href="' +
|
||||
href +
|
||||
'">' +
|
||||
'<img src="' +
|
||||
icon +
|
||||
'" title="Download Certificate"></a>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a rim download link for the specified ID
|
||||
* @param id of the rim
|
||||
* @param pagePath path to the link
|
||||
*/
|
||||
function rimDownloadLink(id, pagePath) {
|
||||
let icon = icons + "/ic_file_download_black_24dp.png";
|
||||
let href = pagePath + "/download?id=" + id;
|
||||
|
||||
let html =
|
||||
'<a href="' +
|
||||
href +
|
||||
'">' +
|
||||
'<img src="' +
|
||||
icon +
|
||||
'" title="Download Reference Integrity Manifest"></a>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a given date to a UTC string, or returns an indefinite icon
|
||||
* @param date to format
|
||||
*/
|
||||
function formatCertificateDate(dateText) {
|
||||
let date = +dateText; // Convert to numeric
|
||||
|
||||
if (date == 253402300799000) {
|
||||
return "Indefinite";
|
||||
}
|
||||
|
||||
return new Date(date).toUTCString();
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
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
@ -1,325 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.6.2 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors
|
||||
* Copyright 2011-2022 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #212529;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
[tabindex="-1"]:focus:not(:focus-visible) {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-original-title] {
|
||||
text-decoration: underline;
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
border-bottom: 0;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: .5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #0056b3;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:not([href]):not([class]) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
-ms-overflow-style: scrollbar;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
color: #6c757d;
|
||||
text-align: left;
|
||||
caption-side: bottom;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
input {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
button:not(:disabled),
|
||||
[type="button"]:not(:disabled),
|
||||
[type="reset"]:not(:disabled),
|
||||
[type="submit"]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: .5rem;
|
||||
font-size: 1.5rem;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type="search"] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
File diff suppressed because one or more lines are too long
@ -1,8 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.6.2 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors
|
||||
* Copyright 2011-2022 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([class]){color:inherit;text-decoration:none}a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit;text-align:-webkit-match-parent}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
||||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
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
File diff suppressed because it is too large
Load Diff
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
File diff suppressed because it is too large
Load Diff
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
Loading…
x
Reference in New Issue
Block a user