Merge pull request #530 from nsacyber/migration-update

Migration update
This commit is contained in:
iadgovuser26 2023-06-13 15:08:25 -04:00 committed by GitHub
commit 1d00339a78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
311 changed files with 42916 additions and 651 deletions

View File

@ -27,6 +27,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:3.0.1'
implementation 'com.github.darrachequesne:spring-data-jpa-datatables:6.0.1'
implementation 'org.springframework.retry:spring-retry:2.0.0'
implementation libs.springdatajpa
implementation libs.bouncycastle
implementation libs.commons.codec

View File

@ -1,6 +1,6 @@
package hirs.attestationca.persist;
import hirs.attestationca.persist.entity.userdefined.SupplyChainSettings;
import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@ -46,7 +46,7 @@ public class PCRQuoteValidator {
private String[] baselinePCRS = new String[MAX_PCR_ID + 1];
@Getter
@Setter
private SupplyChainSettings settings;
private PolicySettings settings;
/**
* Constructor to parse PCR values.
@ -54,7 +54,7 @@ public class PCRQuoteValidator {
* @param settings settings for the supply chain portal settings for provisioning
*/
public PCRQuoteValidator(final String[] pcrValues,
final SupplyChainSettings settings) {
final PolicySettings settings) {
if (pcrValues != null) {
baselinePCRS = new String[MAX_PCR_ID + 1];
for (int i = 0; i <= MAX_PCR_ID; i++) {

View File

@ -0,0 +1,92 @@
package hirs.attestationca.persist;
import hirs.attestationca.persist.service.FilesStorageService;
import hirs.attestationca.persist.service.FilesStorageServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Persistence Configuration for Spring enabled applications. Constructs a Hibernate SessionFactory
* backed powered by a HikariCP connection pooled data source. Module-specific settings
* need to be set in the persistence-extended.properties file on the classpath. If another module
* such as the HIRS_Portal uses this class and doesn't have a persistence-extended.properties
* file, the default persistence file will be used instead.
*/
@Configuration
public class PersistenceConfiguration {
@Bean
public FilesStorageService filesStorageService() {
FilesStorageServiceImpl filesStorageService = new FilesStorageServiceImpl(new StorageProperties());
filesStorageService.init();
return filesStorageService;
}
// /**
// * Creates a {@link CertificateServiceImpl} ready to use.
// *
// * @return {@link CertificateServiceImpl}
// */
// @Bean
// public CertificateServiceImpl certificateServiceImpl() {
// CertificateServiceImpl manager = new CertificateServiceImpl();
// setDbManagerRetrySettings(manager);
// return manager;
// }
//
// /**
// * Creates a {@link DeviceServiceImpl} ready to use.
// *
// * @return {@link DeviceServiceImpl}
// */
// @Bean
// public DeviceServiceImpl deviceServiceImpl() {
// DeviceServiceImpl manager = new DeviceServiceImpl();
// setDbManagerRetrySettings(manager);
// return manager;
// }
//
// /**
// * Creates a {@link PolicyServiceImpl} ready to use.
// *
// * @return {@link PolicyServiceImpl}
// */
// @Bean
// public PolicyServiceImpl policyServiceImpl() {
// PolicyServiceImpl manager = new PolicyServiceImpl();
// setDbManagerRetrySettings(manager);
// return manager;
// }
//
// /**
// * Creates a {@link ReferenceManifestServiceImpl} ready to use.
// *
// * @return {@link ReferenceManifestServiceImpl}
// */
// @Bean
// public ReferenceManifestServiceImpl referenceManifestServiceImpl() {
// ReferenceManifestServiceImpl manager = new ReferenceManifestServiceImpl();
// setDbManagerRetrySettings(manager);
// return manager;
// }
//
// /**
// * Creates a {@link ReferenceDigestValueServiceImpl} ready to use.
// *
// * @return {@link ReferenceDigestValueServiceImpl}
// */
// @Bean
// public ReferenceDigestValueServiceImpl referenceDigestValueServiceImpl() {
// ReferenceDigestValueServiceImpl manager = new ReferenceDigestValueServiceImpl();
// setDbManagerRetrySettings(manager);
// return manager;
// }
//
// /**
// * Apply the spring-wired retry template settings to the db manager.
// * @param dbManager the manager to apply the retry settings to
// */
// private void setDbManagerRetrySettings(final DefaultDbService dbManager) {
// dbManager.setRetryTemplate();
// }
}

View File

@ -0,0 +1,21 @@
package hirs.attestationca.persist;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("storage")
public class StorageProperties {
/**
* Folder location for storing files
*/
private String location = "/tmp/hirs";
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}

View File

@ -1,11 +1,38 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.math.BigInteger;
import java.util.List;
import java.util.UUID;
@Repository
public interface CertificateRepository extends JpaRepository<Certificate, UUID> {
public interface CertificateRepository<T extends Certificate> extends JpaRepository<Certificate, UUID> {
@Query(value = "SELECT * FROM Certificate where id = ?1", nativeQuery = true)
Certificate getCertificate(UUID uuid);
@Query(value = "SELECT * FROM Certificate where issuer = ?1 AND DTYPE = ?2", nativeQuery = true)
List<Certificate> findBySubject(String issuer, String dType);
@Query(value = "SELECT * FROM Certificate where issuerSorted = ?1 AND DTYPE = ?2", nativeQuery = true)
List<Certificate> findBySubjectSorted(String issuedSort, String dType);
@Query(value = "SELECT * FROM Certificate where DTYPE = ?1", nativeQuery = true)
List<T> findByAll(String dType);
@Query(value = "SELECT * FROM Certificate where device.id = ?1 AND DTYPE = 'PlatformCredential'", nativeQuery = true)
PlatformCredential findByDeviceId(UUID deviceId);
@Query(value = "SELECT * FROM Certificate where serialNumber = ?1 AND DTYPE = ?2", nativeQuery = true)
Certificate findBySerialNumber(BigInteger serialNumber, String dType);
@Query(value = "SELECT * FROM Certificate where platformSerial = ?1 AND DTYPE = 'PlatformCredential'", nativeQuery = true)
List<PlatformCredential> byBoardSerialNumber(String boardSerialNumber);
@Query(value = "SELECT * FROM Certificate where holderSerialNumber = ?1 AND DTYPE = 'PlatformCredential'", nativeQuery = true)
PlatformCredential byHolderSerialNumber(BigInteger holderSerialNumber);
@Query(value = "SELECT * FROM Certificate where holderSerialNumber = ?1 AND DTYPE = dType", nativeQuery = true)
T byHolderSerialNumber(BigInteger holderSerialNumber, String dType);
@Query(value = "SELECT * FROM Certificate where certificateHash = ?1 AND DTYPE = ?2", nativeQuery = true)
T findByCertificateHash(int certificateHash, String dType);
@Query(value = "SELECT * FROM Certificate where subjectKeyIdentifier = ?1", nativeQuery = true)
Certificate findBySubjectKeyIdentifier(byte[] skiCA);
}

View File

@ -0,0 +1,16 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.UUID;
@Repository
public interface ComponentResultRepository extends JpaRepository<ComponentResult, UUID> {
@Query(value = "SELECT * FROM ComponentResult where certificateId = ?1", nativeQuery = true)
List<ComponentResult> getComponentResultsByCertificate(UUID certificateId);
}

View File

@ -4,10 +4,9 @@ import hirs.attestationca.persist.entity.userdefined.Device;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.UUID;
@Repository
public interface DeviceRepository extends JpaRepository<Device, UUID> {
List<Device> findByName(String deviceName);
Device findByName(String deviceName);
}

View File

@ -0,0 +1,12 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.UUID;
@Repository
public interface PolicyRepository extends JpaRepository<PolicySettings, UUID> {
PolicySettings findByName(String name);
}

View File

@ -2,10 +2,23 @@ package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.UUID;
@Repository
public interface ReferenceDigestValueRepository extends JpaRepository<ReferenceDigestValue, UUID> {
@Query(value = "SELECT * FROM ReferenceDigestValue", nativeQuery = true)
List<ReferenceDigestValue> listAll();
@Query(value = "SELECT * FROM ReferenceDigestValue WHERE model = ?1", nativeQuery = true)
List<ReferenceDigestValue> listByModel(String model);
@Query(value = "SELECT * FROM ReferenceDigestValue WHERE manufacturer = ?1", nativeQuery = true)
List<ReferenceDigestValue> listByManufacturer(String manufacturer);
@Query(value = "SELECT * FROM ReferenceDigestValue WHERE baseRimId = '?1' OR supportRimId = '?1'", nativeQuery = true)
List<ReferenceDigestValue> getValuesByRimId(UUID associatedRimId);
@Query(value = "SELECT * FROM ReferenceDigestValue WHERE supportRimId = '?1'", nativeQuery = true)
List<ReferenceDigestValue> getValuesBySupportRimId(UUID supportRimId);
}

View File

@ -1,11 +1,39 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.rim.BaseReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.rim.EventLogMeasurements;
import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.UUID;
@Repository
public interface ReferenceManifestRepository extends JpaRepository<ReferenceManifest, UUID> {
@Query(value = "SELECT * FROM ReferenceManifest WHERE hexDecHash = ?1", nativeQuery = true)
ReferenceManifest findByHash(String rimHash);
@Query(value = "SELECT * FROM ReferenceManifest WHERE hexDecHash = ?1 AND rimType = ?2", nativeQuery = true)
ReferenceManifest findByHash(String rimHash, String rimType);
@Query(value = "SELECT * FROM ReferenceManifest WHERE platformManufacturer = ?1 AND platformModel = ?2 AND rimType = 'Base'", nativeQuery = true)
List<BaseReferenceManifest> getBaseByManufacturerModel(String manufacturer, String model);
@Query(value = "SELECT * FROM ReferenceManifest WHERE platformManufacturer = ?1 AND DTYPE = ?2", nativeQuery = true)
ReferenceManifest getByManufacturer(String manufacturer, String dType);
@Query(value = "SELECT * FROM ReferenceManifest WHERE platformModel = ?1 AND DTYPE = ?2", nativeQuery = true)
ReferenceManifest getByModel(String model, String dType);
@Query(value = "SELECT * FROM ReferenceManifest WHERE DTYPE = 'BaseReferenceManifest'", nativeQuery = true)
List<BaseReferenceManifest> findAllBaseRims();
@Query(value = "SELECT * FROM ReferenceManifest WHERE DTYPE = 'SupportReferenceManifest'", nativeQuery = true)
List<SupportReferenceManifest> findAllSupportRims();
@Query(value = "SELECT * FROM ReferenceManifest WHERE id = ?1 AND DTYPE = 'BaseReferenceManifest'", nativeQuery = true)
BaseReferenceManifest getBaseRimEntityById(UUID uuid);
@Query(value = "SELECT * FROM ReferenceManifest WHERE id = ?1 AND DTYPE = 'SupportReferenceManifest'", nativeQuery = true)
SupportReferenceManifest getSupportRimEntityById(UUID uuid);
@Query(value = "SELECT * FROM ReferenceManifest WHERE id = ?1 AND DTYPE = 'EventLogMeasurements'", nativeQuery = true)
EventLogMeasurements getEventLogRimEntityById(UUID uuid);
@Query(value = "SELECT * FROM ReferenceManifest WHERE deviceName = ?1 AND DTYPE = 'SupportReferenceManifest'", nativeQuery = true)
List<SupportReferenceManifest> byDeviceName(String deviceName);
}

View File

@ -2,8 +2,10 @@ package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.UUID;
@Repository
public interface SupplyChainValidationRepository extends JpaRepository<SupplyChainValidation, UUID> {
}

View File

@ -0,0 +1,11 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.UUID;
@Repository
public interface SupplyChainValidationSummaryRepository extends JpaRepository<SupplyChainValidationSummary, UUID> {
}

View File

@ -7,6 +7,8 @@ import hirs.attestationca.persist.entity.userdefined.certificate.CertificateVari
import hirs.utils.HexUtils;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.persistence.Transient;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;
@ -75,6 +77,7 @@ import java.util.Objects;
* It stores certain attributes separately from the serialized certificate to enable querying on
* those attributes.
*/
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Log4j2
@Entity
public abstract class Certificate extends ArchivableEntity {
@ -128,6 +131,7 @@ public abstract class Certificate extends ArchivableEntity {
* Holds the name of the 'issuer' field.
*/
public static final String ISSUER_FIELD = "issuer";
@Getter
@Column(nullable = false)
private final String issuer;
/**
@ -171,6 +175,7 @@ public abstract class Certificate extends ArchivableEntity {
@Column(length = CertificateVariables.MAX_PUB_KEY_MODULUS_HEX_LENGTH, nullable = true)
private final String publicKeyModulusHexValue;
@Getter
@Column(length = CertificateVariables.MAX_CERT_LENGTH_BYTES, nullable = false)
private final byte[] signature;
@ -180,7 +185,7 @@ public abstract class Certificate extends ArchivableEntity {
@Column(nullable = false)
private final Date endValidity;
@Column(length = CertificateVariables.MAX_CERT_LENGTH_BYTES, nullable = false)
@Column(length = CertificateVariables.MAX_CERT_LENGTH_BYTES*CertificateVariables.KEY_USAGE_BIT4, nullable = false)
@JsonIgnore
private byte[] certificateBytes;
@ -250,7 +255,6 @@ public abstract class Certificate extends ArchivableEntity {
this.subject = null;
this.issuerSorted = null;
this.subjectSorted = null;
this.encodedPublicKey = null;
this.publicKeyModulusHexValue = null;
this.signature = null;

View File

@ -0,0 +1,123 @@
package hirs.attestationca.persist.entity.userdefined;
import hirs.attestationca.persist.entity.UserDefinedEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* Class represents Supply Chain policy. Supply Chain Policy identifies the methods in
* SupplyChainValidator that should be used in order to validate a supply chain.
* By default, the policy does not enable any validations.
*/
@Table(name = "PolicySettings")
@Getter
@Setter
@Entity
@ToString(callSuper = true)
public class PolicySettings extends UserDefinedEntity {
/**
* Name of the default Supply Chain Policy.
*/
public static final String DEFAULT_POLICY = "Default Supply Chain Policy";
/**
* Number of days in 10 years.
*/
public static final String TEN_YEARS = "3651";
/**
* Number of days in 1 year.
*/
public static final String YEAR = "365";
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean ecValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean pcValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean pcAttributeValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean firmwareValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean utcValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean expiredCertificateValidationEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean replaceEC = false;
@Column(nullable = false, columnDefinition = "boolean default true")
private boolean issueAttestationCertificate = true;
@Column(nullable = false, columnDefinition = "boolean default true")
private boolean issueDevIdCertificate = true;
@Column(nullable = false)
private String validityDays = TEN_YEARS;
@Column(nullable = false)
private String devIdValidityDays = TEN_YEARS;
@Column(nullable = false)
private String reissueThreshold = YEAR;
@Column(nullable = false)
private String devIdReissueThreshold = YEAR;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean generateOnExpiration = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean devIdExpirationFlag = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean ignoreImaEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean ignoretBootEnabled = false;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean linuxOs = false;
@Column(nullable = false, columnDefinition = "boolean default true")
private boolean ignoreGptEnabled = true;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean ignoreOsEvtEnabled = false;
/**
* Default constructor necessary for Hibernate.
*/
protected PolicySettings() {
super();
}
/**
* Constructor used to initialize PolicySettings object.
*
* @param name
* A name used to uniquely identify and reference the Supply Chain policy.
*/
public PolicySettings(final String name) {
super(name);
}
/**
* Constructor used to initialize PolicySettings object.
*
* @param name
* A name used to uniquely identify and reference the supply chain policy.
* @param description
* Optional description of the policy that can be added by the user
*/
public PolicySettings(final String name, final String description) {
super(name, description);
}
}

View File

@ -7,6 +7,8 @@ import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import jakarta.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@ -29,6 +31,7 @@ import java.util.UUID;
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
@Log4j2
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "ReferenceManifest")
@Access(AccessType.FIELD)
public class ReferenceManifest extends ArchivableEntity {

View File

@ -16,6 +16,7 @@ import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import lombok.Getter;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
@ -39,6 +40,7 @@ import java.util.UUID;
@Entity
public class SupplyChainValidationSummary extends ArchivableEntity {
@Getter
@ManyToOne
@JoinColumn(name = "device_id")
private final Device device;
@ -49,6 +51,7 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
@Enumerated(EnumType.STRING)
private final AppraisalStatus.Status overallValidationResult;
@Getter
@Column(length = RESULT_MESSAGE_LENGTH)
private final String message;
@ -201,15 +204,6 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
this.message = status.getMessage();
}
/**
* This retrieves the device associated with the supply chain validation summaries.
*
* @return the validated device
*/
public Device getDevice() {
return device;
}
/**
* @return the overall appraisal result
*/
@ -217,13 +211,6 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
return overallValidationResult;
}
/**
* @return the fail message if there is a failure.
*/
public String getMessage() {
return message;
}
/**
* @return the validations that this summary contains
*/

View File

@ -1,7 +1,7 @@
package hirs.attestationca.persist.entity.userdefined.certificate;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.service.CertificateService;
import hirs.attestationca.persist.service.CertificateServiceImpl;
import hirs.attestationca.persist.service.selector.CertificateSelector;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@ -51,13 +51,13 @@ public class CertificateAuthorityCredential extends Certificate {
*/
public static class Selector extends CertificateSelector<CertificateAuthorityCredential> {
/**
* Construct a new CertificateSelector that will use the given {@link CertificateService} to
* Construct a new CertificateSelector that will use the given {@link CertificateServiceImpl} to
* retrieve one or many CertificateAuthorityCredentials.
*
* @param certificateManager the certificate manager to be used to retrieve certificates
* @param certificateService the certificate manager to be used to retrieve certificates
*/
public Selector(final CertificateService certificateManager) {
super(certificateManager, CertificateAuthorityCredential.class);
public Selector(final CertificateServiceImpl certificateService) {
super(certificateService, CertificateAuthorityCredential.class);
}
/**
@ -79,7 +79,7 @@ public class CertificateAuthorityCredential extends Certificate {
* @param certMan the CertificateService to be used to retrieve persisted certificates
* @return a CertificateAuthorityCredential.Selector instance to use for retrieving certificates
*/
public static Selector select(final CertificateService certMan) {
public static Selector select(final CertificateServiceImpl certMan) {
return new Selector(certMan);
}

View File

@ -2,8 +2,10 @@ package hirs.attestationca.persist.entity.userdefined.certificate;
import hirs.attestationca.persist.entity.AbstractEntity;
import jakarta.persistence.Entity;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.Objects;
import java.util.UUID;
@ -11,6 +13,7 @@ import java.util.UUID;
@EqualsAndHashCode(callSuper=false)
@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ComponentResult extends AbstractEntity {
private UUID certificateId;
@ -19,12 +22,6 @@ public class ComponentResult extends AbstractEntity {
private String actual;
private boolean mismatched;
/**
* Hibernate default constructor
*/
protected ComponentResult() {
}
public ComponentResult(final UUID certificateId, final int componentHash,
final String expected, final String actual) {
this.certificateId = certificateId;

View File

@ -10,10 +10,9 @@ import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.asn1.ASN1ApplicationSpecific;
import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1Boolean;
@ -63,6 +62,7 @@ import java.util.Set;
*
* trustedcomputinggroup.org/wp-content/uploads/Credential_Profiles_V1.2_Level2_Revision8.pdf
*/
@Log4j2
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor(access= AccessLevel.PROTECTED)
@Entity
@ -105,8 +105,6 @@ public class EndorsementCredential extends DeviceAssociatedCertificate {
// number of extra bytes potentially present in a cert header.
private static final int EK_CERT_HEADER_BYTE_COUNT = 7;
private static final Logger LOG = LogManager.getLogger(EndorsementCredential.class);
/**
* This class enables the retrieval of EndorsementCredential by their attributes.
*/
@ -227,8 +225,6 @@ public class EndorsementCredential extends DeviceAssociatedCertificate {
@Transient
private Map<String, Object> parsedFields;
private static final Logger LOGGER = LogManager.getLogger(EndorsementCredential.class);
/**
* Construct a new EndorsementCredential given its binary contents. The given
* certificate should represent either an X509 certificate or X509 attribute certificate.
@ -260,7 +256,6 @@ public class EndorsementCredential extends DeviceAssociatedCertificate {
* @return the EC if a valid credential, null otherwise
*/
public static EndorsementCredential parseWithPossibleHeader(final byte[] certificateBytes) {
try {
// first, attempt parsing as is
return new EndorsementCredential(certificateBytes);
@ -272,7 +267,7 @@ public class EndorsementCredential extends DeviceAssociatedCertificate {
}
}
LOG.debug("Attempting parse after removing extra header bytes");
log.debug("Attempting parse after removing extra header bytes");
try {
byte[] truncatedBytes = ArrayUtils.subarray(
certificateBytes, EK_CERT_HEADER_BYTE_COUNT,
@ -341,13 +336,13 @@ public class EndorsementCredential extends DeviceAssociatedCertificate {
value = entry.getValue();
if (oid.equals(TPM_MODEL)) {
model = value.toString();
LOGGER.debug("Found TPM Model: " + model);
log.debug("Found TPM Model: " + model);
} else if (oid.equals(TPM_VERSION)) {
version = value.toString();
LOGGER.debug("Found TPM Version: " + version);
log.debug("Found TPM Version: " + version);
} else if (oid.equals(TPM_MANUFACTURER)) {
manufacturer = value.toString();
LOGGER.debug("Found TPM Manufacturer: " + manufacturer);
log.debug("Found TPM Manufacturer: " + manufacturer);
}
}
}
@ -392,7 +387,7 @@ public class EndorsementCredential extends DeviceAssociatedCertificate {
ASN1Integer revision = (ASN1Integer) seq.getObjectAt(ASN1_REV_INDEX);
tpmSpecification = new TPMSpecification(family.getString(), level.getValue(),
revision.getValue());
LOGGER.debug("Found TPM Spec:" + tpmSpecification.toString());
log.debug("Found TPM Spec:" + tpmSpecification.toString());
} else if (addToMapping && key.equals(TPM_SECURITY_ASSERTIONS)) {
// Parse TPM Security Assertions
int seqPosition = 0;
@ -420,7 +415,7 @@ public class EndorsementCredential extends DeviceAssociatedCertificate {
tpmSecurityAssertions = new TPMSecurityAssertions(ver.getValue(),
fieldUpgradeable.isTrue());
LOGGER.debug("Found TPM Assertions: " + tpmSecurityAssertions.toString());
log.debug("Found TPM Assertions: " + tpmSecurityAssertions.toString());
// Iterate through remaining fields to set optional attributes
int tag;
DERTaggedObject obj;
@ -536,7 +531,7 @@ public class EndorsementCredential extends DeviceAssociatedCertificate {
while (setContents.hasMoreElements()) {
subComp = (ASN1Encodable) setContents.nextElement();
if (subComp instanceof ASN1ObjectIdentifier) {
LOGGER.warn("OID in top level of ASN1Set");
log.warn("OID in top level of ASN1Set");
}
parseSingle((ASN1Primitive) subComp, addToMapping, key);
}
@ -646,7 +641,7 @@ public class EndorsementCredential extends DeviceAssociatedCertificate {
} else {
// there are some deprecated types that we don't parse
LOGGER.error("Unparsed type: " + component.getClass());
log.error("Unparsed type: " + component.getClass());
}
}
}

View File

@ -7,7 +7,7 @@ import hirs.attestationca.persist.entity.userdefined.certificate.attributes.Plat
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.TBBSecurityAssertion;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.URIReference;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.PlatformConfigurationV2;
import hirs.attestationca.persist.service.CertificateService;
import hirs.attestationca.persist.service.CertificateServiceImpl;
import hirs.attestationca.persist.service.selector.CertificateSelector;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@ -133,13 +133,13 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
*/
public static class Selector extends CertificateSelector<PlatformCredential> {
/**
* Construct a new CertificateSelector that will use the given {@link CertificateService} to
* Construct a new CertificateSelector that will use the given {@link CertificateServiceImpl} to
* retrieve one or many PlatformCredentials.
*
* @param certificateManager the certificate manager to be used to retrieve certificates
* @param certificateService the certificate manager to be used to retrieve certificates
*/
public Selector(final CertificateService certificateManager) {
super(certificateManager, PlatformCredential.class);
public Selector(final CertificateServiceImpl certificateService) {
super(certificateService, PlatformCredential.class);
}
/**
@ -275,11 +275,11 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
/**
* Get a Selector for use in retrieving PlatformCredentials.
*
* @param certMan the CertificateManager to be used to retrieve persisted certificates
* @param certificateService the CertificateManager to be used to retrieve persisted certificates
* @return a PlatformCredential.Selector instance to use for retrieving certificates
*/
public static Selector select(final CertificateService certMan) {
return new Selector(certMan);
public static Selector select(final CertificateServiceImpl certificateService) {
return new Selector(certificateService);
}
/**

View File

@ -211,7 +211,7 @@ public class ComponentClass {
for (Member member : components) {
typeID = verifyComponentValue(member.getName());
if (component.equals(typeID)) {
if (component.equalsIgnoreCase(typeID)) {
componentStr = member.getValue().asString();
}
}

View File

@ -2,7 +2,6 @@ package hirs.attestationca.persist.entity.userdefined.rim;
import com.fasterxml.jackson.annotation.JsonIgnore;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.service.ReferenceManifestService;
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
import hirs.attestationca.persist.service.selector.ReferenceManifestSelector;
import hirs.utils.SwidResource;
@ -26,8 +25,7 @@ import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import lombok.extern.log4j.Log4j2;
import javax.xml.namespace.QName;
import javax.xml.validation.Schema;
@ -44,13 +42,12 @@ import java.util.Map;
/**
*
*/
@Log4j2
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class BaseReferenceManifest extends ReferenceManifest {
private static final Logger LOGGER = LogManager.getLogger(BaseReferenceManifest.class);
/**
* Holds the name of the 'base64Hash' field.
*/
@ -107,7 +104,7 @@ public class BaseReferenceManifest extends ReferenceManifest {
* @param referenceManifestManager the reference manifest manager to be used to retrieve
* reference manifests.
*/
public Selector(final ReferenceManifestService referenceManifestManager) {
public Selector(final ReferenceManifestServiceImpl referenceManifestManager) {
super(referenceManifestManager, BaseReferenceManifest.class);
}
@ -227,7 +224,7 @@ public class BaseReferenceManifest extends ReferenceManifest {
this.base64Hash = Base64.getEncoder().encodeToString(
digest.digest(rimBytes));
} catch (NoSuchAlgorithmException noSaEx) {
LOGGER.error(noSaEx);
log.error(noSaEx);
}
// begin parsing valid swid tag
@ -350,7 +347,7 @@ public class BaseReferenceManifest extends ReferenceManifest {
* persisted RIMs
* @return a Selector instance to use for retrieving RIMs
*/
public static Selector select(final ReferenceManifestService rimMan) {
public static Selector select(final ReferenceManifestServiceImpl rimMan) {
return new Selector(rimMan);
}
@ -367,7 +364,7 @@ public class BaseReferenceManifest extends ReferenceManifest {
JAXBElement jaxbe = unmarshallSwidTag(fileStream);
SoftwareIdentity swidTag = (SoftwareIdentity) jaxbe.getValue();
LOGGER.info(String.format("SWID Tag found: %nname: %s;%ntagId: %s%n%s",
log.debug(String.format("SWID Tag found: %nname: %s;%ntagId: %s%n%s",
swidTag.getName(), swidTag.getTagId(), SCHEMA_STATEMENT));
return swidTag;
}
@ -397,7 +394,7 @@ public class BaseReferenceManifest extends ReferenceManifest {
}
} catch (IOException ioEx) {
LOGGER.error("Failed to parse Swid Tag bytes.", ioEx);
log.error("Failed to parse Swid Tag bytes.", ioEx);
}
}
@ -425,16 +422,16 @@ public class BaseReferenceManifest extends ReferenceManifest {
unmarshaller.setSchema(schema);
jaxbe = (JAXBElement) unmarshaller.unmarshal(stream);
} catch (UnmarshalException umEx) {
LOGGER.error(String.format("Error validating swidtag file!%n%s%n%s",
log.error(String.format("Error validating swidtag file!%n%s%n%s",
umEx.getMessage(), umEx.toString()));
for (StackTraceElement ste : umEx.getStackTrace()) {
LOGGER.error(ste.toString());
log.error(ste.toString());
}
} catch (IllegalArgumentException iaEx) {
LOGGER.error("Input file empty.");
log.error("Input file empty.");
} catch (JAXBException jaxEx) {
for (StackTraceElement ste : jaxEx.getStackTrace()) {
LOGGER.error(ste.toString());
log.error(ste.toString());
}
}
@ -463,27 +460,30 @@ public class BaseReferenceManifest extends ReferenceManifest {
public final List<SwidResource> parseResource(final ResourceCollection rc) {
List<SwidResource> resources = new ArrayList<>();
log.error("Parsing stuff");
try {
if (rc != null) {
for (Meta meta : rc.getDirectoryOrFileOrProcess()) {
if (meta != null) {
if (meta instanceof Directory) {
Directory directory = (Directory) meta;
for (FilesystemItem fsi : directory.getDirectoryOrFile()) {
if (fsi != null) {
resources.add(new SwidResource(
(File) fsi, null));
}
if (meta instanceof Directory) {
Directory directory = (Directory) meta;
for (FilesystemItem fsi : directory.getDirectoryOrFile()) {
if (fsi != null) {
resources.add(new SwidResource(
(File) fsi, null));
} else {
log.error("fsi is negative");
}
} else if (meta instanceof File) {
resources.add(new SwidResource((File) meta, null));
}
} else if (meta instanceof File) {
resources.add(new SwidResource((File) meta, null));
}
}
} else {
log.error("ResourceCollection is negative");
}
} catch (ClassCastException ccEx) {
LOGGER.error(ccEx);
LOGGER.error("At this time, the code does not support the "
log.error(ccEx);
log.error("At this time, the code does not support the "
+ "particular formatting of this SwidTag's Payload.");
}
@ -495,7 +495,7 @@ public class BaseReferenceManifest extends ReferenceManifest {
return String.format("ReferenceManifest{swidName=%s,"
+ "platformManufacturer=%s,"
+ " platformModel=%s,"
+ "tagId=%s, rimHash=%s}",
+ "tagId=%s, base64Hash=%s}",
swidName, this.getPlatformManufacturer(),
this.getPlatformModel(), getTagId(), this.getBase64Hash());
}

View File

@ -3,7 +3,7 @@ package hirs.attestationca.persist.entity.userdefined.rim;
import com.fasterxml.jackson.annotation.JsonIgnore;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.service.ReferenceManifestService;
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
import hirs.attestationca.persist.service.selector.ReferenceManifestSelector;
import hirs.utils.tpm.eventlog.TCGEventLog;
import hirs.utils.tpm.eventlog.TpmPcrEvent;
@ -53,7 +53,7 @@ public class EventLogMeasurements extends ReferenceManifest {
* @param referenceManifestManager the reference manifest manager to be used to retrieve
* reference manifests.
*/
public Selector(final ReferenceManifestService referenceManifestManager) {
public Selector(final ReferenceManifestServiceImpl referenceManifestManager) {
super(referenceManifestManager, EventLogMeasurements.class, false);
}
@ -142,7 +142,7 @@ public class EventLogMeasurements extends ReferenceManifest {
* persisted RIMs
* @return a Selector instance to use for retrieving RIMs
*/
public static Selector select(final ReferenceManifestService rimMan) {
public static Selector select(final ReferenceManifestServiceImpl rimMan) {
return new Selector(rimMan);
}

View File

@ -2,7 +2,7 @@ package hirs.attestationca.persist.entity.userdefined.rim;
import com.fasterxml.jackson.annotation.JsonIgnore;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.service.ReferenceManifestService;
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
import hirs.attestationca.persist.service.selector.ReferenceManifestSelector;
import hirs.utils.tpm.eventlog.TCGEventLog;
import hirs.utils.tpm.eventlog.TpmPcrEvent;
@ -48,7 +48,7 @@ public class SupportReferenceManifest extends ReferenceManifest {
* @param referenceManifestManager the reference manifest manager to be used to retrieve
* reference manifests.
*/
public Selector(final ReferenceManifestService referenceManifestManager) {
public Selector(final ReferenceManifestServiceImpl referenceManifestManager) {
super(referenceManifestManager, SupportReferenceManifest.class);
}
@ -150,7 +150,7 @@ public class SupportReferenceManifest extends ReferenceManifest {
* persisted RIMs
* @return a Selector instance to use for retrieving RIMs
*/
public static Selector select(final ReferenceManifestService rimMan) {
public static Selector select(final ReferenceManifestServiceImpl rimMan) {
return new Selector(rimMan);
}

View File

@ -1,45 +1,35 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.DBManagerException;
import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.service.selector.CertificateSelector;
import jakarta.persistence.EntityManager;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@Log4j2
@NoArgsConstructor
@Service
public class CertificateServiceImpl<T extends Certificate> extends DefaultDbService<Certificate> implements CertificateService<Certificate> {
public class CertificateServiceImpl<T extends Certificate> extends DefaultDbService<T> {
@Autowired(required = false)
private EntityManager entityManager;
// @PersistenceContext // I'll need this if I want to make custom native calls
// private EntityManager entityManager;
@Autowired
private CertificateRepository repository;
private CertificateRepository certificateRepository;
@Override
public Certificate saveCertificate(Certificate certificate) {
return repository.save(certificate);
}
@Override
@SuppressWarnings("unchecked")
public <T extends Certificate> List<T> fetchCertificates(Class<T> classType) {
return (List<T>) repository.findAll(Sort.sort(classType));
}
@Override
public Certificate updateCertificate(Certificate certificate, UUID certificateId) {
return saveCertificate(certificate);
}
@Override
public Certificate updateCertificate(Certificate certificate) {
return saveCertificate(certificate);
/**
* Default Constructor.
*/
public CertificateServiceImpl(final Class<T> clazz) {
super(clazz);
this.defineRepository(certificateRepository);
}
/**
@ -73,13 +63,29 @@ public class CertificateServiceImpl<T extends Certificate> extends DefaultDbServ
return null;
}
/**
* Remove a certificate from the database.
* Archives the named object and updates it in the database.
*
* @param certificate the certificate to delete
* @return true if deletion was successful, false otherwise
* @param id UUID of the object to archive
* @return true if the object was successfully found and archived, false if the object was not
* found
* @throws hirs.attestationca.persist.DBManagerException if the object is not an instance of <code>ArchivableEntity</code>
*/
public void deleteCertificate(final Certificate certificate) {
repository.delete(certificate);
public final boolean archive(final UUID id) throws DBManagerException {
log.debug("archiving object: {}", id);
if (id == null) {
log.debug("null id argument");
return false;
}
T target = get(id);
if (target == null) {
return false;
}
((ArchivableEntity) target).archive();
this.certificateRepository.save(target);
return true;
}
}

View File

@ -1,7 +1,7 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.DBManagerException;
import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.AbstractEntity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import lombok.NoArgsConstructor;
@ -19,12 +19,14 @@ import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Log4j2
@Service
@NoArgsConstructor
public class DefaultDbService<T extends ArchivableEntity> extends HibernateDbService<T> {
public class DefaultDbService<T extends AbstractEntity> {
/**
* The default maximum number of retries to attempt a database transaction.
*/
@ -49,10 +51,29 @@ public class DefaultDbService<T extends ArchivableEntity> extends HibernateDbSer
* unfortunately class type of T cannot be determined using only T
*/
public DefaultDbService(final Class<T> clazz) {
super(clazz, null);
setRetryTemplate();
}
public void defineRepository(final JpaRepository repository) {
this.repository = repository;
}
public List<T> listAll() {
return this.repository.findAll();
}
public void save(final T entity) {
this.repository.save(entity);
}
public void delete(final T entity) {
this.repository.delete(entity);
}
public void delete(final UUID id) {
this.repository.deleteById(id);
}
/**
* Set the parameters used to retry database transactions. The retry template will
* retry transactions that throw a LockAcquisitionException or StaleObjectStateException.
@ -167,33 +188,4 @@ public class DefaultDbService<T extends ArchivableEntity> extends HibernateDbSer
return clazz.cast(entity);
}
/**
* Archives the named object and updates it in the database.
*
* @param name name of the object to archive
* @return true if the object was successfully found and archived, false if the object was not
* found
* @throws DBManagerException if the object is not an instance of <code>ArchivableEntity</code>
*/
// @Override
// public final boolean archive(final String name) throws DBManagerException {
// log.debug("archiving object: {}", name);
// if (name == null) {
// log.debug("null name argument");
// return false;
// }
//
// T target = get(name);
// if (target == null) {
// return false;
// }
// if (!(target instanceof ArchivableEntity)) {
// throw new DBManagerException("unable to archive non-archivable object");
// }
//
// ((ArchivableEntity) target).archive();
// repository.save(target);
// return true;
// }
}

View File

@ -12,9 +12,9 @@ import java.util.List;
* https://github.com/darrachequesne/spring-data-jpa-datatables
*/
@Service
public class DeviceServiceImpl {
public class DeviceServiceImpl extends DefaultDbService<Device> {
@Autowired(required = false)
@Autowired
private EntityManager entityManager;
@Autowired
private DeviceRepository deviceRepository;

View File

@ -0,0 +1,20 @@
package hirs.attestationca.persist.service;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Path;
import java.util.stream.Stream;
public interface FilesStorageService {
public void init();
public void save(MultipartFile file);
public Path load(String filename);
public boolean delete(String filename);
public void deleteAll();
public Stream<Path> loadAll();
}

View File

@ -0,0 +1,88 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.StorageProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.stream.Stream;
@Service
public class FilesStorageServiceImpl implements FilesStorageService {
private final Path rootLocation;
@Autowired
public FilesStorageServiceImpl(StorageProperties properties) {
this.rootLocation = Paths.get(properties.getLocation());
}
@Override
public void init() {
try {
Files.createDirectories(rootLocation);
} catch (IOException e) {
throw new RuntimeException("Could not initialize folder for upload!");
}
}
@Override
public void save(MultipartFile file) {
try {
if (file.isEmpty()) {
return ;
}
Path destinationFile = this.rootLocation.resolve(
Paths.get(file.getOriginalFilename()))
.normalize().toAbsolutePath();
if (!destinationFile.getParent().equals(this.rootLocation.toAbsolutePath())) {
// This is a security check
return ;
}
try (InputStream inputStream = file.getInputStream()) {
Files.copy(inputStream, destinationFile,
StandardCopyOption.REPLACE_EXISTING);
}
} catch (Exception e) {
if (e instanceof FileAlreadyExistsException) {
throw new RuntimeException("A file of that name already exists.");
}
throw new RuntimeException(e.getMessage());
}
}
@Override
public Path load(String filename) {
return rootLocation.resolve(filename);
}
@Override
public boolean delete(String filename) {
return false;
}
@Override
public void deleteAll() {
}
@Override
public Stream<Path> loadAll() {
try {
return Files.walk(this.rootLocation, 1)
.filter(path -> !path.equals(this.rootLocation))
.map(this.rootLocation::relativize);
}
catch (IOException e) {
return null;
}
}
}

View File

@ -0,0 +1,25 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.entity.manager.PolicyRepository;
import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import jakarta.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
//@Service
public class PolicyServiceImpl extends DefaultDbService<PolicySettings> {
@Autowired
private EntityManager entityManager;
@Autowired
private PolicyRepository repository;
public void saveSettings(PolicySettings settings) {
repository.save(settings);
}
// public Policy getDefaultPolicy(Appraiser appraiser) {
// return repository.findByAppraiser(appraiser);
// }
}

View File

@ -1,11 +1,8 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.datatables.mapping.DataTablesInput;
import org.springframework.data.jpa.datatables.mapping.DataTablesOutput;
import org.springframework.stereotype.Service;
import java.util.LinkedList;
@ -13,52 +10,12 @@ import java.util.List;
import java.util.UUID;
@Service
public class ReferenceDigestValueServiceImpl extends DefaultDbService<ReferenceDigestValue> implements ReferenceDigestValueService {
public class ReferenceDigestValueServiceImpl extends DefaultDbService<ReferenceDigestValue> {
@Autowired
private ReferenceDigestValueRepository repository;
@Override
public ReferenceDigestValue saveReferenceDigestValue(ReferenceDigestValue referenceDigestValue) {
return repository.save(referenceDigestValue);
}
public List<ReferenceDigestValue> findAll() {
return repository.findAll();
}
@Override
public List<ReferenceDigestValue> fetchDigestValues() {
return repository.findAll();
}
@Override
public ReferenceDigestValue updateRefDigestValue(ReferenceDigestValue referenceDigestValue, UUID rdvId) {
return saveReferenceDigestValue(referenceDigestValue);
}
public ReferenceDigestValue updateRefDigestValue(ReferenceDigestValue referenceDigestValue) {
if (referenceDigestValue.getId() != null) {
return updateRefDigestValue(referenceDigestValue, referenceDigestValue.getId());
}
return null;
}
public List<ReferenceDigestValue> getValuesByRimId(ReferenceManifest baseRim) {
List<ReferenceDigestValue> results = new LinkedList<>();
if (baseRim != null) {
for (ReferenceDigestValue rdv : repository.findAll()) {
if (rdv.getBaseRimId() == baseRim.getId()) {
results.add(rdv);
}
}
}
return results;
}
@Override
public void deleteRefDigestValueById(UUID rdvId) {
repository.getReferenceById(rdvId).archive();
public List<ReferenceDigestValue> getValuesByRimId(final UUID baseId) {
return new LinkedList<>();
}
}

View File

@ -3,13 +3,13 @@ package hirs.attestationca.persist.service;
import hirs.attestationca.persist.CriteriaModifier;
import hirs.attestationca.persist.DBManagerException;
import hirs.attestationca.persist.FilteredRecordsList;
import hirs.attestationca.persist.OrderedListQuerier;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.service.selector.ReferenceManifestSelector;
import jakarta.persistence.EntityManager;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.xml.sax.SAXException;
@ -20,12 +20,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@Log4j2
@Service
public class ReferenceManifestServiceImpl<T extends ReferenceManifest> extends DefaultDbService<ReferenceManifest> implements ReferenceManifestService<ReferenceManifest> {
public class ReferenceManifestServiceImpl<T extends ReferenceManifest> extends DefaultDbService<ReferenceManifest> implements OrderedListQuerier<ReferenceManifest> {
/**
* The variable that establishes a schema factory for xml processing.
@ -33,7 +31,7 @@ public class ReferenceManifestServiceImpl<T extends ReferenceManifest> extends D
public static final SchemaFactory SCHEMA_FACTORY
= SchemaFactory.newInstance(ReferenceManifest.SCHEMA_LANGUAGE);
@Autowired(required = false)
@Autowired
private EntityManager entityManager;
@Autowired
@ -77,29 +75,18 @@ public class ReferenceManifestServiceImpl<T extends ReferenceManifest> extends D
return schema;
}
@Override
public ReferenceManifest saveReferenceManifest(ReferenceManifest referenceManifest) {
return repository.save(referenceManifest);
}
@Override
public List<ReferenceManifest> fetchReferenceManifests() {
return repository.findAll();
}
/**
* This method does not need to be used directly as it is used by
* {@link ReferenceManifestSelector}'s get* methods. Regardless, it may be
* used to retrieve ReferenceManifest by other code in this package, given a
* configured ReferenceManifestSelector.
*
* @param referenceManifestSelector a configured
* {@link ReferenceManifestSelector} to use for querying
* @return the resulting set of ReferenceManifest, possibly empty
*/
@SuppressWarnings("unchecked")
public <T extends ReferenceManifest> List<T> get(
Class<T> classType) {
final ReferenceManifestSelector referenceManifestSelector) {
log.info("Getting the full set of Reference Manifest files.");
// return new HashSet<>(
// (List<T>) getWithCriteria(
@ -107,22 +94,7 @@ public class ReferenceManifestServiceImpl<T extends ReferenceManifest> extends D
// Collections.singleton(referenceManifestSelector.getCriterion())
// )
// );
return (List<T>) repository.findAll(Sort.sort(classType));
}
@Override
public ReferenceManifest updateReferenceManifest(ReferenceManifest referenceManifest, UUID rimId) {
return null;
}
@Override
public void deleteReferenceManifestById(UUID rimId) {
repository.deleteById(rimId);
}
@Override
public <T extends ReferenceManifest> Set<T> get(ReferenceManifestSelector referenceManifestSelector) {
return null;
return (List<T>) repository.findAll();
}
@Override
@ -130,7 +102,7 @@ public class ReferenceManifestServiceImpl<T extends ReferenceManifest> extends D
String columnToOrder, boolean ascending, int firstResult,
int maxResults, String search,
Map<String, Boolean> searchableColumns) throws DBManagerException {
return null;
return new FilteredRecordsList();
}
@Override
@ -139,6 +111,6 @@ public class ReferenceManifestServiceImpl<T extends ReferenceManifest> extends D
int firstResult, int maxResults, String search,
Map<String, Boolean> searchableColumns,
CriteriaModifier<ReferenceManifest> criteriaModifier) throws DBManagerException {
return null;
return new FilteredRecordsList<>();
}
}

View File

@ -1,5 +1,6 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.SupplyChainValidationRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
@ -9,7 +10,6 @@ import hirs.utils.BouncyCastleUtils;
import lombok.extern.log4j.Log4j2;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.security.KeyStore;
@ -18,43 +18,22 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@Log4j2
@Service
public class SupplyChainValidationServiceImpl extends DefaultDbService<SupplyChainValidation> implements SupplyChainValidationService {
//@Service
public class SupplyChainValidationServiceImpl extends DefaultDbService<SupplyChainValidation> {
@Autowired
SupplyChainValidationRepository repository;
@Autowired
private CertificateService certificateService;
private CertificateRepository certificateRepository;
public SupplyChainValidationServiceImpl(final CertificateService certificateService) {
public SupplyChainValidationServiceImpl(final CertificateRepository certificateRepository) {
super();
this.certificateService = certificateService;
}
@Override
public SupplyChainValidation saveSupplyChainValidation(SupplyChainValidation supplyChainValidation) {
return repository.save(supplyChainValidation);
}
@Override
public List<SupplyChainValidation> fetchSupplyChainValidations() {
return repository.findAll();
}
@Override
public SupplyChainValidation updateSupplyChainValidation(SupplyChainValidation supplyChainValidation, UUID scvId) {
return null;
}
@Override
public void deleteSupplyChainValidation(UUID scvId) {
repository.deleteById(scvId);
this.certificateRepository = certificateRepository;
}
/**
@ -111,28 +90,23 @@ public class SupplyChainValidationServiceImpl extends DefaultDbService<SupplyCha
final Certificate credential,
final Set<String> previouslyQueriedSubjects) {
CertificateAuthorityCredential skiCA = null;
Set<CertificateAuthorityCredential> certAuthsWithMatchingIssuer = new HashSet<>();
List<CertificateAuthorityCredential> certAuthsWithMatchingIssuer = new LinkedList<>();
if (credential.getAuthorityKeyIdentifier() != null
&& !credential.getAuthorityKeyIdentifier().isEmpty()) {
byte[] bytes = Hex.decode(credential.getAuthorityKeyIdentifier());
skiCA = CertificateAuthorityCredential
.select(certificateService)
.bySubjectKeyIdentifier(bytes).getCertificate();
skiCA = (CertificateAuthorityCredential) certificateRepository.findBySubjectKeyIdentifier(bytes);
}
if (skiCA == null) {
if (credential.getIssuerSorted() == null
|| credential.getIssuerSorted().isEmpty()) {
certAuthsWithMatchingIssuer = CertificateAuthorityCredential
.select(certificateService)
.bySubject(credential.getHolderIssuer())
.getCertificates();
certAuthsWithMatchingIssuer = certificateRepository.findBySubject(credential.getHolderIssuer(),
"CertificateAuthorityCredential");
} else {
//Get certificates by subject organization
certAuthsWithMatchingIssuer = CertificateAuthorityCredential
.select(certificateService)
.bySubjectSorted(credential.getIssuerSorted())
.getCertificates();
certAuthsWithMatchingIssuer = certificateRepository.findBySubjectSorted(credential.getIssuerSorted(),
"CertificateAuthorityCredential");
}
} else {
certAuthsWithMatchingIssuer.add(skiCA);
@ -171,10 +145,8 @@ public class SupplyChainValidationServiceImpl extends DefaultDbService<SupplyCha
PlatformCredential baseCredential = null;
if (platformSerialNumber != null) {
List<PlatformCredential> chainCertificates = PlatformCredential
.select(certificateService)
.byBoardSerialNumber(platformSerialNumber)
.getCertificates().stream().collect(Collectors.toList());
List<PlatformCredential> chainCertificates = certificateRepository
.byBoardSerialNumber(platformSerialNumber);
for (PlatformCredential pc : chainCertificates) {
if (baseCredential != null && pc.isPlatformBase()) {

View File

@ -2,7 +2,6 @@ package hirs.attestationca.persist.service.selector;
import com.google.common.base.Preconditions;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.service.CertificateService;
import hirs.attestationca.persist.service.CertificateServiceImpl;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
@ -77,7 +76,7 @@ import java.util.UUID;
*/
public abstract class CertificateSelector<T extends Certificate> {
private final CertificateService certificateManager;
private final CertificateServiceImpl certificateService;
private final Class<T> certificateClass;
private final Map<String, Object> fieldValueSelections;
@ -87,28 +86,28 @@ public abstract class CertificateSelector<T extends Certificate> {
* Construct a new CertificateSelector that will use the given {@link CertificateServiceImpl} to
* retrieve certificates of the given type.
*
* @param certificateManager the certificate manager to be used to retrieve certificates
* @param certificateService the certificate manager to be used to retrieve certificates
* @param certificateClass the class of certificate to be retrieved
*/
public CertificateSelector(
final CertificateService certificateManager,
final CertificateServiceImpl certificateService,
final Class<T> certificateClass) {
this(certificateManager, certificateClass, true);
this(certificateService, certificateClass, true);
}
/**
* Construct a new CertificateSelector that will use the given {@link CertificateService} to
* Construct a new CertificateSelector that will use the given {@link CertificateServiceImpl } to
* retrieve certificates of the given type.
*
* @param certificateManager the certificate manager to be used to retrieve certificates
* @param certificateService the certificate manager to be used to retrieve certificates
* @param certificateClass the class of certificate to be retrieved
* @param excludeArchivedCertificates true if excluding archived certificates
*/
public CertificateSelector(
final CertificateService certificateManager,
final CertificateServiceImpl certificateService,
final Class<T> certificateClass, final boolean excludeArchivedCertificates) {
Preconditions.checkArgument(
certificateManager != null,
certificateService != null,
"certificate manager cannot be null"
);
@ -117,7 +116,7 @@ public abstract class CertificateSelector<T extends Certificate> {
"type cannot be null"
);
this.certificateManager = certificateManager;
this.certificateService = certificateService;
this.certificateClass = certificateClass;
this.fieldValueSelections = new HashMap<>();
this.excludeArchivedCertificates = excludeArchivedCertificates;
@ -459,7 +458,7 @@ public abstract class CertificateSelector<T extends Certificate> {
// construct and execute query
private Set<T> execute() {
return certificateManager.get(this);
return certificateService.get(this);
}
/**

View File

@ -3,7 +3,7 @@ package hirs.attestationca.persist.service.selector;
import com.google.common.base.Preconditions;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.service.ReferenceManifestService;
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
@ -12,16 +12,15 @@ import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* This class is used to select one or many RIMs in conjunction
* with a {@link ReferenceManifestService}. To make use of this object,
* with a {@link ReferenceManifestServiceImpl}. To make use of this object,
* use (some ReferenceManifest).select(ReferenceManifestManager).
*
* @param <T> the type of Reference Integrity Manifest that will be retrieved.
@ -45,7 +44,7 @@ public abstract class ReferenceManifestSelector<T extends ReferenceManifest> {
public static final String RIM_FILENAME_FIELD = "fileName";
private static final String RIM_TYPE_FIELD = "rimType";
private final ReferenceManifestService referenceManifestManager;
private final ReferenceManifestServiceImpl referenceManifestManager;
private final Class<T> referenceTypeClass;
private final Map<String, Object> fieldValueSelections;
@ -57,7 +56,7 @@ public abstract class ReferenceManifestSelector<T extends ReferenceManifest> {
* @param referenceManifestManager the RIM manager to be used to retrieve RIMs
* @param referenceTypeClass the type of Reference Manifest to process.
*/
public ReferenceManifestSelector(final ReferenceManifestService referenceManifestManager,
public ReferenceManifestSelector(final ReferenceManifestServiceImpl referenceManifestManager,
final Class<T> referenceTypeClass) {
this(referenceManifestManager, referenceTypeClass, true);
}
@ -69,7 +68,7 @@ public abstract class ReferenceManifestSelector<T extends ReferenceManifest> {
* @param referenceTypeClass the type of Reference Manifest to process.
* @param excludeArchivedRims true if excluding archived RIMs
*/
public ReferenceManifestSelector(final ReferenceManifestService referenceManifestManager,
public ReferenceManifestSelector(final ReferenceManifestServiceImpl referenceManifestManager,
final Class<T> referenceTypeClass,
final boolean excludeArchivedRims) {
Preconditions.checkArgument(
@ -164,7 +163,7 @@ public abstract class ReferenceManifestSelector<T extends ReferenceManifest> {
* @return a matching RIM or null if none is found
*/
public T getRIM() {
Set<T> rims = execute();
List<T> rims = execute();
if (rims.isEmpty()) {
return null;
}
@ -216,8 +215,8 @@ public abstract class ReferenceManifestSelector<T extends ReferenceManifest> {
}
// construct and execute query
private Set<T> execute() {
Set<T> results = this.referenceManifestManager.get(this);
private List<T> execute() {
List<T> results = this.referenceManifestManager.get(this);
return results;
}

View File

@ -34,6 +34,7 @@ dependencies {
implementation project(':HIRS_AttestationCA')
implementation libs.pci
implementation libs.gson
implementation libs.bouncycastle
implementation libs.guava
implementation libs.jakarta.servlet
@ -41,8 +42,10 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.github.darrachequesne:spring-data-jpa-datatables:6.0.1'
implementation 'org.projectlombok:lombok'
implementation 'commons-fileupload:commons-fileupload:1.5'
implementation 'org.junit.jupiter:junit-jupiter:5.4.2'
implementation 'org.junit.jupiter:junit-jupiter:5.4.2'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
@ -50,6 +53,7 @@ dependencies {
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation libs.testng
}
war {

View File

@ -1,19 +1,22 @@
package hirs.attestationca.portal;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRegistration;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import java.util.Collections;
@SpringBootApplication
@EnableAutoConfiguration
@Log4j2
@ComponentScan({"hirs.attestationca.portal", "hirs.attestationca.portal.page.controllers", "hirs.attestationca.persist.entity", "hirs.attestationca.persist.service"})
public class HIRSApplication extends SpringBootServletInitializer {
@Override
@ -21,16 +24,24 @@ public class HIRSApplication extends SpringBootServletInitializer {
return application.sources(HIRSApplication.class);
}
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
ServletRegistration.Dynamic appServlet = servletContext.addServlet("mvc", new DispatcherServlet(
new GenericWebApplicationContext()));
appServlet.setLoadOnStartup(1);
}
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(HIRSApplication.class);
springApplication.setDefaultProperties(Collections.singletonMap("server.servlet.context-path", "/portal"));
springApplication.run(args);
log.debug("Debug log message");
// log.debug("Debug log message");
log.info("Info log message");
log.error("Error log message");
log.warn("Warn log message");
log.fatal("Fatal log message");
log.trace("Trace log message");
// log.trace("Trace log message");
}
}

View File

@ -1,16 +1,55 @@
package hirs.attestationca.portal;
import hirs.attestationca.persist.service.SettingsServiceImpl;
import hirs.attestationca.persist.PersistenceConfiguration;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
@Log4j2
@WebListener
public class HIRSDbInitializer implements ServletContextListener {
public class HIRSDbInitializer extends AbstractAnnotationConfigDispatcherServletInitializer implements ServletContextListener {
@Override
public void contextInitialized(final ServletContextEvent servletContextEvent) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.getEnvironment().addActiveProfile("Server");
// applicationContext.register(PersistenceConfiguration.class);
try {
applicationContext.refresh();
} catch (NoSuchBeanDefinitionException nsbdEx) {
if (log.isDebugEnabled()) {
log.debug("Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided");
}
} catch (Exception ex) {
log.error("DAVY********************************************************************************");
log.error(ex.getMessage());
}
}
@Override
protected Class <?>[] getRootConfigClasses() {
return new Class[] {
PersistenceJPAConfig.class, PageConfiguration.class, PersistenceConfiguration.class
};
}
@Override
protected Class <?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] {
"/"
};
}
@Autowired
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@Autowired
static SettingsServiceImpl settingsService = new SettingsServiceImpl();
}

View File

@ -0,0 +1,60 @@
package hirs.attestationca.portal;
import hirs.attestationca.portal.datatables.DataTableView;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
/**
* Specifies the location to scan for page controllers, view resolver for JSON data, and view
* resolver to map view names to jsp files.
*/
@Configuration
@EnableWebMvc
@ComponentScan("hirs.attestationca.portal.page.controllers")
public class PageConfiguration {
/**
* @return bean to resolve injected annotation.Value
* property expressions for beans.
*/
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
/**
* Makes all URLs that end in "dataTable" use DataTableView to serialize DataTableResponse.
*
* @return ViewResolver that uses DataTableView.
*/
@Bean
public ViewResolver dataTableViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setViewClass(DataTableView.class);
resolver.setViewNames("*dataTable");
resolver.setOrder(0);
return resolver;
}
/**
* Maps view names to the appropriate jsp file.
* <p>
* Only seems to apply to GET requests.
*
* @return a ViewResolver bean containing the mapping.
*/
@Bean
public ViewResolver pageViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
}

View File

@ -1,6 +1,5 @@
package hirs.attestationca.portal;
import hirs.attestationca.persist.entity.userdefined.SupplyChainSettings;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -18,6 +17,10 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.sql.DataSource;
import java.security.cert.X509Certificate;
@ -25,11 +28,12 @@ import java.util.Properties;
@Log4j2
@Configuration
@EnableWebMvc
@EnableTransactionManagement
@PropertySource({ "classpath:hibernate.properties", "classpath:portal.properties" })
@ComponentScan({ "hirs.attestationca.portal.page.controllers", "hirs.attestationca.persist.entity" })
@ComponentScan({"hirs.attestationca.portal", "hirs.attestationca.portal.page.controllers", "hirs.attestationca.persist.entity"})//, "hirs.attestationca.persist.service"})
@EnableJpaRepositories(basePackages = "hirs.attestationca.persist.entity.manager")
public class PersistenceJPAConfig {
public class PersistenceJPAConfig implements WebMvcConfigurer {
@Value("${aca.directories.certificates}")
private String certificatesLocation;
@ -50,7 +54,7 @@ public class PersistenceJPAConfig {
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean entityManagerBean = new LocalContainerEntityManagerFactoryBean();
entityManagerBean.setDataSource(dataSource());
entityManagerBean.setPackagesToScan(new String[] {"hirs.attestationca.persist"});
entityManagerBean.setPackagesToScan("hirs.attestationca.persist.entity");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManagerBean.setJpaVendorAdapter(vendorAdapter);
@ -62,7 +66,8 @@ public class PersistenceJPAConfig {
@Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getProperty("hibernate.connection.driver_class"));
dataSource.setDriverClassName(environment.getProperty("hibernate.connection.driver_class",
"org.mariadb.jdbc.Driver"));
dataSource.setUrl(environment.getProperty("hibernate.connection.url"));
dataSource.setUsername(environment.getProperty("hibernate.connection.username"));
dataSource.setPassword(environment.getProperty("hibernate.connection.password"));
@ -185,10 +190,29 @@ public class PersistenceJPAConfig {
return hibernateProperties;
}
@Bean(name="default-settings")
public SupplyChainSettings supplyChainSettings() {
SupplyChainSettings scSettings = new SupplyChainSettings("Default", "Settings are configured for no validation flags set.");
return scSettings;
/**
* Creates a Spring Resolver for Multi-part form uploads. This is required
* for spring controllers to be able to process Spring MultiPartFiles
*
* @return bean to handle multipart form requests
*/
@Bean(name = "multipartResolver")
public StandardServletMultipartResolver multipartResolver() {
StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
return resolver;
}
// @Bean(name="default-settings")
// public PolicySettings supplyChainSettings() {
// PolicySettings scSettings = new PolicySettings("Default", "Settings are configured for no validation flags set.");
//
// return scSettings;
// }
@Override
public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}

View File

@ -0,0 +1,45 @@
package hirs.attestationca.portal.datatables;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.Map;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.view.AbstractUrlBasedView;
/**
* Serializes the DataTableResponse from the view as JSON and writes it to the HTTP response.
*
*/
public class DataTableView extends AbstractUrlBasedView {
private static final Gson GSON = new GsonBuilder().create();
private static final String MODEL_FIELD;
static {
final String name = DataTableResponse.class.getSimpleName();
MODEL_FIELD = name.substring(0, 1).toLowerCase() + name.substring(1);
}
/**
* Serializes the DataTableResponse from the view as JSON and writes it to the HTTP response.
*
* @param model combined output Map (never {@code null}), with dynamic values taking precedence
* over static attributes
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception if rendering failed
*/
@Override
protected void renderMergedOutputModel(
final Map<String, Object> model,
final HttpServletRequest request,
final HttpServletResponse response) throws Exception {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
DataTableResponse dataTable = (DataTableResponse) model.get(MODEL_FIELD);
ServletOutputStream out = response.getOutputStream();
String json = GSON.toJson(dataTable);
out.print(json);
}
}

View File

@ -2,12 +2,13 @@ package hirs.attestationca.portal.datatables;
import hirs.attestationca.persist.CriteriaModifier;
import hirs.attestationca.persist.FilteredRecordsList;
import hirs.attestationca.persist.OrderedListQuerier;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.util.CollectionUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* A class to adapt the Javascript DataTable java class abstractions to the DBManager's getting
@ -30,7 +31,7 @@ public final class OrderedListQueryDataTableAdapter<T> {
* @return the filtered record list
*/
public static <T> FilteredRecordsList<T> getOrderedList(final Class<? extends T> clazz,
final OrderedListQuerier<T> dbManager,
final JpaRepository<T, UUID> dbManager,
final DataTableInput dataTableInput,
final String orderColumnName) {
return getOrderedList(clazz, dbManager, dataTableInput, orderColumnName, null);
@ -47,7 +48,7 @@ public final class OrderedListQueryDataTableAdapter<T> {
* @return the filtered record list
*/
public static <T> FilteredRecordsList<T> getOrderedList(final Class<? extends T> clazz,
final OrderedListQuerier<T> dbManager,
final JpaRepository<T, UUID> dbManager,
final DataTableInput dataTableInput,
final String orderColumnName,
final CriteriaModifier criteriaModifier) {
@ -63,10 +64,19 @@ public final class OrderedListQueryDataTableAdapter<T> {
isAscending = orders.get(0).isAscending();
}
return dbManager.getOrderedList(clazz, orderColumnName, isAscending,
dataTableInput.getStart(), dataTableInput.getLength(),
dataTableInput.getSearch().getValue(),
searchableColumnMap, criteriaModifier);
//Object that will store query values
FilteredRecordsList<T> filteredRecordsList = new FilteredRecordsList<>();
filteredRecordsList.setRecordsTotal(dbManager.count());
filteredRecordsList.addAll(dbManager.findAll());
filteredRecordsList.setRecordsFiltered(10);
return filteredRecordsList;
// return dbManager.getOrderedList(clazz, orderColumnName, isAscending,
// dataTableInput.getStart(), dataTableInput.getLength(),
// dataTableInput.getSearch().getValue(),
// searchableColumnMap, criteriaModifier);
}
}

View File

@ -32,6 +32,10 @@ public enum Page {
*/
ISSUED_CERTIFICATES("Issued Certificates", "ic_library_books",
null, "certificate-request/"),
/**
* Page to display certificate validation reports.
*/
VALIDATION_REPORTS("Validation Reports", "ic_assignment", "first"),
/**
* Non-menu page to display certificate. Reachable from all certificate pages.
*/

View File

@ -146,7 +146,7 @@ public abstract class PageController<P extends PageParams> {
if (params != null) {
for (Map.Entry<String, ?> e : params.asMap().entrySet()) {
Object v = Optional.ofNullable(e.getValue()).orElse("");
Object v = Optional.ofNullable(e.getValue()).orElse(null);
uri.addParameter(e.getKey(), v.toString());
}
}

View File

@ -1,6 +1,6 @@
package hirs.attestationca.portal.page;
import hirs.attestationca.persist.entity.userdefined.SupplyChainSettings;
import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@ -55,7 +55,7 @@ public class PolicyPageModel {
*
* @param policy The supply chain policy
*/
public PolicyPageModel(final SupplyChainSettings policy) {
public PolicyPageModel(final PolicySettings policy) {
this.enableEcValidation = policy.isEcValidationEnabled();
this.enablePcCertificateValidation = policy.isPcValidationEnabled();
this.enablePcCertificateAttributeValidation = policy.isPcAttributeValidationEnabled();

View File

@ -1,7 +1,8 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.persist.service.CertificateServiceImpl;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.PageMessages;
import hirs.attestationca.portal.page.params.CertificateDetailsPageParams;
@ -29,16 +30,20 @@ public class CertificateDetailsPageController extends PageController<Certificate
* Model attribute name used by initPage for the initial data passed to the page.
*/
static final String INITIAL_DATA = "initialData";
private final CertificateServiceImpl certificateServiceImpl;
private final CertificateRepository certificateRepository;
private final ComponentResultRepository componentResultRepository;
/**
* Constructor providing the Page's display and routing specification.
* @param certificateServiceImpl the certificate manager
* @param certificateRepository the certificate repository
* @param componentResultRepository the component result repository
*/
@Autowired
public CertificateDetailsPageController(final CertificateServiceImpl certificateServiceImpl) {
public CertificateDetailsPageController(final CertificateRepository certificateRepository,
final ComponentResultRepository componentResultRepository) {
super(Page.CERTIFICATE_DETAILS);
this.certificateServiceImpl = certificateServiceImpl;
this.certificateRepository = certificateRepository;
this.componentResultRepository = componentResultRepository;
}
/**
@ -76,19 +81,19 @@ public class CertificateDetailsPageController extends PageController<Certificate
switch (type) {
case "certificateauthority":
data.putAll(CertificateStringMapBuilder.getCertificateAuthorityInformation(
uuid, certificateServiceImpl));
uuid, certificateRepository));
break;
case "endorsement":
data.putAll(CertificateStringMapBuilder.getEndorsementInformation(uuid,
certificateServiceImpl));
certificateRepository));
break;
case "platform":
data.putAll(CertificateStringMapBuilder.getPlatformInformation(uuid,
certificateServiceImpl));
certificateRepository, componentResultRepository));
break;
case "issued":
data.putAll(CertificateStringMapBuilder.getIssuedInformation(uuid,
certificateServiceImpl));
certificateRepository));
break;
default:
String typeError = "Invalid certificate type: " + params.getType();

View File

@ -1,22 +1,32 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.CriteriaModifier;
import hirs.attestationca.persist.DBServiceException;
import hirs.attestationca.persist.FilteredRecordsList;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestationCertificate;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.service.CertificateService;
import hirs.attestationca.persist.service.CertificateServiceImpl;
import hirs.attestationca.portal.datatables.DataTableInput;
import hirs.attestationca.portal.datatables.DataTableResponse;
import hirs.attestationca.portal.datatables.OrderedListQueryDataTableAdapter;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController;
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.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.bouncycastle.util.encoders.DecoderException;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StreamUtils;
@ -31,25 +41,31 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.view.RedirectView;
import java.io.IOException;
import java.lang.ref.Reference;
import java.net.URISyntaxException;
//import java.security.cert.CertificateEncodingException;
//import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
//import java.security.cert.CertificateEncodingException;
//import java.security.cert.X509Certificate;
// note uploading base64 certs, old or new having decode issues check ACA channel
/**
* Controller for the Certificates list all pages.
*/
@Log4j2
@Controller
@RequestMapping("/certificate-request")
public class CertificatePageController extends PageController<NoPageParams> {
@Autowired(required = false)
private EntityManager entityManager;
private final CertificateServiceImpl certificateServiceImpl;
private CertificateAuthorityCredential certificateAuthorityCredential;
private final CertificateRepository certificateRepository;
private static final String TRUSTCHAIN = "trust-chain";
private static final String PLATFORMCREDENTIAL = "platform-credentials";
@ -64,22 +80,18 @@ public class CertificatePageController extends PageController<NoPageParams> {
/**
* Constructor providing the Page's display and routing specification.
*
* @param certificateServiceImpl the certificate manager
// * @param crudManager the CRUD manager for certificates
// * @param acaCertificate the ACA's X509 certificate
* @param certificateRepository the certificate manager
// * @param acaCertificate the ACA's X509 certificate
*/
@Autowired
public CertificatePageController(
final CertificateServiceImpl certificateServiceImpl//,
// final CrudManager<Certificate> crudManager,
public CertificatePageController(final CertificateRepository certificateRepository
// final X509Certificate acaCertificate
) {
super(Page.TRUST_CHAIN);
this.certificateServiceImpl = certificateServiceImpl;
// this.dataTableQuerier = crudManager;
this.certificateRepository = certificateRepository;
// try {
// certificateAuthorityCredential
certificateAuthorityCredential = null;
// = new CertificateAuthorityCredential(acaCertificate.getEncoded());
// } catch (IOException ioEx) {
// log.error("Failed to read ACA certificate", ioEx);
@ -132,7 +144,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
mav = getBaseModelAndView(Page.TRUST_CHAIN);
// Map with the ACA certificate information
data.putAll(CertificateStringMapBuilder.getCertificateAuthorityInformation(
certificateAuthorityCredential, this.certificateServiceImpl));
certificateAuthorityCredential, this.certificateRepository));
mav.addObject(ACA_CERT_DATA, data);
break;
default:
@ -143,6 +155,81 @@ public class CertificatePageController extends PageController<NoPageParams> {
return mav;
}
/**
* Queries for the list of Certificates and returns a data table response
* with the records.
*
* @param certificateType String containing the certificate type
* @param input the DataTables search/query parameters
* @return the data table
*/
@ResponseBody
@RequestMapping(value = "/{certificateType}/list",
produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.GET)
public DataTableResponse<? extends Certificate> getTableData(
@PathVariable("certificateType") final String certificateType,
final DataTableInput input) {
log.debug("Handling list request: " + input);
// attempt to get the column property based on the order index.
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);
}
}
};
FilteredRecordsList<Certificate> records
= OrderedListQueryDataTableAdapter.getOrderedList(
getCertificateClass(certificateType), this.certificateRepository,
input, orderColumnName, criteriaModifier);
// special parsing for platform credential
// Add the EndorsementCredential for each PlatformCredential based on the
// serial number. (pc.HolderSerialNumber = ec.SerialNumber)
if (certificateType.equals(PLATFORMCREDENTIAL)) {
EndorsementCredential associatedEC;
if (!records.isEmpty()) {
// loop all the platform certificates
for (int i = 0; i < records.size(); i++) {
PlatformCredential pc = (PlatformCredential) records.get(i);
// find the EC using the PC's "holder serial number"
associatedEC = (EndorsementCredential) certificateRepository
.byHolderSerialNumber(pc.getHolderSerialNumber(),
"EndorsementCredential");
if (associatedEC != null) {
log.debug("EC ID for holder s/n " + pc
.getHolderSerialNumber() + " = " + associatedEC.getId());
}
pc.setEndorsementCredential(associatedEC);
}
}
}
log.debug("Returning list of size: " + records.size());
return new DataTableResponse<>(records, input);
}
/**
* Upload and processes a credential.
*
@ -170,8 +257,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
storeCertificate(
certificateType,
file.getOriginalFilename(),
messages, certificate,
certificateServiceImpl);
messages, certificate);
}
}
@ -224,7 +310,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
// get all files
bulkDownload(zipOut, this.certificateServiceImpl.fetchCertificates(CertificateAuthorityCredential.class), singleFileName);
bulkDownload(zipOut, this.certificateRepository.findByAll("CertificateAuthorityCredential"), singleFileName);
// write cert to output stream
} catch (IllegalArgumentException ex) {
String uuidError = "Failed to parse ID from: ";
@ -256,7 +342,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
// get all files
bulkDownload(zipOut, this.certificateServiceImpl.fetchCertificates(PlatformCredential.class), singleFileName);
bulkDownload(zipOut, this.certificateRepository.findByAll("PlatformCredential"), singleFileName);
// write cert to output stream
} catch (IllegalArgumentException ex) {
String uuidError = "Failed to parse ID from: ";
@ -288,7 +374,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
// get all files
bulkDownload(zipOut, this.certificateServiceImpl.fetchCertificates(IssuedAttestationCertificate.class), singleFileName);
bulkDownload(zipOut, this.certificateRepository.findByAll("IssuedAttestationCertificate"), singleFileName);
// write cert to output stream
} catch (IllegalArgumentException ex) {
String uuidError = "Failed to parse ID from: ";
@ -319,7 +405,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
// get all files
bulkDownload(zipOut, this.certificateServiceImpl.fetchCertificates(EndorsementCredential.class), singleFileName);
bulkDownload(zipOut, this.certificateRepository.findByAll("EndorsementCredential"), singleFileName);
// write cert to output stream
} catch (IllegalArgumentException ex) {
String uuidError = "Failed to parse ID from: ";
@ -350,6 +436,24 @@ public class CertificatePageController extends PageController<NoPageParams> {
return zipOut;
}
/**
* Get flag indicating if a device-name join/alias is required for
* displaying the table data. This will be true if displaying a cert that is
* associated with a device.
*
* @param certificateType String containing the certificate type
* @return true if the list criteria modifier requires aliasing the device
* table, false otherwise.
*/
private boolean hasDeviceTableToJoin(final String certificateType) {
boolean hasDevice = true;
// Trust_Chain Credential do not contain the device table to join.
if (certificateType.equals(TRUSTCHAIN)) {
hasDevice = false;
}
return hasDevice;
}
/**
* Get the page based on the certificate type.
*
@ -366,39 +470,53 @@ public class CertificatePageController extends PageController<NoPageParams> {
};
}
/**
* Gets the concrete certificate class type to query for.
*
* @param certificateType String containing the certificate type
* @return the certificate class type
*/
private static Class<? extends Certificate> getCertificateClass(final String certificateType) {
switch (certificateType) {
case PLATFORMCREDENTIAL:
return PlatformCredential.class;
case ENDORSEMENTCREDENTIAL:
return EndorsementCredential.class;
case ISSUEDCERTIFICATES:
return IssuedAttestationCertificate.class;
case TRUSTCHAIN:
return CertificateAuthorityCredential.class;
default:
throw new IllegalArgumentException(
String.format("Unknown certificate type: %s", certificateType));
}
}
/**
* Gets the certificate by the hash code of its bytes. Looks for both
* archived and unarchived certificates.
*
* @param certificateType String containing the certificate type
* @param certificateHash the hash of the certificate's bytes
* @param certificateManager the certificate manager to query
* @return the certificate or null if none is found
*/
private Certificate getCertificateByHash(
final String certificateType,
final int certificateHash,
final CertificateService certificateManager) {
final int certificateHash) {
switch (certificateType) {
case PLATFORMCREDENTIAL:
return PlatformCredential
.select(certificateManager)
.includeArchived()
.byHashCode(certificateHash)
.getCertificate();
return this.certificateRepository
.findByCertificateHash(certificateHash,
"PlatformCredential");
case ENDORSEMENTCREDENTIAL:
// return EndorsementCredential
// .select(certificateManager)
// .includeArchived()
// .byHashCode(certificateHash)
// .getCertificate();
return this.certificateRepository
.findByCertificateHash(certificateHash,
"EndorsementCredential");
case TRUSTCHAIN:
return CertificateAuthorityCredential
.select(certificateManager)
.includeArchived()
.byHashCode(certificateHash)
.getCertificate();
return this.certificateRepository
.findByCertificateHash(certificateHash,
"CertificateAuthorityCredential");
default:
return null;
}
@ -409,13 +527,11 @@ public class CertificatePageController extends PageController<NoPageParams> {
*
* @param certificateType String containing the certificate type
* @param serialNumber the platform serial number
* @param certificateManager the certificate manager to query
* @return the certificate or null if none is found
*/
private List<PlatformCredential> getCertificateByBoardSN(
final String certificateType,
final String serialNumber,
final CertificateService certificateManager) {
final String serialNumber) {
if (serialNumber == null) {
return null;
@ -423,10 +539,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
switch (certificateType) {
case PLATFORMCREDENTIAL:
return PlatformCredential
.select(certificateManager)
.byBoardSerialNumber(serialNumber)
.getCertificates().stream().collect(Collectors.toList());
return this.certificateRepository.byBoardSerialNumber(serialNumber);
default:
return null;
}
@ -504,15 +617,13 @@ public class CertificatePageController extends PageController<NoPageParams> {
* be stored
* @param messages contains any messages that will be display on the page
* @param certificate the certificate to store
* @param certificateManager the DB manager to use
* @return the messages for the page
*/
private void storeCertificate(
final String certificateType,
final String fileName,
final PageMessages messages,
final Certificate certificate,
final CertificateService certificateManager) {
final Certificate certificate) {
Certificate existingCertificate;
@ -520,8 +631,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
try {
existingCertificate = getCertificateByHash(
certificateType,
certificate.getCertificateHash(),
certificateManager);
certificate.getCertificateHash());
} catch (DBServiceException e) {
final String failMessage = "Querying for existing certificate failed ("
+ fileName + "): ";
@ -538,8 +648,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
if (platformCertificate.isPlatformBase()) {
List<PlatformCredential> sharedCertificates = getCertificateByBoardSN(
certificateType,
platformCertificate.getPlatformSerial(),
certificateManager);
platformCertificate.getPlatformSerial());
if (sharedCertificates != null) {
for (PlatformCredential pc : sharedCertificates) {
@ -575,7 +684,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
}**/
}
certificateManager.saveCertificate(certificate);
this.certificateRepository.save(certificate);
final String successMsg
= String.format("New certificate successfully uploaded (%s): ", fileName);
@ -597,7 +706,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
if (existingCertificate.isArchived()) {
existingCertificate.restore();
existingCertificate.resetCreateTime();
certificateManager.updateCertificate(existingCertificate);
this.certificateRepository.save(existingCertificate);
final String successMsg = String.format("Pre-existing certificate "
+ "found and unarchived (%s): ", fileName);

View File

@ -1,37 +1,47 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.FilteredRecordsList;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.DeviceRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.Device;
import hirs.attestationca.portal.datatables.DataTableInput;
import hirs.attestationca.portal.datatables.DataTableResponse;
import hirs.attestationca.portal.datatables.OrderedListQueryDataTableAdapter;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.persist.service.DeviceServiceImpl;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.params.NoPageParams;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
/**
* Controller for the Device page.
*/
@Log4j2
@Controller
@RequestMapping("/devices")
public class DevicePageController extends PageController<NoPageParams> {
/**
* https://odrotbohm.de/2013/11/why-field-injection-is-evil/
*
* Autowiring property vs constructor
*/
private final DeviceServiceImpl deviceServiceImpl;
private final DeviceRepository deviceRepository;
private final CertificateRepository certificateRepository;
@Autowired
public DevicePageController(DeviceServiceImpl deviceServiceImpl,
DeviceRepository deviceRepository) {
public DevicePageController(final DeviceRepository deviceRepository,
final CertificateRepository certificateRepository) {
super(Page.DEVICES);
this.deviceServiceImpl = deviceServiceImpl;
this.deviceRepository = deviceRepository;
this.certificateRepository = certificateRepository;
}
@Override
@ -40,21 +50,100 @@ public class DevicePageController extends PageController<NoPageParams> {
return getBaseModelAndView();
}
// @RequestMapping(value = "list", produces = MediaType.APPLICATION_JSON_VALUE,
// method = RequestMethod.GET)
// public DataTableResponse<HashMap<String, Object>> getTableData(
// final DataTableInput input) {
// String orderColumnName = input.getOrderColumnName();
// FilteredRecordsList<HashMap<String, Object>> record
// = retrieveDevicesAndAssociatedCertificates(deviceList);
// modelMap.put("devices", deviceServiceImpl.retrieveDevices());
// return new DataTableResponse<>(record, input);
// }
@RequestMapping(value = "/list", produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.GET)
public DataTableResponse<HashMap<String, Object>> getTableData(
final DataTableInput input) {
log.debug("Handling request for device list");
String orderColumnName = input.getOrderColumnName();
log.info("Ordering on column: " + orderColumnName);
// get all the devices
FilteredRecordsList<Device> deviceList =
OrderedListQueryDataTableAdapter.getOrderedList(Device.class,
deviceRepository, input, orderColumnName);
@GetMapping(path="/all")
public @ResponseBody Iterable<Device> getAllDevices() {
return deviceRepository.findAll();
FilteredRecordsList<HashMap<String, Object>> record
= retrieveDevicesAndAssociatedCertificates(deviceList);
return new DataTableResponse<>(record, input);
}
/**
* Returns the list of devices combined with the certificates.
* @param deviceList list containing the devices
* @return a record list after the device and certificate was mapped together.
*/
private FilteredRecordsList<HashMap<String, Object>> retrieveDevicesAndAssociatedCertificates(
final FilteredRecordsList<Device> deviceList) {
FilteredRecordsList<HashMap<String, Object>> records = new FilteredRecordsList<>();
// hashmap containing the device-certificate relationship
HashMap<String, Object> deviceCertMap = new HashMap<>();
Device device;
Certificate certificate;
//
// // parse if there is a Device
// if (!deviceList.isEmpty()) {
// // get a list of Certificates that contains the device IDs from the list
// List<Certificate> certificateList = certificateDBManager.getList(
// Certificate.class,
// RowMutationOperations.Restrictions.in("device.id", getDevicesIds(deviceList).toArray()));
//
// // loop all the devices
// for (int i = 0; i < deviceList.size(); i++) {
// // hashmap containing the list of certificates based on the certificate type
// HashMap<String, List<Object>> certificatePropertyMap = new HashMap<>();
//
// device = deviceList.get(i);
// deviceCertMap.put("device", device);
//
// // loop all the certificates and combined the ones that match the ID
// for (int j = 0; j < certificateList.size(); j++) {
// certificate = certificateList.get(j);
//
// // set the certificate if it's the same ID
// if (device.getId().equals(
// ((DeviceAssociatedCertificate) certificate).getDevice().getId())) {
// String certificateId = certificate.getClass().getSimpleName();
// // create a new list for the certificate type if does not exist
// // else add it to the current certificate type list
// List<Object> certificateListFromMap
// = certificatePropertyMap.get(certificateId);
// if (certificateListFromMap != null) {
// certificateListFromMap.add(certificate);
// } else {
// certificatePropertyMap.put(certificateId,
// new ArrayList<>(Collections.singletonList(certificate)));
// }
// }
// }
//
// // add the device-certificate map to the record
// deviceCertMap.putAll(certificatePropertyMap);
// records.add(new HashMap<>(deviceCertMap));
// deviceCertMap.clear();
// }
// }
// set pagination values
// records.setRecordsTotal(deviceList.getRecordsTotal());
// records.setRecordsFiltered(deviceList.getRecordsFiltered());
return records;
}
/**
* Returns the list of devices IDs.
* @param deviceList list containing the devices
* @return a list of the devices IDs
*/
private List<UUID> getDevicesIds(final FilteredRecordsList<Device> deviceList) {
List<UUID> deviceIds = new ArrayList<UUID>();
// loop all the devices
for (int i = 0; i < deviceList.size(); i++) {
deviceIds.add(deviceList.get(i).getId());
}
return deviceIds;
}
}

View File

@ -0,0 +1,62 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.params.NoPageParams;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.io.File;
import java.io.IOException;
import static hirs.attestationca.portal.page.Page.HELP;
/**
* Controller for the Help page.
*/
@Log4j2
@Controller
@RequestMapping("/help")
public class HelpPageController extends PageController<NoPageParams> {
@Autowired
private ApplicationContext applicationContext;
private static final String PATH = "/docs";
/**
* Constructor providing the Page's display and routing specification.
*/
public HelpPageController() {
super(HELP);
}
/**
* Returns the path for the view and the data model for the page.
*
* @param params The object to map url parameters into.
* @param model The data model for the request. Can contain data from redirect.
* @return the path for the view and data model for the page.
*/
@Override
@RequestMapping
public ModelAndView initPage(final NoPageParams params, final Model model) {
ModelAndView mav = getBaseModelAndView();
try {
File[] documents = new File(
applicationContext.getResource(PATH).getFile().getPath()
).listFiles();
mav.addObject("docs", documents);
} catch (IOException ex) {
log.error("Could not get files from resource.");
}
return mav;
}
}

View File

@ -9,6 +9,9 @@ import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* Controller for the Index page.
*/
@Controller
@Log4j2
@RequestMapping("/index")
@ -34,9 +37,4 @@ public class IndexPageController extends PageController<NoPageParams> {
return getBaseModelAndView();
}
// @RequestMapping(value = "/", method = RequestMethod.GET)
// public String showIndexPage(ModelMap model) {
// model.put("name", "welcome");
// return "welcome";
// }
}

View File

@ -1,7 +1,7 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.entity.userdefined.SupplyChainSettings;
import hirs.attestationca.persist.service.SettingsServiceImpl;
import hirs.attestationca.persist.entity.manager.PolicyRepository;
import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.PageMessages;
@ -39,7 +39,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
private static final String ENABLED_EXPIRES_PARAMETER_VALUE = "expires";
private SettingsServiceImpl settingsService;
private final PolicyRepository policyRepository;
/**
* Model attribute name used by initPage for the initial data passed to the
@ -56,15 +56,15 @@ public class PolicyPageController extends PageController<NoPageParams> {
/**
* Constructor.
*
* @param policyService the policy service
* @param policyRepository the policy service
*/
@Autowired
public PolicyPageController(final SettingsServiceImpl policyService) {
public PolicyPageController(final PolicyRepository policyRepository) {
super(Page.POLICY);
this.settingsService = policyService;
this.policyRepository = policyRepository;
if (this.settingsService.getByName("Default") == null) {
this.settingsService.saveSettings(new SupplyChainSettings("Default", "Settings are configured for no validation flags set."));
if (this.policyRepository.findByName("Default") == null) {
this.policyRepository.saveAndFlush(new PolicySettings("Default", "Settings are configured for no validation flags set."));
}
}
@ -82,7 +82,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
// get the basic information to render the page
ModelAndView mav = getBaseModelAndView();
SupplyChainSettings policy = getDefaultPolicy();
PolicySettings policy = getDefaultPolicy();
log.debug(policy);
PolicyPageModel pageModel = new PolicyPageModel(policy);
mav.addObject(INITIAL_DATA, pageModel);
@ -113,7 +113,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
= ppModel.getPcValidate().equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
// If PC policy setting change results in invalid policy, inform user
if (!isPolicyValid(policy.isEcValidationEnabled(), pcValidationOptionEnabled,
@ -164,7 +164,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
// If PC Attribute Validation is enabled without PC Validation, disallow change
if (!isPolicyValid(policy.isEcValidationEnabled(),
@ -216,7 +216,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
if (issuedAttestationOptionEnabled) {
successMessage = "Attestation Certificate generation enabled.";
@ -260,7 +260,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
if (issuedDevIdOptionEnabled) {
successMessage = "DevID Certificate generation enabled.";
@ -312,7 +312,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
}
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
boolean issuedAttestationOptionEnabled
= policy.isIssueAttestationCertificate();
@ -326,7 +326,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
if (generateCertificateEnabled) {
numOfDays = ppModel.getExpirationValue();
if (numOfDays == null) {
numOfDays = SupplyChainSettings.TEN_YEARS;
numOfDays = PolicySettings.TEN_YEARS;
}
} else {
numOfDays = policy.getValidityDays();
@ -382,7 +382,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
}
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
boolean issuedDevIdOptionEnabled
= policy.isIssueDevIdCertificate();
@ -396,7 +396,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
if (generateDevIdCertificateEnabled) {
numOfDays = ppModel.getDevIdExpirationValue();
if (numOfDays == null) {
numOfDays = SupplyChainSettings.TEN_YEARS;
numOfDays = PolicySettings.TEN_YEARS;
}
} else {
numOfDays = policy.getDevIdValidityDays();
@ -452,7 +452,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
}
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
boolean issuedAttestationOptionEnabled
= policy.isIssueAttestationCertificate();
@ -470,7 +470,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
}
if (threshold == null || threshold.isEmpty()) {
threshold = SupplyChainSettings.YEAR;
threshold = PolicySettings.YEAR;
}
policy.setReissueThreshold(threshold);
@ -522,7 +522,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
}
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
boolean issuedDevIdOptionEnabled
= policy.isIssueDevIdCertificate();
@ -540,7 +540,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
}
if (threshold == null || threshold.isEmpty()) {
threshold = SupplyChainSettings.YEAR;
threshold = PolicySettings.YEAR;
}
policy.setDevIdReissueThreshold(threshold);
@ -584,7 +584,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
= ppModel.getEcValidate().equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If PC Validation is enabled without EC Validation, disallow change
if (!isPolicyValid(ecValidationOptionEnabled, policy.isPcValidationEnabled(),
@ -636,7 +636,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If firmware is enabled without PC attributes, disallow change
if (firmwareValidationOptionEnabled && !policy.isPcAttributeValidationEnabled()) {
@ -692,7 +692,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If Ignore IMA is enabled without firmware, disallow change
if (ignoreImaOptionEnabled && !policy.isFirmwareValidationEnabled()) {
@ -743,7 +743,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If Ignore TBoot is enabled without firmware, disallow change
if (ignoreTbootOptionEnabled && !policy.isFirmwareValidationEnabled()) {
@ -794,7 +794,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If Ignore TBoot is enabled without firmware, disallow change
if (ignoreGptOptionEnabled && !policy.isFirmwareValidationEnabled()) {
@ -847,7 +847,7 @@ public class PolicyPageController extends PageController<NoPageParams> {
.equalsIgnoreCase(ENABLED_CHECKED_PARAMETER_VALUE);
try {
SupplyChainSettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
PolicySettings policy = getDefaultPolicyAndSetInModel(ppModel, model);
//If Ignore TBoot is enabled without firmware, disallow change
if (ignoreOsEvtOptionEnabled && !policy.isFirmwareValidationEnabled()) {
@ -918,11 +918,11 @@ public class PolicyPageController extends PageController<NoPageParams> {
*
* @return The default Supply Chain Policy
*/
private SupplyChainSettings getDefaultPolicy() {
SupplyChainSettings defaultSettings = this.settingsService.getByName("Default");
private PolicySettings getDefaultPolicy() {
PolicySettings defaultSettings = this.policyRepository.findByName("Default");
if (defaultSettings == null) {
defaultSettings = new SupplyChainSettings("Default", "Settings are configured for no validation flags set.");
defaultSettings = new PolicySettings("Default", "Settings are configured for no validation flags set.");
}
return defaultSettings;
}
@ -935,10 +935,10 @@ public class PolicyPageController extends PageController<NoPageParams> {
* @param model the map of string messages to be displayed on the view
* @return The default Supply Chain Policy
*/
private SupplyChainSettings getDefaultPolicyAndSetInModel(
private PolicySettings getDefaultPolicyAndSetInModel(
final PolicyPageModel ppModel, final Map<String, Object> model) {
// load the current default policy from the DB
SupplyChainSettings policy = getDefaultPolicy();
PolicySettings policy = getDefaultPolicy();
// set the data received to be populated back into the form
model.put(RESULT_DATA, ppModel);
@ -948,9 +948,9 @@ public class PolicyPageController extends PageController<NoPageParams> {
private void savePolicyAndApplySuccessMessage(
final PolicyPageModel ppModel, final Map<String, Object> model,
final PageMessages messages, final String successMessage,
final SupplyChainSettings settings) {
final PolicySettings settings) {
// save the policy to the DB
settingsService.updateSettings(settings);
policyRepository.saveAndFlush(settings);
// Log and set the success message
messages.addSuccess(successMessage);

View File

@ -1,17 +1,15 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.DBServiceException;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
import hirs.attestationca.persist.entity.userdefined.rim.BaseReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.rim.EventLogMeasurements;
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
import hirs.attestationca.persist.service.CertificateService;
import hirs.attestationca.persist.service.ReferenceDigestValueService;
import hirs.attestationca.persist.service.ReferenceDigestValueServiceImpl;
import hirs.attestationca.persist.service.ReferenceManifestService;
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
import hirs.attestationca.persist.service.SupplyChainValidationServiceImpl;
import hirs.attestationca.persist.validation.ReferenceManifestValidator;
import hirs.attestationca.persist.validation.SupplyChainValidatorException;
@ -41,7 +39,6 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
@ -52,28 +49,27 @@ import java.util.UUID;
@RequestMapping("/rim-details")
public class ReferenceManifestDetailsPageController extends PageController<ReferenceManifestDetailsPageParams> {
private final ReferenceManifestService referenceManifestManager;
private final ReferenceDigestValueService referenceEventManager;
private final CertificateService certificateService;
private final ReferenceManifestRepository referenceManifestRepository;
private final ReferenceDigestValueRepository referenceDigestValueRepository;
private final CertificateRepository certificateRepository;
private static final ReferenceManifestValidator RIM_VALIDATOR
= new ReferenceManifestValidator();
/**
* Constructor providing the Page's display and routing specification.
*
* @param referenceManifestManager the reference manifest manager.
* @param referenceEventManager the reference event manager.
* @param certificateService the certificate manager.
* @param referenceManifestRepository the repository for RIM.
* @param referenceDigestValueRepository the reference event manager.
* @param certificateRepository the certificate manager.
*/
@Autowired
public ReferenceManifestDetailsPageController(
final ReferenceManifestServiceImpl referenceManifestManager,
final ReferenceDigestValueServiceImpl referenceEventManager,
final CertificateService certificateService) {
public ReferenceManifestDetailsPageController(final ReferenceManifestRepository referenceManifestRepository,
final ReferenceDigestValueRepository referenceDigestValueRepository,
final CertificateRepository certificateRepository) {
super(Page.RIM_DETAILS);
this.referenceManifestManager = referenceManifestManager;
this.referenceEventManager = referenceEventManager;
this.certificateService = certificateService;
this.referenceManifestRepository = referenceManifestRepository;
this.referenceDigestValueRepository = referenceDigestValueRepository;
this.certificateRepository = certificateRepository;
}
/**
@ -103,8 +99,10 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
} else {
try {
UUID uuid = UUID.fromString(params.getId());
data.putAll(getRimDetailInfo(uuid, referenceManifestManager,
referenceEventManager, certificateService));
data.putAll(getRimDetailInfo(uuid, referenceManifestRepository,
referenceDigestValueRepository, certificateRepository));
data.putAll(getRimDetailInfo(uuid, referenceManifestRepository,
referenceDigestValueRepository, certificateRepository));
} catch (IllegalArgumentException iaEx) {
String uuidError = "Failed to parse ID from: " + params.getId();
messages.addError(uuidError);
@ -131,42 +129,39 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
* Gathers all information and returns it for displays.
*
* @param uuid database reference for the requested RIM.
* @param referenceManifestManager the reference manifest manager.
* @param referenceEventManager the reference event manager.
* @param certificateManager the certificate manager.
* @param referenceManifestRepository the reference manifest manager.
* @param referenceDigestValueRepository the reference event manager.
* @param certificateRepository the certificate manager.
* @return mapping of the RIM information from the database.
* @throws java.io.IOException error for reading file bytes.
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
* @throws CertificateException if a certificate doesn't parse.
*/
public static HashMap<String, Object> getRimDetailInfo(final UUID uuid,
final ReferenceManifestService referenceManifestManager,
final ReferenceDigestValueService referenceEventManager,
final CertificateService certificateManager)
final ReferenceManifestRepository referenceManifestRepository,
final ReferenceDigestValueRepository referenceDigestValueRepository,
final CertificateRepository certificateRepository)
throws IOException,
CertificateException, NoSuchAlgorithmException {
HashMap<String, Object> data = new HashMap<>();
BaseReferenceManifest bRim = BaseReferenceManifest.select(referenceManifestManager)
.byEntityId(uuid).getRIM();
BaseReferenceManifest bRim = referenceManifestRepository.getBaseRimEntityById(uuid);
if (bRim != null) {
data.putAll(getBaseRimInfo(bRim, referenceManifestManager, certificateManager));
data.putAll(getBaseRimInfo(bRim, referenceManifestRepository, certificateRepository));
}
SupportReferenceManifest sRim = SupportReferenceManifest.select(referenceManifestManager)
.byEntityId(uuid).getRIM();
SupportReferenceManifest sRim = referenceManifestRepository.getSupportRimEntityById(uuid);
if (sRim != null) {
data.putAll(getSupportRimInfo(sRim, referenceManifestManager));
data.putAll(getSupportRimInfo(sRim, referenceManifestRepository));
}
EventLogMeasurements bios = EventLogMeasurements.select(referenceManifestManager)
.byEntityId(uuid).getRIM();
EventLogMeasurements bios = referenceManifestRepository.getEventLogRimEntityById(uuid);
if (bios != null) {
data.putAll(getMeasurementsRimInfo(bios, referenceManifestManager,
referenceEventManager));
data.putAll(getMeasurementsRimInfo(bios, referenceManifestRepository,
referenceDigestValueRepository));
}
return data;
@ -177,8 +172,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
* Gathers all information and returns it for displays.
*
* @param baseRim established ReferenceManifest Type.
* @param referenceManifestManager the reference manifest manager.
* @param certificateManager the certificate manager.
* @param referenceManifestRepository the reference manifest manager.
* @param certificateRepository the certificate manager.
* @return mapping of the RIM information from the database.
* @throws java.io.IOException error for reading file bytes.
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
@ -186,8 +181,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
*/
private static HashMap<String, Object> getBaseRimInfo(
final BaseReferenceManifest baseRim,
final ReferenceManifestService referenceManifestManager,
final CertificateService certificateManager)
final ReferenceManifestRepository referenceManifestRepository,
final CertificateRepository certificateRepository)
throws IOException, CertificateException, NoSuchAlgorithmException {
HashMap<String, Object> data = new HashMap<>();
@ -219,8 +214,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
// Link
data.put("linkHref", baseRim.getLinkHref());
data.put("linkHrefLink", "");
for (BaseReferenceManifest bRim : BaseReferenceManifest
.select(referenceManifestManager).getRIMs()) {
for (BaseReferenceManifest bRim : referenceManifestRepository.findAllBaseRims()) {
if (baseRim.getLinkHref().contains(bRim.getTagId())) {
data.put("linkHrefLink", bRim.getId());
}
@ -241,8 +235,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
data.put("pcUriLocal", baseRim.getPcURILocal());
data.put("rimLinkHash", baseRim.getRimLinkHash());
if (baseRim.getRimLinkHash() != null) {
ReferenceManifest rim = BaseReferenceManifest.select(referenceManifestManager)
.byHexDecHash(baseRim.getRimLinkHash()).getRIM();
ReferenceManifest rim = referenceManifestRepository.findByHash(baseRim.getRimLinkHash(),
"BaseReferenceManifest");
if (rim != null) {
data.put("rimLinkId", rim.getId());
data.put("linkHashValid", true);
@ -257,15 +251,15 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
SupportReferenceManifest support = null;
if (baseRim.getAssociatedRim() == null) {
support = SupportReferenceManifest.select(referenceManifestManager)
.byManufacturer(baseRim.getPlatformManufacturer())
.getRIM();
support = (SupportReferenceManifest) referenceManifestRepository
.getByManufacturer(baseRim.getPlatformManufacturer(),
"SupportReferenceManifest");
if (support != null) {
baseRim.setAssociatedRim(support.getId());
}
} else {
support = SupportReferenceManifest.select(referenceManifestManager)
.byEntityId(baseRim.getAssociatedRim()).getRIM();
support = (SupportReferenceManifest) referenceManifestRepository
.getReferenceById(baseRim.getAssociatedRim());
}
// going to have to pull the filename and grab that from the DB
// to get the id to make the link
@ -291,14 +285,13 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
data.put("pcrList", support.getExpectedPCRList());
}
Set<CertificateAuthorityCredential> certificates =
CertificateAuthorityCredential.select(certificateManager)
.getCertificates();
List<CertificateAuthorityCredential> certificates = certificateRepository
.findByAll("CertificateAuthorityCredential");
//Report invalid signature unless RIM_VALIDATOR validates it and cert path is valid
data.put("signatureValid", false);
for (CertificateAuthorityCredential cert : certificates) {
SupplyChainValidationServiceImpl scvsImpl =
new SupplyChainValidationServiceImpl(certificateManager);
new SupplyChainValidationServiceImpl(certificateRepository);
KeyStore keystore = scvsImpl.getCaChain(cert);
if (RIM_VALIDATOR.validateXmlSignature(cert)) {
try {
@ -331,7 +324,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
* Gathers all information and returns it for displays.
*
* @param support established ReferenceManifest Type.
* @param referenceManifestManager the reference manifest manager.
* @param referenceManifestRepository the reference manifest manager.
* @return mapping of the RIM information from the database.
* @throws java.io.IOException error for reading file bytes.
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
@ -339,21 +332,20 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
*/
private static HashMap<String, Object> getSupportRimInfo(
final SupportReferenceManifest support,
final ReferenceManifestService referenceManifestManager)
final ReferenceManifestRepository referenceManifestRepository)
throws IOException, CertificateException, NoSuchAlgorithmException {
HashMap<String, Object> data = new HashMap<>();
EventLogMeasurements measurements = null;
if (support.getAssociatedRim() == null) {
Set<BaseReferenceManifest> baseRims = BaseReferenceManifest
.select(referenceManifestManager)
.byRimType(ReferenceManifest.BASE_RIM).getRIMs();
List<BaseReferenceManifest> baseRims = referenceManifestRepository.findAllBaseRims();
for (BaseReferenceManifest baseRim : baseRims) {
if (baseRim != null && baseRim.getAssociatedRim() != null
&& baseRim.getAssociatedRim().equals(support.getId())) {
support.setAssociatedRim(baseRim.getId());
try {
referenceManifestManager.updateReferenceManifest(support, support.getId());
referenceManifestRepository.save(support);
} catch (DBServiceException ex) {
log.error("Failed to update Support RIM", ex);
}
@ -365,8 +357,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
// testing this independent of the above if statement because the above
// starts off checking if associated rim is null; that is irrelevant for
// this statement.
measurements = EventLogMeasurements.select(referenceManifestManager)
.byHexDecHash(support.getHexDecHash()).getRIM();
measurements = (EventLogMeasurements) referenceManifestRepository.findByHash(support.getHexDecHash(),
"EventLogMeasurements");
if (support.isSwidPatch()) {
data.put("swidPatch", "True");
@ -491,8 +483,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
* Gathers all information and returns it for displays.
*
* @param measurements established ReferenceManifest Type.
* @param referenceManifestManager the reference manifest manager.
* @param referenceEventManager the reference event manager.
* @param referenceManifestRepository the reference manifest manager.
* @param referenceDigestValueRepository the reference event manager.
* @return mapping of the RIM information from the database.
* @throws java.io.IOException error for reading file bytes.
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
@ -500,8 +492,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
*/
private static HashMap<String, Object> getMeasurementsRimInfo(
final EventLogMeasurements measurements,
final ReferenceManifestService referenceManifestManager,
final ReferenceDigestValueService referenceEventManager)
final ReferenceManifestRepository referenceManifestRepository,
final ReferenceDigestValueRepository referenceDigestValueRepository)
throws IOException, CertificateException, NoSuchAlgorithmException {
HashMap<String, Object> data = new HashMap<>();
LinkedList<TpmPcrEvent> livelogEvents = new LinkedList<>();
@ -519,10 +511,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
List<ReferenceDigestValue> eventValues = new ArrayList<>();
if (measurements.getDeviceName() != null) {
supports.addAll(SupportReferenceManifest
.select(referenceManifestManager)
.byDeviceName(measurements
.getDeviceName()).getRIMs());
supports.addAll(referenceManifestRepository.byDeviceName(measurements
.getDeviceName()));
for (SupportReferenceManifest support : supports) {
if (support.isBaseSupport()) {
baseSupport = support;
@ -532,18 +522,14 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
if (baseSupport != null) {
data.put("supportFilename", baseSupport.getFileName());
data.put("supportId", baseSupport.getId());
base = BaseReferenceManifest
.select(referenceManifestManager)
.byEntityId(baseSupport.getAssociatedRim())
.getRIM();
data.put("tagId", baseSupport.getTagId());
base = referenceManifestRepository.getBaseRimEntityById(baseSupport.getAssociatedRim());
if (base != null) {
data.put("associatedRim", base.getId());
}
eventValues.addAll(referenceEventManager.getValuesByRimId(base));
eventValues.addAll(referenceDigestValueRepository.getValuesByRimId(base.getId()));
}
}

View File

@ -1,23 +1,30 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.CriteriaModifier;
import hirs.attestationca.persist.DBManagerException;
import hirs.attestationca.persist.FilteredRecordsList;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.service.ReferenceDigestValueService;
import hirs.attestationca.persist.service.ReferenceDigestValueServiceImpl;
import hirs.attestationca.persist.service.ReferenceManifestService;
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
import hirs.attestationca.persist.entity.userdefined.rim.BaseReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
import hirs.attestationca.persist.service.FilesStorageService;
import hirs.attestationca.portal.datatables.DataTableInput;
import hirs.attestationca.portal.datatables.DataTableResponse;
import hirs.attestationca.portal.datatables.OrderedListQueryDataTableAdapter;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.PageMessages;
import hirs.attestationca.portal.page.params.NoPageParams;
import hirs.utils.tpm.eventlog.TCGEventLog;
import hirs.utils.tpm.eventlog.TpmPcrEvent;
import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.extern.log4j.Log4j2;
import org.hibernate.Session;
@ -25,12 +32,32 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.view.RedirectView;
import java.io.IOException;
import java.lang.ref.Reference;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* Controller for the Reference Manifest page.
@ -40,25 +67,30 @@ import java.lang.ref.Reference;
@RequestMapping("/reference-manifests")
public class ReferenceManifestPageController extends PageController<NoPageParams> {
private static final String LOG_FILE_PATTERN = "([^\\s]+(\\.(?i)(rimpcr|rimel|bin|log))$)";
@Autowired(required = false)
private EntityManager entityManager;
private final ReferenceManifestService referenceManifestManager;
private final ReferenceDigestValueService referenceEventManager;
private final FilesStorageService filesStorageService;
private final ReferenceManifestRepository referenceManifestRepository;
private final ReferenceDigestValueRepository referenceDigestValueRepository;
/**
* Constructor providing the Page's display and routing specification.
*
* @param referenceManifestManager the reference manifest manager
* @param referenceEventManager this is the reference event manager
* @param filesStorageService storage services
* @param referenceManifestRepository the reference manifest manager
* @param referenceDigestValueRepository this is the reference event manager
*/
@Autowired
public ReferenceManifestPageController(
final ReferenceManifestServiceImpl referenceManifestManager,
final ReferenceDigestValueServiceImpl referenceEventManager) {
public ReferenceManifestPageController(final FilesStorageService filesStorageService,
final ReferenceManifestRepository referenceManifestRepository,
final ReferenceDigestValueRepository referenceDigestValueRepository) {
super(Page.REFERENCE_MANIFESTS);
this.referenceManifestManager = referenceManifestManager;
this.referenceEventManager = referenceEventManager;
this.filesStorageService = filesStorageService;
this.referenceManifestRepository = referenceManifestRepository;
this.referenceDigestValueRepository = referenceDigestValueRepository;
}
/**
@ -89,12 +121,10 @@ public class ReferenceManifestPageController extends PageController<NoPageParams
method = RequestMethod.GET)
public DataTableResponse<ReferenceManifest> getTableData(
@Valid final DataTableInput input) {
log.info("Handling request for summary list: " + input);
// return this.referenceManifestManager.fetchReferenceManifests(input);
log.debug("Handling request for summary list: " + input);
String orderColumnName = input.getOrderColumnName();
log.debug("Ordering on column: " + orderColumnName);
log.info("Ordering on column: " + orderColumnName);
// check that the alert is not archived and that it is in the specified report
CriteriaModifier criteriaModifier = new CriteriaModifier() {
@ -105,16 +135,395 @@ public class ReferenceManifestPageController extends PageController<NoPageParams
Root<ReferenceManifest> rimRoot = criteriaQuery.from(Reference.class);
criteriaQuery.select(rimRoot).distinct(true).where(cb.isNull(rimRoot.get(Certificate.ARCHIVE_FIELD)));
// criteria.add(Restrictions.isNull(Certificate.ARCHIVE_FIELD));
}
};
FilteredRecordsList<ReferenceManifest> records
= OrderedListQueryDataTableAdapter.getOrderedList(
ReferenceManifest.class,
referenceManifestManager,
this.referenceManifestRepository,
input, orderColumnName, criteriaModifier);
log.debug("Returning list of size: " + records.size());
return new DataTableResponse<>(records, input);
}
/**
* Upload and processes a reference manifest(s).
*
* @param files the files to process
* @param attr the redirection attributes
* @return the redirection view
* @throws URISyntaxException if malformed URI
* @throws Exception if malformed URI
*/
@RequestMapping(value = "/upload", method = RequestMethod.POST)
protected RedirectView upload(
@RequestParam("file") final MultipartFile[] files,
final RedirectAttributes attr) throws URISyntaxException, Exception {
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
String fileName;
Pattern logPattern = Pattern.compile(LOG_FILE_PATTERN);
Matcher matcher;
boolean supportRIM = false;
List<BaseReferenceManifest> baseRims = new ArrayList<>();
List<SupportReferenceManifest> supportRims = new ArrayList<>();
log.info(String.format("Processing %s uploaded files", files.length));
// loop through the files
for (MultipartFile file : files) {
fileName = file.getOriginalFilename();
matcher = logPattern.matcher(fileName);
supportRIM = matcher.matches();
//Parse reference manifests
parseRIM(file, supportRIM, messages, baseRims, supportRims);
}
baseRims.stream().forEach((rim) -> {
log.info(String.format("Storing swidtag %s", rim.getFileName()));
this.referenceManifestRepository.save(rim);
});
supportRims.stream().forEach((rim) -> {
log.info(String.format("Storing event log %s", rim.getFileName()));
this.referenceManifestRepository.save(rim);
});
// Prep a map to associated the swidtag payload hash to the swidtag.
// pass it in to update support rims that either were uploaded
// or already exist
// create a map of the supports rims in case an uploaded swidtag
// isn't one to one with the uploaded support rims.
Map<String, SupportReferenceManifest> updatedSupportRims
= updateSupportRimInfo(referenceManifestRepository.findAllSupportRims());
// pass in the updated support rims
// and either update or add the events
processTpmEvents(new ArrayList<SupportReferenceManifest>(updatedSupportRims.values()));
//Add messages to the model
model.put(MESSAGES_ATTRIBUTE, messages);
return redirectTo(Page.REFERENCE_MANIFESTS,
new NoPageParams(), model, attr);
}
/**
* Archives (soft delete) the Reference Integrity Manifest entry.
*
* @param id the UUID of the rim to delete
* @param attr RedirectAttributes used to forward data back to the original
* page.
* @return redirect to this page
* @throws URISyntaxException if malformed URI
*/
@RequestMapping(value = "/delete", method = RequestMethod.POST)
public RedirectView delete(@RequestParam final String id,
final RedirectAttributes attr) throws URISyntaxException {
log.info("Handling request to delete " + id);
Map<String, Object> model = new HashMap<>();
PageMessages messages = new PageMessages();
try {
ReferenceManifest referenceManifest = getRimFromDb(id);
if (referenceManifest == null) {
String notFoundMessage = "Unable to locate RIM with ID: " + id;
messages.addError(notFoundMessage);
log.warn(notFoundMessage);
} else {
referenceManifestRepository.delete(referenceManifest);
String deleteCompletedMessage = "RIM successfully deleted";
messages.addInfo(deleteCompletedMessage);
log.info(deleteCompletedMessage);
// if support rim, update associated events
if (referenceManifest instanceof SupportReferenceManifest) {
List<ReferenceDigestValue> values = referenceDigestValueRepository
.getValuesByRimId(referenceManifest.getId());
for (ReferenceDigestValue value : values) {
referenceDigestValueRepository.delete(value);
}
}
}
} catch (IllegalArgumentException iaEx) {
String uuidError = "Failed to parse ID from: " + id;
messages.addError(uuidError);
log.error(uuidError, iaEx);
} catch (DBManagerException dbmEx) {
String dbError = "Failed to archive cert: " + id;
messages.addError(dbError);
log.error(dbError, dbmEx);
}
model.put(MESSAGES_ATTRIBUTE, messages);
return redirectTo(Page.REFERENCE_MANIFESTS, new NoPageParams(), model, attr);
}
/**
* Handles request to download the rim by writing it to the response stream
* for download.
*
* @param id the UUID of the rim to download
* @param response the response object (needed to update the header with the
* file name)
* @throws java.io.IOException when writing to response output stream
*/
@RequestMapping(value = "/download", method = RequestMethod.GET)
public void download(@RequestParam final String id,
final HttpServletResponse response)
throws IOException {
log.info("Handling RIM request to download " + id);
try {
ReferenceManifest referenceManifest = getRimFromDb(id);
if (referenceManifest == null) {
String notFoundMessage = "Unable to locate RIM with ID: " + id;
log.warn(notFoundMessage);
// 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.setContentType("application/octet-stream");
// write cert to output stream
response.getOutputStream().write(referenceManifest.getRimBytes());
}
} catch (IllegalArgumentException ex) {
String uuidError = "Failed to parse ID from: " + id;
log.error(uuidError, ex);
// send a 404 error when invalid certificate
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
/**
* Handles request to download bulk of RIMs by writing it to the response stream
* for download in bulk.
*
* @param response the response object (needed to update the header with the
* file name)
* @throws java.io.IOException when writing to response output stream
*/
@RequestMapping(value = "/bulk", method = RequestMethod.GET)
public void bulk(final HttpServletResponse response)
throws IOException {
log.info("Handling request to download all Reference Integrity Manifests");
String fileName = "rims.zip";
String zipFileName;
// Set filename for download.
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
response.setContentType("application/zip");
List<ReferenceManifest> referenceManifestList = new LinkedList<>();
for (ReferenceManifest rim : referenceManifestRepository.findAll()) {
if ((rim instanceof BaseReferenceManifest)
|| (rim instanceof SupportReferenceManifest)) {
referenceManifestList.add(rim);
}
}
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
// get all files
for (ReferenceManifest rim : referenceManifestList) {
if (rim.getFileName().isEmpty()) {
zipFileName = "";
} else {
// configure the zip entry, the properties of the 'file'
zipFileName = rim.getFileName();
}
ZipEntry zipEntry = new ZipEntry(zipFileName);
zipEntry.setSize((long) rim.getRimBytes().length * Byte.SIZE);
zipEntry.setTime(System.currentTimeMillis());
zipOut.putNextEntry(zipEntry);
// the content of the resource
StreamUtils.copy(rim.getRimBytes(), zipOut);
zipOut.closeEntry();
}
zipOut.finish();
// write cert to output stream
} catch (IllegalArgumentException ex) {
String uuidError = "Failed to parse ID from: ";
log.error(uuidError, ex);
// send a 404 error when invalid certificate
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
/**
* This method takes the parameter and looks for this information in the
* Database.
*
* @param id of the RIM
* @return the associated RIM from the DB
* @throws IllegalArgumentException
*/
private ReferenceManifest getRimFromDb(final String id) throws IllegalArgumentException {
UUID uuid = UUID.fromString(id);
// ReferenceManifest rim = BaseReferenceManifest.select(referenceManifestManager)
// .byEntityId(uuid).getRIM();
//
// if (rim == null) {
// rim = SupportReferenceManifest.select(referenceManifestManager)
// .byEntityId(uuid).getRIM();
// }
//
// if (rim == null) {
// rim = EventLogMeasurements.select(referenceManifestManager)
// .byEntityId(uuid).getRIM();
// }
return this.referenceManifestRepository.getReferenceById(uuid);
}
/**
* Takes the rim files provided and returns a {@link ReferenceManifest}
* object.
*
* @param file the provide user file via browser.
* @param supportRIM matcher result
* @param messages the object that handles displaying information to the
* user.
* @param baseRims object to store multiple files
* @param supportRims object to store multiple files
* @return a single or collection of reference manifest files.
*/
private void parseRIM(
final MultipartFile file, final boolean supportRIM,
final PageMessages messages, final List<BaseReferenceManifest> baseRims,
final List<SupportReferenceManifest> supportRims) {
byte[] fileBytes = new byte[0];
String fileName = file.getOriginalFilename();
// build the manifest from the uploaded bytes
try {
fileBytes = file.getBytes();
} catch (IOException e) {
final String failMessage
= String.format("Failed to read uploaded file (%s): ", fileName);
log.error(failMessage, e);
messages.addError(failMessage + e.getMessage());
}
try {
if (supportRIM) {
supportRims.add(new SupportReferenceManifest(fileName, fileBytes));
} else {
baseRims.add(new BaseReferenceManifest(fileName, fileBytes));
}
} catch (IOException ioEx) {
final String failMessage
= String.format("Failed to parse uploaded file (%s): ", fileName);
log.error(failMessage, ioEx);
messages.addError(failMessage + ioEx.getMessage());
}
}
private Map<String, SupportReferenceManifest> updateSupportRimInfo(
final List<SupportReferenceManifest> dbSupportRims) {
SupportReferenceManifest supportRim;
String fileString;
Map<String, SupportReferenceManifest> updatedSupportRims = new HashMap<>();
Map<String, SupportReferenceManifest> hashValues = new HashMap<>();
for (SupportReferenceManifest support : dbSupportRims) {
hashValues.put(support.getHexDecHash(), support);
}
for (BaseReferenceManifest dbBaseRim : referenceManifestRepository.findAllBaseRims()) {
for (String supportHash : hashValues.keySet()) {
fileString = new String(dbBaseRim.getRimBytes(), StandardCharsets.UTF_8);
if (fileString.contains(supportHash)) {
supportRim = hashValues.get(supportHash);
// I have to assume the baseRim is from the database
// Updating the id values, manufacturer, model
if (supportRim != null && !supportRim.isUpdated()) {
supportRim.setSwidTagVersion(dbBaseRim.getSwidTagVersion());
supportRim.setPlatformManufacturer(dbBaseRim.getPlatformManufacturer());
supportRim.setPlatformModel(dbBaseRim.getPlatformModel());
supportRim.setTagId(dbBaseRim.getTagId());
supportRim.setAssociatedRim(dbBaseRim.getId());
supportRim.setUpdated(true);
referenceManifestRepository.save(supportRim);
updatedSupportRims.put(supportHash, supportRim);
}
}
}
}
return updatedSupportRims;
}
/**
* If the support rim is a supplemental or base, this method looks for the
* original oem base rim to associate with each event.
* @param supportRim assumed db object
* @return reference to the base rim
*/
private ReferenceManifest findBaseRim(final SupportReferenceManifest supportRim) {
if (supportRim != null && (supportRim.getId() != null
&& !supportRim.getId().toString().equals(""))) {
List<BaseReferenceManifest> baseRims = this.referenceManifestRepository
.getBaseByManufacturerModel(supportRim.getPlatformManufacturer(),
supportRim.getPlatformModel());
for (BaseReferenceManifest base : baseRims) {
if (base.isBase()) {
// there should be only one
return base;
}
}
}
return null;
}
private void processTpmEvents(final List<SupportReferenceManifest> dbSupportRims) {
List<ReferenceDigestValue> tpmEvents;
TCGEventLog logProcessor = null;
ReferenceManifest baseRim;
ReferenceDigestValue newRdv;
for (SupportReferenceManifest dbSupport : dbSupportRims) {
// So first we'll have to pull values based on support rim
// get by support rim id NEXT
if (dbSupport.getPlatformManufacturer() != null) {
tpmEvents = referenceDigestValueRepository.getValuesBySupportRimId(dbSupport.getAssociatedRim());
baseRim = findBaseRim(dbSupport);
if (tpmEvents.isEmpty()) {
try {
logProcessor = new TCGEventLog(dbSupport.getRimBytes());
for (TpmPcrEvent tpe : logProcessor.getEventList()) {
newRdv = new ReferenceDigestValue(baseRim.getId(),
dbSupport.getId(), dbSupport.getPlatformManufacturer(),
dbSupport.getPlatformModel(), tpe.getPcrIndex(),
tpe.getEventDigestStr(), tpe.getEventTypeStr(),
false, false, true, tpe.getEventContent());
this.referenceDigestValueRepository.save(newRdv);
}
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
for (ReferenceDigestValue rdv : tpmEvents) {
if (!rdv.isUpdated()) {
rdv.updateInfo(dbSupport, baseRim.getId());
this.referenceDigestValueRepository.save(rdv);
}
}
}
}
}
}
}

View File

@ -0,0 +1,35 @@
package hirs.attestationca.portal.page.controllers;
/**
* Restful implementation of the {@link }.
* Exposes the ACA methods as REST endpoints.
*/
//@RestController
//@RequestMapping("/")
public class RestfulAttestationCertificateAuthority {
// private final ReferenceManifestRepository referenceManifestRepository;
// private final ReferenceDigestValueRepository referenceDigestValueRepository;
//
// @Autowired
// public RestfulAttestationCertificateAuthority(
// final ReferenceManifestRepository referenceManifestRepository,
// final ReferenceDigestValueRepository referenceDigestValueRepository) {
//
// this.referenceManifestRepository = referenceManifestRepository;
// this.referenceDigestValueRepository = referenceDigestValueRepository;
//
// }
//
//
// @ResponseBody
// @RequestMapping(value = "/upload-swidtag", method = RequestMethod.POST, consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
// public byte[] uploadSwidtag(@RequestBody final byte[] request) {
// return null;
// }
//
// @ResponseBody
// @RequestMapping(value = "/upload-rimel", method = RequestMethod.POST, consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
// public byte[] uploadRimel(@RequestBody final byte[] request) {
// return null;
// }
}

View File

@ -1,17 +1,27 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.CriteriaModifier;
import hirs.attestationca.persist.DBManagerException;
import hirs.attestationca.persist.FilteredRecordsList;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
import hirs.attestationca.persist.service.ReferenceDigestValueService;
import hirs.attestationca.persist.service.ReferenceDigestValueServiceImpl;
import hirs.attestationca.persist.service.ReferenceManifestService;
import hirs.attestationca.persist.service.ReferenceManifestServiceImpl;
import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
import hirs.attestationca.portal.datatables.DataTableInput;
import hirs.attestationca.portal.datatables.DataTableResponse;
import hirs.attestationca.portal.datatables.OrderedListQueryDataTableAdapter;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.params.NoPageParams;
import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import jakarta.validation.Valid;
import lombok.extern.log4j.Log4j2;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.datatables.mapping.DataTablesInput;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
@ -20,7 +30,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
import java.lang.ref.Reference;
/**
* Controller for the TPM Events page.
@ -30,21 +40,24 @@ import java.util.List;
@RequestMapping("/rim-database")
public class RimDatabasePageController extends PageController<NoPageParams> {
private final ReferenceManifestService referenceManifestManager;
private final ReferenceDigestValueService referenceEventManager;
@Autowired(required = false)
private EntityManager entityManager;
private final ReferenceDigestValueRepository referenceDigestValueRepository;
private final ReferenceManifestRepository referenceManifestRepository;
/**
* Constructor providing the Page's display and routing specification.
*
* @param referenceManifestManager the ReferenceManifestManager object
* @param referenceEventManager the referenceEventManager object
* @param referenceDigestValueRepository the referenceDigestValueRepository object
* @param referenceManifestRepository the reference manifest manager object
*/
@Autowired
public RimDatabasePageController(final ReferenceManifestServiceImpl referenceManifestManager,
final ReferenceDigestValueServiceImpl referenceEventManager) {
public RimDatabasePageController(final ReferenceDigestValueRepository referenceDigestValueRepository,
final ReferenceManifestRepository referenceManifestRepository) {
super(Page.RIM_DATABASE);
this.referenceManifestManager = referenceManifestManager;
this.referenceEventManager = referenceEventManager;
this.referenceDigestValueRepository = referenceDigestValueRepository;
this.referenceManifestRepository = referenceManifestRepository;
}
/**
@ -73,50 +86,49 @@ public class RimDatabasePageController extends PageController<NoPageParams> {
@RequestMapping(value = "/list",
produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.GET)
public List<ReferenceDigestValue> getTableData(
@Valid final DataTablesInput input) {
public DataTableResponse<ReferenceDigestValue> getTableData(
@Valid final DataTableInput input) {
log.info("Handling request for summary list: " + input);
return this.referenceEventManager.fetchDigestValues();
String orderColumnName = input.getOrderColumnName();
log.info("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<ReferenceDigestValue> rimRoot = criteriaQuery.from(Reference.class);
criteriaQuery.select(rimRoot).distinct(true).where(cb.isNull(rimRoot.get(Certificate.ARCHIVE_FIELD)));
}
};
// String orderColumnName = input.getOrderColumnName();
// log.info("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 Criteria criteria) {
// criteria.add(Restrictions.isNull(Certificate.ARCHIVE_FIELD));
// }
// };
//
// log.info("Querying with the following datatableinput: " + input.toString());
//
// FilteredRecordsList<ReferenceDigestValue> referenceDigestValues =
// OrderedListQueryDataTableAdapter.getOrderedList(
// ReferenceDigestValue.class,
// referenceEventManager,
// input, orderColumnName, criteriaModifier);
//
// SupportReferenceManifest support;
// for (ReferenceDigestValue rdv : referenceDigestValues) {
// // We are updating the base rim ID field if necessary and
// if (rdv.getBaseRimId() == null) {
// support = SupportReferenceManifest.select(referenceManifestManager)
// .byEntityId(rdv.getSupportRimId()).getRIM();
// if (support != null) {
// rdv.setBaseRimId(support.getAssociatedRim());
// try {
// referenceEventManager.updateRefDigestValue(rdv);
// } catch (DBManagerException e) {
// log.error("Failed to update TPM Event with Base RIM ID");
// log.error(rdv);
// }
// }
// }
// }
//
// return new DataTableResponse<>(referenceDigestValues, input);
log.info("Querying with the following datatableinput: " + input.toString());
FilteredRecordsList<ReferenceDigestValue> referenceDigestValues =
OrderedListQueryDataTableAdapter.getOrderedList(
ReferenceDigestValue.class,
referenceDigestValueRepository,
input, orderColumnName, criteriaModifier);
SupportReferenceManifest support;
for (ReferenceDigestValue rdv : referenceDigestValues) {
// We are updating the base rim ID field if necessary and
if (rdv.getBaseRimId() == null) {
support = (SupportReferenceManifest) referenceManifestRepository.getReferenceById(rdv.getSupportRimId());
if (support != null) {
rdv.setBaseRimId(support.getAssociatedRim());
try {
referenceDigestValueRepository.save(rdv);
} catch (DBManagerException e) {
log.error("Failed to update TPM Event with Base RIM ID");
log.error(rdv);
}
}
}
}
return new DataTableResponse<>(referenceDigestValues, input);
}
}

View File

@ -0,0 +1,457 @@
package hirs.attestationca.portal.page.controllers;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import hirs.attestationca.persist.CriteriaModifier;
import hirs.attestationca.persist.FilteredRecordsList;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.DeviceRepository;
import hirs.attestationca.persist.entity.manager.SupplyChainValidationSummaryRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
import hirs.attestationca.portal.datatables.DataTableInput;
import hirs.attestationca.portal.datatables.DataTableResponse;
import hirs.attestationca.portal.datatables.OrderedListQueryDataTableAdapter;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.params.NoPageParams;
import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.ref.Reference;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Controller for the Validation Reports page.
*/
@Log4j2
@Controller
@RequestMapping("/validation-reports")
public class ValidationReportsPageController extends PageController<NoPageParams> {
private final SupplyChainValidationSummaryRepository supplyChainValidatorSummaryRepository;
private final CertificateRepository certificateRepository;
private final DeviceRepository deviceRepository;
@Autowired(required = false)
private EntityManager entityManager;
private static String systemColumnHeaders = "Verified Manufacturer,"
+ "Model,SN,Verification Date,Device Status";
private static String componentColumnHeaders = "Component name,Component manufacturer,"
+ "Component model,Component SN,Issuer,Component status";
private static final String DEFAULT_COMPANY = "AllDevices";
private static final String UNDEFINED = "undefined";
private static final String TRUE = "true";
/**
* Constructor providing the Page's display and routing specification.
* @param supplyChainValidatorSummaryRepository the manager
* @param certificateRepository the certificate manager
* @param deviceRepository the device manager
*/
@Autowired
public ValidationReportsPageController(
final SupplyChainValidationSummaryRepository supplyChainValidatorSummaryRepository,
final CertificateRepository certificateRepository,
final DeviceRepository deviceRepository) {
super(Page.VALIDATION_REPORTS);
this.supplyChainValidatorSummaryRepository = supplyChainValidatorSummaryRepository;
this.certificateRepository = certificateRepository;
this.deviceRepository = deviceRepository;
}
/**
* Returns the path for the view and the data model for the page.
*
* @param params The object to map url parameters into.
* @param model The data model for the request. Can contain data from redirect.
* @return the path for the view and data model for the page.
*/
@Override
@RequestMapping
public ModelAndView initPage(final NoPageParams params, final Model model) {
return getBaseModelAndView();
}
/**
* Gets the list of validation summaries per the data table input query.
* @param input the data table query.
* @return the data table response containing the supply chain summary records
*/
@ResponseBody
@RequestMapping(value = "/list", produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.GET)
public DataTableResponse<SupplyChainValidationSummary> getTableData(
final DataTableInput input) {
log.debug("Handling request for summary list: " + input);
// attempt to get the column property based on the order index.
String orderColumnName = input.getOrderColumnName();
log.debug("Ordering on column: " + orderColumnName);
// define an alias so the composite object, device, can be used by the
// datatables / query. This is necessary so the device.name property can
// be used.
// CriteriaModifier criteriaModifier = new CriteriaModifier() {
// @Override
// public void modify(final Criteria criteria) {
// criteria.add(RowMutationOperations.Restrictions.isNull(Certificate.ARCHIVE_FIELD));
// criteria.createAlias("device", "device");
// }
// };
CriteriaModifier criteriaModifier = new CriteriaModifier() {
@Override
public void modify(final CriteriaQuery criteriaQuery) {
Session session = entityManager.unwrap(Session.class);
CriteriaBuilder cb = session.getCriteriaBuilder();
Root<Certificate> scvRoot = criteriaQuery.from(Reference.class);
criteriaQuery.select(scvRoot).distinct(true).where(cb.isNull(scvRoot.get(Certificate.ARCHIVE_FIELD)));
}
};
FilteredRecordsList<SupplyChainValidationSummary> records =
OrderedListQueryDataTableAdapter.getOrderedList(
SupplyChainValidationSummary.class,
supplyChainValidatorSummaryRepository, input, orderColumnName,
criteriaModifier);
return new DataTableResponse<>(records, input);
}
/**
* This method handles downloading a validation report.
* @param request object
* @param response object
* @throws IOException thrown by BufferedWriter object
*/
@SuppressWarnings({"checkstyle:magicnumber", "checkstyle:methodlength" })
@RequestMapping(value = "download", method = RequestMethod.POST)
public void download(final HttpServletRequest request,
final HttpServletResponse response) throws IOException {
log.info("Downloading validation report");
String company = "";
String contractNumber = "";
Pattern pattern = Pattern.compile("^\\w*$");
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("uuuu-MM-dd");
DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
LocalDate startDate = null;
LocalDate endDate = null;
ArrayList<LocalDate> createTimes = new ArrayList<LocalDate>();
String[] deviceNames = new String[]{};
String columnHeaders = "";
boolean systemOnly = false;
boolean componentOnly = false;
String filterManufacturer = "";
String filterSerial = "";
boolean jsonVersion = false;
Enumeration parameters = request.getParameterNames();
while (parameters.hasMoreElements()) {
String parameter = (String) parameters.nextElement();
String parameterValue = request.getParameter(parameter);
log.info(parameter + ": " + parameterValue);
switch (parameter) {
case "company":
Matcher companyMatcher = pattern.matcher(parameterValue);
if (companyMatcher.matches()) {
company = parameterValue;
} else {
company = DEFAULT_COMPANY;
}
break;
case "contract":
Matcher contractMatcher = pattern.matcher(parameterValue);
if (contractMatcher.matches()) {
contractNumber = parameterValue;
} else {
contractNumber = "none";
}
break;
case "dateStart":
if (parameterValue != null && !parameterValue.isEmpty()) {
startDate = LocalDate.parse(parameterValue, dateFormat);
} else {
startDate = LocalDate.ofEpochDay(0);
}
break;
case "dateEnd":
if (parameterValue != null && !parameterValue.isEmpty()) {
endDate = LocalDate.parse(parameterValue, dateFormat);
} else {
endDate = LocalDate.now(ZoneId.of("America/New_York"));
}
break;
case "createTimes":
if (!parameterValue.equals(UNDEFINED)
&& !parameterValue.isEmpty()) {
String[] timestamps = parameterValue.split(",");
for (String timestamp : timestamps) {
createTimes.add(LocalDateTime.parse(timestamp,
dateTimeFormat).toLocalDate());
}
}
break;
case "deviceNames":
if (!parameterValue.equals(UNDEFINED)
&& !parameterValue.isEmpty()) {
deviceNames = parameterValue.split(",");
}
break;
case "system":
if (parameterValue.equals(TRUE)) {
systemOnly = true;
if (!columnHeaders.isEmpty()) {
columnHeaders = "," + columnHeaders;
}
columnHeaders = systemColumnHeaders + columnHeaders;
}
break;
case "component":
if (parameterValue.equals(TRUE)) {
componentOnly = true;
if (!columnHeaders.isEmpty()) {
columnHeaders += ",";
}
columnHeaders += componentColumnHeaders;
}
break;
case "manufacturer":
if (parameterValue != null && !parameterValue.isEmpty()) {
filterManufacturer = parameterValue;
}
break;
case "serial":
if (parameterValue != null && !parameterValue.isEmpty()) {
filterSerial = parameterValue;
}
break;
case "json":
response.setHeader("Content-Type", "application/json");
jsonVersion = true;
break;
default:
}
}
if (!jsonVersion) {
response.setHeader("Content-Type", "text/csv");
response.setHeader("Content-Disposition",
"attachment;filename=validation_report.csv");
}
BufferedWriter bufferedWriter = new BufferedWriter(
new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8));
StringBuilder reportData = new StringBuilder();
JsonArray jsonReportData = new JsonArray();
for (int i = 0; i < deviceNames.length; i++) {
if ((createTimes.get(i).isAfter(startDate) || createTimes.get(i).isEqual(startDate))
&& (createTimes.get(i).isBefore(endDate)
|| createTimes.get(i).isEqual(endDate))) {
UUID deviceId = deviceRepository.findByName(deviceNames[i]).getId();
PlatformCredential pc = certificateRepository.findByDeviceId(deviceId);
if (jsonVersion) {
jsonReportData.add(assembleJsonContent(pc, parseComponents(pc),
company, contractNumber));
} else {
if (i == 0) {
bufferedWriter.append("Company: " + company + "\n");
bufferedWriter.append("Contract number: " + contractNumber + "\n");
}
if (systemOnly && componentOnly) {
systemOnly = false;
componentOnly = false;
}
if ((filterManufacturer.isEmpty() || filterManufacturer.equals(
pc.getManufacturer()))
&& (filterSerial.isEmpty() || filterSerial.equals(
pc.getPlatformSerial()))) {
if (!componentOnly) {
reportData.append(pc.getManufacturer() + ","
+ pc.getModel() + ","
+ pc.getPlatformSerial() + ","
+ LocalDateTime.now().toString() + ","
+ pc.getDevice().getSupplyChainValidationStatus() + ",");
}
if (!systemOnly) {
ArrayList<ArrayList<String>> parsedComponents = parseComponents(pc);
for (ArrayList<String> component : parsedComponents) {
for (String data : component) {
reportData.append(data + ",");
}
reportData.deleteCharAt(reportData.length() - 1);
reportData.append(System.lineSeparator());
if (!componentOnly) {
reportData.append(",,,,,");
}
}
reportData = reportData.delete(
reportData.lastIndexOf(System.lineSeparator()) + 1,
reportData.length());
}
}
}
}
}
if (!jsonVersion) {
if (columnHeaders.isEmpty()) {
columnHeaders = systemColumnHeaders + "," + componentColumnHeaders;
}
bufferedWriter.append(columnHeaders + System.lineSeparator());
bufferedWriter.append(reportData.toString());
} else {
bufferedWriter.append(jsonReportData.toString());
}
bufferedWriter.flush();
}
/**
* This method builds a JSON object from the system and component data in a
* validation report.
* @param pc the platform credential used to validate.
* @param parsedComponents component data parsed from the platform credential.
* @param company company name.
* @param contractNumber contract number.
* @return the JSON object in String format.
*/
@SuppressWarnings({"checkstyle:magicnumber" })
private JsonObject assembleJsonContent(final PlatformCredential pc,
final ArrayList<ArrayList<String>> parsedComponents,
final String company,
final String contractNumber) {
JsonObject systemData = new JsonObject();
systemData.addProperty("Company", company);
systemData.addProperty("Contract number", contractNumber);
systemData.addProperty("Verified Manufacturer", pc.getManufacturer());
systemData.addProperty("Model", pc.getModel());
systemData.addProperty("SN", pc.getPlatformSerial());
systemData.addProperty("Verification Date", LocalDateTime.now().toString());
systemData.addProperty("Device Status", pc.getDevice().getSupplyChainValidationStatus().toString());
JsonArray components = new JsonArray();
for (ArrayList<String> componentData : parsedComponents) {
JsonObject component = new JsonObject();
component.addProperty("Component name", componentData.get(0));
component.addProperty("Component manufacturer", componentData.get(1));
component.addProperty("Component model", componentData.get(2));
component.addProperty("Component SN", componentData.get(3));
component.addProperty("Issuer", componentData.get(4));
component.addProperty("Component status", componentData.get(5));
components.add(component);
}
systemData.add("Components", components);
return systemData;
}
/**
* This method parses the following ComponentIdentifier fields into an ArrayList of ArrayLists.
* - ComponentClass
* - Manufacturer
* - Model
* - Serial number
* - Pass/fail status (based on componentFailures string)
* @param pc the platform credential.
* @return the ArrayList of ArrayLists containing the parsed component data.
*/
private ArrayList<ArrayList<String>> parseComponents(final PlatformCredential pc) {
ArrayList<ArrayList<String>> parsedComponents = new ArrayList<ArrayList<String>>();
ArrayList<ArrayList<Object>> chainComponents = new ArrayList<>();
StringBuilder componentFailureString = new StringBuilder();
if (pc.getComponentIdentifiers() != null
&& pc.getComponentIdentifiers().size() > 0) {
componentFailureString.append(pc.getComponentFailures());
// get all the certificates associated with the platform serial
List<PlatformCredential> chainCertificates = certificateRepository.byBoardSerialNumber(pc.getPlatformSerial());
// combine all components in each certificate
for (ComponentIdentifier ci : pc.getComponentIdentifiers()) {
ArrayList<Object> issuerAndComponent = new ArrayList<Object>();
issuerAndComponent.add(pc.getHolderIssuer());
issuerAndComponent.add(ci);
chainComponents.add(issuerAndComponent);
}
for (PlatformCredential cert : chainCertificates) {
componentFailureString.append(cert.getComponentFailures());
if (!cert.isPlatformBase()) {
for (ComponentIdentifier ci : cert.getComponentIdentifiers()) {
ArrayList<Object> issuerAndComponent = new ArrayList<Object>();
issuerAndComponent.add(cert.getHolderIssuer());
issuerAndComponent.add(ci);
chainComponents.add(issuerAndComponent);
}
}
}
log.info("Component failures: " + componentFailureString.toString());
for (ArrayList<Object> issuerAndComponent : chainComponents) {
ArrayList<String> componentData = new ArrayList<String>();
String issuer = (String) issuerAndComponent.get(0);
issuer = issuer.replaceAll(",", " ");
ComponentIdentifier ci = (ComponentIdentifier) issuerAndComponent.get(1);
if (ci instanceof ComponentIdentifierV2) {
String componentClass =
((ComponentIdentifierV2) ci).getComponentClass().toString();
String[] splitStrings = componentClass.split("\r\n|\n|\r");
StringBuilder sb = new StringBuilder();
for (String s : splitStrings) {
sb.append(s);
sb.append(" ");
}
sb = sb.deleteCharAt(sb.length() - 1);
componentData.add(sb.toString());
} else {
componentData.add("Platform Component");
}
componentData.add(ci.getComponentManufacturer().getString());
componentData.add(ci.getComponentModel().getString());
componentData.add(ci.getComponentSerial().getString());
componentData.add(issuer);
//Failing components are identified by hashcode
if (componentFailureString.toString().contains(String.valueOf(ci.hashCode()))) {
componentData.add("Fail");
} else {
componentData.add("Pass");
}
parsedComponents.add(componentData);
log.info(String.join(",", componentData));
}
}
return parsedComponents;
}
}

View File

@ -1,16 +1,29 @@
package hirs.attestationca.portal.page.utils;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
import hirs.attestationca.persist.service.CertificateServiceImpl;
import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestationCertificate;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration;
import hirs.utils.BouncyCastleUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.bouncycastle.util.encoders.Hex;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
/**
@ -25,13 +38,96 @@ public final class CertificateStringMapBuilder {
* Returns the general information.
*
* @param certificate certificate to get the general information.
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @param certificateRepository the certificate repository for retrieving certs.
* @return a hash map with the general certificate information.
*/
public static HashMap<String, String> getGeneralCertificateInfo(
final Certificate certificate, final CertificateServiceImpl certificateServiceImpl) {
final Certificate certificate, final CertificateRepository certificateRepository) {
HashMap<String, String> data = new HashMap<>();
if (certificate != null) {
data.put("issuer", certificate.getHolderIssuer());
//Serial number in hex value
data.put("serialNumber", Hex.toHexString(certificate.getSerialNumber().toByteArray()));
if (!certificate.getAuthoritySerialNumber().equals(BigInteger.ZERO)) {
data.put("authSerialNumber", Hex.toHexString(certificate
.getAuthoritySerialNumber().toByteArray()));
}
if (certificate.getId() != null) {
data.put("certificateId", certificate.getId().toString());
}
data.put("authInfoAccess", certificate.getAuthorityInfoAccess());
data.put("beginValidity", certificate.getBeginValidity().toString());
data.put("endValidity", certificate.getEndValidity().toString());
data.put("signature", Arrays.toString(certificate.getSignature()));
data.put("signatureSize", Integer.toString(certificate.getSignature().length
* Certificate.MIN_ATTR_CERT_LENGTH));
if (certificate.getSubject() != null) {
data.put("subject", certificate.getSubject());
data.put("isSelfSigned",
String.valueOf(certificate.getHolderIssuer().equals(certificate.getSubject())));
} else {
data.put("isSelfSigned", "false");
}
data.put("authKeyId", certificate.getAuthorityKeyIdentifier());
data.put("crlPoints", certificate.getCrlPoints());
data.put("signatureAlgorithm", certificate.getSignatureAlgorithm());
if (certificate.getEncodedPublicKey() != null) {
data.put("encodedPublicKey",
Arrays.toString(certificate.getEncodedPublicKey()));
data.put("publicKeyAlgorithm", certificate.getPublicKeyAlgorithm());
}
if (certificate.getPublicKeyModulusHexValue() != null) {
data.put("publicKeyValue", certificate.getPublicKeyModulusHexValue());
data.put("publicKeySize", String.valueOf(certificate.getPublicKeySize()));
}
if (certificate.getKeyUsage() != null) {
data.put("keyUsage", certificate.getKeyUsage());
}
if (certificate.getExtendedKeyUsage() != null
&& !certificate.getExtendedKeyUsage().isEmpty()) {
data.put("extendedKeyUsage", certificate.getExtendedKeyUsage());
}
//Get issuer ID if not self signed
if (data.get("isSelfSigned").equals("false")) {
//Get the missing certificate chain for not self sign
Certificate missingCert = containsAllChain(certificate, certificateRepository);
String issuerResult;
if (missingCert != null) {
data.put("missingChainIssuer", String.format("Missing %s from the chain.",
missingCert.getHolderIssuer()));
}
List<Certificate> certificates = certificateRepository.findBySubjectSorted(
certificate.getIssuerSorted(), "CertificateAuthorityCredential");
//Find all certificates that could be the issuer certificate based on subject name
for (Certificate issuerCert : certificates) {
try {
//Find the certificate that actually signed this cert
issuerResult = certificate.isIssuer(issuerCert);
if (issuerResult.isEmpty()) {
data.put("issuerID", issuerCert.getId().toString());
break;
} else {
data.put("issuerID", issuerCert.getId().toString());
issuerResult = String.format("%s: %s", issuerResult,
issuerCert.getSubject());
data.put("missingChainIssuer", issuerResult);
break;
}
} catch (IOException e) {
log.error(e);
}
}
}
}
return data;
}
@ -39,60 +135,109 @@ public final class CertificateStringMapBuilder {
* Recursive function that check if all the certificate chain is present.
*
* @param certificate certificate to get the issuer
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @param certificateRepository the certificate repository for retrieving certs.
* @return a boolean indicating if it has the full chain or not.
*/
public static Certificate containsAllChain(
final Certificate certificate,
final CertificateServiceImpl certificateServiceImpl) {
Set<CertificateAuthorityCredential> issuerCertificates = new HashSet<>();
final CertificateRepository certificateRepository) {
List<CertificateAuthorityCredential> issuerCertificates = new LinkedList<>();
CertificateAuthorityCredential skiCA = null;
String issuerResult;
return null;
//Check if there is a subject organization
if (certificate.getAuthorityKeyIdentifier() != null
&& !certificate.getAuthorityKeyIdentifier().isEmpty()) {
byte[] bytes = Hex.decode(certificate.getAuthorityKeyIdentifier());
skiCA = (CertificateAuthorityCredential) certificateRepository.findBySubjectKeyIdentifier(bytes);
} else {
log.error(String.format("Certificate (%s) for %s has no authority key identifier.",
certificate.getClass().toString(), certificate.getSubject()));
}
if (skiCA == null) {
if (certificate.getIssuerSorted() == null
|| certificate.getIssuerSorted().isEmpty()) {
//Get certificates by subject
issuerCertificates = certificateRepository.findBySubject(certificate.getIssuer(),
"CertificateAuthorityCredential");
} else {
//Get certificates by subject organization
issuerCertificates = certificateRepository.findBySubjectSorted(certificate.getIssuerSorted(),
"CertificateAuthorityCredential");
}
} else {
issuerCertificates.add(skiCA);
}
for (Certificate issuerCert : issuerCertificates) {
try {
// Find the certificate that actually signed this cert
issuerResult = certificate.isIssuer(issuerCert);
if (issuerResult.isEmpty()) {
//Check if it's root certificate
if (BouncyCastleUtils.x500NameCompare(issuerCert.getIssuerSorted(),
issuerCert.getSubject())) {
return null;
}
return containsAllChain(issuerCert, certificateRepository);
}
} catch (IOException e) {
log.error(e);
return certificate;
}
}
return certificate;
}
/**
* Returns the Certificate Authority information.
*
* @param uuid ID for the certificate.
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @param certificateRepository the certificate manager for retrieving certs.
* @return a hash map with the endorsement certificate information.
*/
public static HashMap<String, String> getCertificateAuthorityInformation(final UUID uuid,
final CertificateServiceImpl certificateServiceImpl) {
// CertificateAuthorityCredential certificate =
// CertificateAuthorityCredential
// .select(certificateManager)
// .byEntityId(uuid)
// .getCertificate();
final CertificateRepository certificateRepository) {
CertificateAuthorityCredential certificate = (CertificateAuthorityCredential) certificateRepository.getCertificate(uuid);
String notFoundMessage = "Unable to find Certificate Authority "
+ "Credential with ID: " + uuid;
// return getCertificateAuthorityInfoHelper(certificateServiceImpl, certificate, notFoundMessage);
return null;
return getCertificateAuthorityInfoHelper(certificateRepository, certificate, notFoundMessage);
}
/**
* Returns the Trust Chain credential information.
*
* @param certificate the certificate
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @param certificateRepository the certificate repository for retrieving certs.
* @return a hash map with the endorsement certificate information.
*/
public static HashMap<String, String> getCertificateAuthorityInformation(
final CertificateAuthorityCredential certificate,
final CertificateServiceImpl certificateServiceImpl) {
// return getCertificateAuthorityInfoHelper(certificateManager, certificate,
// "No cert provided for mapping");
return null;
final CertificateRepository certificateRepository) {
return getCertificateAuthorityInfoHelper(certificateRepository, certificate,
"No cert provided for mapping");
}
private static HashMap<String, String> getCertificateAuthorityInfoHelper(
final CertificateServiceImpl certificateServiceImpl,
final CertificateRepository certificateRepository,
final CertificateAuthorityCredential certificate, final String notFoundMessage) {
HashMap<String, String> data = new HashMap<>();
if (certificate != null) {
data.putAll(getGeneralCertificateInfo(certificate, certificateRepository));
data.put("subjectKeyIdentifier",
Arrays.toString(certificate.getSubjectKeyIdentifier()));
//x509 credential version
data.put("x509Version", Integer.toString(certificate
.getX509CredentialVersion()));
data.put("credentialType", certificate.getCredentialType());
} else {
log.error(notFoundMessage);
}
return data;
}
@ -100,13 +245,40 @@ public final class CertificateStringMapBuilder {
* Returns the endorsement credential information.
*
* @param uuid ID for the certificate.
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @param certificateRepository the certificate repository for retrieving certs.
* @return a hash map with the endorsement certificate information.
*/
public static HashMap<String, String> getEndorsementInformation(final UUID uuid,
final CertificateServiceImpl certificateServiceImpl) {
final CertificateRepository certificateRepository) {
HashMap<String, String> data = new HashMap<>();
EndorsementCredential certificate = (EndorsementCredential) certificateRepository.findById(uuid).get();
if (certificate != null) {
data.putAll(getGeneralCertificateInfo(certificate, certificateRepository));
// Set extra fields
data.put("manufacturer", certificate.getManufacturer());
data.put("model", certificate.getModel());
data.put("version", certificate.getVersion());
data.put("policyReference", certificate.getPolicyReference());
data.put("crlPoints", certificate.getCrlPoints());
data.put("credentialType", certificate.getCredentialType());
//x509 credential version
data.put("x509Version", Integer.toString(certificate
.getX509CredentialVersion()));
// Add hashmap with TPM information if available
if (certificate.getTpmSpecification() != null) {
data.putAll(
convertStringToHash(certificate.getTpmSpecification().toString()));
}
if (certificate.getTpmSecurityAssertions() != null) {
data.putAll(
convertStringToHash(certificate.getTpmSecurityAssertions().toString()));
}
} else {
String notFoundMessage = "Unable to find Endorsement Credential "
+ "with ID: " + uuid;
log.error(notFoundMessage);
}
return data;
}
@ -114,16 +286,136 @@ public final class CertificateStringMapBuilder {
* Returns the Platform credential information.
*
* @param uuid ID for the certificate.
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @param certificateRepository the certificate manager for retrieving certs.
* @return a hash map with the endorsement certificate information.
* @throws IOException when parsing the certificate
* @throws IllegalArgumentException invalid argument on parsing the certificate
*/
public static HashMap<String, Object> getPlatformInformation(final UUID uuid,
final CertificateServiceImpl certificateServiceImpl)
final CertificateRepository certificateRepository,
final ComponentResultRepository componentResultRepository)
throws IllegalArgumentException, IOException {
HashMap<String, Object> data = new HashMap<>();
PlatformCredential certificate = (PlatformCredential) certificateRepository.findById(uuid).get();
if (certificate != null) {
data.putAll(getGeneralCertificateInfo(certificate, certificateRepository));
data.put("credentialType", certificate.getCredentialType());
data.put("platformType", certificate.getPlatformChainType());
data.put("manufacturer", certificate.getManufacturer());
data.put("model", certificate.getModel());
data.put("version", certificate.getVersion());
data.put("platformSerial", certificate.getPlatformSerial());
data.put("chassisSerialNumber", certificate.getChassisSerialNumber());
data.put("platformClass", certificate.getPlatformClass());
data.put("majorVersion",
Integer.toString(certificate.getMajorVersion()));
data.put("minorVersion",
Integer.toString(certificate.getMinorVersion()));
data.put("revisionLevel",
Integer.toString(certificate.getRevisionLevel()));
data.put("holderSerialNumber", certificate.getHolderSerialNumber()
.toString(Certificate.HEX_BASE)
.replaceAll("(?<=..)(..)", ":$1"));
data.put("holderIssuer", certificate.getHolderIssuer());
if (certificate.isPlatformBase()) {
EndorsementCredential ekCertificate = (EndorsementCredential) certificateRepository
.findBySerialNumber(certificate.getHolderSerialNumber(),
"EndorsementCredential");
if (ekCertificate != null) {
data.put("holderId", ekCertificate.getId().toString());
}
} else {
if (certificate.getPlatformChainType()!= null
&& certificate.getPlatformChainType().equals("Delta")) {
PlatformCredential holderCertificate = (PlatformCredential) certificateRepository
.findBySerialNumber(certificate.getHolderSerialNumber(),
"PlatformCredential");
if (holderCertificate != null) {
data.put("holderId", holderCertificate.getId().toString());
}
}
}
PlatformCredential prevCertificate = certificateRepository
.byHolderSerialNumber(certificate.getSerialNumber());
if (prevCertificate != null) {
data.put("prevCertId", prevCertificate.getId().toString());
}
//x509 credential version
data.put("x509Version", certificate.getX509CredentialVersion());
//CPSuri
data.put("CPSuri", certificate.getCPSuri());
if (!certificate.getComponentFailures().isEmpty()) {
data.put("failures", certificate.getComponentFailures());
HashMap<Integer, String> results = new HashMap<>();
for (ComponentResult componentResult : componentResultRepository.findAll()) {
if (componentResult.getCertificateId()
.equals(certificate.getId())) {
results.put(componentResult.getComponentHash(),
componentResult.getExpected());
}
}
data.put("componentResults", results);
data.put("failureMessages", certificate.getComponentFailures());
}
//Get platform Configuration values and set map with it
PlatformConfiguration platformConfiguration = certificate.getPlatformConfiguration();
if (platformConfiguration != null) {
//Component Identifier - attempt to translate hardware IDs
List<ComponentIdentifier> comps = platformConfiguration.getComponentIdentifier();
if (PciIds.DB.isReady()) {
comps = PciIds.translate(comps);
}
data.put("componentsIdentifier", comps);
//Component Identifier URI
data.put("componentsIdentifierURI", platformConfiguration
.getComponentIdentifierUri());
//Platform Properties
data.put("platformProperties", platformConfiguration.getPlatformProperties());
//Platform Properties URI
data.put("platformPropertiesURI", platformConfiguration.getPlatformPropertiesUri());
}
//TBB Security Assertion
data.put("tbbSecurityAssertion", certificate.getTBBSecurityAssertion());
if (certificate.getPlatformSerial() != null) {
// link certificate chain
List<PlatformCredential> chainCertificates = certificateRepository.byBoardSerialNumber(certificate.getPlatformSerial());
data.put("numInChain", chainCertificates.size());
Collections.sort(chainCertificates, new Comparator<PlatformCredential>() {
@Override
public int compare(final PlatformCredential obj1,
final PlatformCredential obj2) {
return obj1.getBeginValidity().compareTo(obj2.getBeginValidity());
}
});
data.put("chainCertificates", chainCertificates);
if (!certificate.isPlatformBase()) {
for (PlatformCredential pc : chainCertificates) {
if (pc.isPlatformBase()) {
if (!pc.getComponentFailures().isEmpty()) {
data.put("failures", pc.getComponentFailures());
}
break;
}
}
}
}
} else {
String notFoundMessage = "Unable to find Platform Certificate "
+ "with ID: " + uuid;
log.error(notFoundMessage);
}
return data;
}
@ -158,13 +450,66 @@ public final class CertificateStringMapBuilder {
* Returns the Issued Attestation Certificate information.
*
* @param uuid ID for the certificate.
* @param certificateServiceImpl the certificate manager for retrieving certs.
* @param certificateRepository the certificate manager for retrieving certs.
* @return a hash map with the endorsement certificate information.
*/
public static HashMap<String, String> getIssuedInformation(final UUID uuid,
final CertificateServiceImpl certificateServiceImpl) {
final CertificateRepository certificateRepository) {
HashMap<String, String> data = new HashMap<>();
IssuedAttestationCertificate certificate = (IssuedAttestationCertificate) certificateRepository.getCertificate(uuid);
if (certificate != null) {
data.putAll(getGeneralCertificateInfo(certificate, certificateRepository));
// add endorsement credential ID if not null
if (certificate.getEndorsementCredential() != null) {
EndorsementCredential ek = certificate.getEndorsementCredential();
data.put("endorsementID", ek.getId().toString());
// Add hashmap with TPM information if available
if (ek.getTpmSpecification() != null) {
data.putAll(
convertStringToHash(ek.getTpmSpecification().toString()));
}
if (ek.getTpmSecurityAssertions() != null) {
data.putAll(
convertStringToHash(ek.getTpmSecurityAssertions().toString()));
}
data.put("policyReference", ek.getPolicyReference());
data.put("crlPoints", ek.getCrlPoints());
data.put("credentialType", IssuedAttestationCertificate.AIC_TYPE_LABEL);
}
// add platform credential IDs if not empty
if (!certificate.getPlatformCredentials().isEmpty()) {
StringBuilder buf = new StringBuilder();
for (PlatformCredential pc : certificate.getPlatformCredentials()) {
buf.append(pc.getId().toString());
buf.append(',');
data.put("manufacturer", pc.getManufacturer());
data.put("model", pc.getModel());
data.put("version", pc.getVersion());
data.put("majorVersion",
Integer.toString(pc.getMajorVersion()));
data.put("minorVersion",
Integer.toString(pc.getMinorVersion()));
data.put("revisionLevel",
Integer.toString(pc.getRevisionLevel()));
data.put("tcgMajorVersion",
Integer.toString(pc.getTcgCredentialMajorVersion()));
data.put("tcgMinorVersion",
Integer.toString(pc.getTcgCredentialMinorVersion()));
data.put("tcgRevisionLevel",
Integer.toString(pc.getTcgCredentialRevisionLevel()));
}
// remove last comma character
buf.deleteCharAt(buf.lastIndexOf(","));
data.put("platformID", buf.toString());
}
} else {
String notFoundMessage = "Unable to find Issued Attestation Certificate "
+ "with ID: " + uuid;
log.error(notFoundMessage);
}
return data;
}
}

View File

@ -0,0 +1,106 @@
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%-- JSP TAGS --%>
<%@taglib prefix="c" uri="jakarta.tags.core" %>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@taglib prefix="my" tagdir="/WEB-INF/tags"%>
<%-- 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">Endorsement Key Credentials</jsp:attribute>
<jsp:body>
<div class="aca-input-box-header">
<form:form method="POST" action="${portal}/certificate-request/endorsement-key-credentials/upload" enctype="multipart/form-data">
Import Endorsement Key Credentials
<my:file-chooser id="ek-editor" label="Import Endorsement Key Credentials">
<input id="importFile" type="file" name="file" multiple="multiple" />
</my:file-chooser>
<a href="${portal}/certificate-request/endorsement-key-credentials/bulk">
<img src="${icons}/ic_file_download_black_24dp.png" title="Download All Endorsement Certificates">
</a>
</form:form>
</div>
<br/>
<div class="aca-data-table">
<table id="endorsementKeyTable" 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>Valid (begin)</th>
<th>Valid (end)</th>
<th>Options</th>
</tr>
</thead>
</table>
</div>
<script>
$(document).ready(function() {
var url = pagePath +'/list';
var columns = [
{
data: 'device.name',
render: function (data, type, full, meta) {
// if there's a device, display its name, otherwise
// display nothing
if (full.device) {
// TODO render a link to a device details page,
// passing the device.id
return full.device.name;
}
return '';
}
},
{data: 'issuer'},
{data: 'credentialType'},
{data: 'manufacturer'},
{data: 'model'},
{data: 'version'},
{
data: 'beginValidity',
searchable:false,
render: function (data, type, full, meta) {
return formatDateTime(full.beginValidity);
}
},
{
data: 'endValidity',
searchable:false,
render: function (data, type, full, meta) {
return formatDateTime(full.endValidity);
}
},
{
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
var html = '';
html += certificateDetailsLink('endorsement', full.id, true);
html += certificateDownloadLink(full.id, pagePath);
html += certificateDeleteLink(full.id, pagePath);
return html;
}
}
];
//Set data tables
setDataTables("#endorsementKeyTable", url, columns);
});
</script>
</jsp:body>
</my:page>

View File

@ -40,8 +40,8 @@
<link type="text/css" rel="stylesheet" href="${common}/common.css"/>
<link type="text/css" rel="stylesheet" href="${common}/sidebar.css"/>
<link type="text/css" rel="stylesheet" href="${lib}/bootstrap-3.3.7/css/bootstrap.min.css"/>
<link type="text/css" rel="stylesheet" href="${lib}/jquery.dataTables-1.10.13/media/css/jquery.dataTables.min.css"></link>
<link type="text/css" rel="stylesheet" href="${lib}/bootstrap-3.3.7/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="${lib}/jquery.dataTables-1.10.13/media/css/jquery.dataTables.min.css" />
<%-- page-specific style --%>
<jsp:invoke fragment="style"/>

View File

@ -25,13 +25,24 @@
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<multipart-config>
<location>/tmp</location>
<max-file-size>28393832</max-file-size>
<max-request-size>482818342</max-request-size>
<file-size-threshold>1031234</file-size-threshold>
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>pages</servlet-name>
<url-pattern>/portal/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>hirs.attestationca.portal.HIRSDbInitializer</listener-class>
</listener>
<error-page>
<location>/errors</location>
</error-page>
</web-app>
</web-app>

View File

@ -0,0 +1,59 @@
# DataTables plug-in for jQuery
DataTables is a table enhancing plug-in for the [jQuery](//jquery.com) Javascript library, adding sorting, paging and filtering abilities to plain HTML tables with minimal effort. The stated goal of DataTables is:
> To enhance the accessibility of data in HTML tables.
To meet this goal, DataTables is developed with two distinct groups of users in mind:
* You the developers using DataTables. For developers DataTables provides a wide array of options for how data should be obtained, displayed and acted upon, along with an extensive API for accessing and manipulating the table.
* End users. For those using the interface DataTables presents, actions to get the most from the information contained in tables, such as sorting and filtering, along with paging and scrolling of the data in table, are easy to use, intuitive and fast.
## Installing DataTables
To use DataTables, the primary way to obtain the software is to use the [DataTables downloader](//datatables.net/download). You can also include the individual files from the [DataTables CDN](//cdn.datatables.net). See the [documentation](//datatables.net/manual/installation) for full details.
### NPM and Bower
If you prefer to use a package manager such as NPM or Bower, distribution repositories are available with software built from this repository under the name `datatables.net`. Styling packages for Bootstrap, Foundation and other styling libraries are also available by adding a suffix to the package name.
Please see the DataTables [NPM](//datatables.net/download/npm) and [Bower](//datatables.net/download/bower) installation pages for further information. The [DataTables installation manual](//datatables.net/manual/installation) also has details on how to use package managers with DataTables.
## Usage
In its simplest case, DataTables can be initialised with a single line of Javascript:
```js
$('table').dataTable();
```
where the jQuery selector is used to obtain a reference to the table you want to enhance with DataTables. Optional configuration parameters can be passed in to DataTables to have it perform certain actions by using a configuration object as the parameter passed in to the DataTables constructor. For example:
```js
$('table').dataTable( {
paginate: false,
scrollY: 300
} );
```
will disable paging and enable scrolling.
A full list of the options available for DataTables are available in the [documentation](//datatables.net).
## Documentation
Full documentation of the DataTables options, API and plug-in interface are available on the [DataTables web-site](//datatables.net). The site also contains information on the wide variety of plug-ins that are available for DataTables, which can be used to enhance and customise your table even further.
## Support
Support for DataTables is available through the [DataTables forums](//datatables.net/forums) and [commercial support options](//datatables.net/support) are available.
## License
DataTables is release under the [MIT license](//datatables.net/license). You are free to use, modify and distribute this software, as long as the copyright header is left intact (specifically the comment block which starts with `/*!`.

View File

@ -0,0 +1,22 @@
MIT license
Copyright (c) 2008-2015 SpryMedia Limited
http://datatables.net
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,39 @@
# AutoFill
AutoFill adds an Excel data fill like option to a DataTable to click and drag over multiple cells, filling in information over the selected cells and incrementing numbers as needed.
# Installation
To use AutoFill the best way to obtain the software is to use the [DataTables downloader](//datatables.net/download). You can also include the individual files from the [DataTables CDN](//cdn.datatables.net). See the [documentation](http://datatables.net/extensions/autofill/) for full details.
## NPM and Bower
If you prefer to use a package manager such as NPM or Bower, distribution repositories are available with software built from this repository under the name `datatables.net-autofill`. Styling packages for Bootstrap, Foundation and other styling libraries are also available by adding a suffix to the package name.
Please see the DataTables [NPM](//datatables.net/download/npm) and [Bower](//datatables.net/download/bower) installation pages for further information. The [DataTables installation manual](//datatables.net/manual/installation) also has details on how to use package managers with DataTables.
# Basic usage
AutoFill is initialised using the `autoFill` option in the DataTables constructor. Further options can be specified using this option as an object - see the documentation for details. For example:
```js
$(document).ready( function () {
$('#example').DataTable( {
autoFill: true
} );
} );
```
# Documentation / support
* [Documentation](https://datatables.net/extensions/autofill/)
* [DataTables support forums](http://datatables.net/forums)
# GitHub
If you fancy getting involved with the development of AutoFill and help make it better, please refer to its [GitHub repo](https://github.com/DataTables/AutoFill)

View File

@ -0,0 +1,81 @@
div.dt-autofill-handle {
position: absolute;
height: 8px;
width: 8px;
z-index: 102;
box-sizing: border-box;
border: 1px solid #337ab7;
background: #337ab7;
}
div.dt-autofill-select {
position: absolute;
z-index: 1001;
background-color: #337ab7;
background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);
}
div.dt-autofill-select.top, div.dt-autofill-select.bottom {
height: 3px;
margin-top: -1px;
}
div.dt-autofill-select.left, div.dt-autofill-select.right {
width: 3px;
margin-left: -1px;
}
div.dt-autofill-list {
position: fixed;
top: 50%;
left: 50%;
width: 500px;
margin-left: -250px;
background-color: white;
border-radius: 6px;
box-shadow: 0 0 5px #555;
border: 2px solid #444;
z-index: 11;
box-sizing: border-box;
padding: 1.5em 2em;
}
div.dt-autofill-list ul {
display: table;
margin: 0;
padding: 0;
list-style: none;
width: 100%;
}
div.dt-autofill-list ul li {
display: table-row;
}
div.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {
border-bottom: none;
}
div.dt-autofill-list ul li:hover {
background-color: #f6f6f6;
}
div.dt-autofill-list div.dt-autofill-question {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-list div.dt-autofill-question input[type=number] {
padding: 6px;
width: 30px;
margin: -2px 0;
}
div.dt-autofill-list div.dt-autofill-button {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
z-index: 10;
}

View File

@ -0,0 +1 @@
div.dt-autofill-handle{position:absolute;height:8px;width:8px;z-index:102;box-sizing:border-box;border:1px solid #337ab7;background:#337ab7}div.dt-autofill-select{position:absolute;z-index:1001;background-color:#337ab7;background-image:repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255,255,255,0.5) 5px, rgba(255,255,255,0.5) 10px)}div.dt-autofill-select.top,div.dt-autofill-select.bottom{height:3px;margin-top:-1px}div.dt-autofill-select.left,div.dt-autofill-select.right{width:3px;margin-left:-1px}div.dt-autofill-list{position:fixed;top:50%;left:50%;width:500px;margin-left:-250px;background-color:white;border-radius:6px;box-shadow:0 0 5px #555;border:2px solid #444;z-index:11;box-sizing:border-box;padding:1.5em 2em}div.dt-autofill-list ul{display:table;margin:0;padding:0;list-style:none;width:100%}div.dt-autofill-list ul li{display:table-row}div.dt-autofill-list ul li:last-child div.dt-autofill-question,div.dt-autofill-list ul li:last-child div.dt-autofill-button{border-bottom:none}div.dt-autofill-list ul li:hover{background-color:#f6f6f6}div.dt-autofill-list div.dt-autofill-question{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-list div.dt-autofill-question input[type=number]{padding:6px;width:30px;margin:-2px 0}div.dt-autofill-list div.dt-autofill-button{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:10}

View File

@ -0,0 +1,81 @@
div.dt-autofill-handle {
position: absolute;
height: 8px;
width: 8px;
z-index: 102;
box-sizing: border-box;
border: 1px solid #0275d8;
background: #0275d8;
}
div.dt-autofill-select {
position: absolute;
z-index: 1001;
background-color: #0275d8;
background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);
}
div.dt-autofill-select.top, div.dt-autofill-select.bottom {
height: 3px;
margin-top: -1px;
}
div.dt-autofill-select.left, div.dt-autofill-select.right {
width: 3px;
margin-left: -1px;
}
div.dt-autofill-list {
position: fixed;
top: 50%;
left: 50%;
width: 500px;
margin-left: -250px;
background-color: white;
border-radius: 6px;
box-shadow: 0 0 5px #555;
border: 2px solid #444;
z-index: 11;
box-sizing: border-box;
padding: 1.5em 2em;
}
div.dt-autofill-list ul {
display: table;
margin: 0;
padding: 0;
list-style: none;
width: 100%;
}
div.dt-autofill-list ul li {
display: table-row;
}
div.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {
border-bottom: none;
}
div.dt-autofill-list ul li:hover {
background-color: #f6f6f6;
}
div.dt-autofill-list div.dt-autofill-question {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-list div.dt-autofill-question input[type=number] {
padding: 6px;
width: 30px;
margin: -2px 0;
}
div.dt-autofill-list div.dt-autofill-button {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
z-index: 10;
}

View File

@ -0,0 +1 @@
div.dt-autofill-handle{position:absolute;height:8px;width:8px;z-index:102;box-sizing:border-box;border:1px solid #0275d8;background:#0275d8}div.dt-autofill-select{position:absolute;z-index:1001;background-color:#0275d8;background-image:repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255,255,255,0.5) 5px, rgba(255,255,255,0.5) 10px)}div.dt-autofill-select.top,div.dt-autofill-select.bottom{height:3px;margin-top:-1px}div.dt-autofill-select.left,div.dt-autofill-select.right{width:3px;margin-left:-1px}div.dt-autofill-list{position:fixed;top:50%;left:50%;width:500px;margin-left:-250px;background-color:white;border-radius:6px;box-shadow:0 0 5px #555;border:2px solid #444;z-index:11;box-sizing:border-box;padding:1.5em 2em}div.dt-autofill-list ul{display:table;margin:0;padding:0;list-style:none;width:100%}div.dt-autofill-list ul li{display:table-row}div.dt-autofill-list ul li:last-child div.dt-autofill-question,div.dt-autofill-list ul li:last-child div.dt-autofill-button{border-bottom:none}div.dt-autofill-list ul li:hover{background-color:#f6f6f6}div.dt-autofill-list div.dt-autofill-question{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-list div.dt-autofill-question input[type=number]{padding:6px;width:30px;margin:-2px 0}div.dt-autofill-list div.dt-autofill-button{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:10}

View File

@ -0,0 +1,92 @@
div.dt-autofill-handle {
position: absolute;
height: 8px;
width: 8px;
z-index: 102;
box-sizing: border-box;
border: 1px solid #316ad1;
background: linear-gradient(to bottom, #abcffb 0%, #4989de 100%);
}
div.dt-autofill-select {
position: absolute;
z-index: 1001;
background-color: #4989de;
background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);
}
div.dt-autofill-select.top, div.dt-autofill-select.bottom {
height: 3px;
margin-top: -1px;
}
div.dt-autofill-select.left, div.dt-autofill-select.right {
width: 3px;
margin-left: -1px;
}
div.dt-autofill-list {
position: fixed;
top: 50%;
left: 50%;
width: 500px;
margin-left: -250px;
background-color: white;
border-radius: 6px;
box-shadow: 0 0 5px #555;
border: 2px solid #444;
z-index: 11;
box-sizing: border-box;
padding: 1.5em 2em;
}
div.dt-autofill-list ul {
display: table;
margin: 0;
padding: 0;
list-style: none;
width: 100%;
}
div.dt-autofill-list ul li {
display: table-row;
}
div.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {
border-bottom: none;
}
div.dt-autofill-list ul li:hover {
background-color: #f6f6f6;
}
div.dt-autofill-list div.dt-autofill-question {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-list div.dt-autofill-question input[type=number] {
padding: 6px;
width: 30px;
margin: -2px 0;
}
div.dt-autofill-list div.dt-autofill-button {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-list div.dt-autofill-button button {
color: white;
margin: 0;
padding: 6px 12px;
text-align: center;
border: 1px solid #2e6da4;
background-color: #337ab7;
border-radius: 4px;
cursor: pointer;
vertical-align: middle;
}
div.dt-autofill-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
z-index: 10;
}

View File

@ -0,0 +1 @@
div.dt-autofill-handle{position:absolute;height:8px;width:8px;z-index:102;box-sizing:border-box;border:1px solid #316ad1;background:linear-gradient(to bottom, #abcffb 0%, #4989de 100%)}div.dt-autofill-select{position:absolute;z-index:1001;background-color:#4989de;background-image:repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255,255,255,0.5) 5px, rgba(255,255,255,0.5) 10px)}div.dt-autofill-select.top,div.dt-autofill-select.bottom{height:3px;margin-top:-1px}div.dt-autofill-select.left,div.dt-autofill-select.right{width:3px;margin-left:-1px}div.dt-autofill-list{position:fixed;top:50%;left:50%;width:500px;margin-left:-250px;background-color:white;border-radius:6px;box-shadow:0 0 5px #555;border:2px solid #444;z-index:11;box-sizing:border-box;padding:1.5em 2em}div.dt-autofill-list ul{display:table;margin:0;padding:0;list-style:none;width:100%}div.dt-autofill-list ul li{display:table-row}div.dt-autofill-list ul li:last-child div.dt-autofill-question,div.dt-autofill-list ul li:last-child div.dt-autofill-button{border-bottom:none}div.dt-autofill-list ul li:hover{background-color:#f6f6f6}div.dt-autofill-list div.dt-autofill-question{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-list div.dt-autofill-question input[type=number]{padding:6px;width:30px;margin:-2px 0}div.dt-autofill-list div.dt-autofill-button{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-list div.dt-autofill-button button{color:white;margin:0;padding:6px 12px;text-align:center;border:1px solid #2e6da4;background-color:#337ab7;border-radius:4px;cursor:pointer;vertical-align:middle}div.dt-autofill-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:10}

View File

@ -0,0 +1,85 @@
div.dt-autofill-handle {
position: absolute;
height: 8px;
width: 8px;
z-index: 102;
box-sizing: border-box;
border: 1px solid #008CBA;
background: #008CBA;
}
div.dt-autofill-select {
position: absolute;
z-index: 1001;
background-color: #008CBA;
background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);
}
div.dt-autofill-select.top, div.dt-autofill-select.bottom {
height: 3px;
margin-top: -1px;
}
div.dt-autofill-select.left, div.dt-autofill-select.right {
width: 3px;
margin-left: -1px;
}
div.dt-autofill-list {
position: fixed;
top: 50%;
left: 50%;
width: 500px;
margin-left: -250px;
background-color: white;
border-radius: 6px;
box-shadow: 0 0 5px #555;
border: 2px solid #444;
z-index: 11;
box-sizing: border-box;
padding: 1.5em 2em;
}
div.dt-autofill-list ul {
display: table;
margin: 0;
padding: 0;
list-style: none;
width: 100%;
}
div.dt-autofill-list ul li {
display: table-row;
}
div.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {
border-bottom: none;
}
div.dt-autofill-list ul li:hover {
background-color: #f6f6f6;
}
div.dt-autofill-list div.dt-autofill-question {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-list div.dt-autofill-question input[type=number] {
padding: 6px;
width: 30px;
margin: -2px 0;
}
div.dt-autofill-list div.dt-autofill-button {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
z-index: 10;
}
div.dt-autofill-list button {
margin: 0;
}

View File

@ -0,0 +1 @@
div.dt-autofill-handle{position:absolute;height:8px;width:8px;z-index:102;box-sizing:border-box;border:1px solid #008CBA;background:#008CBA}div.dt-autofill-select{position:absolute;z-index:1001;background-color:#008CBA;background-image:repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255,255,255,0.5) 5px, rgba(255,255,255,0.5) 10px)}div.dt-autofill-select.top,div.dt-autofill-select.bottom{height:3px;margin-top:-1px}div.dt-autofill-select.left,div.dt-autofill-select.right{width:3px;margin-left:-1px}div.dt-autofill-list{position:fixed;top:50%;left:50%;width:500px;margin-left:-250px;background-color:white;border-radius:6px;box-shadow:0 0 5px #555;border:2px solid #444;z-index:11;box-sizing:border-box;padding:1.5em 2em}div.dt-autofill-list ul{display:table;margin:0;padding:0;list-style:none;width:100%}div.dt-autofill-list ul li{display:table-row}div.dt-autofill-list ul li:last-child div.dt-autofill-question,div.dt-autofill-list ul li:last-child div.dt-autofill-button{border-bottom:none}div.dt-autofill-list ul li:hover{background-color:#f6f6f6}div.dt-autofill-list div.dt-autofill-question{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-list div.dt-autofill-question input[type=number]{padding:6px;width:30px;margin:-2px 0}div.dt-autofill-list div.dt-autofill-button{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:10}div.dt-autofill-list button{margin:0}

View File

@ -0,0 +1,85 @@
div.dt-autofill-handle {
position: absolute;
height: 8px;
width: 8px;
z-index: 102;
box-sizing: border-box;
border: 1px solid #316ad1;
background: linear-gradient(to bottom, #abcffb 0%, #4989de 100%);
}
div.dt-autofill-select {
position: absolute;
z-index: 1001;
background-color: #4989de;
background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);
}
div.dt-autofill-select.top, div.dt-autofill-select.bottom {
height: 3px;
margin-top: -1px;
}
div.dt-autofill-select.left, div.dt-autofill-select.right {
width: 3px;
margin-left: -1px;
}
div.dt-autofill-list {
position: fixed;
top: 50%;
left: 50%;
width: 500px;
margin-left: -250px;
background-color: white;
border-radius: 6px;
box-shadow: 0 0 5px #555;
border: 2px solid #444;
z-index: 11;
box-sizing: border-box;
padding: 1.5em 2em;
}
div.dt-autofill-list ul {
display: table;
margin: 0;
padding: 0;
list-style: none;
width: 100%;
}
div.dt-autofill-list ul li {
display: table-row;
}
div.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {
border-bottom: none;
}
div.dt-autofill-list ul li:hover {
background-color: #f6f6f6;
}
div.dt-autofill-list div.dt-autofill-question {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-list div.dt-autofill-question input[type=number] {
padding: 6px;
width: 30px;
margin: -2px 0;
}
div.dt-autofill-list div.dt-autofill-button {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
z-index: 10;
}
div.dt-autofill-list button {
padding: 0.35em 1em;
}

View File

@ -0,0 +1 @@
div.dt-autofill-handle{position:absolute;height:8px;width:8px;z-index:102;box-sizing:border-box;border:1px solid #316ad1;background:linear-gradient(to bottom, #abcffb 0%, #4989de 100%)}div.dt-autofill-select{position:absolute;z-index:1001;background-color:#4989de;background-image:repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255,255,255,0.5) 5px, rgba(255,255,255,0.5) 10px)}div.dt-autofill-select.top,div.dt-autofill-select.bottom{height:3px;margin-top:-1px}div.dt-autofill-select.left,div.dt-autofill-select.right{width:3px;margin-left:-1px}div.dt-autofill-list{position:fixed;top:50%;left:50%;width:500px;margin-left:-250px;background-color:white;border-radius:6px;box-shadow:0 0 5px #555;border:2px solid #444;z-index:11;box-sizing:border-box;padding:1.5em 2em}div.dt-autofill-list ul{display:table;margin:0;padding:0;list-style:none;width:100%}div.dt-autofill-list ul li{display:table-row}div.dt-autofill-list ul li:last-child div.dt-autofill-question,div.dt-autofill-list ul li:last-child div.dt-autofill-button{border-bottom:none}div.dt-autofill-list ul li:hover{background-color:#f6f6f6}div.dt-autofill-list div.dt-autofill-question{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-list div.dt-autofill-question input[type=number]{padding:6px;width:30px;margin:-2px 0}div.dt-autofill-list div.dt-autofill-button{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:10}div.dt-autofill-list button{padding:0.35em 1em}

View File

@ -0,0 +1,81 @@
div.dt-autofill-handle {
position: absolute;
height: 8px;
width: 8px;
z-index: 102;
box-sizing: border-box;
border: 1px solid #888;
background: #888;
}
div.dt-autofill-select {
position: absolute;
z-index: 1001;
background-color: #888;
background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);
}
div.dt-autofill-select.top, div.dt-autofill-select.bottom {
height: 3px;
margin-top: -1px;
}
div.dt-autofill-select.left, div.dt-autofill-select.right {
width: 3px;
margin-left: -1px;
}
div.dt-autofill-list {
position: fixed;
top: 50%;
left: 50%;
width: 500px;
margin-left: -250px;
background-color: white;
border-radius: 6px;
box-shadow: 0 0 5px #555;
border: 2px solid #444;
z-index: 11;
box-sizing: border-box;
padding: 1.5em 2em;
}
div.dt-autofill-list ul {
display: table;
margin: 0;
padding: 0;
list-style: none;
width: 100%;
}
div.dt-autofill-list ul li {
display: table-row;
}
div.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {
border-bottom: none;
}
div.dt-autofill-list ul li:hover {
background-color: #f6f6f6;
}
div.dt-autofill-list div.dt-autofill-question {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-list div.dt-autofill-question input[type=number] {
padding: 6px;
width: 30px;
margin: -2px 0;
}
div.dt-autofill-list div.dt-autofill-button {
display: table-cell;
padding: 0.5em 0;
border-bottom: 1px solid #ccc;
}
div.dt-autofill-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
z-index: 10;
}

View File

@ -0,0 +1 @@
div.dt-autofill-handle{position:absolute;height:8px;width:8px;z-index:102;box-sizing:border-box;border:1px solid #888;background:#888}div.dt-autofill-select{position:absolute;z-index:1001;background-color:#888;background-image:repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255,255,255,0.5) 5px, rgba(255,255,255,0.5) 10px)}div.dt-autofill-select.top,div.dt-autofill-select.bottom{height:3px;margin-top:-1px}div.dt-autofill-select.left,div.dt-autofill-select.right{width:3px;margin-left:-1px}div.dt-autofill-list{position:fixed;top:50%;left:50%;width:500px;margin-left:-250px;background-color:white;border-radius:6px;box-shadow:0 0 5px #555;border:2px solid #444;z-index:11;box-sizing:border-box;padding:1.5em 2em}div.dt-autofill-list ul{display:table;margin:0;padding:0;list-style:none;width:100%}div.dt-autofill-list ul li{display:table-row}div.dt-autofill-list ul li:last-child div.dt-autofill-question,div.dt-autofill-list ul li:last-child div.dt-autofill-button{border-bottom:none}div.dt-autofill-list ul li:hover{background-color:#f6f6f6}div.dt-autofill-list div.dt-autofill-question{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-list div.dt-autofill-question input[type=number]{padding:6px;width:30px;margin:-2px 0}div.dt-autofill-list div.dt-autofill-button{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:10}

View File

@ -0,0 +1,43 @@
/*! Bootstrap integration for DataTables' AutoFill
* ©2015 SpryMedia Ltd - datatables.net/license
*/
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
define( ['jquery', 'datatables.net-bs', 'datatables.net-autofill'], function ( $ ) {
return factory( $, window, document );
} );
}
else if ( typeof exports === 'object' ) {
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
root = window;
}
if ( ! $ || ! $.fn.dataTable ) {
$ = require('datatables.net-bs')(root, $).$;
}
if ( ! $.fn.dataTable.AutoFill ) {
require('datatables.net-autofill')(root, $);
}
return factory( $, root, root.document );
};
}
else {
// Browser
factory( jQuery, window, document );
}
}(function( $, window, document, undefined ) {
'use strict';
var DataTable = $.fn.dataTable;
DataTable.AutoFill.classes.btn = 'btn btn-primary';
return DataTable;
}));

View File

@ -0,0 +1,5 @@
/*!
Bootstrap integration for DataTables' AutoFill
©2015 SpryMedia Ltd - datatables.net/license
*/
(function(a){"function"===typeof define&&define.amd?define(["jquery","datatables.net-bs","datatables.net-autofill"],function(b){return a(b,window,document)}):"object"===typeof exports?module.exports=function(b,c){b||(b=window);if(!c||!c.fn.dataTable)c=require("datatables.net-bs")(b,c).$;c.fn.dataTable.AutoFill||require("datatables.net-autofill")(b,c);return a(c,b,b.document)}:a(jQuery,window,document)})(function(a){a=a.fn.dataTable;a.AutoFill.classes.btn="btn btn-primary";return a});

View File

@ -0,0 +1,43 @@
/*! Bootstrap integration for DataTables' AutoFill
* ©2015 SpryMedia Ltd - datatables.net/license
*/
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
define( ['jquery', 'datatables.net-bs4', 'datatables.net-autofill'], function ( $ ) {
return factory( $, window, document );
} );
}
else if ( typeof exports === 'object' ) {
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
root = window;
}
if ( ! $ || ! $.fn.dataTable ) {
$ = require('datatables.net-bs4')(root, $).$;
}
if ( ! $.fn.dataTable.AutoFill ) {
require('datatables.net-autofill')(root, $);
}
return factory( $, root, root.document );
};
}
else {
// Browser
factory( jQuery, window, document );
}
}(function( $, window, document, undefined ) {
'use strict';
var DataTable = $.fn.dataTable;
DataTable.AutoFill.classes.btn = 'btn btn-primary';
return DataTable;
}));

View File

@ -0,0 +1,5 @@
/*!
Bootstrap integration for DataTables' AutoFill
©2015 SpryMedia Ltd - datatables.net/license
*/
(function(a){"function"===typeof define&&define.amd?define(["jquery","datatables.net-bs4","datatables.net-autofill"],function(b){return a(b,window,document)}):"object"===typeof exports?module.exports=function(b,c){b||(b=window);if(!c||!c.fn.dataTable)c=require("datatables.net-bs4")(b,c).$;c.fn.dataTable.AutoFill||require("datatables.net-autofill")(b,c);return a(c,b,b.document)}:a(jQuery,window,document)})(function(a){a=a.fn.dataTable;a.AutoFill.classes.btn="btn btn-primary";return a});

View File

@ -0,0 +1,43 @@
/*! Foundation integration for DataTables' AutoFill
* ©2015 SpryMedia Ltd - datatables.net/license
*/
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
define( ['jquery', 'datatables.net-zf', 'datatables.net-autofill'], function ( $ ) {
return factory( $, window, document );
} );
}
else if ( typeof exports === 'object' ) {
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
root = window;
}
if ( ! $ || ! $.fn.dataTable ) {
$ = require('datatables.net-zf')(root, $).$;
}
if ( ! $.fn.dataTable.AutoFill ) {
require('datatables.net-autofill')(root, $);
}
return factory( $, root, root.document );
};
}
else {
// Browser
factory( jQuery, window, document );
}
}(function( $, window, document, undefined ) {
'use strict';
var DataTable = $.fn.dataTable;
DataTable.AutoFill.classes.btn = 'button tiny';
return DataTable;
}));

View File

@ -0,0 +1,5 @@
/*!
Foundation integration for DataTables' AutoFill
©2015 SpryMedia Ltd - datatables.net/license
*/
(function(a){"function"===typeof define&&define.amd?define(["jquery","datatables.net-zf","datatables.net-autofill"],function(b){return a(b,window,document)}):"object"===typeof exports?module.exports=function(b,c){b||(b=window);if(!c||!c.fn.dataTable)c=require("datatables.net-zf")(b,c).$;c.fn.dataTable.AutoFill||require("datatables.net-autofill")(b,c);return a(c,b,b.document)}:a(jQuery,window,document)})(function(a){a=a.fn.dataTable;a.AutoFill.classes.btn="button tiny";return a});

View File

@ -0,0 +1,43 @@
/*! jQuery UI integration for DataTables' AutoFill
* ©2015 SpryMedia Ltd - datatables.net/license
*/
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
define( ['jquery', 'datatables.net-jqui', 'datatables.net-autofill'], function ( $ ) {
return factory( $, window, document );
} );
}
else if ( typeof exports === 'object' ) {
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
root = window;
}
if ( ! $ || ! $.fn.dataTable ) {
$ = require('datatables.net-jqui')(root, $).$;
}
if ( ! $.fn.dataTable.AutoFill ) {
require('datatables.net-autofill')(root, $);
}
return factory( $, root, root.document );
};
}
else {
// Browser
factory( jQuery, window, document );
}
}(function( $, window, document, undefined ) {
'use strict';
var DataTable = $.fn.dataTable;
DataTable.AutoFill.classes.btn = 'ui-button ui-state-default ui-corner-all';
return DataTable;
}));

View File

@ -0,0 +1,6 @@
/*!
jQuery UI integration for DataTables' AutoFill
©2015 SpryMedia Ltd - datatables.net/license
*/
(function(a){"function"===typeof define&&define.amd?define(["jquery","datatables.net-jqui","datatables.net-autofill"],function(b){return a(b,window,document)}):"object"===typeof exports?module.exports=function(b,c){b||(b=window);if(!c||!c.fn.dataTable)c=require("datatables.net-jqui")(b,c).$;c.fn.dataTable.AutoFill||require("datatables.net-autofill")(b,c);return a(c,b,b.document)}:a(jQuery,window,document)})(function(a){a=a.fn.dataTable;a.AutoFill.classes.btn="ui-button ui-state-default ui-corner-all";
return a});

View File

@ -0,0 +1,43 @@
/*! Bootstrap integration for DataTables' AutoFill
* ©2015 SpryMedia Ltd - datatables.net/license
*/
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
define( ['jquery', 'datatables.net-se', 'datatables.net-autofill'], function ( $ ) {
return factory( $, window, document );
} );
}
else if ( typeof exports === 'object' ) {
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
root = window;
}
if ( ! $ || ! $.fn.dataTable ) {
$ = require('datatables.net-se')(root, $).$;
}
if ( ! $.fn.dataTable.AutoFill ) {
require('datatables.net-autofill')(root, $);
}
return factory( $, root, root.document );
};
}
else {
// Browser
factory( jQuery, window, document );
}
}(function( $, window, document, undefined ) {
'use strict';
var DataTable = $.fn.dataTable;
DataTable.AutoFill.classes.btn = 'ui button';
return DataTable;
}));

View File

@ -0,0 +1,5 @@
/*!
Bootstrap integration for DataTables' AutoFill
©2015 SpryMedia Ltd - datatables.net/license
*/
(function(a){"function"===typeof define&&define.amd?define(["jquery","datatables.net-se","datatables.net-autofill"],function(b){return a(b,window,document)}):"object"===typeof exports?module.exports=function(b,c){b||(b=window);if(!c||!c.fn.dataTable)c=require("datatables.net-se")(b,c).$;c.fn.dataTable.AutoFill||require("datatables.net-autofill")(b,c);return a(c,b,b.document)}:a(jQuery,window,document)})(function(a){a=a.fn.dataTable;a.AutoFill.classes.btn="ui button";return a});

View File

@ -0,0 +1,23 @@
/*!
AutoFill 2.1.3
©2008-2016 SpryMedia Ltd - datatables.net/license
*/
(function(e){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(l){return e(l,window,document)}):"object"===typeof exports?module.exports=function(l,i){l||(l=window);if(!i||!i.fn.dataTable)i=require("datatables.net")(l,i).$;return e(i,l,l.document)}:e(jQuery,window,document)})(function(e,l,i,q){var k=e.fn.dataTable,o=0,j=function(c,b){if(!k.versionCheck||!k.versionCheck("1.10.8"))throw"Warning: AutoFill requires DataTables 1.10.8 or greater";this.c=e.extend(!0,{},k.defaults.autoFill,
j.defaults,b);this.s={dt:new k.Api(c),namespace:".autoFill"+o++,scroll:{},scrollInterval:null,handle:{height:0,width:0}};this.dom={handle:e('<div class="dt-autofill-handle"/>'),select:{top:e('<div class="dt-autofill-select top"/>'),right:e('<div class="dt-autofill-select right"/>'),bottom:e('<div class="dt-autofill-select bottom"/>'),left:e('<div class="dt-autofill-select left"/>')},background:e('<div class="dt-autofill-background"/>'),list:e('<div class="dt-autofill-list">'+this.s.dt.i18n("autoFill.info",
"")+"<ul/></div>"),dtScroll:null,offsetParent:null};this._constructor()};e.extend(j.prototype,{_constructor:function(){var c=this,b=this.s.dt,a=e("div.dataTables_scrollBody",this.s.dt.table().container());a.length&&(this.dom.dtScroll=a,"static"===a.css("position")&&a.css("position","relative"));this._focusListener();this.dom.handle.on("mousedown",function(a){c._mousedown(a);return false});b.on("destroy.autoFill",function(){b.off(".autoFill");e(b.table().body()).off(c.s.namespace);e(i.body).off(c.s.namespace)})},
_attach:function(c){var b=this.s.dt,a=b.cell(c).index(),d=this.dom.handle,f=this.s.handle;if(!a||-1===b.columns(this.c.columns).indexes().indexOf(a.column))this._detach();else{this.dom.offsetParent||(this.dom.offsetParent=e(b.table().node()).offsetParent());if(!f.height||!f.width)d.appendTo("body"),f.height=d.outerHeight(),f.width=d.outerWidth();b=this._getPosition(c,this.dom.offsetParent);this.dom.attachedTo=c;d.css({top:b.top+c.offsetHeight-f.height,left:b.left+c.offsetWidth-f.width}).appendTo(this.dom.offsetParent)}},
_actionSelector:function(c){var b=this,a=this.s.dt,d=j.actions,f=[];e.each(d,function(b,d){d.available(a,c)&&f.push(b)});if(1===f.length&&!1===this.c.alwaysAsk){var h=d[f[0]].execute(a,c);this._update(h,c)}else{var g=this.dom.list.children("ul").empty();f.push("cancel");e.each(f,function(f,h){g.append(e("<li/>").append('<div class="dt-autofill-question">'+d[h].option(a,c)+"<div>").append(e('<div class="dt-autofill-button">').append(e('<button class="'+j.classes.btn+'">'+a.i18n("autoFill.button","&gt;")+
"</button>").on("click",function(){var f=d[h].execute(a,c,e(this).closest("li"));b._update(f,c);b.dom.background.remove();b.dom.list.remove()}))))});this.dom.background.appendTo("body");this.dom.list.appendTo("body");this.dom.list.css("margin-top",-1*(this.dom.list.outerHeight()/2))}},_detach:function(){this.dom.attachedTo=null;this.dom.handle.detach()},_drawSelection:function(c){var b=this.s.dt,a=this.s.start,d=e(this.dom.start),f=e(c),h={row:b.rows({page:"current"}).nodes().indexOf(f.parent()[0]),
column:f.index()},c=b.column.index("toData",h.column);if(b.cell(f).any()&&-1!==b.columns(this.c.columns).indexes().indexOf(c)){this.s.end=h;var g,b=a.row<h.row?d:f;g=a.row<h.row?f:d;c=a.column<h.column?d:f;d=a.column<h.column?f:d;b=this._getPosition(b).top;c=this._getPosition(c).left;a=this._getPosition(g).top+g.outerHeight()-b;d=this._getPosition(d).left+d.outerWidth()-c;f=this.dom.select;f.top.css({top:b,left:c,width:d});f.left.css({top:b,left:c,height:a});f.bottom.css({top:b+a,left:c,width:d});
f.right.css({top:b,left:c+d,height:a})}},_editor:function(c){var b=this.s.dt,a=this.c.editor;if(a){for(var d={},f=[],e=a.fields(),g=0,i=c.length;g<i;g++)for(var j=0,l=c[g].length;j<l;j++){var n=c[g][j],k=b.settings()[0].aoColumns[n.index.column],m=k.editField;if(m===q)for(var k=k.mData,p=0,o=e.length;p<o;p++){var r=a.field(e[p]);if(r.dataSrc()===k){m=r.name();break}}if(!m)throw"Could not automatically determine field data. Please see https://datatables.net/tn/11";d[m]||(d[m]={});k=b.row(n.index.row).id();
d[m][k]=n.set;f.push(n.index)}a.bubble(f,!1).multiSet(d).submit()}},_emitEvent:function(c,b){this.s.dt.iterator("table",function(a){e(a.nTable).triggerHandler(c+".dt",b)})},_focusListener:function(){var c=this,b=this.s.dt,a=this.s.namespace,d=null!==this.c.focus?this.c.focus:b.init().keys||b.settings()[0].keytable?"focus":"hover";if("focus"===d)b.on("key-focus.autoFill",function(a,b,d){c._attach(d.node())}).on("key-blur.autoFill",function(){c._detach()});else if("click"===d)e(b.table().body()).on("click"+
a,"td, th",function(){c._attach(this)}),e(i.body).on("click"+a,function(a){e(a.target).parents().filter(b.table().body()).length||c._detach()});else e(b.table().body()).on("mouseenter"+a,"td, th",function(){c._attach(this)}).on("mouseleave"+a,function(a){e(a.relatedTarget).hasClass("dt-autofill-handle")||c._detach()})},_getPosition:function(c,b){var a=e(c),d,f,h=0,g=0;b||(b=e(this.s.dt.table().node()).offsetParent());do{f=a.position();d=a.offsetParent();h+=f.top+d.scrollTop();g+=f.left+d.scrollLeft();
if("body"===a.get(0).nodeName.toLowerCase())break;a=d}while(d.get(0)!==b.get(0));return{top:h,left:g}},_mousedown:function(c){var b=this,a=this.s.dt;this.dom.start=this.dom.attachedTo;this.s.start={row:a.rows({page:"current"}).nodes().indexOf(e(this.dom.start).parent()[0]),column:e(this.dom.start).index()};e(i.body).on("mousemove.autoFill",function(a){b._mousemove(a)}).on("mouseup.autoFill",function(a){b._mouseup(a)});var d=this.dom.select,a=e(a.table().node()).offsetParent();d.top.appendTo(a);d.left.appendTo(a);
d.right.appendTo(a);d.bottom.appendTo(a);this._drawSelection(this.dom.start,c);this.dom.handle.css("display","none");c=this.dom.dtScroll;this.s.scroll={windowHeight:e(l).height(),windowWidth:e(l).width(),dtTop:c?c.offset().top:null,dtLeft:c?c.offset().left:null,dtHeight:c?c.outerHeight():null,dtWidth:c?c.outerWidth():null}},_mousemove:function(c){var b=c.target.nodeName.toLowerCase();"td"!==b&&"th"!==b||(this._drawSelection(c.target,c),this._shiftScroll(c))},_mouseup:function(){e(i.body).off(".autoFill");
var c=this.s.dt,b=this.dom.select;b.top.remove();b.left.remove();b.right.remove();b.bottom.remove();this.dom.handle.css("display","block");var b=this.s.start,a=this.s.end;if(!(b.row===a.row&&b.column===a.column)){for(var d=this._range(b.row,a.row),b=this._range(b.column,a.column),a=[],f=c.settings()[0],h=f.aoColumns,g=0;g<d.length;g++)a.push(e.map(b,function(a){var a=c.cell(":eq("+d[g]+")",a+":visible",{page:"current"}),b=a.data(),e=a.index(),i=h[e.column].editField;i!==q&&(b=f.oApi._fnGetObjectDataFn(i)(c.row(e.row).data()));
return{cell:a,data:b,label:a.data(),index:e}}));this._actionSelector(a);clearInterval(this.s.scrollInterval);this.s.scrollInterval=null}},_range:function(c,b){var a=[],d;if(c<=b)for(d=c;d<=b;d++)a.push(d);else for(d=c;d>=b;d--)a.push(d);return a},_shiftScroll:function(c){var b=this,a=this.s.scroll,d=!1,f=c.pageY-i.body.scrollTop,e=c.pageX-i.body.scrollLeft,g,j,k,l;65>f?g=-5:f>a.windowHeight-65&&(g=5);65>e?j=-5:e>a.windowWidth-65&&(j=5);null!==a.dtTop&&c.pageY<a.dtTop+65?k=-5:null!==a.dtTop&&c.pageY>
a.dtTop+a.dtHeight-65&&(k=5);null!==a.dtLeft&&c.pageX<a.dtLeft+65?l=-5:null!==a.dtLeft&&c.pageX>a.dtLeft+a.dtWidth-65&&(l=5);g||j||k||l?(a.windowVert=g,a.windowHoriz=j,a.dtVert=k,a.dtHoriz=l,d=!0):this.s.scrollInterval&&(clearInterval(this.s.scrollInterval),this.s.scrollInterval=null);!this.s.scrollInterval&&d&&(this.s.scrollInterval=setInterval(function(){if(a.windowVert)i.body.scrollTop=i.body.scrollTop+a.windowVert;if(a.windowHoriz)i.body.scrollLeft=i.body.scrollLeft+a.windowHoriz;if(a.dtVert||
a.dtHoriz){var c=b.dom.dtScroll[0];if(a.dtVert)c.scrollTop=c.scrollTop+a.dtVert;if(a.dtHoriz)c.scrollLeft=c.scrollLeft+a.dtHoriz}},20))},_update:function(c,b){if(!1!==c){var a=this.s.dt,d;this._emitEvent("preAutoFill",[a,b]);this._editor(b);if(null!==this.c.update?this.c.update:!this.c.editor){for(var f=0,e=b.length;f<e;f++)for(var g=0,i=b[f].length;g<i;g++)d=b[f][g],d.cell.data(d.set);a.draw(!1)}this._emitEvent("autoFill",[a,b])}}});j.actions={increment:{available:function(c,b){return e.isNumeric(b[0][0].label)},
option:function(c){return c.i18n("autoFill.increment",'Increment / decrement each cell by: <input type="number" value="1">')},execute:function(c,b,a){for(var c=1*b[0][0].data,a=1*e("input",a).val(),d=0,f=b.length;d<f;d++)for(var h=0,g=b[d].length;h<g;h++)b[d][h].set=c,c+=a}},fill:{available:function(){return!0},option:function(c,b){return c.i18n("autoFill.fill","Fill all cells with <i>"+b[0][0].label+"</i>")},execute:function(c,b){for(var a=b[0][0].data,d=0,f=b.length;d<f;d++)for(var e=0,g=b[d].length;e<
g;e++)b[d][e].set=a}},fillHorizontal:{available:function(c,b){return 1<b.length&&1<b[0].length},option:function(c){return c.i18n("autoFill.fillHorizontal","Fill cells horizontally")},execute:function(c,b){for(var a=0,d=b.length;a<d;a++)for(var e=0,h=b[a].length;e<h;e++)b[a][e].set=b[a][0].data}},fillVertical:{available:function(c,b){return 1<b.length&&1<b[0].length},option:function(c){return c.i18n("autoFill.fillVertical","Fill cells vertically")},execute:function(c,b){for(var a=0,d=b.length;a<d;a++)for(var e=
0,h=b[a].length;e<h;e++)b[a][e].set=b[0][e].data}},cancel:{available:function(){return!1},option:function(c){return c.i18n("autoFill.cancel","Cancel")},execute:function(){return!1}}};j.version="2.1.3";j.defaults={alwaysAsk:!1,focus:null,columns:"",update:null,editor:null};j.classes={btn:"btn"};e(i).on("preInit.dt.autofill",function(c,b){if("dt"===c.namespace){var a=b.oInit.autoFill,d=k.defaults.autoFill;if(a||d)d=e.extend({},a,d),!1!==a&&new j(b,d)}});k.AutoFill=j;return k.AutoFill=j});

View File

@ -0,0 +1,22 @@
MIT license
Copyright (c) 2015-2016 SpryMedia Limited
http://datatables.net
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,39 @@
# Buttons
The Buttons extension for DataTables provides a common set of options, API methods and styling to display buttons on a page that will interact with a DataTable. Modules are also provided for data export, printing and column visibility control.
# Installation
To use Buttons the primary way to obtain the software is to use the [DataTables downloader](//datatables.net/download). You can also include the individual files from the [DataTables CDN](//cdn.datatables.net). See the [documentation](http://datatables.net/extensions/buttons/) for full details.
## NPM and Bower
If you prefer to use a package manager such as NPM or Bower, distribution repositories are available with software built from this repository under the name `datatables.net-buttons`. Styling packages for Bootstrap, Foundation and other styling libraries are also available by adding a suffix to the package name.
Please see the DataTables [NPM](//datatables.net/download/npm) and [Bower](//datatables.net/download/bower) installation pages for further information. The [DataTables installation manual](//datatables.net/manual/installation) also has details on how to use package managers with DataTables.
# Basic usage
Buttons is initialised using the `buttons` option in the DataTables constructor, giving an array of the buttons that should be shown. Further options can be specified using this option as an object - see the documentation for details. For example:
```js
$(document).ready( function () {
$('#example').DataTable( {
buttons: [ 'csv', 'excel', 'pdf', 'print' ]
} );
} );
```
# Documentation / support
* [Documentation](https://datatables.net/extensions/buttons/)
* [DataTables support forums](http://datatables.net/forums)
# GitHub
If you fancy getting involved with the development of Buttons and help make it better, please refer to its [GitHub repo](https://github.com/DataTables/Buttons)

View File

@ -0,0 +1,102 @@
div.dt-button-info {
position: fixed;
top: 50%;
left: 50%;
width: 400px;
margin-top: -100px;
margin-left: -200px;
background-color: white;
border: 2px solid #111;
box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);
border-radius: 3px;
text-align: center;
z-index: 21;
}
div.dt-button-info h2 {
padding: 0.5em;
margin: 0;
font-weight: normal;
border-bottom: 1px solid #ddd;
background-color: #f3f3f3;
}
div.dt-button-info > div {
padding: 1em;
}
ul.dt-button-collection.dropdown-menu {
display: block;
z-index: 2002;
-webkit-column-gap: 8px;
-moz-column-gap: 8px;
-ms-column-gap: 8px;
-o-column-gap: 8px;
column-gap: 8px;
}
ul.dt-button-collection.dropdown-menu.fixed {
position: fixed;
top: 50%;
left: 50%;
margin-left: -75px;
border-radius: 0;
}
ul.dt-button-collection.dropdown-menu.fixed.two-column {
margin-left: -150px;
}
ul.dt-button-collection.dropdown-menu.fixed.three-column {
margin-left: -225px;
}
ul.dt-button-collection.dropdown-menu.fixed.four-column {
margin-left: -300px;
}
ul.dt-button-collection.dropdown-menu > * {
-webkit-column-break-inside: avoid;
break-inside: avoid;
}
ul.dt-button-collection.dropdown-menu.two-column {
width: 300px;
padding-bottom: 1px;
-webkit-column-count: 2;
-moz-column-count: 2;
-ms-column-count: 2;
-o-column-count: 2;
column-count: 2;
}
ul.dt-button-collection.dropdown-menu.three-column {
width: 450px;
padding-bottom: 1px;
-webkit-column-count: 3;
-moz-column-count: 3;
-ms-column-count: 3;
-o-column-count: 3;
column-count: 3;
}
ul.dt-button-collection.dropdown-menu.four-column {
width: 600px;
padding-bottom: 1px;
-webkit-column-count: 4;
-moz-column-count: 4;
-ms-column-count: 4;
-o-column-count: 4;
column-count: 4;
}
div.dt-button-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2001;
}
@media screen and (max-width: 767px) {
div.dt-buttons {
float: none;
width: 100%;
text-align: center;
margin-bottom: 0.5em;
}
div.dt-buttons a.btn {
float: none;
}
}

View File

@ -0,0 +1 @@
div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0,0,0,0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:0.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}ul.dt-button-collection.dropdown-menu{display:block;z-index:2002;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}ul.dt-button-collection.dropdown-menu.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}ul.dt-button-collection.dropdown-menu.fixed.two-column{margin-left:-150px}ul.dt-button-collection.dropdown-menu.fixed.three-column{margin-left:-225px}ul.dt-button-collection.dropdown-menu.fixed.four-column{margin-left:-300px}ul.dt-button-collection.dropdown-menu>*{-webkit-column-break-inside:avoid;break-inside:avoid}ul.dt-button-collection.dropdown-menu.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}ul.dt-button-collection.dropdown-menu.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}ul.dt-button-collection.dropdown-menu.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:2001}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:0.5em}div.dt-buttons a.btn{float:none}}

View File

@ -0,0 +1,163 @@
div.dt-button-info {
position: fixed;
top: 50%;
left: 50%;
width: 400px;
margin-top: -100px;
margin-left: -200px;
background-color: white;
border: 2px solid #111;
box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);
border-radius: 3px;
text-align: center;
z-index: 21;
}
div.dt-button-info h2 {
padding: 0.5em;
margin: 0;
font-weight: normal;
border-bottom: 1px solid #ddd;
background-color: #f3f3f3;
}
div.dt-button-info > div {
padding: 1em;
}
ul.dt-button-collection.dropdown-menu {
display: block;
z-index: 2002;
-webkit-column-gap: 8px;
-moz-column-gap: 8px;
-ms-column-gap: 8px;
-o-column-gap: 8px;
column-gap: 8px;
}
ul.dt-button-collection.dropdown-menu.fixed {
position: fixed;
top: 50%;
left: 50%;
margin-left: -75px;
border-radius: 0;
}
ul.dt-button-collection.dropdown-menu.fixed.two-column {
margin-left: -150px;
}
ul.dt-button-collection.dropdown-menu.fixed.three-column {
margin-left: -225px;
}
ul.dt-button-collection.dropdown-menu.fixed.four-column {
margin-left: -300px;
}
ul.dt-button-collection.dropdown-menu > * {
-webkit-column-break-inside: avoid;
break-inside: avoid;
}
ul.dt-button-collection.dropdown-menu.two-column {
width: 300px;
padding-bottom: 1px;
-webkit-column-count: 2;
-moz-column-count: 2;
-ms-column-count: 2;
-o-column-count: 2;
column-count: 2;
}
ul.dt-button-collection.dropdown-menu.three-column {
width: 450px;
padding-bottom: 1px;
-webkit-column-count: 3;
-moz-column-count: 3;
-ms-column-count: 3;
-o-column-count: 3;
column-count: 3;
}
ul.dt-button-collection.dropdown-menu.four-column {
width: 600px;
padding-bottom: 1px;
-webkit-column-count: 4;
-moz-column-count: 4;
-ms-column-count: 4;
-o-column-count: 4;
column-count: 4;
}
ul.dt-button-collection {
-webkit-column-gap: 8px;
-moz-column-gap: 8px;
-ms-column-gap: 8px;
-o-column-gap: 8px;
column-gap: 8px;
}
ul.dt-button-collection.fixed {
position: fixed;
top: 50%;
left: 50%;
margin-left: -75px;
border-radius: 0;
}
ul.dt-button-collection.fixed.two-column {
margin-left: -150px;
}
ul.dt-button-collection.fixed.three-column {
margin-left: -225px;
}
ul.dt-button-collection.fixed.four-column {
margin-left: -300px;
}
ul.dt-button-collection > * {
-webkit-column-break-inside: avoid;
break-inside: avoid;
}
ul.dt-button-collection.two-column {
width: 300px;
padding-bottom: 1px;
-webkit-column-count: 2;
-moz-column-count: 2;
-ms-column-count: 2;
-o-column-count: 2;
column-count: 2;
}
ul.dt-button-collection.three-column {
width: 450px;
padding-bottom: 1px;
-webkit-column-count: 3;
-moz-column-count: 3;
-ms-column-count: 3;
-o-column-count: 3;
column-count: 3;
}
ul.dt-button-collection.four-column {
width: 600px;
padding-bottom: 1px;
-webkit-column-count: 4;
-moz-column-count: 4;
-ms-column-count: 4;
-o-column-count: 4;
column-count: 4;
}
ul.dt-button-collection.fixed {
max-width: none;
}
ul.dt-button-collection.fixed:before, ul.dt-button-collection.fixed:after {
display: none;
}
div.dt-button-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999;
}
@media screen and (max-width: 767px) {
div.dt-buttons {
float: none;
width: 100%;
text-align: center;
margin-bottom: 0.5em;
}
div.dt-buttons a.btn {
float: none;
}
}

View File

@ -0,0 +1 @@
div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0,0,0,0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:0.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}ul.dt-button-collection.dropdown-menu{display:block;z-index:2002;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}ul.dt-button-collection.dropdown-menu.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}ul.dt-button-collection.dropdown-menu.fixed.two-column{margin-left:-150px}ul.dt-button-collection.dropdown-menu.fixed.three-column{margin-left:-225px}ul.dt-button-collection.dropdown-menu.fixed.four-column{margin-left:-300px}ul.dt-button-collection.dropdown-menu>*{-webkit-column-break-inside:avoid;break-inside:avoid}ul.dt-button-collection.dropdown-menu.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}ul.dt-button-collection.dropdown-menu.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}ul.dt-button-collection.dropdown-menu.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}ul.dt-button-collection{-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}ul.dt-button-collection.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}ul.dt-button-collection.fixed.two-column{margin-left:-150px}ul.dt-button-collection.fixed.three-column{margin-left:-225px}ul.dt-button-collection.fixed.four-column{margin-left:-300px}ul.dt-button-collection>*{-webkit-column-break-inside:avoid;break-inside:avoid}ul.dt-button-collection.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}ul.dt-button-collection.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}ul.dt-button-collection.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}ul.dt-button-collection.fixed{max-width:none}ul.dt-button-collection.fixed:before,ul.dt-button-collection.fixed:after{display:none}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:0.5em}div.dt-buttons a.btn{float:none}}

View File

@ -0,0 +1,298 @@
div.dt-button-info {
position: fixed;
top: 50%;
left: 50%;
width: 400px;
margin-top: -100px;
margin-left: -200px;
background-color: white;
border: 2px solid #111;
box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);
border-radius: 3px;
text-align: center;
z-index: 21;
}
div.dt-button-info h2 {
padding: 0.5em;
margin: 0;
font-weight: normal;
border-bottom: 1px solid #ddd;
background-color: #f3f3f3;
}
div.dt-button-info > div {
padding: 1em;
}
button.dt-button,
div.dt-button,
a.dt-button {
position: relative;
display: inline-block;
box-sizing: border-box;
margin-right: 0.333em;
padding: 0.5em 1em;
border: 1px solid #999;
border-radius: 2px;
cursor: pointer;
font-size: 0.88em;
color: black;
white-space: nowrap;
overflow: hidden;
background-color: #e9e9e9;
/* Fallback */
background-image: -webkit-linear-gradient(top, white 0%, #e9e9e9 100%);
/* Chrome 10+, Saf5.1+, iOS 5+ */
background-image: -moz-linear-gradient(top, white 0%, #e9e9e9 100%);
/* FF3.6 */
background-image: -ms-linear-gradient(top, white 0%, #e9e9e9 100%);
/* IE10 */
background-image: -o-linear-gradient(top, white 0%, #e9e9e9 100%);
/* Opera 11.10+ */
background-image: linear-gradient(to bottom, white 0%, #e9e9e9 100%);
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='white', EndColorStr='#e9e9e9');
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
text-decoration: none;
outline: none;
}
button.dt-button.disabled,
div.dt-button.disabled,
a.dt-button.disabled {
color: #999;
border: 1px solid #d0d0d0;
cursor: default;
background-color: #f9f9f9;
/* Fallback */
background-image: -webkit-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);
/* Chrome 10+, Saf5.1+, iOS 5+ */
background-image: -moz-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);
/* FF3.6 */
background-image: -ms-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);
/* IE10 */
background-image: -o-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);
/* Opera 11.10+ */
background-image: linear-gradient(to bottom, #ffffff 0%, #f9f9f9 100%);
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#ffffff', EndColorStr='#f9f9f9');
}
button.dt-button:active:not(.disabled), button.dt-button.active:not(.disabled),
div.dt-button:active:not(.disabled),
div.dt-button.active:not(.disabled),
a.dt-button:active:not(.disabled),
a.dt-button.active:not(.disabled) {
background-color: #e2e2e2;
/* Fallback */
background-image: -webkit-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);
/* Chrome 10+, Saf5.1+, iOS 5+ */
background-image: -moz-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);
/* FF3.6 */
background-image: -ms-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);
/* IE10 */
background-image: -o-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);
/* Opera 11.10+ */
background-image: linear-gradient(to bottom, #f3f3f3 0%, #e2e2e2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f3f3f3', EndColorStr='#e2e2e2');
box-shadow: inset 1px 1px 3px #999999;
}
button.dt-button:active:not(.disabled):hover:not(.disabled), button.dt-button.active:not(.disabled):hover:not(.disabled),
div.dt-button:active:not(.disabled):hover:not(.disabled),
div.dt-button.active:not(.disabled):hover:not(.disabled),
a.dt-button:active:not(.disabled):hover:not(.disabled),
a.dt-button.active:not(.disabled):hover:not(.disabled) {
box-shadow: inset 1px 1px 3px #999999;
background-color: #cccccc;
/* Fallback */
background-image: -webkit-linear-gradient(top, #eaeaea 0%, #cccccc 100%);
/* Chrome 10+, Saf5.1+, iOS 5+ */
background-image: -moz-linear-gradient(top, #eaeaea 0%, #cccccc 100%);
/* FF3.6 */
background-image: -ms-linear-gradient(top, #eaeaea 0%, #cccccc 100%);
/* IE10 */
background-image: -o-linear-gradient(top, #eaeaea 0%, #cccccc 100%);
/* Opera 11.10+ */
background-image: linear-gradient(to bottom, #eaeaea 0%, #cccccc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#eaeaea', EndColorStr='#cccccc');
}
button.dt-button:hover,
div.dt-button:hover,
a.dt-button:hover {
text-decoration: none;
}
button.dt-button:hover:not(.disabled),
div.dt-button:hover:not(.disabled),
a.dt-button:hover:not(.disabled) {
border: 1px solid #666;
background-color: #e0e0e0;
/* Fallback */
background-image: -webkit-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);
/* Chrome 10+, Saf5.1+, iOS 5+ */
background-image: -moz-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);
/* FF3.6 */
background-image: -ms-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);
/* IE10 */
background-image: -o-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);
/* Opera 11.10+ */
background-image: linear-gradient(to bottom, #f9f9f9 0%, #e0e0e0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f9f9f9', EndColorStr='#e0e0e0');
}
button.dt-button:focus:not(.disabled),
div.dt-button:focus:not(.disabled),
a.dt-button:focus:not(.disabled) {
border: 1px solid #426c9e;
text-shadow: 0 1px 0 #c4def1;
outline: none;
background-color: #79ace9;
/* Fallback */
background-image: -webkit-linear-gradient(top, #bddef4 0%, #79ace9 100%);
/* Chrome 10+, Saf5.1+, iOS 5+ */
background-image: -moz-linear-gradient(top, #bddef4 0%, #79ace9 100%);
/* FF3.6 */
background-image: -ms-linear-gradient(top, #bddef4 0%, #79ace9 100%);
/* IE10 */
background-image: -o-linear-gradient(top, #bddef4 0%, #79ace9 100%);
/* Opera 11.10+ */
background-image: linear-gradient(to bottom, #bddef4 0%, #79ace9 100%);
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#bddef4', EndColorStr='#79ace9');
}
.dt-button embed {
outline: none;
}
div.dt-buttons {
position: relative;
float: left;
}
div.dt-buttons.buttons-right {
float: right;
}
div.dt-button-collection {
position: absolute;
top: 0;
left: 0;
width: 150px;
margin-top: 3px;
padding: 8px 8px 4px 8px;
border: 1px solid #ccc;
border: 1px solid rgba(0, 0, 0, 0.4);
background-color: white;
overflow: hidden;
z-index: 2002;
border-radius: 5px;
box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3);
z-index: 2002;
-webkit-column-gap: 8px;
-moz-column-gap: 8px;
-ms-column-gap: 8px;
-o-column-gap: 8px;
column-gap: 8px;
}
div.dt-button-collection button.dt-button,
div.dt-button-collection div.dt-button,
div.dt-button-collection a.dt-button {
position: relative;
left: 0;
right: 0;
display: block;
float: none;
margin-bottom: 4px;
margin-right: 0;
}
div.dt-button-collection button.dt-button:active:not(.disabled), div.dt-button-collection button.dt-button.active:not(.disabled),
div.dt-button-collection div.dt-button:active:not(.disabled),
div.dt-button-collection div.dt-button.active:not(.disabled),
div.dt-button-collection a.dt-button:active:not(.disabled),
div.dt-button-collection a.dt-button.active:not(.disabled) {
background-color: #dadada;
/* Fallback */
background-image: -webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%);
/* Chrome 10+, Saf5.1+, iOS 5+ */
background-image: -moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%);
/* FF3.6 */
background-image: -ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%);
/* IE10 */
background-image: -o-linear-gradient(top, #f0f0f0 0%, #dadada 100%);
/* Opera 11.10+ */
background-image: linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f0f0f0', EndColorStr='#dadada');
box-shadow: inset 1px 1px 3px #666;
}
div.dt-button-collection.fixed {
position: fixed;
top: 50%;
left: 50%;
margin-left: -75px;
border-radius: 0;
}
div.dt-button-collection.fixed.two-column {
margin-left: -150px;
}
div.dt-button-collection.fixed.three-column {
margin-left: -225px;
}
div.dt-button-collection.fixed.four-column {
margin-left: -300px;
}
div.dt-button-collection > * {
-webkit-column-break-inside: avoid;
break-inside: avoid;
}
div.dt-button-collection.two-column {
width: 300px;
padding-bottom: 1px;
-webkit-column-count: 2;
-moz-column-count: 2;
-ms-column-count: 2;
-o-column-count: 2;
column-count: 2;
}
div.dt-button-collection.three-column {
width: 450px;
padding-bottom: 1px;
-webkit-column-count: 3;
-moz-column-count: 3;
-ms-column-count: 3;
-o-column-count: 3;
column-count: 3;
}
div.dt-button-collection.four-column {
width: 600px;
padding-bottom: 1px;
-webkit-column-count: 4;
-moz-column-count: 4;
-ms-column-count: 4;
-o-column-count: 4;
column-count: 4;
}
div.dt-button-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
/* Fallback */
background: -ms-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
/* IE10 Consumer Preview */
background: -moz-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
/* Firefox */
background: -o-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
/* Opera */
background: -webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0, 0, 0, 0.3)), color-stop(1, rgba(0, 0, 0, 0.7)));
/* Webkit (Safari/Chrome 10) */
background: -webkit-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
/* Webkit (Chrome 11+) */
background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
/* W3C Markup, IE10 Release Preview */
z-index: 2001;
}
@media screen and (max-width: 640px) {
div.dt-buttons {
float: none !important;
text-align: center;
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,129 @@
div.dt-button-info {
position: fixed;
top: 50%;
left: 50%;
width: 400px;
margin-top: -100px;
margin-left: -200px;
background-color: white;
border: 2px solid #111;
box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);
border-radius: 3px;
text-align: center;
z-index: 21;
}
div.dt-button-info h2 {
padding: 0.5em;
margin: 0;
font-weight: normal;
border-bottom: 1px solid #ddd;
background-color: #f3f3f3;
}
div.dt-button-info > div {
padding: 1em;
}
ul.dt-buttons li {
margin: 0;
}
ul.dt-buttons li.active a {
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.6);
}
ul.dt-buttons.button-group a {
margin-bottom: 0;
}
ul.dt-button-collection.f-dropdown {
-webkit-column-gap: 8px;
-moz-column-gap: 8px;
-ms-column-gap: 8px;
-o-column-gap: 8px;
column-gap: 8px;
}
ul.dt-button-collection.f-dropdown.fixed {
position: fixed;
top: 50%;
left: 50%;
margin-left: -75px;
border-radius: 0;
}
ul.dt-button-collection.f-dropdown.fixed.two-column {
margin-left: -150px;
}
ul.dt-button-collection.f-dropdown.fixed.three-column {
margin-left: -225px;
}
ul.dt-button-collection.f-dropdown.fixed.four-column {
margin-left: -300px;
}
ul.dt-button-collection.f-dropdown > * {
-webkit-column-break-inside: avoid;
break-inside: avoid;
}
ul.dt-button-collection.f-dropdown.two-column {
width: 300px;
padding-bottom: 1px;
-webkit-column-count: 2;
-moz-column-count: 2;
-ms-column-count: 2;
-o-column-count: 2;
column-count: 2;
}
ul.dt-button-collection.f-dropdown.three-column {
width: 450px;
padding-bottom: 1px;
-webkit-column-count: 3;
-moz-column-count: 3;
-ms-column-count: 3;
-o-column-count: 3;
column-count: 3;
}
ul.dt-button-collection.f-dropdown.four-column {
width: 600px;
padding-bottom: 1px;
-webkit-column-count: 4;
-moz-column-count: 4;
-ms-column-count: 4;
-o-column-count: 4;
column-count: 4;
}
ul.dt-button-collection.f-dropdown.fixed {
max-width: none;
}
ul.dt-button-collection.f-dropdown.fixed:before, ul.dt-button-collection.f-dropdown.fixed:after {
display: none;
}
div.dt-button-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 88;
}
@media screen and (max-width: 767px) {
ul.dt-buttons {
float: none;
width: 100%;
text-align: center;
margin-bottom: 0.5rem;
}
ul.dt-buttons li {
float: none;
}
}
div.button-group.stacked.dropdown-pane {
margin-top: 2px;
padding: 1px;
z-index: 89;
}
div.button-group.stacked.dropdown-pane a.button {
margin-bottom: 1px;
border-right: none;
}
div.button-group.stacked.dropdown-pane a.button:last-child {
margin-bottom: 0;
}

View File

@ -0,0 +1 @@
div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0,0,0,0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:0.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}ul.dt-buttons li{margin:0}ul.dt-buttons li.active a{box-shadow:inset 0 0 10px rgba(0,0,0,0.6)}ul.dt-buttons.button-group a{margin-bottom:0}ul.dt-button-collection.f-dropdown{-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}ul.dt-button-collection.f-dropdown.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}ul.dt-button-collection.f-dropdown.fixed.two-column{margin-left:-150px}ul.dt-button-collection.f-dropdown.fixed.three-column{margin-left:-225px}ul.dt-button-collection.f-dropdown.fixed.four-column{margin-left:-300px}ul.dt-button-collection.f-dropdown>*{-webkit-column-break-inside:avoid;break-inside:avoid}ul.dt-button-collection.f-dropdown.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}ul.dt-button-collection.f-dropdown.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}ul.dt-button-collection.f-dropdown.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}ul.dt-button-collection.f-dropdown.fixed{max-width:none}ul.dt-button-collection.f-dropdown.fixed:before,ul.dt-button-collection.f-dropdown.fixed:after{display:none}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:88}@media screen and (max-width: 767px){ul.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:0.5rem}ul.dt-buttons li{float:none}}div.button-group.stacked.dropdown-pane{margin-top:2px;padding:1px;z-index:89}div.button-group.stacked.dropdown-pane a.button{margin-bottom:1px;border-right:none}div.button-group.stacked.dropdown-pane a.button:last-child{margin-bottom:0}

View File

@ -0,0 +1,162 @@
div.dt-button-info {
position: fixed;
top: 50%;
left: 50%;
width: 400px;
margin-top: -100px;
margin-left: -200px;
background-color: white;
border: 2px solid #111;
box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);
border-radius: 3px;
text-align: center;
z-index: 21;
}
div.dt-button-info h2 {
padding: 0.5em;
margin: 0;
font-weight: normal;
border-bottom: 1px solid #ddd;
background-color: #f3f3f3;
}
div.dt-button-info > div {
padding: 1em;
}
div.dt-buttons {
position: relative;
float: left;
}
div.dt-buttons .dt-button {
margin-right: 0;
}
div.dt-buttons .dt-button span.ui-icon {
display: inline-block;
vertical-align: middle;
margin-top: -2px;
}
div.dt-buttons .dt-button:active {
outline: none;
}
div.dt-buttons .dt-button:hover > span {
background-color: rgba(0, 0, 0, 0.05);
}
div.dt-button-collection {
position: absolute;
top: 0;
left: 0;
width: 150px;
margin-top: 3px;
padding: 8px 8px 4px 8px;
border: 1px solid #ccc;
border: 1px solid rgba(0, 0, 0, 0.4);
background-color: #f3f3f3;
background-color: rgba(255, 255, 255, 0.3);
overflow: hidden;
z-index: 2002;
border-radius: 5px;
box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3);
z-index: 2002;
-webkit-column-gap: 8px;
-moz-column-gap: 8px;
-ms-column-gap: 8px;
-o-column-gap: 8px;
column-gap: 8px;
-webkit-column-gap: 0;
-moz-column-gap: 0;
-ms-column-gap: 0;
-o-column-gap: 0;
column-gap: 0;
}
div.dt-button-collection .dt-button {
position: relative;
left: 0;
right: 0;
display: block;
float: none;
margin-right: 0;
}
div.dt-button-collection .dt-button:last-child {
margin-bottom: 4px;
}
div.dt-button-collection .dt-button:hover > span {
background-color: rgba(0, 0, 0, 0.05);
}
div.dt-button-collection.fixed {
position: fixed;
top: 50%;
left: 50%;
margin-left: -75px;
border-radius: 0;
}
div.dt-button-collection.fixed.two-column {
margin-left: -150px;
}
div.dt-button-collection.fixed.three-column {
margin-left: -225px;
}
div.dt-button-collection.fixed.four-column {
margin-left: -300px;
}
div.dt-button-collection > * {
-webkit-column-break-inside: avoid;
break-inside: avoid;
}
div.dt-button-collection.two-column {
width: 300px;
padding-bottom: 1px;
-webkit-column-count: 2;
-moz-column-count: 2;
-ms-column-count: 2;
-o-column-count: 2;
column-count: 2;
}
div.dt-button-collection.three-column {
width: 450px;
padding-bottom: 1px;
-webkit-column-count: 3;
-moz-column-count: 3;
-ms-column-count: 3;
-o-column-count: 3;
column-count: 3;
}
div.dt-button-collection.four-column {
width: 600px;
padding-bottom: 1px;
-webkit-column-count: 4;
-moz-column-count: 4;
-ms-column-count: 4;
-o-column-count: 4;
column-count: 4;
}
div.dt-button-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
/* Fallback */
background: -ms-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
/* IE10 Consumer Preview */
background: -moz-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
/* Firefox */
background: -o-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
/* Opera */
background: -webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0, 0, 0, 0.3)), color-stop(1, rgba(0, 0, 0, 0.7)));
/* Webkit (Safari/Chrome 10) */
background: -webkit-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
/* Webkit (Chrome 11+) */
background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
/* W3C Markup, IE10 Release Preview */
z-index: 2001;
}
@media screen and (max-width: 640px) {
div.dt-buttons {
float: none !important;
text-align: center;
}
}

View File

@ -0,0 +1 @@
div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0,0,0,0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:0.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dt-buttons{position:relative;float:left}div.dt-buttons .dt-button{margin-right:0}div.dt-buttons .dt-button span.ui-icon{display:inline-block;vertical-align:middle;margin-top:-2px}div.dt-buttons .dt-button:active{outline:none}div.dt-buttons .dt-button:hover>span{background-color:rgba(0,0,0,0.05)}div.dt-button-collection{position:absolute;top:0;left:0;width:150px;margin-top:3px;padding:8px 8px 4px 8px;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.4);background-color:#f3f3f3;background-color:rgba(255,255,255,0.3);overflow:hidden;z-index:2002;border-radius:5px;box-shadow:3px 3px 5px rgba(0,0,0,0.3);z-index:2002;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px;-webkit-column-gap:0;-moz-column-gap:0;-ms-column-gap:0;-o-column-gap:0;column-gap:0}div.dt-button-collection .dt-button{position:relative;left:0;right:0;display:block;float:none;margin-right:0}div.dt-button-collection .dt-button:last-child{margin-bottom:4px}div.dt-button-collection .dt-button:hover>span{background-color:rgba(0,0,0,0.05)}div.dt-button-collection.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}div.dt-button-collection.fixed.two-column{margin-left:-150px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}div.dt-button-collection.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}div.dt-button-collection.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:-ms-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-moz-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-o-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0,0,0,0.3)), color-stop(1, rgba(0,0,0,0.7)));background:-webkit-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:2001}@media screen and (max-width: 640px){div.dt-buttons{float:none !important;text-align:center}}

View File

@ -0,0 +1,114 @@
@charset "UTF-8";
div.dt-button-info {
position: fixed;
top: 50%;
left: 50%;
width: 400px;
margin-top: -100px;
margin-left: -200px;
background-color: white;
border: 2px solid #111;
box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);
border-radius: 3px;
text-align: center;
z-index: 21;
}
div.dt-button-info h2 {
padding: 0.5em;
margin: 0;
font-weight: normal;
border-bottom: 1px solid #ddd;
background-color: #f3f3f3;
}
div.dt-button-info > div {
padding: 1em;
}
div.dt-button-collection {
position: absolute;
top: 0;
left: 0;
width: 150px;
margin-top: 3px !important;
z-index: 2002;
background: white;
-webkit-column-gap: 8px;
-moz-column-gap: 8px;
-ms-column-gap: 8px;
-o-column-gap: 8px;
column-gap: 8px;
}
div.dt-button-collection.fixed {
position: fixed;
top: 50%;
left: 50%;
margin-left: -75px;
border-radius: 0;
}
div.dt-button-collection.fixed.two-column {
margin-left: -150px;
}
div.dt-button-collection.fixed.three-column {
margin-left: -225px;
}
div.dt-button-collection.fixed.four-column {
margin-left: -300px;
}
div.dt-button-collection > * {
-webkit-column-break-inside: avoid;
break-inside: avoid;
}
div.dt-button-collection.two-column {
width: 300px;
padding-bottom: 1px;
-webkit-column-count: 2;
-moz-column-count: 2;
-ms-column-count: 2;
-o-column-count: 2;
column-count: 2;
}
div.dt-button-collection.three-column {
width: 450px;
padding-bottom: 1px;
-webkit-column-count: 3;
-moz-column-count: 3;
-ms-column-count: 3;
-o-column-count: 3;
column-count: 3;
}
div.dt-button-collection.four-column {
width: 600px;
padding-bottom: 1px;
-webkit-column-count: 4;
-moz-column-count: 4;
-ms-column-count: 4;
-o-column-count: 4;
column-count: 4;
}
button.buttons-collection.ui.button span:after {
display: inline-block;
content: "▾";
padding-left: 0.5em;
}
div.dt-button-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2001;
}
@media screen and (max-width: 767px) {
div.dt-buttons {
float: none;
width: 100%;
text-align: center;
margin-bottom: 0.5em;
}
div.dt-buttons a.btn {
float: none;
}
}

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