diff --git a/pom.xml b/pom.xml index 7805105d2..6b5e03f51 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ org.esupportail esup-signature - 1.12.3 + 1.13 esup-signature org.esupportail.esupsignature.EsupSignatureApplication @@ -179,6 +179,16 @@ + + org.webjars.bower + google-code-prettify + 1.0.5 + + + org.webjars + popper.js + 2.5.4 + org.webjars jquery @@ -639,9 +649,9 @@ 2.4.0 - com.github.AgNO3 + eu.agno3.jcifs jcifs-ng - 3db3e62157 + 2.1.6 org.apache.chemistry.opencmis diff --git a/src/main/java/org/esupportail/esupsignature/config/GlobalProperties.java b/src/main/java/org/esupportail/esupsignature/config/GlobalProperties.java index b8301cb37..0bffc5e46 100644 --- a/src/main/java/org/esupportail/esupsignature/config/GlobalProperties.java +++ b/src/main/java/org/esupportail/esupsignature/config/GlobalProperties.java @@ -32,6 +32,7 @@ public class GlobalProperties implements Cloneable { private String applicationEmail = "esup.signature@univ-ville.fr"; private int hoursBeforeRefreshNotif = 24; private Boolean infiniteScrolling = true; + private Boolean returnToHomeAfterSign = true; /** * Choisir le fonctionnement des délégations : * @@ -202,4 +203,12 @@ public Boolean getInfiniteScrolling() { public void setInfiniteScrolling(Boolean infiniteScrolling) { this.infiniteScrolling = infiniteScrolling; } + + public Boolean getReturnToHomeAfterSign() { + return returnToHomeAfterSign; + } + + public void setReturnToHomeAfterSign(Boolean returnToHomeAfterSign) { + this.returnToHomeAfterSign = returnToHomeAfterSign; + } } diff --git a/src/main/java/org/esupportail/esupsignature/config/WebAppConfig.java b/src/main/java/org/esupportail/esupsignature/config/WebAppConfig.java index c0e745f16..8542da9ec 100644 --- a/src/main/java/org/esupportail/esupsignature/config/WebAppConfig.java +++ b/src/main/java/org/esupportail/esupsignature/config/WebAppConfig.java @@ -91,6 +91,7 @@ public FilterRegistrationBean registerOpenEntityManagerInViewFilterBean() { registrationBean.addUrlPatterns( "/user/", "/user/*", "/admin/", "/admin/*", + "/manager/", "/manager/*", "/public/", "/public/*", "/ws/", "/ws/*" ); diff --git a/src/main/java/org/esupportail/esupsignature/config/pdf/PdfConfig.java b/src/main/java/org/esupportail/esupsignature/config/pdf/PdfConfig.java index a0659584f..270d95992 100644 --- a/src/main/java/org/esupportail/esupsignature/config/pdf/PdfConfig.java +++ b/src/main/java/org/esupportail/esupsignature/config/pdf/PdfConfig.java @@ -2,9 +2,9 @@ import org.esupportail.esupsignature.exception.EsupSignatureRuntimeException; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import javax.annotation.PostConstruct; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -25,7 +25,7 @@ public PdfProperties getPdfProperties() { return pdfProperties; } - @Bean + @PostConstruct public void setPdfColorProfileUrl() { try { Path iccPath = Path.of(PdfConfig.class.getResource("/srgb.icc").getPath()); diff --git a/src/main/java/org/esupportail/esupsignature/config/security/WebSecurityConfig.java b/src/main/java/org/esupportail/esupsignature/config/security/WebSecurityConfig.java index af397ed61..4cd260a3a 100644 --- a/src/main/java/org/esupportail/esupsignature/config/security/WebSecurityConfig.java +++ b/src/main/java/org/esupportail/esupsignature/config/security/WebSecurityConfig.java @@ -109,7 +109,6 @@ private void setAuthorizeRequests(HttpSecurity http) throws Exception { .antMatchers("/").permitAll() .antMatchers("/admin/", "/admin/**").access("hasRole('ROLE_ADMIN')") .antMatchers("/user/", "/user/**").access("hasAnyRole('ROLE_USER', 'ROLE_OTP')") - .antMatchers("/sse/", "/sse/**").access("hasAnyRole('ROLE_USER', 'ROLE_OTP')") .antMatchers("/public/", "/public/**").permitAll() .antMatchers("/h2-console/**").access("hasRole('ROLE_ADMIN')") .antMatchers("/webjars/**").permitAll(); diff --git a/src/main/java/org/esupportail/esupsignature/config/sign/SignProperties.java b/src/main/java/org/esupportail/esupsignature/config/sign/SignProperties.java index e4bc1eed2..f0b541289 100644 --- a/src/main/java/org/esupportail/esupsignature/config/sign/SignProperties.java +++ b/src/main/java/org/esupportail/esupsignature/config/sign/SignProperties.java @@ -16,6 +16,7 @@ public class SignProperties { private ASiCContainerType containerType; private SignaturePackaging signaturePackaging; private Long passwordTimeout; + private String aesKey; public SignatureForm getDefaultSignatureForm() { return defaultSignatureForm; @@ -95,4 +96,12 @@ public Long getPasswordTimeout() { public void setPasswordTimeout(Long passwordTimeout) { this.passwordTimeout = passwordTimeout; } + + public String getAesKey() { + return aesKey; + } + + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } } diff --git a/src/main/java/org/esupportail/esupsignature/dss/config/DSSBeanConfig.java b/src/main/java/org/esupportail/esupsignature/dss/config/DSSBeanConfig.java index ff8ee46aa..413bae407 100644 --- a/src/main/java/org/esupportail/esupsignature/dss/config/DSSBeanConfig.java +++ b/src/main/java/org/esupportail/esupsignature/dss/config/DSSBeanConfig.java @@ -1,30 +1,22 @@ package org.esupportail.esupsignature.dss.config; import com.zaxxer.hikari.HikariDataSource; -import eu.europa.esig.dss.DomUtils; +import eu.europa.esig.dss.alert.ExceptionOnStatusAlert; import eu.europa.esig.dss.asic.cades.signature.ASiCWithCAdESService; import eu.europa.esig.dss.asic.xades.signature.ASiCWithXAdESService; import eu.europa.esig.dss.cades.signature.CAdESService; -import eu.europa.esig.dss.jaxb.ValidatorConfigurator; -import eu.europa.esig.dss.jaxb.XmlDefinerUtils; -import eu.europa.esig.dss.model.x509.CertificateToken; +import eu.europa.esig.dss.model.DSSException; import eu.europa.esig.dss.pades.signature.PAdESService; import eu.europa.esig.dss.service.crl.JdbcCacheCRLSource; import eu.europa.esig.dss.service.crl.OnlineCRLSource; -import eu.europa.esig.dss.service.http.commons.CommonsDataLoader; -import eu.europa.esig.dss.service.http.commons.FileCacheDataLoader; -import eu.europa.esig.dss.service.http.commons.OCSPDataLoader; -import eu.europa.esig.dss.service.http.commons.TimestampDataLoader; +import eu.europa.esig.dss.service.http.commons.*; import eu.europa.esig.dss.service.http.proxy.ProxyConfig; import eu.europa.esig.dss.service.ocsp.JdbcCacheOCSPSource; import eu.europa.esig.dss.service.ocsp.OnlineOCSPSource; import eu.europa.esig.dss.service.tsp.OnlineTSPSource; -import eu.europa.esig.dss.spi.DSSUtils; import eu.europa.esig.dss.spi.client.http.DSSFileLoader; import eu.europa.esig.dss.spi.client.http.IgnoreDataLoader; import eu.europa.esig.dss.spi.tsl.TrustedListsCertificateSource; -import eu.europa.esig.dss.spi.x509.CertificateSource; -import eu.europa.esig.dss.spi.x509.CommonTrustedCertificateSource; import eu.europa.esig.dss.spi.x509.KeyStoreCertificateSource; import eu.europa.esig.dss.spi.x509.tsp.TSPSource; import eu.europa.esig.dss.tsl.alerts.LOTLAlert; @@ -37,21 +29,16 @@ import eu.europa.esig.dss.tsl.alerts.handlers.log.LogOJUrlChangeAlertHandler; import eu.europa.esig.dss.tsl.alerts.handlers.log.LogTLExpirationAlertHandler; import eu.europa.esig.dss.tsl.alerts.handlers.log.LogTLSignatureErrorAlertHandler; -import eu.europa.esig.dss.tsl.function.GrantedTrustService; import eu.europa.esig.dss.tsl.function.OfficialJournalSchemeInformationURI; import eu.europa.esig.dss.tsl.job.TLValidationJob; import eu.europa.esig.dss.tsl.source.LOTLSource; import eu.europa.esig.dss.validation.CertificateVerifier; import eu.europa.esig.dss.validation.CommonCertificateVerifier; -import eu.europa.esig.dss.ws.signature.common.RemoteDocumentSignatureServiceImpl; -import eu.europa.esig.dss.ws.signature.common.RemoteMultipleDocumentsSignatureServiceImpl; -import eu.europa.esig.dss.ws.validation.common.RemoteDocumentValidationService; import eu.europa.esig.dss.xades.signature.XAdESService; import org.apache.http.conn.ssl.TrustAllStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -60,19 +47,12 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.sql.DataSource; -import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.net.URL; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; @Configuration @EnableConfigurationProperties(DSSProperties.class) -@ConditionalOnProperty({"dss.tsp-server"}) public class DSSBeanConfig { private static final Logger logger = LoggerFactory.getLogger(DSSBeanConfig.class); @@ -96,50 +76,51 @@ public void cachedCRLSourceInitialization() throws SQLException { jdbcCacheCRLSource.initTable(); } - @PostConstruct - public void cachedOCSPSourceInitialization() throws SQLException { - JdbcCacheOCSPSource jdbcCacheOCSPSource = cachedOCSPSource(); - jdbcCacheOCSPSource.initTable(); - } - @PreDestroy public void cachedCRLSourceClean() throws SQLException { JdbcCacheCRLSource jdbcCacheCRLSource = cachedCRLSource(); jdbcCacheCRLSource.destroyTable(); } - @PreDestroy - public void cachedOCSPSourceClean() throws SQLException { - JdbcCacheOCSPSource jdbcCacheOCSPSource = cachedOCSPSource(); - jdbcCacheOCSPSource.destroyTable(); + @Bean + public TSPSource tspSource() { + OnlineTSPSource tspSource = new OnlineTSPSource(dssProperties.getTspServer()); + TimestampDataLoader timestampDataLoader = new TimestampDataLoader(); + timestampDataLoader.setTimeoutConnection(10000); + timestampDataLoader.setTrustStrategy(new TrustAllStrategy()); + if(proxyConfig != null) { + timestampDataLoader.setProxyConfig(proxyConfig); + } + tspSource.setDataLoader(timestampDataLoader); + return tspSource; } @Bean public CommonsDataLoader dataLoader() { CommonsDataLoader dataLoader = new CommonsDataLoader(); - if(proxyConfig != null) { - dataLoader.setProxyConfig(proxyConfig); - } - dataLoader.setTimeoutConnection(10000); - dataLoader.setTrustStrategy(new TrustAllStrategy()); + dataLoader.setProxyConfig(proxyConfig); + return dataLoader; + } + + @Bean + public CommonsDataLoader trustAllDataLoader() { + CommonsDataLoader dataLoader = new CommonsDataLoader(); + dataLoader.setProxyConfig(proxyConfig); + dataLoader.setTrustStrategy(TrustAllStrategy.INSTANCE); return dataLoader; } @Bean public OCSPDataLoader ocspDataLoader() { OCSPDataLoader ocspDataLoader = new OCSPDataLoader(); - if(proxyConfig != null) { - ocspDataLoader.setProxyConfig(proxyConfig); - } - ocspDataLoader.setTimeoutConnection(10000); - ocspDataLoader.setTrustStrategy(new TrustAllStrategy()); + ocspDataLoader.setProxyConfig(proxyConfig); return ocspDataLoader; } @Bean public OnlineCRLSource onlineCRLSource() { OnlineCRLSource onlineCRLSource = new OnlineCRLSource(); - onlineCRLSource.setDataLoader(dataLoader()); + onlineCRLSource.setDataLoader(trustAllDataLoader()); return onlineCRLSource; } @@ -169,25 +150,19 @@ public OnlineOCSPSource onlineOcspSource() { } @Bean - public KeyStoreCertificateSource ojContentKeyStore() throws IOException { - File keystoreFile = new File(dssProperties.getKsFilename()); - KeyStoreCertificateSource keyStoreCertificateSource = null; - if(keystoreFile.exists()) { - logger.info("delete old oj file"); - keystoreFile.delete(); - } - logger.info("creating oj file in " + keystoreFile.getAbsolutePath()); - if(keystoreFile.createNewFile()) { - keyStoreCertificateSource = new KeyStoreCertificateSource((InputStream) null, dssProperties.getKsType(), dssProperties.getKsPassword()); + public KeyStoreCertificateSource ojContentKeyStore() { + try { + return new KeyStoreCertificateSource(new ClassPathResource("keystore.p12").getFile(), "PKCS12", "dss-password"); + } catch (IOException e) { + throw new DSSException("Unable to load the file " + "keystore.p12", e); } - return keyStoreCertificateSource; } @Bean public DSSFileLoader onlineLoader() { FileCacheDataLoader onlineFileLoader = new FileCacheDataLoader(); onlineFileLoader.setCacheExpirationTime(0); - onlineFileLoader.setDataLoader(dataLoader()); + onlineFileLoader.setDataLoader(trustAllDataLoader()); onlineFileLoader.setFileCacheDirectory(tlCacheDirectory()); return onlineFileLoader; } @@ -201,16 +176,19 @@ public DSSFileLoader offlineLoader() { return offlineFileLoader; } + @Bean(name = "european-trusted-list-certificate-source") + public TrustedListsCertificateSource trustedListSource() { + return new TrustedListsCertificateSource(); + } + @Bean - public TLValidationJob job() throws IOException { + public TLValidationJob job() { TLValidationJob job = new TLValidationJob(); - LOTLSource lotlSource = europeanLOTL(); job.setTrustedListCertificateSource(trustedListSource()); - job.setListOfTrustedListSources(lotlSource); + job.setListOfTrustedListSources(europeanLOTL()); job.setOfflineDataLoader(offlineLoader()); job.setOnlineDataLoader(onlineLoader()); - job.setLOTLAlerts(Arrays.asList(ojUrlAlert(lotlSource), lotlLocationAlert(lotlSource))); - job.setTLAlerts(Arrays.asList(tlSigningAlert(), tlExpirationDetection())); + job.setDebug(false); return job; } @@ -225,66 +203,32 @@ public File tlCacheDirectory() { } @Bean(name = "european-lotl-source") - public LOTLSource europeanLOTL() throws IOException { + public LOTLSource europeanLOTL() { LOTLSource lotlSource = new LOTLSource(); lotlSource.setUrl(dssProperties.getLotlUrl()); lotlSource.setCertificateSource(ojContentKeyStore()); lotlSource.setSigningCertificatesAnnouncementPredicate(new OfficialJournalSchemeInformationURI(dssProperties.getOjUrl())); - lotlSource.setTrustServicePredicate(new GrantedTrustService()); lotlSource.setPivotSupport(true); return lotlSource; } - @Bean(name = "european-trusted-list-certificate-source") - public TrustedListsCertificateSource trustedListSource() { - return new TrustedListsCertificateSource(); - } - - @Bean - public CommonTrustedCertificateSource myTrustedCertificateSource() { - CommonTrustedCertificateSource certSource = new CommonTrustedCertificateSource(); - for(String trustedCertificatUrl : dssProperties.getTrustedCertificatUrlList()) { - logger.info("adding trusted certificat : " + trustedCertificatUrl); - try { - InputStream in = new URL(trustedCertificatUrl).openStream(); - CertificateToken certificateToken = DSSUtils.loadCertificate(in); - certSource.addCertificate(certificateToken); - } catch (IOException e) { - logger.warn("unable to add trusted certificat : " + trustedCertificatUrl, e); - } - } - return certSource; - } - @Bean public CertificateVerifier certificateVerifier() { - List trustedCertSources = new ArrayList<>(); - trustedCertSources.add(trustedListSource()); - trustedCertSources.add(myTrustedCertificateSource()); - CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(trustedCertSources, cachedCRLSource(), cachedOCSPSource(), dataLoader()); - return commonCertificateVerifier; + CommonCertificateVerifier certificateVerifier = new CommonCertificateVerifier(); + certificateVerifier.setCrlSource(cachedCRLSource()); + certificateVerifier.setOcspSource(onlineOcspSource()); + certificateVerifier.setDataLoader(dataLoader()); + certificateVerifier.setTrustedCertSources(trustedListSource()); + certificateVerifier.setAlertOnMissingRevocationData(new ExceptionOnStatusAlert()); + certificateVerifier.setCheckRevocationForUntrustedChains(false); + return certificateVerifier; } @Bean - public ClassPathResource defaultPolicy() throws IOException { - ClassPathResource classPathResource = new ClassPathResource(dssProperties.getDefaultValidationPolicy()); - if(!classPathResource.exists()) { - logger.error("Default Validation Policy doesn't exist"); - } + public ClassPathResource defaultPolicy() { return new ClassPathResource(dssProperties.getDefaultValidationPolicy()); } - @Bean - public TSPSource tspSource() { - OnlineTSPSource tspSource = new OnlineTSPSource(dssProperties.getTspServer()); - TimestampDataLoader timestampDataLoader = new TimestampDataLoader(); - if(proxyConfig != null) { - timestampDataLoader.setProxyConfig(proxyConfig); - } - tspSource.setDataLoader(timestampDataLoader); - return tspSource; - } - @Bean public CAdESService cadesService() { CAdESService service = new CAdESService(certificateVerifier()); @@ -320,42 +264,6 @@ public ASiCWithXAdESService asicWithXadesService() { return service; } - @Bean - public RemoteDocumentSignatureServiceImpl remoteSignatureService() { - RemoteDocumentSignatureServiceImpl service = new RemoteDocumentSignatureServiceImpl(); - service.setAsicWithCAdESService(asicWithCadesService()); - service.setAsicWithXAdESService(asicWithXadesService()); - service.setCadesService(cadesService()); - service.setXadesService(xadesService()); - service.setPadesService(padesService()); - return service; - } - - @Bean - public RemoteMultipleDocumentsSignatureServiceImpl remoteMultipleDocumentsSignatureService() { - RemoteMultipleDocumentsSignatureServiceImpl service = new RemoteMultipleDocumentsSignatureServiceImpl(); - service.setAsicWithCAdESService(asicWithCadesService()); - service.setAsicWithXAdESService(asicWithXadesService()); - service.setXadesService(xadesService()); - return service; - } - - @Bean - public XmlDefinerUtils xmlDefinerUtils() throws ParserConfigurationException { - XmlDefinerUtils xmlDefinerUtils = XmlDefinerUtils.getInstance(); - ValidatorConfigurator.getSecureValidatorConfigurator(); - DomUtils.enableFeature("http://xml.org/sax/features/external-general-entities"); - DomUtils.disableFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd"); - return xmlDefinerUtils; - } - - @Bean - public RemoteDocumentValidationService remoteValidationService() throws Exception { - RemoteDocumentValidationService service = new RemoteDocumentValidationService(); - service.setVerifier(certificateVerifier()); - return service; - } - public DataSource cacheDataSource() { HikariDataSource ds = new HikariDataSource(); ds.setPoolName("DSS-Hikari-Pool"); @@ -364,11 +272,6 @@ public DataSource cacheDataSource() { ds.setUsername(dssProperties.getCacheUsername()); ds.setPassword(dssProperties.getCachePassword()); ds.setAutoCommit(false); - try { - ds.getConnection(); - } catch (SQLException throwables) { - throwables.printStackTrace(); - } return ds; } @@ -396,4 +299,4 @@ public LOTLAlert lotlLocationAlert(LOTLSource source) { return new LOTLAlert(lotlLocationDetection, handler); } -} \ No newline at end of file +} diff --git a/src/main/java/org/esupportail/esupsignature/dss/config/DSSProperties.java b/src/main/java/org/esupportail/esupsignature/dss/config/DSSProperties.java index 5bf25420f..cd1b37f9b 100644 --- a/src/main/java/org/esupportail/esupsignature/dss/config/DSSProperties.java +++ b/src/main/java/org/esupportail/esupsignature/dss/config/DSSProperties.java @@ -2,8 +2,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties; -import java.util.List; - @ConfigurationProperties(prefix="dss") public class DSSProperties { @@ -22,7 +20,6 @@ public class DSSProperties { private String lotlUrl; private String lotlCountryCode; private String ojUrl; - private List trustedCertificatUrlList; public String getCacheUsername() { return cacheUsername; @@ -144,11 +141,4 @@ public void setOjUrl(String ojUrl) { this.ojUrl = ojUrl; } - public List getTrustedCertificatUrlList() { - return trustedCertificatUrlList; - } - - public void setTrustedCertificatUrlList(List trustedCertificatUrlList) { - this.trustedCertificatUrlList = trustedCertificatUrlList; - } } diff --git a/src/main/java/org/esupportail/esupsignature/dss/service/FOPService.java b/src/main/java/org/esupportail/esupsignature/dss/service/FOPService.java index 955a111e8..66a39e0c9 100644 --- a/src/main/java/org/esupportail/esupsignature/dss/service/FOPService.java +++ b/src/main/java/org/esupportail/esupsignature/dss/service/FOPService.java @@ -2,6 +2,8 @@ import eu.europa.esig.dss.DSSXmlErrorListener; import eu.europa.esig.dss.DomUtils; +import eu.europa.esig.dss.detailedreport.DetailedReportFacade; +import eu.europa.esig.dss.simplereport.SimpleReportFacade; import eu.europa.esig.dss.utils.Utils; import org.apache.fop.apps.*; import org.springframework.stereotype.Component; @@ -18,7 +20,6 @@ import java.io.File; import java.io.InputStream; import java.io.OutputStream; -import java.io.StringReader; @Component public class FOPService { @@ -53,10 +54,8 @@ public void init() throws Exception { public void generateSimpleReport(String simpleReport, OutputStream os) throws Exception { Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, os); - Result res = new SAXResult(fop.getDefaultHandler()); - Transformer transformer = templateSimpleReport.newTransformer(); - transformer.setErrorListener(new DSSXmlErrorListener()); - transformer.transform(new StreamSource(new StringReader(simpleReport)), res); + Result result = new SAXResult(fop.getDefaultHandler()); + SimpleReportFacade.newFacade().generatePdfReport(simpleReport, result); } public void generateSimpleReport(Document dom, OutputStream os) throws Exception { @@ -69,10 +68,8 @@ public void generateSimpleReport(Document dom, OutputStream os) throws Exception public void generateDetailedReport(String detailedReport, OutputStream os) throws Exception { Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, os); - Result res = new SAXResult(fop.getDefaultHandler()); - Transformer transformer = templateDetailedReport.newTransformer(); - transformer.setErrorListener(new DSSXmlErrorListener()); - transformer.transform(new StreamSource(new StringReader(detailedReport)), res); + Result result = new SAXResult(fop.getDefaultHandler()); + DetailedReportFacade.newFacade().generatePdfReport(detailedReport, result); } } diff --git a/src/main/java/org/esupportail/esupsignature/dss/service/OJService.java b/src/main/java/org/esupportail/esupsignature/dss/service/OJService.java index ac40ec31c..443cb82a7 100644 --- a/src/main/java/org/esupportail/esupsignature/dss/service/OJService.java +++ b/src/main/java/org/esupportail/esupsignature/dss/service/OJService.java @@ -6,7 +6,6 @@ import eu.europa.esig.dss.spi.tsl.TrustedListsCertificateSource; import eu.europa.esig.dss.spi.x509.CommonTrustedCertificateSource; import eu.europa.esig.dss.spi.x509.KeyStoreCertificateSource; -import eu.europa.esig.dss.utils.Utils; import org.esupportail.esupsignature.dss.config.DSSBeanConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,15 +14,13 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; @Service @ConditionalOnBean(DSSBeanConfig.class) public class OJService { - private static final Logger log = LoggerFactory.getLogger(OJService.class); + private static final Logger logger = LoggerFactory.getLogger(OJService.class); @Resource private DSSBeanConfig dssBeanConfig; @@ -39,36 +36,27 @@ public class OJService { private CommonTrustedCertificateSource myTrustedCertificateSource; public void getCertificats() { - try { - log.info("start offline refreshing oj keystore"); - dssBeanConfig.job().offlineRefresh(); - refresh(); - ojContentKeyStore.addAllCertificatesToKeyStore(trustedListsCertificateSource.getCertificates()); - ojContentKeyStore.addAllCertificatesToKeyStore(myTrustedCertificateSource.getCertificates()); - OutputStream fos = new FileOutputStream(dssBeanConfig.getDssProperties().getKsFilename()); - ojContentKeyStore.store(fos); - Utils.closeQuietly(fos); - log.info("init trusted lists OK"); - } catch(IOException e) { - log.error("Error getting certificats", e); - } + ojContentKeyStore.addAllCertificatesToKeyStore(myTrustedCertificateSource.getCertificates()); + dssBeanConfig.job().offlineRefresh(); + dssBeanConfig.job().onlineRefresh(); } public void refresh() { try { if(checkOjFreshness()) { - log.info("start online refreshing oj keystore"); + logger.info("start online refreshing oj keystore"); dssBeanConfig.job().onlineRefresh(); } else { - log.info("no online refresh needed for trusted lists"); + logger.info("no online refresh needed for trusted lists"); } } catch(IOException e) { - log.error("Error refreshing dss", e); + logger.error("Error refreshing dss", e); } } - public boolean checkOjFreshness() { + public boolean checkOjFreshness() throws IOException { TLValidationJobSummary summary = trustedListsCertificateSource.getSummary(); + if(summary == null) return true; LOTLInfo lotlInfo = summary.getLOTLInfos().get(0); return !lotlInfo.getValidationCacheInfo().isValid() || lotlInfo.getValidationCacheInfo().isRefreshNeeded() diff --git a/src/main/java/org/esupportail/esupsignature/dss/service/XSLTService.java b/src/main/java/org/esupportail/esupsignature/dss/service/XSLTService.java index f2a0134ec..cf84fd79b 100644 --- a/src/main/java/org/esupportail/esupsignature/dss/service/XSLTService.java +++ b/src/main/java/org/esupportail/esupsignature/dss/service/XSLTService.java @@ -2,17 +2,17 @@ import eu.europa.esig.dss.DSSXmlErrorListener; import eu.europa.esig.dss.DomUtils; +import eu.europa.esig.dss.diagnostic.DiagnosticDataFacade; +import eu.europa.esig.dss.diagnostic.jaxb.XmlDiagnosticData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; -import org.w3c.dom.Document; import javax.annotation.PostConstruct; import javax.xml.transform.Templates; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import java.io.*; @@ -22,6 +22,7 @@ public class XSLTService { private static final Logger logger = LoggerFactory.getLogger(XSLTService.class); + private Templates templateShortReport; private Templates templateSimpleReport; private Templates templateDetailedReport; @@ -29,6 +30,10 @@ public class XSLTService { public void init() throws TransformerConfigurationException, IOException { TransformerFactory transformerFactory = DomUtils.getSecureTransformerFactory(); + try (InputStream is = XSLTService.class.getResourceAsStream("/xslt/html/short-report-bootstrap4.xslt")) { + templateShortReport = transformerFactory.newTemplates(new StreamSource(is)); + } + try (InputStream is = XSLTService.class.getResourceAsStream("/xslt/html/simple-report-bootstrap4.xslt")) { templateSimpleReport = transformerFactory.newTemplates(new StreamSource(is)); } @@ -38,10 +43,10 @@ public void init() throws TransformerConfigurationException, IOException { } } - public String generateSimpleReport(String simpleReport) { + public String generateShortReport(String simpleReport) { Writer writer = new StringWriter(); try { - Transformer transformer = templateSimpleReport.newTransformer(); + Transformer transformer = templateShortReport.newTransformer(); transformer.setErrorListener(new DSSXmlErrorListener()); transformer.transform(new StreamSource(new StringReader(simpleReport)), new StreamResult(writer)); } catch (Exception e) { @@ -50,12 +55,12 @@ public String generateSimpleReport(String simpleReport) { return writer.toString(); } - public String generateSimpleReport(Document dom) { + public String generateSimpleReport(String simpleReport) { Writer writer = new StringWriter(); try { Transformer transformer = templateSimpleReport.newTransformer(); transformer.setErrorListener(new DSSXmlErrorListener()); - transformer.transform(new DOMSource(dom), new StreamResult(writer)); + transformer.transform(new StreamSource(new StringReader(simpleReport)), new StreamResult(writer)); } catch (Exception e) { logger.error("Error while generating simple report : " + e.getMessage(), e); } @@ -74,4 +79,15 @@ public String generateDetailedReport(String detailedReport) { return writer.toString(); } + public String generateSVG(String diagnosticDataXml) { + try (Writer writer = new StringWriter()) { + XmlDiagnosticData diagnosticData = DiagnosticDataFacade.newFacade().unmarshall(diagnosticDataXml); + DiagnosticDataFacade.newFacade().generateSVG(diagnosticData, new StreamResult(writer)); + return writer.toString(); + } catch (Exception e) { + logger.error("Error while generating the SVG : " + e.getMessage(), e); + return null; + } + } + } \ No newline at end of file diff --git a/src/main/java/org/esupportail/esupsignature/dss/tsp/MockTSPSource.java b/src/main/java/org/esupportail/esupsignature/dss/tsp/MockTSPSource.java new file mode 100644 index 000000000..68d976638 --- /dev/null +++ b/src/main/java/org/esupportail/esupsignature/dss/tsp/MockTSPSource.java @@ -0,0 +1,111 @@ +package org.esupportail.esupsignature.dss.tsp; + +import eu.europa.esig.dss.enumerations.DigestAlgorithm; +import eu.europa.esig.dss.model.DSSException; +import eu.europa.esig.dss.model.TimestampBinary; +import eu.europa.esig.dss.model.x509.CertificateToken; +import eu.europa.esig.dss.spi.DSSASN1Utils; +import eu.europa.esig.dss.spi.x509.tsp.TSPSource; +import eu.europa.esig.dss.token.KSPrivateKeyEntry; +import eu.europa.esig.dss.token.KeyStoreSignatureTokenConnection; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaCertStore; +import org.bouncycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator; +import org.bouncycastle.cms.SignerInfoGenerator; +import org.bouncycastle.cms.SignerInfoGeneratorBuilder; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.DigestCalculator; +import org.bouncycastle.operator.OperatorException; +import org.bouncycastle.operator.bc.BcDigestCalculatorProvider; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; +import org.bouncycastle.tsp.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.*; + +public class MockTSPSource implements TSPSource { + + private static final long serialVersionUID = 8863748492343274842L; + + private final Logger LOG = LoggerFactory.getLogger(MockTSPSource.class); + + private static SecureRandom random = new SecureRandom(); + + private KeyStoreSignatureTokenConnection token; + + private String alias; + + public void setToken(KeyStoreSignatureTokenConnection token) { + this.token = token; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + @Override + public TimestampBinary getTimeStampResponse(DigestAlgorithm digestAlgorithm, byte[] digest) { + if (token == null) { + throw new DSSException("KeyStore token is not defined!"); + } + try { + TimeStampRequestGenerator requestGenerator = new TimeStampRequestGenerator(); + requestGenerator.setCertReq(true); + TimeStampRequest request = requestGenerator.generate(new ASN1ObjectIdentifier(digestAlgorithm.getOid()), digest); + + KSPrivateKeyEntry ksPK = (KSPrivateKeyEntry) token.getKey(alias); + if (ksPK == null) { + throw new DSSException("Unable to initialize the MockTSPSource"); + } + + LOG.info("Timestamping with {}", ksPK.getCertificate()); + + X509CertificateHolder certificate = new X509CertificateHolder(ksPK.getCertificate().getEncoded()); + List chain = new ArrayList(); + CertificateToken[] certificateChain = ksPK.getCertificateChain(); + for (CertificateToken token : certificateChain) { + chain.add(token.getCertificate()); + } + + Set accepted = new HashSet(); + accepted.add(TSPAlgorithms.SHA1); + accepted.add(TSPAlgorithms.SHA256); + accepted.add(TSPAlgorithms.SHA512); + + AlgorithmIdentifier digestAlgorithmIdentifier = new AlgorithmIdentifier(new ASN1ObjectIdentifier(digestAlgorithm.getOid())); + AlgorithmIdentifier encryptionAlg = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption); + + DefaultCMSSignatureAlgorithmNameGenerator sigAlgoGenerator = new DefaultCMSSignatureAlgorithmNameGenerator(); + String sigAlgoName = sigAlgoGenerator.getSignatureName(digestAlgorithmIdentifier, encryptionAlg); + + ContentSigner signer = new JcaContentSignerBuilder(sigAlgoName).build(ksPK.getPrivateKey()); + + SignerInfoGenerator infoGenerator = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider()).build(signer, certificate); + DigestCalculator digestCalculator = new JcaDigestCalculatorProviderBuilder().build().get(digestAlgorithmIdentifier); + + TimeStampTokenGenerator tokenGenerator = new TimeStampTokenGenerator(infoGenerator, digestCalculator, new ASN1ObjectIdentifier("1.2.3.4")); + tokenGenerator.addCertificates(new JcaCertStore(chain)); + + TimeStampResponseGenerator responseGenerator = new TimeStampResponseGenerator(tokenGenerator, accepted); + TimeStampResponse response = responseGenerator.generate(request, new BigInteger(128, random), new Date()); + TimeStampToken timeStampToken = response.getTimeStampToken(); + + return new TimestampBinary(DSSASN1Utils.getDEREncoded(timeStampToken)); + + } catch (IOException | TSPException | OperatorException | CertificateException e) { + throw new DSSException("Unable to generate a timestamp from the Mock", e); + + } + } + +} diff --git a/src/main/java/org/esupportail/esupsignature/entity/Certificat.java b/src/main/java/org/esupportail/esupsignature/entity/Certificat.java new file mode 100644 index 000000000..00c10a549 --- /dev/null +++ b/src/main/java/org/esupportail/esupsignature/entity/Certificat.java @@ -0,0 +1,71 @@ +package org.esupportail.esupsignature.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@Entity +@Table(name = "certificat") +public class Certificat { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @JsonIgnore + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, orphanRemoval = true) + private Document keystore = new Document(); + + private String password; + + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(pattern = "dd/MM/yyyy HH:mm") + private Date expireDate; + + @ElementCollection(targetClass=String.class) + private List roles = new ArrayList<>(); + + public void setId(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public Document getKeystore() { + return keystore; + } + + public void setKeystore(Document keystore) { + this.keystore = keystore; + } + + public String getPassword() { + return password; + } + + public Date getExpireDate() { + return expireDate; + } + + public void setExpireDate(Date expireDate) { + this.expireDate = expireDate; + } + + public void setPassword(String password) { + this.password = password; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } +} diff --git a/src/main/java/org/esupportail/esupsignature/entity/Form.java b/src/main/java/org/esupportail/esupsignature/entity/Form.java index 209905e2a..b23d95890 100644 --- a/src/main/java/org/esupportail/esupsignature/entity/Form.java +++ b/src/main/java/org/esupportail/esupsignature/entity/Form.java @@ -49,6 +49,8 @@ public class Form { private Boolean activeVersion = false; + private Boolean deleted = false; + @JsonIgnore @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) private Document document = new Document(); @@ -172,6 +174,14 @@ public void setActiveVersion(Boolean activeVersion) { this.activeVersion = activeVersion; } + public Boolean getDeleted() { + return deleted; + } + + public void setDeleted(Boolean deleted) { + this.deleted = deleted; + } + public Document getDocument() { return document; } diff --git a/src/main/java/org/esupportail/esupsignature/entity/User.java b/src/main/java/org/esupportail/esupsignature/entity/User.java index 3a6e30efb..26e32a066 100644 --- a/src/main/java/org/esupportail/esupsignature/entity/User.java +++ b/src/main/java/org/esupportail/esupsignature/entity/User.java @@ -32,6 +32,9 @@ public class User { @Column(unique=true) private String email; + @ElementCollection(targetClass=String.class) + private List managersRoles = new ArrayList<>(); + @ElementCollection @JsonIgnore private Map uiParams = new LinkedHashMap<>(); @@ -137,6 +140,14 @@ public void setEmail(String email) { this.email = email; } + public List getManagersRoles() { + return managersRoles; + } + + public void setManagersRoles(List managersRoles) { + this.managersRoles = managersRoles; + } + public Map getUiParams() { return uiParams; } diff --git a/src/main/java/org/esupportail/esupsignature/entity/Workflow.java b/src/main/java/org/esupportail/esupsignature/entity/Workflow.java index 48f378970..1638455c8 100644 --- a/src/main/java/org/esupportail/esupsignature/entity/Workflow.java +++ b/src/main/java/org/esupportail/esupsignature/entity/Workflow.java @@ -67,6 +67,8 @@ public class Workflow { private Boolean fromCode; + private Boolean visibility = false; + public Long getId() { return id; } @@ -242,4 +244,15 @@ public Boolean getFromCode() { public void setFromCode(Boolean fromCode) { this.fromCode = fromCode; } + + public Boolean getVisibility() { + if (this.visibility == null) { + return false; + } + return visibility; + } + + public void setVisibility(Boolean hidden) { + this.visibility = hidden; + } } diff --git a/src/main/java/org/esupportail/esupsignature/repository/CertificatRepository.java b/src/main/java/org/esupportail/esupsignature/repository/CertificatRepository.java new file mode 100644 index 000000000..a67954548 --- /dev/null +++ b/src/main/java/org/esupportail/esupsignature/repository/CertificatRepository.java @@ -0,0 +1,10 @@ +package org.esupportail.esupsignature.repository; + +import org.esupportail.esupsignature.entity.Certificat; +import org.springframework.data.repository.CrudRepository; + +import java.util.List; + +public interface CertificatRepository extends CrudRepository { + List findByRolesIn(List roles); +} diff --git a/src/main/java/org/esupportail/esupsignature/repository/FormRepository.java b/src/main/java/org/esupportail/esupsignature/repository/FormRepository.java index 03e4d746c..484f54dc3 100644 --- a/src/main/java/org/esupportail/esupsignature/repository/FormRepository.java +++ b/src/main/java/org/esupportail/esupsignature/repository/FormRepository.java @@ -8,12 +8,14 @@ import java.util.List; public interface FormRepository extends CrudRepository { - List findFormByNameAndActiveVersion(String name, Boolean activeVersion); - @Query("select distinct f from Form f join f.managers m where m = :email") - List findFormByManagersContains(@Param("email") String email); - List findDistinctByAuthorizedShareTypesIsNotNull(); - List findFormByName(String name); - @Query("select distinct f from Form f where f.activeVersion = true and (f.publicUsage = true or :role member of f.roles) order by f.name") + List findFormByDeletedIsNullOrDeletedIsFalse(); + List findFormByNameAndActiveVersionAndDeletedIsNullOrDeletedIsFalse(String name, Boolean activeVersion); + @Query("select distinct f from Form f join f.managers m where m = :email and (f.deleted is null or f.deleted = false)") + List findFormByManagersContainsAndDeletedIsNullOrDeletedIsFalse(@Param("email") String email); + List findDistinctByAuthorizedShareTypesIsNotNullAndDeletedIsNullOrDeletedIsFalse(); + List findFormByNameAndDeletedIsNullOrDeletedIsFalse(String name); + @Query("select distinct f from Form f where (f.deleted is null or f.deleted = false) and f.activeVersion = true and (f.publicUsage = true or :role member of f.roles) order by f.name") List findAuthorizedForms(String role); + List findByRolesInAndDeletedIsNullOrDeletedIsFalse(List role); } diff --git a/src/main/java/org/esupportail/esupsignature/repository/UserRepository.java b/src/main/java/org/esupportail/esupsignature/repository/UserRepository.java index 8f3b01448..c83f8d7ff 100644 --- a/src/main/java/org/esupportail/esupsignature/repository/UserRepository.java +++ b/src/main/java/org/esupportail/esupsignature/repository/UserRepository.java @@ -14,6 +14,7 @@ public interface UserRepository extends CrudRepository { List findByEmailStartingWith(String email); @Query(value = "select distinct roles from user_roles", nativeQuery = true) List getAllRoles(); + List findByManagersRolesIn(List role); Long countByEppn(String eppn); Long countByEmail(String email); } diff --git a/src/main/java/org/esupportail/esupsignature/repository/WorkflowRepository.java b/src/main/java/org/esupportail/esupsignature/repository/WorkflowRepository.java index 4509212d3..5244bc1fa 100644 --- a/src/main/java/org/esupportail/esupsignature/repository/WorkflowRepository.java +++ b/src/main/java/org/esupportail/esupsignature/repository/WorkflowRepository.java @@ -1,6 +1,7 @@ package org.esupportail.esupsignature.repository; import org.esupportail.esupsignature.entity.Workflow; +import org.hibernate.jdbc.Work; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; @@ -15,8 +16,9 @@ public interface WorkflowRepository extends CrudRepository { @Query("select w from Workflow w join w.managers m where m = :email") List findByManagersContains(@Param("email") String email); List findDistinctByAuthorizedShareTypesIsNotNull(); + List findByRolesIn(List roles); Long countByName(String name); Long countByNameAndCreateByEppn(String name, String userEppn); - @Query("select distinct w from Workflow w where w.publicUsage = true or :role member of w.roles order by w.name") + @Query("select distinct w from Workflow w where w.publicUsage = true or (w.visibility = true and :role member of w.roles) order by w.name") List findAuthorizedForms(String role); } diff --git a/src/main/java/org/esupportail/esupsignature/service/CertificatService.java b/src/main/java/org/esupportail/esupsignature/service/CertificatService.java new file mode 100644 index 000000000..d9c1509b9 --- /dev/null +++ b/src/main/java/org/esupportail/esupsignature/service/CertificatService.java @@ -0,0 +1,110 @@ +package org.esupportail.esupsignature.service; + +import eu.europa.esig.dss.model.x509.CertificateToken; +import eu.europa.esig.dss.token.Pkcs12SignatureToken; +import org.esupportail.esupsignature.config.sign.SignProperties; +import org.esupportail.esupsignature.entity.Certificat; +import org.esupportail.esupsignature.entity.User; +import org.esupportail.esupsignature.exception.EsupSignatureKeystoreException; +import org.esupportail.esupsignature.repository.CertificatRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.Key; +import java.util.*; + +@Service +public class CertificatService { + + private static final Logger logger = LoggerFactory.getLogger(CertificatService.class); + + @Resource + private UserService userService; + + @Resource + private UserKeystoreService userKeystoreService; + + @Resource + private CertificatRepository certificatRepository; + + @Resource + private DocumentService documentService; + + @Resource + private SignProperties signProperties; + + + public Certificat getById(Long id) { + return certificatRepository.findById(id).get(); + } + + public Certificat getCertificatByRole(String role) { + return certificatRepository.findByRolesIn(Collections.singletonList(role)).get(0); + } + + public List getCertificatByUser(String userEppn) { + User user = userService.getUserByEppn(userEppn); + Set certificats = new HashSet<>(certificatRepository.findByRolesIn(user.getRoles())); + return new ArrayList<>(certificats); + } + + public List getAllCertificats() { + List certificats = new ArrayList<>(); + certificatRepository.findAll().forEach(certificats::add); + return certificats; + } + + @Transactional + public void addCertificat(MultipartFile keystore, List roles, String password) throws IOException, EsupSignatureKeystoreException { + Certificat certificat = new Certificat(); + byte[] keystoreBytes = keystore.getBytes(); + Pkcs12SignatureToken pkcs12SignatureToken = userKeystoreService.getPkcs12Token(new ByteArrayInputStream(keystoreBytes), password); + CertificateToken certificateToken = userKeystoreService.getCertificateToken(pkcs12SignatureToken); + certificat.setKeystore(documentService.createDocument(new ByteArrayInputStream(keystoreBytes), certificateToken.getSubject().getPrincipal().getName("CANONICAL"), keystore.getContentType())); + certificat.setRoles(roles); + certificat.setPassword(encryptPassword(password)); + certificat.setExpireDate(certificateToken.getNotAfter()); + certificatRepository.save(certificat); + } + + @Transactional + public void delete(Long id) { + Certificat certificat = getById(id); + certificatRepository.delete(certificat); + } + + public String encryptPassword(String password) { + try { + Key aesKey = new SecretKeySpec(signProperties.getAesKey().getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, aesKey); + String charSet = "UTF-8"; + byte[] encrypted = cipher.doFinal(password.getBytes(charSet)); + return new String(Base64.getEncoder().encode(encrypted)); + } catch (Exception e) { + logger.error(e.getMessage()); + } + return null; + } + + public String decryptPassword(String key) { + try { + Key aesKey = new SecretKeySpec(signProperties.getAesKey().getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.DECRYPT_MODE, aesKey); + return new String(cipher.doFinal(Base64.getDecoder().decode(key))); + } catch (Exception e) { + logger.error(e.getMessage()); + } + return null; + } + +} diff --git a/src/main/java/org/esupportail/esupsignature/service/FormService.java b/src/main/java/org/esupportail/esupsignature/service/FormService.java index bb69830be..5bde810e3 100644 --- a/src/main/java/org/esupportail/esupsignature/service/FormService.java +++ b/src/main/java/org/esupportail/esupsignature/service/FormService.java @@ -83,7 +83,7 @@ public List getFormsByUser(String userEppn, String authUserEppn){ } else { List userShares = userShareService.getUserShares(userEppn, Collections.singletonList(authUserEppn), ShareType.create); for(UserShare userShare : userShares) { - if(userShare.getForm() != null){ + if(userShare.getForm() != null && !userShare.getForm().getDeleted()){ forms.add(userShare.getForm()); } } @@ -107,12 +107,12 @@ public Boolean isFormAuthorized(String userEppn, String authUserEppn, Long id) { public List getAllForms(){ List list = new ArrayList<>(); - formRepository.findAll().forEach(e -> list.add(e)); + formRepository.findFormByDeletedIsNullOrDeletedIsFalse().forEach(e -> list.add(e)); return list; } public List getAuthorizedToShareForms() { - return formRepository.findDistinctByAuthorizedShareTypesIsNotNull(); + return formRepository.findDistinctByAuthorizedShareTypesIsNotNullAndDeletedIsNullOrDeletedIsFalse(); } @Transactional @@ -134,6 +134,7 @@ public void updateForm(Long id, Form updateForm, List managers, String[] form.setPublicUsage(updateForm.getPublicUsage()); form.setAction(updateForm.getAction()); form.getAuthorizedShareTypes().clear(); + form.setActiveVersion(updateForm.getActiveVersion()); List shareTypes = new ArrayList<>(); if(types != null) { for (String type : types) { @@ -175,21 +176,25 @@ public void updateFormModel(Long id, MultipartFile multipartModel) throws EsupSi @Transactional public void deleteForm(Long formId) { Form form = formRepository.findById(formId).get(); - List userShares = userShareService.getUserSharesByForm(form); - for(UserShare userShare : userShares) { - userShareService.delete(userShare); - } - dataService.nullifyForm(form); - List fieldToDelete = form.getFields().stream().map(Field::getId).collect(Collectors.toList()); - form.getFields().clear(); - for(Long fieldId : fieldToDelete) { - List fieldProperties = fieldPropertieService.getFieldPropertie(fieldId); - for(FieldPropertie fieldPropertie : fieldProperties) { - fieldPropertieService.delete(fieldPropertie.getId()); + if(form.getDeleted() != null && form.getDeleted()) { + List userShares = userShareService.getUserSharesByForm(form); + for (UserShare userShare : userShares) { + userShareService.delete(userShare); } - fieldService.deleteField(fieldId); + dataService.nullifyForm(form); + List fieldToDelete = form.getFields().stream().map(Field::getId).collect(Collectors.toList()); + form.getFields().clear(); + for (Long fieldId : fieldToDelete) { + List fieldProperties = fieldPropertieService.getFieldPropertie(fieldId); + for (FieldPropertie fieldPropertie : fieldProperties) { + fieldPropertieService.delete(fieldPropertie.getId()); + } + fieldService.deleteField(fieldId); + } + formRepository.delete(form); + } else { + form.setDeleted(true); } - formRepository.delete(form); } private Map getPageNumberByAnnotDict(PDDocumentCatalog docCatalog) throws IOException { @@ -208,7 +213,7 @@ private Map getPageNumberByAnnotDict(PDDocumentCatalog d @Transactional public Form createForm(Document document, String name, String title, Workflow workflow, String prefillType, List roleNames, Boolean publicUsage, String... fieldNames) throws IOException, EsupSignatureException { - List testForms = formRepository.findFormByNameAndActiveVersion(name, true); + List testForms = formRepository.findFormByNameAndActiveVersionAndDeletedIsNullOrDeletedIsFalse(name, true); Form form = new Form(); form.setName(name); form.setTitle(title); @@ -386,17 +391,17 @@ private void computeActions(Field field, String actionsString) { } public List getFormByNameAndActiveVersion(String name, boolean activeVersion) { - return formRepository.findFormByNameAndActiveVersion(name, activeVersion); + return formRepository.findFormByNameAndActiveVersionAndDeletedIsNullOrDeletedIsFalse(name, activeVersion); } public List getFormByName(String name) { - return formRepository.findFormByName(name); + return formRepository.findFormByNameAndDeletedIsNullOrDeletedIsFalse(name); } public List getFormByManagersContains(String eppn) { User user = userService.getUserByEppn(eppn); - return formRepository.findFormByManagersContains(user.getEmail()); + return formRepository.findFormByManagersContainsAndDeletedIsNullOrDeletedIsFalse(user.getEmail()); } @Transactional @@ -425,4 +430,8 @@ public Map getModel(Long id) throws SQLException, IOException { } return null; } + + public List getByRoles(String role) { + return formRepository.findByRolesInAndDeletedIsNullOrDeletedIsFalse(Collections.singletonList(role)); + } } diff --git a/src/main/java/org/esupportail/esupsignature/service/SignBookService.java b/src/main/java/org/esupportail/esupsignature/service/SignBookService.java index 85fb7ee01..91af91d3f 100644 --- a/src/main/java/org/esupportail/esupsignature/service/SignBookService.java +++ b/src/main/java/org/esupportail/esupsignature/service/SignBookService.java @@ -8,10 +8,9 @@ import org.esupportail.esupsignature.service.interfaces.workflow.DefaultWorkflow; import org.esupportail.esupsignature.service.security.otp.OtpService; import org.esupportail.esupsignature.service.utils.WebUtilsService; -import org.esupportail.esupsignature.service.utils.mail.MailService; +import org.esupportail.esupsignature.service.mail.MailService; import org.esupportail.esupsignature.service.utils.sign.SignService; import org.esupportail.esupsignature.web.ws.json.JsonExternalUserInfo; -import org.esupportail.esupsignature.web.ws.json.JsonMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -382,9 +381,9 @@ public void pendingSignBook(SignBook signBook, Data data, String userEppn, Strin } } for (Recipient recipient : signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getRecipients()) { - if(!signRequest.getCreateBy().getEppn().equals(userEppn)) { - eventService.publishEvent(new JsonMessage("info", "Vous avez une nouvelle demande", null), "user", eventService.getClientIdByEppn(recipient.getUser().getEppn())); - } +// if(!signRequest.getCreateBy().getEppn().equals(userEppn)) { +// eventService.publishEvent(new JsonMessage("info", "Vous avez une nouvelle demande", null), "user", eventService.getClientIdByEppn(recipient.getUser().getEppn())); +// } if(recipient.getUser().getUserType().equals(UserType.external)) { try { otpService.generateOtpForSignRequest(signRequest.getId(), recipient.getUser()); diff --git a/src/main/java/org/esupportail/esupsignature/service/SignRequestService.java b/src/main/java/org/esupportail/esupsignature/service/SignRequestService.java index 7218f0edd..910180b52 100644 --- a/src/main/java/org/esupportail/esupsignature/service/SignRequestService.java +++ b/src/main/java/org/esupportail/esupsignature/service/SignRequestService.java @@ -1,6 +1,5 @@ package org.esupportail.esupsignature.service; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import eu.europa.esig.dss.AbstractSignatureParameters; import eu.europa.esig.dss.asic.cades.ASiCWithCAdESSignatureParameters; @@ -30,7 +29,7 @@ import org.esupportail.esupsignature.service.interfaces.prefill.PreFillService; import org.esupportail.esupsignature.service.security.otp.OtpService; import org.esupportail.esupsignature.service.utils.file.FileService; -import org.esupportail.esupsignature.service.utils.mail.MailService; +import org.esupportail.esupsignature.service.mail.MailService; import org.esupportail.esupsignature.service.utils.metric.CustomMetricsService; import org.esupportail.esupsignature.service.utils.pdf.PdfService; import org.esupportail.esupsignature.service.utils.sign.SignService; @@ -51,8 +50,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.support.TransactionSynchronization; -import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.mvc.support.RedirectAttributes; @@ -154,6 +151,9 @@ public class SignRequestService { @Resource private SignRequestParamsService signRequestParamsService; + @Resource + private CertificatService certificatService; + @Resource private ReportService reportService; @@ -369,7 +369,7 @@ public void pendingSignRequest(SignRequest signRequest, String authUserEppn) { } @Transactional - public boolean initSign(Long signRequestId, String sseId, String signRequestParamsJsonString, String comment, String formData, Boolean visual, String password, Long userShareId, String userEppn, String authUserEppn) { + public boolean initSign(Long signRequestId, String signRequestParamsJsonString, String comment, String formData, Boolean visual, String password, String certType, Long userShareId, String userEppn, String authUserEppn) throws EsupSignatureMailException, IOException, InterruptedException, EsupSignatureException { SignRequest signRequest = getSignRequestsFullById(signRequestId, userEppn, authUserEppn); Map formDataMap = null; List toRemoveKeys = new ArrayList<>(); @@ -394,48 +394,34 @@ public boolean initSign(Long signRequestId, String sseId, String signRequestPara toRemoveKeys.add(entry.getKey()); } } + for (String toRemoveKey : toRemoveKeys) { + formDataMap.remove(toRemoveKey); + } + } else { +// formDataMap.clear(); } } catch (IOException e) { logger.error("form datas error", e); } } - for (String toRemoveKey : toRemoveKeys) { - formDataMap.remove(toRemoveKey); + List signRequestParamses; + if (signRequestParamsJsonString == null) { + signRequestParamses = signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignRequestParams(); + } else { + signRequestParamses = signRequestParamsService.getSignRequestParamsFromJson(signRequestParamsJsonString); } - try { - List signRequestParamses; - if (signRequestParamsJsonString == null) { - signRequestParamses = signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignRequestParams(); - } else { - signRequestParamses = signRequestParamsService.getSignRequestParamsFromJson(signRequestParamsJsonString); - } - if (signRequest.getCurrentSignType().equals(SignType.nexuSign)) { - signRequestParamsService.copySignRequestParams(signRequest, signRequestParamses); - eventService.publishEvent(new JsonMessage("initNexu", "Démarrage de l'application NexU", null), "sign", sseId); - return true; - } - eventService.publishEvent(new JsonMessage("step", "Démarrage de la signature", null), "sign", sseId); - User user = userService.getByEppn(userEppn); - User authUser = userService.getByEppn(authUserEppn); - sign(signRequest, password, visual, signRequestParamses, formDataMap, sseId, user, authUser, userShareId, comment); - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { - public void afterCommit() { - eventService.publishEvent(new JsonMessage("end", "Signature terminée", null), "sign", sseId); - } - }); - return true; - } catch (EsupSignatureKeystoreException e) { - logger.error(e.getMessage()); - return true; - } catch (Exception e) { - logger.error(e.getMessage()); - return false; + if (signRequest.getCurrentSignType().equals(SignType.nexuSign)) { + signRequestParamsService.copySignRequestParams(signRequest, signRequestParamses); + throw new EsupSignatureException("initNexu"); } + User user = userService.getByEppn(userEppn); + User authUser = userService.getByEppn(authUserEppn); + sign(signRequest, password, certType, visual, signRequestParamses, formDataMap, user, authUser, userShareId, comment); + return true; } @Transactional - public void initMassSign(String userEppn, String authUserEppn, String ids, HttpSession httpSession, String sseId, String password) throws JsonProcessingException, InterruptedException { - eventService.publishEvent(new JsonMessage("", "Démarrage de la signature en masse", null), "massSign", sseId); + public void initMassSign(String userEppn, String authUserEppn, String ids, HttpSession httpSession, String password, String certType) throws IOException, InterruptedException, EsupSignatureMailException, EsupSignatureException { List idsString = objectMapper.readValue(ids, List.class); List idsLong = new ArrayList<>(); idsString.forEach(s -> idsLong.add(Long.parseLong(s))); @@ -447,7 +433,6 @@ public void initMassSign(String userEppn, String authUserEppn, String ids, HttpS } for (Long id : idsLong) { SignRequest signRequest = getById(id); - eventService.publishEvent(new JsonMessage("nextSign", "Document : " + signRequest.getTitle(), null), "massSign", sseId); String error = ""; if (!signRequest.getStatus().equals(SignRequestStatus.pending)) { reportService.addSignRequestToReport(report.getId(), signRequest, ReportStatus.badStatus); @@ -460,7 +445,7 @@ public void initMassSign(String userEppn, String authUserEppn, String ids, HttpS reportService.addSignRequestToReport(report.getId(), signRequest, ReportStatus.noSignField); error = messageSource.getMessage("report.reportstatus." + ReportStatus.noSignField, null, Locale.FRENCH); } - else if (signRequest.getStatus().equals(SignRequestStatus.pending) && initSign(id, sseId, null, null, null, true, password, userShareId, userEppn, authUserEppn)) { + else if (signRequest.getStatus().equals(SignRequestStatus.pending) && initSign(id,null, null, null, true, password, certType, userShareId, userEppn, authUserEppn)) { reportService.addSignRequestToReport(report.getId(), signRequest, ReportStatus.signed); error = null; } @@ -468,15 +453,12 @@ else if (signRequest.getStatus().equals(SignRequestStatus.pending) && initSign(i reportService.addSignRequestToReport(report.getId(), signRequest, ReportStatus.error); } if(error != null) { - eventService.publishEvent(new JsonMessage("nextError", error, null), "massSign", sseId); } else { - eventService.publishEvent(new JsonMessage("nextSuccess", "Succès", null), "massSign", sseId); } } - eventService.publishEvent(new JsonMessage("end", "Signatures terminées", null), "massSign", sseId); } - public void sign(SignRequest signRequest, String password, boolean visual, List signRequestParamses, Map formDataMap, String sseId, User user, User authUser, Long userShareId, String comment) throws EsupSignatureException, IOException, InterruptedException, EsupSignatureMailException { + public void sign(SignRequest signRequest, String password, String certType, boolean visual, List signRequestParamses, Map formDataMap, User user, User authUser, Long userShareId, String comment) throws EsupSignatureException, IOException, InterruptedException, EsupSignatureMailException { User signerUser = user; if(userShareId != null) { UserShare userShare = userShareService.getById(userShareId); @@ -501,8 +483,8 @@ public void sign(SignRequest signRequest, String password, boolean visual, List< } } } - if(formDataMap != null && formDataMap.size() > 0 && toSignDocuments.get(0).getContentType().equals("application/pdf")) { - eventService.publishEvent(new JsonMessage("step", "Remplissage du document", null), "sign", sseId); + byte[] bytes = toSignDocuments.get(0).getInputStream().readAllBytes(); + if(formDataMap != null && formDataMap.size() > 0 && toSignDocuments.get(0).getContentType().equals("application/pdf") && validationService.validate(new ByteArrayInputStream(bytes), null).getSimpleReport().getSignatureIdList().size() == 0) { filledInputStream = pdfService.fill(toSignDocuments.get(0).getInputStream(), formDataMap); } else { filledInputStream = toSignDocuments.get(0).getInputStream(); @@ -514,7 +496,6 @@ public void sign(SignRequest signRequest, String password, boolean visual, List< List lastSignLogs = new ArrayList<>(); if (toSignDocuments.size() == 1 && toSignDocuments.get(0).getContentType().equals("application/pdf") && visual) { - eventService.publishEvent(new JsonMessage("step", "Apposition de la signature", null), "sign", sseId); for(SignRequestParams signRequestParams : signRequestParamses) { signedInputStream = pdfService.stampImage(signedInputStream, signRequest, signRequestParams, signerUser); lastSignLogs.add(updateStatus(signRequest, signRequest.getStatus(), "Apposition de la signature", "SUCCESS", signRequestParams.getSignPageNumber(), signRequestParams.getxPos(), signRequestParams.getyPos(), signRequest.getParentSignBook().getLiveWorkflow().getCurrentStepNumber(), user.getEppn(), authUser.getEppn())); @@ -529,9 +510,9 @@ public void sign(SignRequest signRequest, String password, boolean visual, List< if (toSignDocuments.size() == 1 && toSignDocuments.get(0).getContentType().equals("application/pdf")) { signRequestParamsService.copySignRequestParams(signRequest, signRequestParamses); toSignDocuments.get(0).setTransientInputStream(filledInputStream); + visual = true; } - certSign(signRequest, signerUser, password, visual, sseId, "sign"); - eventService.publishEvent(new JsonMessage("step", "Paramétrage de la prochaine étape", null), "sign", sseId); + certSign(signRequest, signerUser, password, certType, visual); applyEndOfSignRules(signRequest, user.getEppn(), authUser.getEppn(), SignType.certSign, comment); } customMetricsService.incValue("esup-signature.signrequests", "signed"); @@ -595,24 +576,26 @@ public void sign(SignRequest signRequest, String password, boolean visual, List< // // } - public void certSign(SignRequest signRequest, User user, String password, boolean visual, String sseId, String channel) throws EsupSignatureException, InterruptedException { + public void certSign(SignRequest signRequest, User user, String password, String certType, boolean visual) throws EsupSignatureException, InterruptedException { SignatureForm signatureForm; List toSignDocuments = new ArrayList<>(); for(Document document : getToSignDocuments(signRequest.getId())) { toSignDocuments.add(document); } - eventService.publishEvent(new JsonMessage("step", "Initialisation de la procédure", null), channel, sseId); Pkcs12SignatureToken pkcs12SignatureToken = null; try { - eventService.publishEvent(new JsonMessage("step", "Déverouillage du keystore", null), channel, sseId); - pkcs12SignatureToken = userKeystoreService.getPkcs12Token(user.getKeystore().getInputStream(), password); + if(user.getKeystore() != null && certType.equals("profil")) { + pkcs12SignatureToken = userKeystoreService.getPkcs12Token(user.getKeystore().getInputStream(), password); + } else { + Certificat certificat = certificatService.getCertificatByUser(user.getEppn()).get(0); + pkcs12SignatureToken = userKeystoreService.getPkcs12Token(certificat.getKeystore().getInputStream(), certificatService.decryptPassword(certificat.getPassword())); + + } CertificateToken certificateToken = userKeystoreService.getCertificateToken(pkcs12SignatureToken); CertificateToken[] certificateTokenChain = userKeystoreService.getCertificateTokenChain(pkcs12SignatureToken); - eventService.publishEvent(new JsonMessage("step", "Formatage des documents", null), channel, sseId); AbstractSignatureForm signatureDocumentForm = signService.getSignatureDocumentForm(toSignDocuments, signRequest, visual); signatureForm = signatureDocumentForm.getSignatureForm(); signatureDocumentForm.setEncryptionAlgorithm(EncryptionAlgorithm.RSA); - eventService.publishEvent(new JsonMessage("step", "Préparation de la signature", null), channel, sseId); signatureDocumentForm.setBase64Certificate(Base64.encodeBase64String(certificateToken.getEncoded())); List base64CertificateChain = new ArrayList<>(); for (CertificateToken token : certificateTokenChain) { @@ -633,12 +616,6 @@ public void certSign(SignRequest signRequest, User user, String password, boolea } else { parameters = signService.fillVisibleParameters((SignatureDocumentForm) signatureDocumentForm, signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignRequestParams().get(0), new ByteArrayInputStream(((SignatureDocumentForm) signatureDocumentForm).getDocumentToSign()), new Color(214, 0, 128), user); } - - if(signatureForm.equals(SignatureForm.PAdES)) { - eventService.publishEvent(new JsonMessage("step", "Signature du document", null), channel, sseId); - } else { - eventService.publishEvent(new JsonMessage("step", "Signature des documents", null), channel, sseId); - } parameters.setSigningCertificate(certificateToken); parameters.setCertificateChain(certificateTokenChain); parameters.setSignatureLevel(signatureDocumentForm.getSignatureLevel()); @@ -650,15 +627,11 @@ public void certSign(SignRequest signRequest, User user, String password, boolea dssDocument = signService.certSignDocument((SignatureDocumentForm) signatureDocumentForm, parameters, pkcs12SignatureToken); } pkcs12SignatureToken.close(); -// InMemoryDocument signedPdfDocument = new InMemoryDocument(DSSUtils.toByteArray(dssDocument), dssDocument.getName(), dssDocument.getMimeType()); - eventService.publishEvent(new JsonMessage("step", "Enregistrement du/des documents(s)", null), channel, sseId); documentService.addSignedFile(signRequest, dssDocument.openStream(), fileService.getNameOnly(signRequest.getTitle()) + "." + fileService.getExtension(dssDocument.getName()), Files.probeContentType(Path.of(dssDocument.getName()))); } catch (EsupSignatureKeystoreException e) { - eventService.publishEvent(new JsonMessage("sign_system_error", "Mauvais mot de passe", null), channel, sseId); if(pkcs12SignatureToken != null) pkcs12SignatureToken.close(); throw new EsupSignatureKeystoreException(e.getMessage(), e); } catch (Exception e) { - eventService.publishEvent(new JsonMessage("sign_system_error", e.getMessage(), null), channel, sseId); if(pkcs12SignatureToken != null) pkcs12SignatureToken.close(); throw new EsupSignatureException(e.getMessage(), e); } @@ -932,7 +905,7 @@ public boolean checkUserViewRights(SignRequest signRequest, String userEppn, Str List signRequests = signRequestRepository.findByIdAndRecipient(signRequest.getId(), userEppn); Data data = dataService.getBySignBook(signRequest.getParentSignBook()); User authUser = userService.getUserByEppn(authUserEppn); - if((data != null && data.getForm().getManagers().contains(authUser.getEmail())) ||signRequest.getCreateBy().getEppn().equals(userEppn) || signRequest.getParentSignBook().getViewers().contains(userService.getUserByEppn(authUserEppn)) || signRequests.size() > 0) { + if((data != null && (data.getForm() != null && data.getForm().getManagers().contains(authUser.getEmail()))) ||signRequest.getCreateBy().getEppn().equals(userEppn) || signRequest.getParentSignBook().getViewers().contains(userService.getUserByEppn(authUserEppn)) || signRequests.size() > 0) { return true; } } @@ -956,13 +929,17 @@ public long generateUniqueId() { public void delete(Long signRequestId, String userEppn) { //TODO critères de suppression ou en conf (if deleteDefinitive) SignRequest signRequest = getById(signRequestId); - signRequest.getOriginalDocuments().clear(); - if(signRequest.getStatus().equals(SignRequestStatus.exported) || signRequest.getStatus().equals(SignRequestStatus.archived)) { - signRequest.getSignedDocuments().clear(); + if(signRequest.getStatus().equals(SignRequestStatus.deleted)) { + deleteDefinitive(signRequestId); + } else { + signRequest.getOriginalDocuments().clear(); + if (signRequest.getStatus().equals(SignRequestStatus.exported) || signRequest.getStatus().equals(SignRequestStatus.archived)) { + signRequest.getSignedDocuments().clear(); + } + signRequest.setStatus(SignRequestStatus.deleted); + logService.create(signRequest, SignRequestStatus.deleted, "DELETE", "", "SUCCESS", null, null, null, null, userEppn, userEppn); + otpService.deleteOtpBySignRequestId(signRequestId); } - signRequest.setStatus(SignRequestStatus.deleted); - logService.create(signRequest, SignRequestStatus.deleted, "DELETE", "", "SUCCESS", null, null, null, null, userEppn, userEppn); - otpService.deleteOtpBySignRequestId(signRequestId); } @Transactional @@ -1270,7 +1247,10 @@ public List getSignImagesForSignRequest(SignRequest signRequestRef, Stri } } if (user.getSignImages().size() > 0 && user.getSignImages().get(0) != null && user.getSignImages().get(0).getSize() > 0) { - if (checkUserSignRights(signRequest, userEppn, authUserEppn) && user.getKeystore() == null && signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignType().equals(SignType.certSign)) { + if (checkUserSignRights(signRequest, userEppn, authUserEppn) + && user.getKeystore() == null + && certificatService.getCertificatByUser(userEppn).size() == 0 + && signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignType().equals(SignType.certSign)) { signRequestRef.setSignable(false); throw new EsupSignatureUserException("Pour signer ce document merci d’ajouter un certificat à votre profil Mes paramètres"); } @@ -1278,7 +1258,7 @@ public List getSignImagesForSignRequest(SignRequest signRequestRef, Stri signImages.add(fileService.getBase64Image(signImage)); } } else { - if (signRequest.getSignable() && signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignType() != null && (signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignType().equals(SignType.pdfImageStamp) || signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignType().equals(SignType.certSign))) { + if (signRequest.getSignable() && signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignType() != null && signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignType().equals(SignType.pdfImageStamp)) { signRequestRef.setSignable(false); throw new EsupSignatureUserException("Pour signer ce document merci d'ajouter une image de votre signature dans Mes paramètres"); @@ -1304,7 +1284,7 @@ public AbstractMap.SimpleEntry, List> checkUserResponse(SignReq return new AbstractMap.SimpleEntry<>(usersHasRefused, usersHasSigned); } - public Long getNbByCreateAndStatus(String userEppn) { + public Long getNbPendingSignRequests(String userEppn) { return signRequestRepository.countByCreateByEppnAndStatus(userEppn, SignRequestStatus.pending); } @@ -1418,7 +1398,9 @@ public void replayNotif(Long id) throws EsupSignatureMailException { SignRequest signRequest = this.getById(id); List recipientEmails = new ArrayList<>(); signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getRecipients().stream().filter(r -> !r.getSigned()).collect(Collectors.toList()).forEach(r -> recipientEmails.add(r.getUser().getEmail())); - mailService.sendSignRequestAlert(recipientEmails, signRequest); + if(recipientEmails.size() > 0) { + mailService.sendSignRequestAlert(recipientEmails, signRequest); + } } public SignRequest getSignRequestByComment(Comment comment) { @@ -1438,6 +1420,16 @@ public static Predicate distinctByKey(Function super T, Object> keyExtr return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; } + @Transactional + public SignRequestParams getToUseSignRequestParams(long id) { + SignRequest signRequest = getById(id); + int index = signRequest.getParentSignBook().getSignRequests().indexOf(signRequest); + if(signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignRequestParams().size() > index) { + return signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignRequestParams().get(index); + } + return null; + } + @Transactional public File getToValidateFile(long id) throws IOException { SignRequest signRequest = getById(id); diff --git a/src/main/java/org/esupportail/esupsignature/service/UserKeystoreService.java b/src/main/java/org/esupportail/esupsignature/service/UserKeystoreService.java index 96e3df418..372df21f4 100644 --- a/src/main/java/org/esupportail/esupsignature/service/UserKeystoreService.java +++ b/src/main/java/org/esupportail/esupsignature/service/UserKeystoreService.java @@ -10,6 +10,7 @@ import org.esupportail.esupsignature.exception.EsupSignatureKeystoreException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -27,7 +28,7 @@ public class UserKeystoreService { private static final Logger logger = LoggerFactory.getLogger(UserKeystoreService.class); - @Resource + @Autowired private CertificateVerifier certificateVerifier; @Resource @@ -43,7 +44,7 @@ public Pkcs12SignatureToken getPkcs12Token(InputStream keyStoreFile, String pass } else { logger.error("open keystore fail :" + e.getMessage()); } - throw new EsupSignatureKeystoreException("open keystore fail", e); + throw new EsupSignatureKeystoreException("Mot de passe incorrect", e); } } @@ -66,7 +67,11 @@ public CertificateToken[] getCertificateTokenChain(Pkcs12SignatureToken token) { @Transactional public String checkKeystore(String authUserEppn, String password) throws EsupSignatureKeystoreException { User authUser = userService.getByEppn(authUserEppn); - InputStream keyStoreFile = authUser.getKeystore().getInputStream(); + return checkKeystore(authUser.getKeystore().getInputStream(), password); + } + + @Transactional + public String checkKeystore(InputStream keyStoreFile, String password) throws EsupSignatureKeystoreException { String certInfo = ""; Pkcs12SignatureToken pkcs12SignatureToken = getPkcs12Token(keyStoreFile, password); CertificateToken certificateToken = getCertificateToken(pkcs12SignatureToken); diff --git a/src/main/java/org/esupportail/esupsignature/service/UserService.java b/src/main/java/org/esupportail/esupsignature/service/UserService.java index 93b1b4d48..d259fe940 100644 --- a/src/main/java/org/esupportail/esupsignature/service/UserService.java +++ b/src/main/java/org/esupportail/esupsignature/service/UserService.java @@ -506,7 +506,18 @@ public List getJsonExternalUserInfos(List emails, return externalUsersInfos; } + @Transactional + public void updateRoles(String userEppn, List roles) { + User user = getUserByEppn(userEppn); + user.getRoles().clear(); + user.getRoles().addAll(roles); + } + public List getAllRoles() { return userRepository.getAllRoles(); } + + public List getByManagersRoles(String role) { + return userRepository.findByManagersRolesIn(Collections.singletonList(role)); + } } diff --git a/src/main/java/org/esupportail/esupsignature/service/ValidationService.java b/src/main/java/org/esupportail/esupsignature/service/ValidationService.java index e6303ac66..a6854827b 100644 --- a/src/main/java/org/esupportail/esupsignature/service/ValidationService.java +++ b/src/main/java/org/esupportail/esupsignature/service/ValidationService.java @@ -1,5 +1,6 @@ package org.esupportail.esupsignature.service; +import eu.europa.esig.dss.enumerations.TokenExtractionStrategy; import eu.europa.esig.dss.model.DSSDocument; import eu.europa.esig.dss.model.DSSException; import eu.europa.esig.dss.validation.CertificateVerifier; @@ -9,10 +10,13 @@ import org.esupportail.esupsignature.dss.DssUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -25,12 +29,21 @@ public class ValidationService { private static final Logger logger = LoggerFactory.getLogger(ValidationService.class); - @Resource + @Autowired private CertificateVerifier certificateVerifier; + @Resource + private SignRequestService signRequestService; + @Resource private org.springframework.core.io.Resource defaultPolicy; + @Transactional + public Reports validate(long signRequestId) throws IOException { + byte[] bytes = signRequestService.getToSignDocuments(signRequestId).get(0).getInputStream().readAllBytes(); + return validate(new ByteArrayInputStream(bytes), null); + } + public Reports validate(InputStream docInputStream, InputStream signInputStream) { try { List detachedContents = new ArrayList<>(); @@ -38,20 +51,18 @@ public Reports validate(InputStream docInputStream, InputStream signInputStream) if(signInputStream != null && signInputStream.available() > 0) { detachedContents.add(DssUtils.toDSSDocument(docInputStream)); documentValidator = SignedDocumentValidator.fromDocument(DssUtils.toDSSDocument(signInputStream)); + documentValidator.setDetachedContents(detachedContents); } else { documentValidator = SignedDocumentValidator.fromDocument(DssUtils.toDSSDocument(docInputStream)); } logger.info("validate with : " + documentValidator.getClass()); documentValidator.setCertificateVerifier(certificateVerifier); + documentValidator.setTokenExtractionStrategy(TokenExtractionStrategy.NONE); documentValidator.setLocale(Locale.FRENCH); - documentValidator.setValidationLevel(ValidationLevel.BASIC_SIGNATURES); - documentValidator.setDetachedContents(detachedContents); + documentValidator.setValidationLevel(ValidationLevel.LONG_TERM_DATA); Reports reports = null; try (InputStream is = defaultPolicy.getInputStream()) { - reports = documentValidator.validateDocument(); - for(String id : reports.getSimpleReport().getSignatureIdList()) { - reports.getSimpleReport().getErrors(id).remove("Unable to build a certificate chain until a trusted list!"); - } + reports = documentValidator.validateDocument(is); } catch (IOException e) { logger.error("Unable to parse policy : " + e.getMessage(), e); } diff --git a/src/main/java/org/esupportail/esupsignature/service/WorkflowService.java b/src/main/java/org/esupportail/esupsignature/service/WorkflowService.java index 0c92e8203..f72434fd7 100644 --- a/src/main/java/org/esupportail/esupsignature/service/WorkflowService.java +++ b/src/main/java/org/esupportail/esupsignature/service/WorkflowService.java @@ -425,7 +425,6 @@ public Workflow computeWorkflow(Long workflowId, List recipientEmails, S } } - @Transactional public List getFavoriteRecipientEmail(int stepNumber, List recipientEmails) { List users = new ArrayList<>(); if (recipientEmails != null && recipientEmails.size() > 0) { @@ -454,7 +453,7 @@ public void replaceStepSystemUsers(String userEppn, Long workflowStepId) { } } - public boolean delete(Workflow workflow) { + public void delete(Workflow workflow) throws EsupSignatureException { List signBooks = signBookService.getSignBooksByWorkflow(workflow); if(signBooks.stream().allMatch(signBook -> signBook.getStatus() == SignRequestStatus.draft || signBook.getStatus() == SignRequestStatus.deleted)) { List liveWorkflows = liveWorkflowService.getByWorkflow(workflow); @@ -463,9 +462,9 @@ public boolean delete(Workflow workflow) { liveWorkflow.getLiveWorkflowSteps().forEach(lws -> lws.setWorkflowStep(null)); } workflowRepository.delete(workflow); - return true; + } else { + throw new EsupSignatureException("Le circuit ne peut pas être supprimé car il est en court d'utilisation"); } - return false; } public List getWorkflowsByDisplayWorkflowType(DisplayWorkflowType displayWorkflowType) { @@ -556,5 +555,19 @@ public void deleteTarget(Long id, Long targetId) { workflow.getTargets().remove(target); targetService.delete(target); } + + public List getWorkflowsByRoles(String role) { + return workflowRepository.findByRolesIn(Collections.singletonList(role)); + } + + public Set getManagerWorkflows(String userEppn) { + User manager = userService.getByEppn(userEppn); + Set workflowsManaged = new HashSet<>(); + for (String role : manager.getManagersRoles()) { + workflowsManaged.addAll(this.getWorkflowsByRoles(role)); + } + workflowsManaged.addAll(this.getWorkflowsByUser(manager.getEppn(), manager.getEppn())); + return workflowsManaged; + } } diff --git a/src/main/java/org/esupportail/esupsignature/service/dss/DSSService.java b/src/main/java/org/esupportail/esupsignature/service/dss/DSSService.java index d9a71dd7f..e53cd1c03 100644 --- a/src/main/java/org/esupportail/esupsignature/service/dss/DSSService.java +++ b/src/main/java/org/esupportail/esupsignature/service/dss/DSSService.java @@ -21,7 +21,6 @@ public class DSSService { @Qualifier("european-trusted-list-certificate-source") private TrustedListsCertificateSource trustedListsCertificateSource; - @Resource @Qualifier("european-lotl-source") private LOTLSource lotlSource; diff --git a/src/main/java/org/esupportail/esupsignature/service/event/EventService.java b/src/main/java/org/esupportail/esupsignature/service/event/EventService.java index 0c3491b98..fdd85623e 100644 --- a/src/main/java/org/esupportail/esupsignature/service/event/EventService.java +++ b/src/main/java/org/esupportail/esupsignature/service/event/EventService.java @@ -30,7 +30,7 @@ public String getClientIdByEppn(String eppn) { return sseClientIds.get(eppn.split("@")[0]); } - public void publishEvent(JsonMessage jsonMessage, String channel, String id) { + private void publishEvent(JsonMessage jsonMessage, String channel, String id) { ObjectMapper mapper = new ObjectMapper(); String jsonMessageString= ""; try { diff --git a/src/main/java/org/esupportail/esupsignature/service/interfaces/fs/smb/SmbAccessImpl.java b/src/main/java/org/esupportail/esupsignature/service/interfaces/fs/smb/SmbAccessImpl.java index bf24238f3..90fad4aa4 100644 --- a/src/main/java/org/esupportail/esupsignature/service/interfaces/fs/smb/SmbAccessImpl.java +++ b/src/main/java/org/esupportail/esupsignature/service/interfaces/fs/smb/SmbAccessImpl.java @@ -140,10 +140,10 @@ public SmbFile cd(String path) { } @NotNull - private SmbFile getSmbFileFromPath(String path) throws URISyntaxException, MalformedURLException { + private SmbFile getSmbFileFromPath(String path) throws URISyntaxException, MalformedURLException, UnsupportedEncodingException { SmbFile smbFile; int pos = path.lastIndexOf('/') + 1; - String path2 = path.substring(0, pos) + URLEncoder.encode(path.substring(pos)); + String path2 = path.substring(0, pos) + URLEncoder.encode(path.substring(pos), "UTF-8"); URI uri = new URI(path2); // URI uri = new URI(path.replace(" ", "%20")); diff --git a/src/main/java/org/esupportail/esupsignature/service/ldap/LdapPersonService.java b/src/main/java/org/esupportail/esupsignature/service/ldap/LdapPersonService.java index fd7bcc292..7d8c62db5 100644 --- a/src/main/java/org/esupportail/esupsignature/service/ldap/LdapPersonService.java +++ b/src/main/java/org/esupportail/esupsignature/service/ldap/LdapPersonService.java @@ -41,7 +41,7 @@ public PersonLdapRepository getPersonLdapRepository() { } public List getPersonLdap(String authName) { - String formattedFilter = MessageFormat.format(ldapProperties.getUserIdSearchFilter(), new String[] { authName }); + String formattedFilter = MessageFormat.format(ldapProperties.getUserIdSearchFilter(), (Object[]) new String[] { authName }); return ldapTemplate.search(ldapProperties.getSearchBase(), formattedFilter, new PersonLdapAttributesMapper()); } diff --git a/src/main/java/org/esupportail/esupsignature/service/utils/mail/MailService.java b/src/main/java/org/esupportail/esupsignature/service/mail/MailService.java similarity index 99% rename from src/main/java/org/esupportail/esupsignature/service/utils/mail/MailService.java rename to src/main/java/org/esupportail/esupsignature/service/mail/MailService.java index 37475ec20..69c837e4d 100644 --- a/src/main/java/org/esupportail/esupsignature/service/utils/mail/MailService.java +++ b/src/main/java/org/esupportail/esupsignature/service/mail/MailService.java @@ -1,4 +1,4 @@ -package org.esupportail.esupsignature.service.utils.mail; +package org.esupportail.esupsignature.service.mail; import org.esupportail.esupsignature.config.GlobalProperties; import org.esupportail.esupsignature.config.mail.MailConfig; diff --git a/src/main/java/org/esupportail/esupsignature/service/security/PreAuthorizeService.java b/src/main/java/org/esupportail/esupsignature/service/security/PreAuthorizeService.java index 1a32d0e80..0d24c4354 100644 --- a/src/main/java/org/esupportail/esupsignature/service/security/PreAuthorizeService.java +++ b/src/main/java/org/esupportail/esupsignature/service/security/PreAuthorizeService.java @@ -1,11 +1,13 @@ package org.esupportail.esupsignature.service.security; +import org.apache.commons.collections.CollectionUtils; import org.esupportail.esupsignature.entity.*; import org.esupportail.esupsignature.service.*; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.util.Collections; @Service @Transactional @@ -87,4 +89,20 @@ public boolean workflowOwner(Long id, String userEppn) { return userEppn.equals(workflow.getCreateBy().getEppn()) || workflow.getCreateBy().equals(userService.getSystemUser()); } + public boolean workflowManager(Long id, String userEppn) { + Workflow workflow = workflowService.getById(id); + User manager = userService.getByEppn(userEppn); + return workflow.getCreateBy().getEppn().equals(manager.getEppn()) || CollectionUtils.containsAny(manager.getManagersRoles(), workflow.getRoles()); + } + + public boolean formManager(Long id, String userEppn) { + Form form = formService.getById(id); + User manager = userService.getByEppn(userEppn); + return CollectionUtils.containsAny(manager.getManagersRoles(), form.getRoles()); + } + + public boolean roleManager(String role, String userEppn) { + User manager = userService.getByEppn(userEppn); + return manager.getManagersRoles().contains(role); + } } diff --git a/src/main/java/org/esupportail/esupsignature/service/security/SessionService.java b/src/main/java/org/esupportail/esupsignature/service/security/SessionService.java new file mode 100644 index 000000000..f8eef480c --- /dev/null +++ b/src/main/java/org/esupportail/esupsignature/service/security/SessionService.java @@ -0,0 +1,23 @@ +package org.esupportail.esupsignature.service.security; + +import org.springframework.session.Session; +import org.springframework.session.SessionRepository; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +@Service +public class SessionService { + + @Resource + private SessionRepository sessionRepository; + + public Session getSessionById(String id) { + return sessionRepository.findById(id); + } + + public void deleteSessionById(String id) { + sessionRepository.deleteById(id); + } + +} diff --git a/src/main/java/org/esupportail/esupsignature/service/security/cas/CasAuthenticationSuccessHandler.java b/src/main/java/org/esupportail/esupsignature/service/security/cas/CasAuthenticationSuccessHandler.java index ff044dad2..8810b3e46 100644 --- a/src/main/java/org/esupportail/esupsignature/service/security/cas/CasAuthenticationSuccessHandler.java +++ b/src/main/java/org/esupportail/esupsignature/service/security/cas/CasAuthenticationSuccessHandler.java @@ -28,7 +28,7 @@ public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpS httpServletRequest.getSession().setAttribute("securityServiceName", "CasSecurityServiceImpl"); DefaultSavedRequest defaultSavedRequest = (DefaultSavedRequest) httpServletRequest.getSession().getAttribute("SPRING_SECURITY_SAVED_REQUEST"); String queryString = defaultSavedRequest.getQueryString(); - if(queryString.split("=")[0].equals("redirect")) { + if(queryString != null && queryString.split("=")[0].equals("redirect")) { this.redirectStrategy.sendRedirect(httpServletRequest, httpServletResponse, queryString.split("=")[1]); } else { this.redirectStrategy.sendRedirect(httpServletRequest, httpServletResponse, "/"); diff --git a/src/main/java/org/esupportail/esupsignature/service/security/otp/OtpService.java b/src/main/java/org/esupportail/esupsignature/service/security/otp/OtpService.java index 0e8575074..d503ac951 100644 --- a/src/main/java/org/esupportail/esupsignature/service/security/otp/OtpService.java +++ b/src/main/java/org/esupportail/esupsignature/service/security/otp/OtpService.java @@ -10,7 +10,7 @@ import org.esupportail.esupsignature.entity.User; import org.esupportail.esupsignature.exception.EsupSignatureMailException; import org.esupportail.esupsignature.service.SignRequestService; -import org.esupportail.esupsignature.service.utils.mail.MailService; +import org.esupportail.esupsignature.service.mail.MailService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; diff --git a/src/main/java/org/esupportail/esupsignature/service/utils/pdf/PdfService.java b/src/main/java/org/esupportail/esupsignature/service/utils/pdf/PdfService.java index a36f6dc85..ad2d57d3e 100644 --- a/src/main/java/org/esupportail/esupsignature/service/utils/pdf/PdfService.java +++ b/src/main/java/org/esupportail/esupsignature/service/utils/pdf/PdfService.java @@ -93,25 +93,25 @@ public InputStream stampImage(InputStream inputStream, SignRequest signRequest, Date newDate = new Date(); DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss", Locale.FRENCH); InputStream signImage; - if ( signType.equals(SignType.visa) || signType.equals(SignType.hiddenVisa) ) { - File fileSignImage = fileService.getEmptyImage(); - signImage = fileService.addTextToImage(new FileInputStream(fileSignImage), signRequestParams, signType); - File fileWithWatermark = fileService.getTempFile("sign_with_mark.png"); - fileService.addImageWatermark(PdfService.class.getResourceAsStream("/static/images/watermark.png"), signImage, fileWithWatermark, new Color(137, 137, 137)); - signImage = new FileInputStream(fileWithWatermark); - } else if (signRequestParams.getAddExtra()) { - signImage = fileService.addTextToImage(user.getSignImages().get(signRequestParams.getSignImageNumber()).getInputStream(), signRequestParams, signType); - if(signRequestParams.getAddWatermark()) { + if(signRequestParams.getSignImageNumber() < 0) { + signImage = fileService.getFaImageByIndex(signRequestParams.getSignImageNumber()); + } else { + if (signType.equals(SignType.visa) || signType.equals(SignType.hiddenVisa)) { + File fileSignImage = fileService.getEmptyImage(); + signImage = fileService.addTextToImage(new FileInputStream(fileSignImage), signRequestParams, signType); File fileWithWatermark = fileService.getTempFile("sign_with_mark.png"); - fileService.addImageWatermark(PdfService.class.getResourceAsStream("/static/images/watermark.png"), signImage, fileWithWatermark, new Color(141, 198, 64)); + fileService.addImageWatermark(PdfService.class.getResourceAsStream("/static/images/watermark.png"), signImage, fileWithWatermark, new Color(137, 137, 137)); signImage = new FileInputStream(fileWithWatermark); - } - } else { - if(signRequestParams.getSignImageNumber() < 0) { - signImage = fileService.getFaImageByIndex(signRequestParams.getSignImageNumber()); + } else if (signRequestParams.getAddExtra()) { + signImage = fileService.addTextToImage(user.getSignImages().get(signRequestParams.getSignImageNumber()).getInputStream(), signRequestParams, signType); + if (signRequestParams.getAddWatermark()) { + File fileWithWatermark = fileService.getTempFile("sign_with_mark.png"); + fileService.addImageWatermark(PdfService.class.getResourceAsStream("/static/images/watermark.png"), signImage, fileWithWatermark, new Color(141, 198, 64)); + signImage = new FileInputStream(fileWithWatermark); + } } else { signImage = user.getSignImages().get(signRequestParams.getSignImageNumber()).getInputStream(); - if(signRequestParams.getAddWatermark()) { + if (signRequestParams.getAddWatermark()) { File fileWithWatermark = fileService.getTempFile("sign_with_mark.png"); fileService.addImageWatermark(PdfService.class.getResourceAsStream("/static/images/watermark.png"), signImage, fileWithWatermark, new Color(141, 198, 64)); signImage = new FileInputStream(fileWithWatermark); @@ -358,7 +358,7 @@ public InputStream writeMetadatas(InputStream inputStream, String fileName, Sign public InputStream convertGS(InputStream inputStream, String UUID) throws IOException, EsupSignatureException { File file = fileService.inputStreamToTempFile(inputStream, "temp.pdf"); - if (!isPdfAComplient(file) && pdfConfig.getPdfProperties().isConvertToPdfA()) { + if (!isPdfAComplient(new FileInputStream(file)) && pdfConfig.getPdfProperties().isConvertToPdfA()) { File targetFile = fileService.getTempFile("afterconvert_tmp.pdf"); String defFile = PdfService.class.getResource("/PDFA_def.ps").getFile(); String cmd = pdfConfig.getPdfProperties().getPathToGS() + " -dPDFA=" + pdfConfig.getPdfProperties().getPdfALevel() + " -dBATCH -dNOPAUSE -dSubsetFonts=true -dPreserveAnnots=true -dShowAnnots=true -dPrinted=false -dNOSAFER -sColorConversionStrategy=UseDeviceIndependentColor -sDEVICE=pdfwrite -dPDFACompatibilityPolicy=1 -dCompatibilityLevel=1.7 -sDocumentUUID=" + UUID + " -d -sOutputFile='" + targetFile.getAbsolutePath() + "' '" + defFile + "' '" + file.getAbsolutePath() + "'"; @@ -406,21 +406,21 @@ public InputStream convertGS(InputStream inputStream, String UUID) throws IOExce } } - public boolean isPdfAComplient(File pdfFile) throws EsupSignatureException { + public boolean isPdfAComplient(InputStream pdfFile) throws EsupSignatureException { if ("success".equals(checkPDFA(pdfFile, false).get(0))) { return true; } return false; } - public List checkPDFA(InputStream inputStream, boolean fillResults) throws IOException, EsupSignatureException { - File file = fileService.inputStreamToTempFile(inputStream, "tmp.pdf"); - List checkResult = checkPDFA(file, fillResults); - file.delete(); - return checkResult; - } +// public List checkPDFA(InputStream inputStream, boolean fillResults) throws IOException, EsupSignatureException { +// File file = fileService.inputStreamToTempFile(inputStream, "tmp.pdf"); +// List checkResult = checkPDFA(inputStream, fillResults); +// file.delete(); +// return checkResult; +// } - public List checkPDFA(File pdfFile, boolean fillResults) throws EsupSignatureException { + public List checkPDFA(InputStream pdfFile, boolean fillResults) throws EsupSignatureException { List result = new ArrayList<>(); VeraGreenfieldFoundryProvider.initialise(); try { diff --git a/src/main/java/org/esupportail/esupsignature/service/utils/sign/SignService.java b/src/main/java/org/esupportail/esupsignature/service/utils/sign/SignService.java index f5c2dc1b0..f78ffb0fc 100644 --- a/src/main/java/org/esupportail/esupsignature/service/utils/sign/SignService.java +++ b/src/main/java/org/esupportail/esupsignature/service/utils/sign/SignService.java @@ -199,45 +199,46 @@ public PAdESSignatureParameters fillVisibleParameters(SignatureDocumentForm form PAdESSignatureParameters pAdESSignatureParameters = new PAdESSignatureParameters(); SignatureImageParameters imageParameters = new SignatureImageParameters(); InMemoryDocument fileDocumentImage; - InputStream signImage; - signImage = fileService.addTextToImage(user.getSignImages().get(signRequestParams.getSignImageNumber()).getInputStream(), signRequestParams, SignType.nexuSign); - if(signRequestParams.getAddWatermark()) { - File fileWithWatermark = fileService.getTempFile("sign_with_mark.png"); - fileService.addImageWatermark(PdfService.class.getResourceAsStream("/static/images/watermark.png"), signImage, fileWithWatermark, color); - signImage = new FileInputStream(fileWithWatermark); - } - BufferedImage bufferedSignImage = ImageIO.read(signImage); - ByteArrayOutputStream os = new ByteArrayOutputStream(); - ImageIO.write(bufferedSignImage, "png", os); - fileDocumentImage = new InMemoryDocument(new ByteArrayInputStream(os.toByteArray()), "sign.png"); - fileDocumentImage.setMimeType(MimeType.PNG); - imageParameters.setImage(fileDocumentImage); - SignatureFieldParameters signatureFieldParameters = imageParameters.getFieldParameters(); - signatureFieldParameters.setPage(signRequestParams.getSignPageNumber()); - imageParameters.setRotation(VisualSignatureRotation.AUTOMATIC); - PdfParameters pdfParameters = pdfService.getPdfParameters(toSignFile); - if(signRequestParams.getAddExtra()) { - signRequestParams.setSignWidth(signRequestParams.getSignWidth() + 200); - } - int widthAdjusted = Math.round((float) (bufferedSignImage.getWidth() / 3 * 0.75)); - int heightAdjusted = Math.round((float) (bufferedSignImage.getHeight() / 3 * 0.75)); + if(user.getSignImages().size() > signRequestParams.getSignImageNumber()) { + InputStream signImage = fileService.addTextToImage(user.getSignImages().get(signRequestParams.getSignImageNumber()).getInputStream(), signRequestParams, SignType.nexuSign); + if(signRequestParams.getAddWatermark()) { + File fileWithWatermark = fileService.getTempFile("sign_with_mark.png"); + fileService.addImageWatermark(PdfService.class.getResourceAsStream("/static/images/watermark.png"), signImage, fileWithWatermark, color); + signImage = new FileInputStream(fileWithWatermark); + } + BufferedImage bufferedSignImage = ImageIO.read(signImage); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ImageIO.write(bufferedSignImage, "png", os); + fileDocumentImage = new InMemoryDocument(new ByteArrayInputStream(os.toByteArray()), "sign.png"); + fileDocumentImage.setMimeType(MimeType.PNG); + imageParameters.setImage(fileDocumentImage); + SignatureFieldParameters signatureFieldParameters = imageParameters.getFieldParameters(); + signatureFieldParameters.setPage(signRequestParams.getSignPageNumber()); + imageParameters.setRotation(VisualSignatureRotation.AUTOMATIC); + PdfParameters pdfParameters = pdfService.getPdfParameters(toSignFile); + if(signRequestParams.getAddExtra()) { + signRequestParams.setSignWidth(signRequestParams.getSignWidth() + 200); + } + int widthAdjusted = Math.round((float) (bufferedSignImage.getWidth() / 3 * 0.75)); + int heightAdjusted = Math.round((float) (bufferedSignImage.getHeight() / 3 * 0.75)); - if(pdfParameters.getRotation() == 0) { - signatureFieldParameters.setWidth(widthAdjusted); - signatureFieldParameters.setHeight(heightAdjusted); - signatureFieldParameters.setOriginX(signRequestParams.getxPos()); - } else { - signatureFieldParameters.setWidth(heightAdjusted); - signatureFieldParameters.setHeight(widthAdjusted); - signatureFieldParameters.setOriginX(signRequestParams.getxPos() - 50); + if(pdfParameters.getRotation() == 0) { + signatureFieldParameters.setWidth(widthAdjusted); + signatureFieldParameters.setHeight(heightAdjusted); + signatureFieldParameters.setOriginX(signRequestParams.getxPos()); + } else { + signatureFieldParameters.setWidth(heightAdjusted); + signatureFieldParameters.setHeight(widthAdjusted); + signatureFieldParameters.setOriginX(signRequestParams.getxPos() - 50); + } + int yPos = Math.round(signRequestParams.getyPos() - ((heightAdjusted - signRequestParams.getSignHeight())) / 0.75f); + signatureFieldParameters.setOriginY(yPos); + imageParameters.setFieldParameters(signatureFieldParameters); + imageParameters.setDpi(300); + imageParameters.setAlignmentHorizontal(VisualSignatureAlignmentHorizontal.LEFT); + imageParameters.setAlignmentVertical(VisualSignatureAlignmentVertical.TOP); + pAdESSignatureParameters.setImageParameters(imageParameters); } - int yPos = Math.round(signRequestParams.getyPos() - ((heightAdjusted - signRequestParams.getSignHeight())) / 0.75f); - signatureFieldParameters.setOriginY(yPos); - imageParameters.setFieldParameters(signatureFieldParameters); - imageParameters.setDpi(300); - imageParameters.setAlignmentHorizontal(VisualSignatureAlignmentHorizontal.LEFT); - imageParameters.setAlignmentVertical(VisualSignatureAlignmentVertical.TOP); - pAdESSignatureParameters.setImageParameters(imageParameters); //signature size 32767 is max for PDF/A-2B pAdESSignatureParameters.setContentSize(32767); pAdESSignatureParameters.setSignaturePackaging(form.getSignaturePackaging()); @@ -336,7 +337,7 @@ public AbstractSignatureForm getSignatureDocumentForm(List documents, } else { inputStream = toSignFile.getInputStream(); } - if(signRequest.getSignedDocuments().size() == 0) { + if(signRequest.getSignedDocuments().size() == 0 && !pdfService.isPdfAComplient(toSignFile.getInputStream())) { inputStream = pdfService.convertGS(pdfService.writeMetadatas(inputStream, toSignFile.getFileName(), signRequest, new ArrayList<>()), signRequest.getToken()); } } else { @@ -579,7 +580,7 @@ public Document nexuSign(SignRequest signRequest, String userEppn, AbstractSigna public boolean checkSignTypeDocType(SignType signType, MultipartFile multipartFile) { boolean check = true; if(!multipartFile.getContentType().toLowerCase().contains("pdf") && !multipartFile.getContentType().toLowerCase().contains("image")) { - if(signType.equals(SignType.pdfImageStamp)) { + if(signType.equals(SignType.pdfImageStamp) || signType.equals(SignType.visa)) { check = false; } } diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/GlobalAttributsControllerAdvice.java b/src/main/java/org/esupportail/esupsignature/web/controller/GlobalAttributsControllerAdvice.java index 07c3f7524..4fa8245b8 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/GlobalAttributsControllerAdvice.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/GlobalAttributsControllerAdvice.java @@ -1,11 +1,16 @@ package org.esupportail.esupsignature.web.controller; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.beanutils.BeanUtils; import org.esupportail.esupsignature.config.GlobalProperties; +import org.esupportail.esupsignature.dss.service.OJService; import org.esupportail.esupsignature.entity.User; import org.esupportail.esupsignature.entity.enums.ShareType; import org.esupportail.esupsignature.entity.enums.SignType; import org.esupportail.esupsignature.service.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.info.BuildProperties; import org.springframework.core.env.Environment; @@ -14,6 +19,7 @@ import org.springframework.web.bind.annotation.ModelAttribute; import javax.annotation.Resource; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Collections; @@ -22,6 +28,8 @@ @ControllerAdvice(basePackages = {"org.esupportail.esupsignature.web.controller"}) public class GlobalAttributsControllerAdvice { + private static final Logger logger = LoggerFactory.getLogger(GlobalAttributsControllerAdvice.class); + @Resource private GlobalProperties globalProperties; @@ -43,6 +51,9 @@ public class GlobalAttributsControllerAdvice { @Resource private ReportService reportService; + @Resource + private OJService ojService; + @Autowired private Environment environment; @@ -63,7 +74,7 @@ public GlobalAttributsControllerAdvice(@Autowired(required = false) BuildPropert } @ModelAttribute - public void globalAttributes(@ModelAttribute("userEppn") String userEppn, @ModelAttribute("authUserEppn") String authUserEppn, Model model) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + public void globalAttributes(@ModelAttribute("userEppn") String userEppn, @ModelAttribute("authUserEppn") String authUserEppn, Model model) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, JsonProcessingException { this.myGlobalProperties = (GlobalProperties) BeanUtils.cloneBean(globalProperties); User user = userService.getUserByEppn(userEppn); model.addAttribute("user", user); @@ -80,6 +91,8 @@ public void globalAttributes(@ModelAttribute("userEppn") String userEppn, @Model model.addAttribute("infiniteScrolling", globalProperties.getInfiniteScrolling()); model.addAttribute("validationToolsEnabled", validationService != null); model.addAttribute("globalProperties", this.myGlobalProperties); + ObjectMapper objectMapper = new ObjectMapper(); + model.addAttribute("globalPropertiesJson", objectMapper.writer().writeValueAsString(this.myGlobalProperties)); model.addAttribute("reportNumber", reportService.countByUser(authUserEppn)); model.addAttribute("hoursBeforeRefreshNotif", this.myGlobalProperties.getHoursBeforeRefreshNotif()); if(environment.getActiveProfiles().length > 0 && environment.getActiveProfiles()[0].equals("dev")) { @@ -87,6 +100,8 @@ public void globalAttributes(@ModelAttribute("userEppn") String userEppn, @Model } if (buildProperties != null) { model.addAttribute("version", buildProperties.getVersion()); + } else { + model.addAttribute("version", "dev"); } List signTypes = Arrays.asList(SignType.values()); if(userKeystoreService == null) { @@ -94,8 +109,13 @@ public void globalAttributes(@ModelAttribute("userEppn") String userEppn, @Model signTypes.remove(SignType.nexuSign); } model.addAttribute("nbDatas", dataService.getNbCreateByAndStatus(userEppn)); - model.addAttribute("nbSignRequests", signRequestService.getNbByCreateAndStatus(userEppn)); + model.addAttribute("nbSignRequests", signRequestService.getNbPendingSignRequests(userEppn)); model.addAttribute("nbToSign", signRequestService.nbToSignSignRequests(userEppn)); + try { + model.addAttribute("dssStatus", ojService.checkOjFreshness()); + } catch (IOException e) { + logger.debug("enable to get dss status"); + } } public void parseRoles(User user) { diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/admin/CertificatController.java b/src/main/java/org/esupportail/esupsignature/web/controller/admin/CertificatController.java new file mode 100644 index 000000000..1b3bdb0b5 --- /dev/null +++ b/src/main/java/org/esupportail/esupsignature/web/controller/admin/CertificatController.java @@ -0,0 +1,68 @@ +package org.esupportail.esupsignature.web.controller.admin; + +import org.esupportail.esupsignature.exception.EsupSignatureKeystoreException; +import org.esupportail.esupsignature.service.CertificatService; +import org.esupportail.esupsignature.service.UserService; +import org.esupportail.esupsignature.web.ws.json.JsonMessage; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.List; + +@RequestMapping("/admin/certificats") +@Controller +public class CertificatController { + + @ModelAttribute("adminMenu") + String getCurrentMenu() { + return "active"; + } + + @ModelAttribute("activeMenu") + public String getActiveMenu() { + return "certificats"; + } + + @Resource + private CertificatService certificatService; + + @Resource + private UserService userService; + + @GetMapping + public String list(Model model) { + model.addAttribute("certificats", certificatService.getAllCertificats()); + model.addAttribute("roles", userService.getAllRoles()); + return "admin/certificats/list"; + } + + @PostMapping + public String addCertificat( + @RequestParam MultipartFile keystore, + @RequestParam List roleNames, + @RequestParam String password, + RedirectAttributes redirectAttributes) { + try { + certificatService.addCertificat(keystore, roleNames, password); + redirectAttributes.addFlashAttribute("message", new JsonMessage("success", "Certificat ajouté")); + } catch (IOException | EsupSignatureKeystoreException e) { + redirectAttributes.addFlashAttribute("message", new JsonMessage("error", "Erreur lors de l'ajout du keystore : " + e.getMessage())); + } + + return "redirect:/admin/certificats"; + } + + @DeleteMapping + public String deleteCertificat(@RequestParam Long id, + RedirectAttributes redirectAttributes) throws IOException { + certificatService.delete(id); + redirectAttributes.addFlashAttribute("message", new JsonMessage("success", "Certificat supprimé")); + return "redirect:/admin/certificats"; + } + +} diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/admin/CurrentSessionsController.java b/src/main/java/org/esupportail/esupsignature/web/controller/admin/CurrentSessionsController.java index 057e0b988..f99331818 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/admin/CurrentSessionsController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/admin/CurrentSessionsController.java @@ -18,16 +18,15 @@ package org.esupportail.esupsignature.web.controller.admin; import org.apache.commons.io.FileUtils; +import org.esupportail.esupsignature.service.security.SessionService; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.core.session.SessionInformation; import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.session.Session; -import org.springframework.session.SessionRepository; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.annotation.Resource; import java.util.ArrayList; @@ -54,7 +53,7 @@ public String getActiveMenu() { private SessionRegistry sessionRegistry; @Resource - private SessionRepository sessionRepository; + private SessionService sessionService; @GetMapping public String getCurrentSessions(Model model) throws NoSuchMethodException { @@ -65,7 +64,7 @@ public String getCurrentSessions(Model model) throws NoSuchMethodException { List sessions = new ArrayList<>(); List sessionInformations = sessionRegistry.getAllSessions(principal, true); for(SessionInformation sessionInformation : sessionInformations) { - Session session = sessionRepository.findById(sessionInformation.getSessionId()); + Session session = sessionService.getSessionById(sessionInformation.getSessionId()); if(session != null) { for(String attr : session.getAttributeNames()) { sessionSize += session.getAttribute(attr).toString().getBytes().length; @@ -85,10 +84,10 @@ public String getCurrentSessions(Model model) throws NoSuchMethodException { } @DeleteMapping - public String deleteSessions(@RequestParam String sessionId, RedirectAttributes redirectAttributes) { - Session session = sessionRepository.findById(sessionId); + public String deleteSessions(@RequestParam String sessionId) { + Session session = sessionService.getSessionById(sessionId); if(session != null) { - sessionRepository.deleteById(session.getId()); + sessionService.deleteSessionById(session.getId()); } return "redirect:/admin/currentsessions"; } diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/admin/DSSController.java b/src/main/java/org/esupportail/esupsignature/web/controller/admin/DSSController.java index 74fe6004a..a04f375ad 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/admin/DSSController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/admin/DSSController.java @@ -3,11 +3,13 @@ import eu.europa.esig.dss.spi.tsl.LOTLInfo; import eu.europa.esig.dss.spi.tsl.TLInfo; import eu.europa.esig.dss.spi.tsl.TLValidationJobSummary; +import eu.europa.esig.dss.spi.tsl.TrustedListsCertificateSource; import eu.europa.esig.dss.tsl.function.OfficialJournalSchemeInformationURI; import org.esupportail.esupsignature.dss.config.DSSBeanConfig; import org.esupportail.esupsignature.dss.service.KeystoreService; import org.esupportail.esupsignature.exception.EsupSignatureException; import org.esupportail.esupsignature.service.dss.DSSService; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -40,21 +42,19 @@ public String getActiveMenu() { @Resource private KeystoreService keystoreService; + @Resource + @Qualifier("european-trusted-list-certificate-source") + private TrustedListsCertificateSource trustedListsCertificateSource; + @GetMapping public String tlInfoPage(Model model) { - TLValidationJobSummary summary = dssService.getTrustedListsCertificateSource().getSummary(); + TLValidationJobSummary summary = trustedListsCertificateSource.getSummary(); model.addAttribute("summary", summary); - return "admin/dss/tl-summary"; - } - - @GetMapping(value = "/oj") - public String showCertificates(Model model) { model.addAttribute("keystoreCertificates", keystoreService.getCertificatesDTOFromKeyStore(dssService.getTrustedListsCertificateSource().getCertificates())); OfficialJournalSchemeInformationURI ojUriInfo = (OfficialJournalSchemeInformationURI) dssService.getLotlSource().getSigningCertificatesAnnouncementPredicate(); model.addAttribute("currentOjUrl", ojUriInfo.getOfficialJournalURL()); model.addAttribute("actualOjUrl", dssService.getActualOjUrl()); - model.addAttribute("customCertificates", keystoreService.getCertificatesDTOFromKeyStore(dssService.getMyTrustedCertificateSource().getCertificates())); - return "admin/dss/oj-certificates"; + return "admin/dss/tl-summary"; } @GetMapping(value = "/lotl/{id}") diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/admin/FormAdminController.java b/src/main/java/org/esupportail/esupsignature/web/controller/admin/FormAdminController.java index e83e684e6..f4036f625 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/admin/FormAdminController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/admin/FormAdminController.java @@ -65,9 +65,6 @@ public String getActiveMenu() { @Resource private FieldService fieldService; - @Resource - private TargetService targetService; - @GetMapping() public String list(Model model) { List forms = formService.getAllForms(); @@ -162,7 +159,7 @@ public String updateForm(@ModelAttribute Form updateForm, } @PostMapping("/update-model/{id}") - public String updateFormmodel(@PathVariable("id") Long id, + public String updateFormModel(@PathVariable("id") Long id, @RequestParam(value = "multipartModel", required=false) MultipartFile multipartModel, RedirectAttributes redirectAttributes) { try { if(multipartModel.getSize() > 0) { diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/admin/MessageAdminController.java b/src/main/java/org/esupportail/esupsignature/web/controller/admin/MessageAdminController.java index bf046ffe7..bcaf72b63 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/admin/MessageAdminController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/admin/MessageAdminController.java @@ -59,7 +59,7 @@ public String messages(Pageable pageable, Model model) { @PostMapping("/add") public String addMessage(@RequestParam String text, @RequestParam String endDate) throws ParseException, InterruptedException { Message message = messageService.createMessage(endDate, text); - eventService.publishEvent(new JsonMessage("custom", message.getText()), "global", null); +// eventService.publishEvent(new JsonMessage("custom", message.getText()), "global", null); return "redirect:/admin/messages"; } diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/admin/RolesManagersController.java b/src/main/java/org/esupportail/esupsignature/web/controller/admin/RolesManagersController.java new file mode 100644 index 000000000..5464964c9 --- /dev/null +++ b/src/main/java/org/esupportail/esupsignature/web/controller/admin/RolesManagersController.java @@ -0,0 +1,60 @@ +package org.esupportail.esupsignature.web.controller.admin; + +import org.esupportail.esupsignature.entity.User; +import org.esupportail.esupsignature.service.UserService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RequestMapping("/admin/roles-managers") +@Controller +public class RolesManagersController { + + @ModelAttribute("adminMenu") + String getCurrentMenu() { + return "active"; + } + + @ModelAttribute("activeMenu") + public String getActiveMenu() { + return "rolesManagers"; + } + + @Resource + UserService userService; + + @GetMapping + public String getRoles(Model model) { + Map> roleManagers = new HashMap<>(); + List allRoles = userService.getAllRoles(); + for (String role : allRoles) { + roleManagers.put(role, userService.getByManagersRoles(role)); + } + model.addAttribute("roleManagers", roleManagers); + return "admin/roles-managers"; + } + + @PostMapping("/editRole") + public String editRoles(@RequestParam String role, @RequestParam List rolesManagers) { + for (User user : userService.getByManagersRoles(role)) { + if (!rolesManagers.contains(user.getEmail())) { + user.getRoles().remove(role); + } + } + + for (String mail : rolesManagers) { + User user = userService.getUserByEmail(mail); + if (!user.getManagersRoles().contains(role)) { + user.getManagersRoles().add(role); + } + } + + return "redirect:/admin/roles-managers"; + + } +} diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/admin/WorkflowAdminController.java b/src/main/java/org/esupportail/esupsignature/web/controller/admin/WorkflowAdminController.java index b7d018ce0..969afdf4f 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/admin/WorkflowAdminController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/admin/WorkflowAdminController.java @@ -107,10 +107,14 @@ public String update(@ModelAttribute("authUserEppn") String authUserEppn, } @DeleteMapping(value = "/{id}", produces = "text/html") - public String delete(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("id") Long id) { + public String delete(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("id") Long id, RedirectAttributes redirectAttributes) { Workflow workflow = workflowService.getById(id); - workflowService.delete(workflow); - return "redirect:/admin/workflows"; + try { + workflowService.delete(workflow); + } catch (EsupSignatureException e) { + redirectAttributes.addFlashAttribute("message", new JsonMessage("error", e.getMessage())); + } + return "redirect:/admin/workflows"; } @PostMapping(value = "/add-step/{id}") diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/manager/ManagerFormController.java b/src/main/java/org/esupportail/esupsignature/web/controller/manager/ManagerFormController.java new file mode 100644 index 000000000..b9bb94ede --- /dev/null +++ b/src/main/java/org/esupportail/esupsignature/web/controller/manager/ManagerFormController.java @@ -0,0 +1,276 @@ +package org.esupportail.esupsignature.web.controller.manager; + +import org.apache.commons.io.IOUtils; +import org.esupportail.esupsignature.entity.Form; +import org.esupportail.esupsignature.entity.User; +import org.esupportail.esupsignature.entity.enums.DocumentIOType; +import org.esupportail.esupsignature.entity.enums.FieldType; +import org.esupportail.esupsignature.entity.enums.ShareType; +import org.esupportail.esupsignature.exception.EsupSignatureException; +import org.esupportail.esupsignature.service.FieldService; +import org.esupportail.esupsignature.service.FormService; +import org.esupportail.esupsignature.service.UserService; +import org.esupportail.esupsignature.service.WorkflowService; +import org.esupportail.esupsignature.service.export.DataExportService; +import org.esupportail.esupsignature.service.interfaces.prefill.PreFill; +import org.esupportail.esupsignature.service.interfaces.prefill.PreFillService; +import org.esupportail.esupsignature.web.ws.json.JsonMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.*; + +@Controller +@RequestMapping("/manager/forms") +public class ManagerFormController { + + private static final Logger logger = LoggerFactory.getLogger(ManagerFormController.class); + + @ModelAttribute("managerMenu") + public String getmanagersMenu() { + return "active"; + } + + @ModelAttribute("activeMenu") + public String getActiveMenu() { + return "forms"; + } + + @Resource + private FormService formService; + + @Resource + private WorkflowService workflowService; + + @Resource + private UserService userService; + + @Resource + private PreFillService preFillService; + + @Resource + private DataExportService dataExportService; + + @Resource + private FieldService fieldService; + + @GetMapping() + public String list(@ModelAttribute("authUserEppn") String authUserEppn, Model model) { + Set forms = new HashSet<>(); + User manager = userService.getByEppn(authUserEppn); + for (String role : manager.getManagersRoles()) { + forms.addAll(formService.getByRoles(role)); + } + model.addAttribute("forms", forms); + model.addAttribute("roles", manager.getManagersRoles()); + model.addAttribute("targetTypes", DocumentIOType.values()); + model.addAttribute("workflowTypes", workflowService.getManagerWorkflows(authUserEppn)); + model.addAttribute("preFillTypes", preFillService.getPreFillValues()); + return "managers/forms/list"; + } + + @GetMapping("{id}") + @PreAuthorize("@preAuthorizeService.formManager(#id, #authUserEppn)") + public String show(@PathVariable("id") Long id, Model model, @ModelAttribute("authUserEppn") String authUserEppn) { + Form form = formService.getById(id); + model.addAttribute("form", form); + model.addAttribute("workflow", form.getWorkflow()); + PreFill preFill = preFillService.getPreFillServiceByName(form.getPreFillType()); + if(preFill != null) { + model.addAttribute("preFillTypes", preFill.getTypes()); + } else { + model.addAttribute("preFillTypes", new HashMap<>()); + } + model.addAttribute("document", form.getDocument()); + return "managers/forms/show"; + } + + @PostMapping() + public String postForm(@RequestParam("name") String name, + @RequestParam("fieldNames[]") String[] fieldNames, + @RequestParam(required = false) Boolean publicUsage, RedirectAttributes redirectAttributes) throws IOException { + try { + Form form = formService.createForm(null, name, null, null, null, null, publicUsage, fieldNames); + return "redirect:/manager/forms/" + form.getId(); + + } catch (EsupSignatureException e) { + logger.error(e.getMessage()); + redirectAttributes.addFlashAttribute("message", new JsonMessage("error", e.getMessage())); + return "redirect:/manager/forms/"; + } + } + + @PostMapping("generate") + public String generateForm( + @RequestParam("multipartFile") MultipartFile multipartFile, + @RequestParam String name, + @RequestParam String title, + @RequestParam Long workflowId, + @RequestParam String prefillType, + @RequestParam(required = false) List roleNames, + @RequestParam(required = false) Boolean publicUsage, + RedirectAttributes redirectAttributes) throws IOException { + try { + Form form = formService.generateForm(multipartFile, name, title, workflowId, prefillType, roleNames, publicUsage); + return "redirect:/manager/forms/" + form.getId(); + } catch (EsupSignatureException e) { + logger.error(e.getMessage()); + redirectAttributes.addFlashAttribute("message", new JsonMessage("error", e.getMessage())); + return "redirect:/manager/forms/"; + } + } + + @GetMapping("update/{id}") + @PreAuthorize("@preAuthorizeService.formManager(#id, #authUserEppn)") + public String updateForm(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("id") long id, Model model) { + Form form = formService.getById(id); + User manager = userService.getUserByEppn(authUserEppn); + model.addAttribute("form", form); + model.addAttribute("fields", form.getFields()); + model.addAttribute("roles", manager.getManagersRoles()); + model.addAttribute("document", form.getDocument()); + model.addAttribute("workflowTypes", workflowService.getManagerWorkflows(authUserEppn)); + List preFillTypes = preFillService.getPreFillValues(); + model.addAttribute("preFillTypes", preFillTypes); + model.addAttribute("shareTypes", ShareType.values()); + model.addAttribute("targetTypes", DocumentIOType.values()); + model.addAttribute("model", form.getDocument()); + return "managers/forms/update"; + } + + @GetMapping("create") + public String createForm(Model model) { + model.addAttribute("form", new Form()); + return "managers/forms/create"; + } + + @PutMapping + @PreAuthorize("@preAuthorizeService.formManager(#updateForm.id, #authUserEppn)") + public String updateForm(@ModelAttribute Form updateForm, + @RequestParam(required = false) List managers, + @RequestParam(value = "types", required = false) String[] types, + @ModelAttribute("authUserEppn") String authUserEppn, + RedirectAttributes redirectAttributes) { + updateForm.setPublicUsage(false); + updateForm.setAction(""); + formService.updateForm(updateForm.getId(), updateForm, managers, types); + redirectAttributes.addFlashAttribute("message", new JsonMessage("success", "Modifications enregistrées")); + return "redirect:/manager/forms/update/" + updateForm.getId(); + } + + @PostMapping("/update-model/{id}") + @PreAuthorize("@preAuthorizeService.formManager(#id, #authUserEppn)") + public String updateFormModel(@PathVariable("id") Long id, + @ModelAttribute("authUserEppn") String authUserEppn, + @RequestParam(value = "multipartModel", required=false) MultipartFile multipartModel, RedirectAttributes redirectAttributes) { + try { + if(multipartModel.getSize() > 0) { + formService.updateFormModel(id, multipartModel); + } + } catch (EsupSignatureException e) { + logger.error(e.getMessage()); + redirectAttributes.addFlashAttribute("message", new JsonMessage("error", e.getMessage())); + return "redirect:/manager/forms/"; + } + redirectAttributes.addFlashAttribute("message", new JsonMessage("success", "Modifications enregistrées")); + return "redirect:/manager/forms/update/" + id; + } + + @DeleteMapping("{id}") + @PreAuthorize("@preAuthorizeService.formManager(#id, #authUserEppn)") + public String deleteForm(@PathVariable("id") Long id, @ModelAttribute("authUserEppn") String authUserEppn, RedirectAttributes redirectAttributes) { + formService.deleteForm(id); + redirectAttributes.addFlashAttribute("message", new JsonMessage("info", "Le formulaire à bien été supprimé")); + return "redirect:/manager/forms"; + } + + @GetMapping(value = "/{name}/datas/csv", produces="text/csv") + public ResponseEntity getFormDatasCsv(@PathVariable String name, HttpServletResponse response) { + List forms = formService.getFormByName(name); + if (forms.size() > 0) { + try { + response.setContentType("text/csv; charset=utf-8"); + response.setHeader("Content-Disposition", "inline; filename=" + URLEncoder.encode(forms.get(0).getName(), StandardCharsets.UTF_8.toString()) + ".csv"); + InputStream csvInputStream = dataExportService.getCsvDatasFromForms(forms); + IOUtils.copy(csvInputStream, response.getOutputStream()); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + logger.error("get file error", e); + } + } else { + logger.warn("form " + name + " not found"); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + + @ResponseBody + @PostMapping("/field/{id}/update") + @PreAuthorize("@preAuthorizeService.formManager(#id, #authUserEppn)") + public ResponseEntity updateField(@PathVariable("id") Long id, + @RequestParam(value = "description", required = false) String description, + @RequestParam(value = "fieldType", required = false, defaultValue = "text") FieldType fieldType, + @RequestParam(value = "required", required = false, defaultValue = "false") Boolean required, + @RequestParam(value = "favorisable", required = false, defaultValue = "false") Boolean favorisable, + @RequestParam(value = "readOnly", required = false, defaultValue = "false") Boolean readOnly, + @RequestParam(value = "prefill", required = false, defaultValue = "false") Boolean prefill, + @RequestParam(value = "search", required = false, defaultValue = "false") Boolean search, + @RequestParam(value = "valueServiceName", required = false) String valueServiceName, + @RequestParam(value = "valueType", required = false) String valueType, + @RequestParam(value = "valueReturn", required = false) String valueReturn, + @RequestParam(value = "stepZero", required = false, defaultValue = "false") Boolean stepZero, + @RequestParam(value = "workflowStepsIds", required = false) List workflowStepsIds, + @ModelAttribute("authUserEppn") String authUserEppn) { + + String extValueServiceName = ""; + String extValueType = ""; + String extValueReturn = ""; + String searchServiceName = ""; + String searchType = ""; + String searchReturn = ""; + if(prefill) { + extValueServiceName = valueServiceName; + extValueType = valueType; + extValueReturn = valueReturn; + } + if(search) { + searchServiceName = valueServiceName; + searchType = valueType; + searchReturn = valueReturn; + } + fieldService.updateField(id, description, fieldType, favorisable, required, readOnly, extValueServiceName, extValueType, extValueReturn, searchServiceName, searchType, searchReturn, stepZero, workflowStepsIds); + return new ResponseEntity<>(HttpStatus.OK); + } + + @GetMapping(value = "/get-file/{id}") + public void getFile(@ModelAttribute("userEppn") String userEppn, @ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("id") Long id, HttpServletResponse httpServletResponse, RedirectAttributes redirectAttributes) throws IOException { + try { + Map attachmentResponse = formService.getModel(id); + if (attachmentResponse != null) { + httpServletResponse.setContentType(attachmentResponse.get("contentType").toString()); + httpServletResponse.setHeader("Content-Disposition", "inline; filename=" + URLEncoder.encode(attachmentResponse.get("fileName").toString(), StandardCharsets.UTF_8.toString())); + IOUtils.copyLarge((InputStream) attachmentResponse.get("inputStream"), httpServletResponse.getOutputStream()); + } else { + redirectAttributes.addFlashAttribute("message", new JsonMessage("error", "Modèle non trouvée ...")); + httpServletResponse.sendRedirect("/user/signsignrequests/" + id); + } + } catch (Exception e) { + logger.error("get file error", e); + } + } + +} \ No newline at end of file diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/manager/ManagerRolesManagersController.java b/src/main/java/org/esupportail/esupsignature/web/controller/manager/ManagerRolesManagersController.java new file mode 100644 index 000000000..edf8912c2 --- /dev/null +++ b/src/main/java/org/esupportail/esupsignature/web/controller/manager/ManagerRolesManagersController.java @@ -0,0 +1,64 @@ +package org.esupportail.esupsignature.web.controller.manager; + +import org.esupportail.esupsignature.entity.User; +import org.esupportail.esupsignature.service.UserService; +import org.esupportail.esupsignature.service.security.PreAuthorizeService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RequestMapping("/manager/rolesManagers") +@Controller +public class ManagerRolesManagersController { + + @ModelAttribute("managerMenu") + String getCurrentMenu() { + return "active"; + } + + @ModelAttribute("activeMenu") + public String getActiveMenu() { + return "rolesManagers"; + } + + @Resource + UserService userService; + + @GetMapping + public String getRoles(@ModelAttribute("authUserEppn") String authUserEppn, Model model) { + Map> roleManagers = new HashMap<>(); + User manager = userService.getByEppn(authUserEppn); + List allRoles = manager.getManagersRoles(); + for (String role : allRoles) { + roleManagers.put(role, userService.getByManagersRoles(role)); + } + model.addAttribute("roleManagers", roleManagers); + return "managers/managerRoles"; + } + + @PostMapping("/editRole") + @PreAuthorize("@preAuthorizeService.roleManager(#role, #authUserEppn)") + public String editRoles(@RequestParam String role, @RequestParam List rolesManagers, @ModelAttribute("authUserEppn") String authUserEppn) { + for (User user : userService.getByManagersRoles(role)) { + if (!rolesManagers.contains(user.getEmail())) { + user.getManagersRoles().remove(role); + } + } + + for (String mail : rolesManagers) { + User user = userService.getUserByEmail(mail); + if (!user.getManagersRoles().contains(role)) { + user.getManagersRoles().add(role); + } + } + + return "redirect:/manager/rolesManagers"; + + } +} diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/manager/ManagerWorkflowController.java b/src/main/java/org/esupportail/esupsignature/web/controller/manager/ManagerWorkflowController.java new file mode 100644 index 000000000..0c120a5ae --- /dev/null +++ b/src/main/java/org/esupportail/esupsignature/web/controller/manager/ManagerWorkflowController.java @@ -0,0 +1,220 @@ +package org.esupportail.esupsignature.web.controller.manager; + +import org.esupportail.esupsignature.entity.User; +import org.esupportail.esupsignature.entity.Workflow; +import org.esupportail.esupsignature.entity.WorkflowStep; +import org.esupportail.esupsignature.entity.enums.DocumentIOType; +import org.esupportail.esupsignature.entity.enums.ShareType; +import org.esupportail.esupsignature.entity.enums.SignType; +import org.esupportail.esupsignature.exception.EsupSignatureException; +import org.esupportail.esupsignature.service.UserService; +import org.esupportail.esupsignature.service.WorkflowService; +import org.esupportail.esupsignature.service.WorkflowStepService; +import org.esupportail.esupsignature.web.ws.json.JsonMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Arrays; +import java.util.List; + +@RequestMapping("/manager/workflows") +@Controller + +public class ManagerWorkflowController { + + private static final Logger logger = LoggerFactory.getLogger(ManagerWorkflowController.class); + + @ModelAttribute("managerMenu") + public String getAdminMenu() { + return "active"; + } + + @ModelAttribute("activeMenu") + public String getActiveMenu() { + return "workflows"; + } + + @Resource + private UserService userService; + + @Resource + private WorkflowService workflowService; + + @Resource + private WorkflowStepService workflowStepService; + + @GetMapping + public String list(@ModelAttribute("authUserEppn") String authUserEppn, Model model) { + model.addAttribute("workflows", workflowService.getManagerWorkflows(authUserEppn)); + return "managers/workflows/list"; + } + + @GetMapping(value = "/{id}") + @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn)") + public String show(@PathVariable("id") Long id, Model model, @ModelAttribute("authUserEppn") String authUserEppn) { + model.addAttribute("fromAdmin", true); + model.addAttribute("signTypes", SignType.values()); + Workflow workflow = workflowService.getById(id); + model.addAttribute("workflow", workflow); + return "managers/workflows/show"; + } + + @PostMapping(produces = "text/html") + public String create(@ModelAttribute("authUserEppn") String authUserEppn, @RequestParam(name = "title", required = false) String title, @RequestParam(name = "description") String description, RedirectAttributes redirectAttributes) { + if(title == null) { + title = description; + } + Workflow workflow; + try { + workflow = workflowService.createWorkflow(title, description, userService.getByEppn(authUserEppn)); + } catch (EsupSignatureException e) { + redirectAttributes.addFlashAttribute("message", new JsonMessage("error", "Un circuit possède déjà ce préfixe")); + return "redirect:/manager/workflows/"; + } + return "redirect:/manager/workflows/" + workflow.getId(); + } + + @GetMapping(value = "/update/{id}") + @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn)") + public String updateForm(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("id") Long id, Model model) { + Workflow workflow = workflowService.getById(id); + User manager = userService.getByEppn(authUserEppn); + model.addAttribute("workflow", workflow); + model.addAttribute("roles", manager.getManagersRoles()); + model.addAttribute("sourceTypes", DocumentIOType.values()); + model.addAttribute("targetTypes", DocumentIOType.values()); + model.addAttribute("shareTypes", ShareType.values()); + model.addAttribute("signTypes", Arrays.asList(SignType.values())); + return "managers/workflows/update"; + } + + @PostMapping(value = "/update") + @PreAuthorize("@preAuthorizeService.workflowManager(#workflow.id, #authUserEppn)") + public String update(@ModelAttribute("authUserEppn") String authUserEppn, + @Valid Workflow workflow, + @RequestParam(value = "types", required = false) String[] types, + @RequestParam(required = false) List managers, Model model) { + User authUser = (User) model.getAttribute("authUser"); + workflow.setPublicUsage(false); + Workflow updateWorkflow = workflowService.update(workflow, authUser, types, managers); + return "redirect:/manager/workflows/update/" + updateWorkflow.getId(); + } + + @DeleteMapping(value = "/{id}", produces = "text/html") + @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn)") + public String delete(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("id") Long id, RedirectAttributes redirectAttributes) { + Workflow workflow = workflowService.getById(id); + try { + workflowService.delete(workflow); + } catch (EsupSignatureException e) { + redirectAttributes.addFlashAttribute("message", new JsonMessage("error", e.getMessage())); + } + return "redirect:/manager/workflows"; + } + + @PostMapping(value = "/add-step/{id}") + @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn)") + public String addStep(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("id") Long id, + @RequestParam("signType") String signType, + @RequestParam(name="description", required = false) String description, + @RequestParam(value = "recipientsEmails", required = false) String[] recipientsEmails, + @RequestParam(name="changeable", required = false) Boolean changeable, + @RequestParam(name="allSignToComplete", required = false) Boolean allSignToComplete) { + workflowStepService.addStep(id, signType, description, recipientsEmails, changeable, allSignToComplete, authUserEppn, false); + return "redirect:/manager/workflows/" + id; + } + + @PostMapping(value = "/update-step/{id}/{step}") + @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn)") + public String changeStepSignType(@ModelAttribute("authUserEppn") String authUserEppn, + @PathVariable("id") Long id, + @PathVariable("step") Integer step, + @RequestParam(name="signType") SignType signType, + @RequestParam(name="description") String description, + @RequestParam(name="repeatable", required = false) Boolean repeatable, + @RequestParam(name="multiSign", required = false) Boolean multiSign, + @RequestParam(name="changeable", required = false) Boolean changeable, + @RequestParam(name="allSignToComplete", required = false) Boolean allSignToComplete) { + Workflow workflow = workflowService.getById(id); + workflowStepService.updateStep(workflow.getWorkflowSteps().get(step).getId(), signType, description, changeable, repeatable, multiSign, allSignToComplete); + return "redirect:/manager/workflows/" + id; + } + + @DeleteMapping(value = "/remove-step-recipent/{id}/{workflowStepId}") + @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn)") + public String removeStepRecipient(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("id") Long id, + @PathVariable("workflowStepId") Long workflowStepId, + @RequestParam(value = "userToRemoveEppn") String userToRemoveEppn, RedirectAttributes redirectAttributes) { + WorkflowStep workflowStep = workflowStepService.removeStepRecipient(workflowStepId, userToRemoveEppn); + redirectAttributes.addFlashAttribute("message", new JsonMessage("info", "Participant supprimé")); + return "redirect:/manager/workflows/" + id + "#" + workflowStep.getId(); + } + + @PostMapping(value = "/add-step-recipents/{id}/{workflowStepId}") + @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn)") + public String addStepRecipient(@ModelAttribute("authUserEppn") String authUserEppn, + @PathVariable("id") Long id, + @PathVariable("workflowStepId") Long workflowStepId, + @RequestParam String recipientsEmails, RedirectAttributes redirectAttributes) { + WorkflowStep workflowStep = workflowStepService.addStepRecipients(workflowStepId, recipientsEmails); + redirectAttributes.addFlashAttribute("message", new JsonMessage("info", "Participant ajouté")); + return "redirect:/manager/workflows/" + id + "#" + workflowStep.getId(); + } + + @DeleteMapping(value = "/remove-step/{id}/{stepNumber}") + @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn)") + public String addStep(@ModelAttribute("authUserEppn") String authUserEppn, + @PathVariable("id") Long id, + @PathVariable("stepNumber") Integer stepNumber) { + Workflow workflow = workflowService.getById(id); + workflowStepService.removeStep(workflow, stepNumber); + return "redirect:/manager/workflows/" + id; + } + + @GetMapping(value = "/get-files-from-source/{id}") + @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn)") + public String getFileFromSource(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("id") Long id, Model model, RedirectAttributes redirectAttributes) { + User authUser = (User) model.getAttribute("authUser"); + int nbImportedFiles = workflowService.importFilesFromSource(id, authUser, authUser); + if(nbImportedFiles == 0) { + redirectAttributes.addFlashAttribute("message", new JsonMessage("error", "Aucun fichier à importer")); + } else { + redirectAttributes.addFlashAttribute("message", new JsonMessage("info", nbImportedFiles + " ficher(s) importé(s)")); + } + return "redirect:/manager/workflows/" + id; + } + + @PostMapping(value = "/add-target/{id}") + @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn)") + public String addTarget(@PathVariable("id") Long id, + @RequestParam("targetType") String targetType, + @RequestParam("documentsTargetUri") String documentsTargetUri, + @ModelAttribute("authUserEppn") String authUserEppn, + RedirectAttributes redirectAttributes) { + if(workflowService.addTarget(id, targetType, documentsTargetUri)) { + redirectAttributes.addFlashAttribute("message", new JsonMessage("info", "Destination ajoutée")); + } else { + redirectAttributes.addFlashAttribute("message", new JsonMessage("warn", "Une destination mail existe déjà")); + } + return "redirect:/manager/workflows/update/" + id; + } + + @GetMapping(value = "/delete-target/{id}/{targetId}") + @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn)") + public String deleteTarget(@PathVariable("id") Long id, + @PathVariable("targetId") Long targetId, + @ModelAttribute("authUserEppn") String authUserEppn, + RedirectAttributes redirectAttributes) { + workflowService.deleteTarget(id, targetId); + redirectAttributes.addFlashAttribute("message", new JsonMessage("info", "Destination supprimée")); + return "redirect:/manager/workflows/update/" + id; + } + +} diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/user/SignRequestController.java b/src/main/java/org/esupportail/esupsignature/web/controller/user/SignRequestController.java index b2d724230..fd266ba43 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/user/SignRequestController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/user/SignRequestController.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import eu.europa.esig.dss.validation.reports.Reports; import org.apache.commons.io.IOUtils; import org.esupportail.esupsignature.config.GlobalProperties; import org.esupportail.esupsignature.entity.*; @@ -68,6 +69,12 @@ public String getActiveMenu() { @Resource private UserService userService; + @Resource + private CertificatService certificatService; + + @Resource + private ValidationService validationService; + @Resource private PreAuthorizeService preAuthorizeService; @@ -111,6 +118,8 @@ public String list(@ModelAttribute("userEppn") String userEppn, @ModelAttribute( @RequestParam(value = "workflowFilter", required = false) String workflowFilter, @RequestParam(value = "docTitleFilter", required = false) String docTitleFilter, @SortDefault(value = "createDate", direction = Direction.DESC) @PageableDefault(size = 10) Pageable pageable, Model model) { + if(statusFilter == null) statusFilter = "pending"; + if(statusFilter.equals("all")) statusFilter = ""; Page signRequests = signRequestService.getSignRequestsPageGrouped(userEppn, authUserEppn, statusFilter, recipientsFilter, workflowFilter, docTitleFilter, pageable); model.addAttribute("statusFilter", statusFilter); model.addAttribute("signRequests", signRequests); @@ -169,6 +178,7 @@ public String show(@ModelAttribute("userEppn") String userEppn, @ModelAttribute( model.addAttribute("nextSignRequest", signRequestService.getNextSignRequest(signRequest.getId(), userEppn, authUserEppn)); model.addAttribute("prevSignRequest", signRequestService.getPreviousSignRequest(signRequest.getId(), userEppn, authUserEppn)); model.addAttribute("fields", signRequestService.prefillSignRequestFields(id, userEppn)); + model.addAttribute("toUseSignRequestParams", Collections.singletonList(signRequestService.getToUseSignRequestParams(id))); model.addAttribute("uiParams", userService.getUiParams(authUserEppn)); if(!signRequest.getStatus().equals(SignRequestStatus.draft)) { try { @@ -181,6 +191,9 @@ public String show(@ModelAttribute("userEppn") String userEppn, @ModelAttribute( model.addAttribute("message", new JsonMessage("warn", e.getMessage())); } } + Reports reports = validationService.validate(id); + model.addAttribute("signatureIds", reports.getSimpleReport().getSignatureIdList()); + model.addAttribute("certificats", certificatService.getCertificatByUser(userEppn)); model.addAttribute("signable", signRequest.getSignable()); model.addAttribute("isTempUsers", signRequestService.isTempUsers(id)); if(signRequest.getStatus().equals(SignRequestStatus.draft)) { @@ -189,7 +202,7 @@ public String show(@ModelAttribute("userEppn") String userEppn, @ModelAttribute( model.addAttribute("refuseLogs", logService.getRefuseLogs(signRequest.getId())); model.addAttribute("viewRight", signRequestService.checkUserViewRights(signRequest, userEppn, authUserEppn)); model.addAttribute("frameMode", frameMode); - if(signRequest.getData() != null) { + if(signRequest.getData() != null && signRequest.getData().getForm() != null) { model.addAttribute("action", signRequest.getData().getForm().getAction()); } List logs = logService.getBySignRequest(signRequest.getId()); @@ -242,16 +255,19 @@ public ResponseEntity sign(@ModelAttribute("userEppn") String userEppn, @RequestParam(value = "formData", required = false) String formData, @RequestParam(value = "visual", required = false) Boolean visual, @RequestParam(value = "password", required = false) String password, - HttpSession httpSession, HttpServletRequest request) { - CsrfToken token = new HttpSessionCsrfTokenRepository().loadToken(request); + @RequestParam(value = "certType", required = false) String certType, + HttpSession httpSession) { if (visual == null) visual = true; Object userShareString = httpSession.getAttribute("userShareId"); Long userShareId = null; if(userShareString != null) userShareId = Long.valueOf(userShareString.toString()); - if(signRequestService.initSign(id, token.getToken(), signRequestParamsJsonString, comment, formData, visual, password, userShareId, userEppn, authUserEppn)) { + try { + signRequestService.initSign(id, signRequestParamsJsonString, comment, formData, visual, password, certType, userShareId, userEppn, authUserEppn); return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + logger.error(e.getMessage(), e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage()); } - return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } @PreAuthorize("@preAuthorizeService.signRequestOwner(#id, #authUserEppn)") @@ -622,9 +638,9 @@ public ResponseEntity massSign(@ModelAttribute("userEppn") String userEp @ModelAttribute("authUserEppn") String authUserEppn, @RequestParam String ids, @RequestParam(value = "password", required = false) String password, - HttpSession httpSession, HttpServletRequest request) throws JsonProcessingException, InterruptedException { - CsrfToken csrfToken = new HttpSessionCsrfTokenRepository().loadToken(request); - signRequestService.initMassSign(userEppn, authUserEppn, ids, httpSession, csrfToken.getToken(), password); + @RequestParam(value = "certType", required = false) String certType, + HttpSession httpSession) throws InterruptedException, EsupSignatureMailException, EsupSignatureException, IOException { + signRequestService.initMassSign(userEppn, authUserEppn, ids, httpSession, password, certType); return new ResponseEntity<>(HttpStatus.OK); } diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/user/ValidationController.java b/src/main/java/org/esupportail/esupsignature/web/controller/user/ValidationController.java index 7c8958826..fc1c3ad39 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/user/ValidationController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/user/ValidationController.java @@ -1,8 +1,17 @@ package org.esupportail.esupsignature.web.controller.user; +import eu.europa.esig.dss.diagnostic.DiagnosticData; +import eu.europa.esig.dss.diagnostic.DiagnosticDataFacade; +import eu.europa.esig.dss.diagnostic.RevocationWrapper; +import eu.europa.esig.dss.diagnostic.TimestampWrapper; +import eu.europa.esig.dss.diagnostic.jaxb.XmlDiagnosticData; +import eu.europa.esig.dss.enumerations.RevocationType; +import eu.europa.esig.dss.enumerations.TimestampType; import eu.europa.esig.dss.model.MimeType; +import eu.europa.esig.dss.utils.Utils; import eu.europa.esig.dss.validation.executor.ValidationLevel; import eu.europa.esig.dss.validation.reports.Reports; +import eu.europa.esig.validationreport.jaxb.ValidationReportType; import org.esupportail.esupsignature.dss.service.FOPService; import org.esupportail.esupsignature.dss.service.XSLTService; import org.esupportail.esupsignature.exception.EsupSignatureException; @@ -13,6 +22,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; @@ -21,13 +34,12 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.Arrays; @Controller -@SessionAttributes({ "simpleReportXml", "detailedReportXml" }) +@SessionAttributes({ "simpleReportXml", "detailedReportXml", "diagnosticDataXml" }) @RequestMapping("/user/validation") @ConditionalOnBean(ValidationService.class) public class ValidationController { @@ -64,46 +76,44 @@ public String showValidationForm() { @PostMapping public String validate(@RequestParam(name = "multipartSignedDoc") MultipartFile multipartSignedDoc, @RequestParam(name = "multipartSignature", required = false) MultipartFile multipartSignature, Model model) throws IOException { - Reports reports = validationService.validate(multipartSignedDoc.getInputStream(), multipartSignature.getInputStream()); + InputStream docInputStream = multipartSignedDoc.getInputStream(); + InputStream sigInputStream = multipartSignature.getInputStream(); + extracted(docInputStream, sigInputStream, model); + return "user/validation/result"; + } + + private void extracted(InputStream docInputStream, InputStream sigInputStream, Model model) throws IOException { + byte[] docBytes = docInputStream.readAllBytes(); + Reports reports = validationService.validate(new ByteArrayInputStream(docBytes), sigInputStream); if(reports != null) { String xmlSimpleReport = reports.getXmlSimpleReport(); model.addAttribute("simpleReport", xsltService.generateSimpleReport(xmlSimpleReport)); + model.addAttribute("simpleReportXml", reports.getXmlSimpleReport()); String xmlDetailedReport = reports.getXmlDetailedReport(); model.addAttribute("detailedReport", xsltService.generateDetailedReport(xmlDetailedReport)); model.addAttribute("detailedReportXml", reports.getXmlDetailedReport()); - model.addAttribute("diagnosticTree", reports.getXmlDiagnosticData()); + ValidationReportType etsiValidationReportJaxb = reports.getEtsiValidationReportJaxb(); + + if (etsiValidationReportJaxb != null) { + model.addAttribute("etsiValidationReport", reports.getXmlValidationReport()); + } + model.addAttribute("diagnosticDataXml", reports.getXmlDiagnosticData()); } else { model.addAttribute("simpleReport", "Impossible de valider ce document"); model.addAttribute("detailedReport", "Impossible de valider ce document"); } - if(multipartSignedDoc.getContentType().contains("pdf")) { - try { - model.addAttribute("pdfaReport", pdfService.checkPDFA(multipartSignedDoc.getInputStream(), true)); - } catch (EsupSignatureException e) { - e.printStackTrace(); - } - } else { + try { + model.addAttribute("pdfaReport", pdfService.checkPDFA(new ByteArrayInputStream(docBytes), true)); + } catch (EsupSignatureException e) { model.addAttribute("pdfaReport", Arrays.asList("danger", "Impossible de valider ce document")); + logger.error(e.getMessage()); } - - return "user/validation/result"; } - + @GetMapping(value = "/document/{id}") public String validateDocument(@PathVariable(name="id") long id, Model model) throws IOException { File file = signRequestService.getToValidateFile(id); - Reports reports = validationService.validate(new FileInputStream(file), null); - String xmlSimpleReport = reports.getXmlSimpleReport(); - model.addAttribute("simpleReport", xsltService.generateSimpleReport(xmlSimpleReport)); - String xmlDetailedReport = reports.getXmlDetailedReport(); - model.addAttribute("detailedReport", xsltService.generateDetailedReport(xmlDetailedReport)); - model.addAttribute("detailedReportXml", reports.getXmlDetailedReport()); - model.addAttribute("diagnosticTree", reports.getXmlDiagnosticData()); - try { - model.addAttribute("pdfaReport", pdfService.checkPDFA(file, true)); - } catch (EsupSignatureException e) { - logger.error("enable to check pdf"); - } + extracted(new FileInputStream(file), null, model); return "user/validation/result"; } @@ -111,10 +121,8 @@ public String validateDocument(@PathVariable(name="id") long id, Model model) th public void downloadSimpleReport(HttpSession session, HttpServletResponse response) { try { String simpleReport = (String) session.getAttribute("simpleReportXml"); - response.setContentType(MimeType.PDF.getMimeTypeString()); response.setHeader("Content-Disposition", "attachment; filename=DSS-Simple-report.pdf"); - fopService.generateSimpleReport(simpleReport, response.getOutputStream()); } catch (Exception e) { logger.error("An error occured while generating pdf for simple report : " + e.getMessage(), e); @@ -125,16 +133,133 @@ public void downloadSimpleReport(HttpSession session, HttpServletResponse respon public void downloadDetailedReport(HttpSession session, HttpServletResponse response) { try { String detailedReport = (String) session.getAttribute("detailedReportXml"); - response.setContentType(MimeType.PDF.getMimeTypeString()); response.setHeader("Content-Disposition", "attachment; filename=DSS-Detailed-report.pdf"); - fopService.generateDetailedReport(detailedReport, response.getOutputStream()); } catch (Exception e) { logger.error("An error occured while generating pdf for detailed report : " + e.getMessage(), e); } } + @RequestMapping(value = "/download-diagnostic-data") + public void downloadDiagnosticData(HttpSession session, HttpServletResponse response) { + String report = (String) session.getAttribute("diagnosticDataXml"); + + response.setContentType(MimeType.XML.getMimeTypeString()); + response.setHeader("Content-Disposition", "attachment; filename=DSS-Diagnotic-data.xml"); + try { + Utils.write(report.getBytes(StandardCharsets.UTF_8), response.getOutputStream()); + } catch (IOException e) { + logger.error("An error occurred while downloading diagnostic data : " + e.getMessage(), e); + } + } + + @RequestMapping(value = "/diag-data.svg") + public @ResponseBody + ResponseEntity downloadSVG(HttpSession session, HttpServletResponse response) { + String report = (String) session.getAttribute("diagnosticDataXml"); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.valueOf(MimeType.SVG.getMimeTypeString())); + ResponseEntity svgEntity = new ResponseEntity(xsltService.generateSVG(report), headers, + HttpStatus.OK); + return svgEntity; + } + + @RequestMapping(value = "/download-revocation") + public void downloadRevocationData(@RequestParam(value = "id") String id, @RequestParam(value = "format") String format, HttpSession session, + HttpServletResponse response) throws Exception { + DiagnosticData diagnosticData = getDiagnosticData(session); + RevocationWrapper revocationData = diagnosticData.getRevocationById(id); + if (revocationData == null) { + String message = "Revocation data " + id + " not found"; + logger.warn(message); + throw new Exception(message); + } + String filename = revocationData.getId(); + MimeType mimeType; + byte[] binaries; + + if (RevocationType.CRL.equals(revocationData.getRevocationType())) { + mimeType = MimeType.CRL; + filename += ".crl"; + + if (Utils.areStringsEqualIgnoreCase(format, "pem")) { + String pem = "-----BEGIN CRL-----\n"; + pem += Utils.toBase64(revocationData.getBinaries()); + pem += "\n-----END CRL-----"; + binaries = pem.getBytes(); + } else { + binaries = revocationData.getBinaries(); + } + } else { + mimeType = MimeType.BINARY; + filename += ".ocsp"; + binaries = revocationData.getBinaries(); + } + + addTokenToResponse(response, filename, mimeType, binaries); + } + + protected void addTokenToResponse(HttpServletResponse response, String filename, MimeType mimeType, byte[] binaries) { + response.setContentType(MimeType.TST.getMimeTypeString()); + response.setHeader("Content-Disposition", "attachment; filename=" + filename); + try (InputStream is = new ByteArrayInputStream(binaries); OutputStream os = response.getOutputStream()) { + Utils.copy(is, os); + } catch (IOException e) { + logger.error("An error occurred while downloading a file : " + e.getMessage(), e); + } + } + + @RequestMapping(value = "/download-timestamp") + public void downloadTimestamp(@RequestParam(value = "id") String id, @RequestParam(value = "format") String format, HttpSession session, + HttpServletResponse response) throws Exception { + DiagnosticData diagnosticData = getDiagnosticData(session); + TimestampWrapper timestamp = diagnosticData.getTimestampById(id); + if (timestamp == null) { + String message = "Timestamp " + id + " not found"; + logger.warn(message); + throw new Exception(message); + } + TimestampType type = timestamp.getType(); + + byte[] binaries; + if (Utils.areStringsEqualIgnoreCase(format, "pem")) { + String pem = "-----BEGIN TIMESTAMP-----\n"; + pem += Utils.toBase64(timestamp.getBinaries()); + pem += "\n-----END TIMESTAMP-----"; + binaries = pem.getBytes(); + } else { + binaries = timestamp.getBinaries(); + } + + String filename = type.name() + ".tst"; + addTokenToResponse(response, filename, MimeType.TST, binaries); + } + + public DiagnosticData getDiagnosticData(HttpSession session) { + String diagnosticDataXml = (String) session.getAttribute("diagnosticDataXml"); + try { + XmlDiagnosticData xmlDiagData = DiagnosticDataFacade.newFacade().unmarshall(diagnosticDataXml); + return new DiagnosticData(xmlDiagData); + } catch (Exception e) { + logger.error("An error occurred while generating DiagnosticData from XML : " + e.getMessage(), e); + } + return null; + } + + @GetMapping(value = "/short/{id}") + @ResponseBody + public String shortValidateDocument(@PathVariable(name="id") long id) throws IOException { + File file = signRequestService.getToValidateFile(id); + Reports reports = validationService.validate(new FileInputStream(file), null); + if(reports != null) { + String xmlSimpleReport = reports.getXmlSimpleReport(); + return xsltService.generateShortReport(xmlSimpleReport); + } + return null; + } + @ModelAttribute("validationLevels") public ValidationLevel[] getValidationLevels() { return new ValidationLevel[] { ValidationLevel.BASIC_SIGNATURES, ValidationLevel.LONG_TERM_DATA, ValidationLevel.ARCHIVAL_DATA }; diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/user/WizardController.java b/src/main/java/org/esupportail/esupsignature/web/controller/user/WizardController.java index e17769ca3..6dec28106 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/user/WizardController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/user/WizardController.java @@ -132,7 +132,7 @@ public String saveWorkflow(@ModelAttribute("userEppn") String userEppn, @PathVar try { signBookService.saveWorkflow(id, name, name, user); } catch (EsupSignatureException e) { - eventService.publishEvent(new JsonMessage("error", "Un circuit de signature porte déjà ce nom"), "user", eventService.getClientIdByEppn(userEppn)); +// eventService.publishEvent(new JsonMessage("error", "Un circuit de signature porte déjà ce nom"), "user", eventService.getClientIdByEppn(userEppn)); return "user/wizard/wiz-save"; } return "user/wizard/wizend"; @@ -184,7 +184,7 @@ public String wiz5Workflow(@ModelAttribute("userEppn") String userEppn, @PathVar } else { Workflow workflow = workflowService.getById(id); model.addAttribute("workflow", workflow); - eventService.publishEvent(new JsonMessage("error", "Un circuit de signature porte déjà ce nom"), "user", eventService.getClientIdByEppn(userEppn)); +// eventService.publishEvent(new JsonMessage("error", "Un circuit de signature porte déjà ce nom"), "user", eventService.getClientIdByEppn(userEppn)); return "user/wizard/wiz-save-workflow"; } } @@ -233,10 +233,11 @@ public String delete(@ModelAttribute("userEppn") String userEppn, @PathVariable( if (!workflow.getCreateBy().getEppn().equals(userEppn)) { redirectAttributes.addFlashAttribute("message", new JsonMessage("error", "Non autorisé")); } else { - if(workflowService.delete(workflow)) { + try { + workflowService.delete(workflow); redirectAttributes.addFlashAttribute("message", new JsonMessage("info", "Circuit supprimé")); - } else { - redirectAttributes.addFlashAttribute("message", new JsonMessage("error", "Impossible de supprimer ce circuit car il contient des demandes")); + } catch (EsupSignatureException e) { + redirectAttributes.addFlashAttribute("message", new JsonMessage("error", e.getMessage())); } } return "redirect:/user/"; diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/user/WorkflowController.java b/src/main/java/org/esupportail/esupsignature/web/controller/user/WorkflowController.java index 79b0f746e..32c164065 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/user/WorkflowController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/user/WorkflowController.java @@ -3,6 +3,7 @@ import org.esupportail.esupsignature.entity.Workflow; import org.esupportail.esupsignature.entity.WorkflowStep; import org.esupportail.esupsignature.entity.enums.SignType; +import org.esupportail.esupsignature.exception.EsupSignatureException; import org.esupportail.esupsignature.service.WorkflowService; import org.esupportail.esupsignature.service.WorkflowStepService; import org.esupportail.esupsignature.web.ws.json.JsonMessage; @@ -99,15 +100,19 @@ public String addStep(@ModelAttribute("userEppn") String userEppn, @PreAuthorize("@preAuthorizeService.workflowOwner(#id, #userEppn)") public String delete(@ModelAttribute("userEppn") String userEppn, @PathVariable("id") Long id, RedirectAttributes redirectAttributes) { Workflow workflow = workflowService.getById(id); - workflowService.delete(workflow); - redirectAttributes.addFlashAttribute("message", new JsonMessage("info", "Le circuit à bien été supprimé")); + try { + workflowService.delete(workflow); + redirectAttributes.addFlashAttribute("message", new JsonMessage("info", "Le circuit à bien été supprimé")); + } catch (EsupSignatureException e) { + redirectAttributes.addFlashAttribute("message", new JsonMessage("error", e.getMessage())); + } return "redirect:/"; } @DeleteMapping(value = "/silent-delete/{id}", produces = "text/html") @PreAuthorize("@preAuthorizeService.workflowOwner(#id, #userEppn)") @ResponseBody - public void silentDelete(@ModelAttribute("userEppn") String userEppn, @PathVariable("id") Long id) { + public void silentDelete(@ModelAttribute("userEppn") String userEppn, @PathVariable("id") Long id) throws EsupSignatureException { Workflow workflow = workflowService.getById(id); workflowService.delete(workflow); } diff --git a/src/main/java/org/esupportail/esupsignature/web/otp/WsOtpSignController.java b/src/main/java/org/esupportail/esupsignature/web/otp/WsOtpSignController.java index 58b4b5892..c58903814 100644 --- a/src/main/java/org/esupportail/esupsignature/web/otp/WsOtpSignController.java +++ b/src/main/java/org/esupportail/esupsignature/web/otp/WsOtpSignController.java @@ -4,9 +4,9 @@ import org.esupportail.esupsignature.exception.EsupSignatureException; import org.esupportail.esupsignature.exception.EsupSignatureUserException; import org.esupportail.esupsignature.service.UserService; +import org.esupportail.esupsignature.service.interfaces.sms.SmsService; import org.esupportail.esupsignature.service.security.otp.Otp; import org.esupportail.esupsignature.service.security.otp.OtpService; -import org.esupportail.esupsignature.service.interfaces.sms.SmsService; import org.esupportail.esupsignature.web.ws.json.JsonMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,6 +14,7 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; @@ -25,6 +26,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; +import java.util.stream.Collectors; + import static org.springframework.security.web.context.HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY; @ConditionalOnProperty(value = "sms.enable-sms", havingValue = "true") @@ -60,6 +63,8 @@ public String signin(@PathVariable String urlId, Model model) { logger.error(e.getMessage(), e); } otp.setSmsSended(true); + } else { + return "otp/expired"; } model.addAttribute("urlid", urlId); return "otp/signin"; @@ -80,6 +85,7 @@ public String auth(@RequestParam String urlId, @RequestParam String password, Mo Authentication authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken); SecurityContext securityContext = SecurityContextHolder.getContext(); securityContext.setAuthentication(authentication); + userService.updateRoles(user.getEppn(), authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList())); HttpSession httpSession = req.getSession(true); httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, securityContext); model.addAttribute("user", user); diff --git a/src/main/java/org/esupportail/esupsignature/web/ws/WorkflowWsController.java b/src/main/java/org/esupportail/esupsignature/web/ws/WorkflowWsController.java index 8c0e240d2..a2802d024 100644 --- a/src/main/java/org/esupportail/esupsignature/web/ws/WorkflowWsController.java +++ b/src/main/java/org/esupportail/esupsignature/web/ws/WorkflowWsController.java @@ -52,9 +52,10 @@ public List getAll() { @DeleteMapping("/{id}") public ResponseEntity delete(@PathVariable Long id) { Workflow workflow = workflowService.getById(id); - if (workflowService.delete(workflow)) { + try { + workflowService.delete(workflow); return new ResponseEntity<>(HttpStatus.OK); - } else { + } catch (EsupSignatureException e) { return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } diff --git a/src/main/java/org/esupportail/esupsignature/web/ws/WsExportController.java b/src/main/java/org/esupportail/esupsignature/web/ws/WsExportController.java index a192eef77..f5962d8d4 100644 --- a/src/main/java/org/esupportail/esupsignature/web/ws/WsExportController.java +++ b/src/main/java/org/esupportail/esupsignature/web/ws/WsExportController.java @@ -35,7 +35,7 @@ public class WsExportController { @GetMapping(value = "/form/{name}/datas/csv", produces="text/csv") public ResponseEntity getFormDatasCsv(@PathVariable String name, HttpServletResponse response) { - List forms = formRepository.findFormByName(name); + List forms = formRepository.findFormByNameAndDeletedIsNullOrDeletedIsFalse(name); if (forms.size() > 0) { try { response.setContentType("text/csv; charset=utf-8"); @@ -56,7 +56,7 @@ public ResponseEntity getFormDatasCsv(@PathVariable String name, HttpServl @ResponseBody @GetMapping(value = "/form/{name}/datas/json", produces = MediaType.APPLICATION_JSON_VALUE) public List> getFormDatasJson(@PathVariable String name) { - List forms = formRepository.findFormByName(name); + List forms = formRepository.findFormByNameAndDeletedIsNullOrDeletedIsFalse(name); if (forms.size() > 0) { try { return dataExportService.getDatasToExport(forms); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index abd5ce496..79cf6b209 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -184,6 +184,7 @@ server: remote-ip-header: X-Forwarded-For sign: + aes-key : "0000000000000000" cades-digest-algorithm: SHA256 cades-signature-level: CAdES_BASELINE_T container-type: ASiC_E diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties index d0be9a26c..79bf31ad5 100644 --- a/src/main/resources/i18n/messages.properties +++ b/src/main/resources/i18n/messages.properties @@ -159,6 +159,9 @@ label.cert.validate = Validate a certificate label.validation.policy = Validation policy constrains label.validation.default.policy.file = Validate signatures and whether they are : AdES, AdES/QC or QES. All certificates and their related chains are validated against the EU MS TSL. label.validation.custom.policy.file = Custom validation constrains file +label.validation.visualrepresentation = Visual Representation +label.signatures.and.timestamps = Signatures and related timestamps +label.certificate.chains = Certificate chains label.report = Report label.validation.results = Validation results label.simple.report = Simple Report @@ -393,3 +396,37 @@ label.nexu.signature.process = NexU signature process label.nexu.download = Download the open source version of NexU label.nexu.more.info = more info label.nexu.ready = NexU ready. Please plug card reader, insert ID card and click on button below. + +label.country.code.EU = European Union +label.country.code.AT = Austria +label.country.code.BE = Belgium +label.country.code.BG = Bulgaria +label.country.code.HR = Croatia +label.country.code.CY = Cyprus +label.country.code.CZ = Czech Republic +label.country.code.DK = Denmark +label.country.code.EE = Estonia +label.country.code.FI = Finland +label.country.code.FR = France +label.country.code.DE = Germany +label.country.code.EL = Greece +label.country.code.HU = Hungary +label.country.code.IS = Iceland +label.country.code.IE = Ireland +label.country.code.IT = Italy +label.country.code.LV = Latvia +label.country.code.LI = Liechtenstein +label.country.code.LT = Lithuania +label.country.code.LU = Luxembourg +label.country.code.MT = Malta +label.country.code.NL = Netherlands +label.country.code.NO = Norway +label.country.code.PL = Poland +label.country.code.PT = Portugal +label.country.code.RO = Romania +label.country.code.SK = Slovakia +label.country.code.SI = Slovenia +label.country.code.ES = Spain +label.country.code.SE = Sweden +label.country.code.UK = United Kingdom +label.country.code.no_country = Unknown diff --git a/src/main/resources/keystore.p12 b/src/main/resources/keystore.p12 new file mode 100644 index 000000000..735166914 Binary files /dev/null and b/src/main/resources/keystore.p12 differ diff --git a/src/main/resources/policy/constraint.xml b/src/main/resources/policy/constraint.xml index c88b99c90..45053731e 100644 --- a/src/main/resources/policy/constraint.xml +++ b/src/main/resources/policy/constraint.xml @@ -23,7 +23,6 @@ - ANY_POLICY NO_POLICY @@ -36,14 +35,8 @@ - - - - - - @@ -75,7 +68,30 @@ - + + + RSA + DSA + ECDSA + + + DSA + RSA + ECDSA + + + SHA1 + SHA224 + SHA256 + SHA384 + SHA512 + SHA3-224 + SHA3-256 + SHA3-384 + SHA3-512 + RIPEMD160 + + @@ -85,9 +101,55 @@ - + + + RSA + DSA + ECDSA + + + DSA + RSA + ECDSA + + + SHA1 + SHA224 + SHA256 + SHA384 + SHA512 + SHA3-224 + SHA3-256 + SHA3-384 + SHA3-512 + RIPEMD160 + + - + + + RSA + DSA + ECDSA + + + DSA + RSA + ECDSA + + + SHA1 + SHA224 + SHA256 + SHA384 + SHA512 + SHA3-224 + SHA3-256 + SHA3-384 + SHA3-512 + RIPEMD160 + + @@ -97,7 +159,6 @@ - @@ -151,7 +211,30 @@ - + + + RSA + DSA + ECDSA + + + DSA + RSA + ECDSA + + + SHA1 + SHA224 + SHA256 + SHA384 + SHA512 + SHA3-224 + SHA3-256 + SHA3-384 + SHA3-512 + RIPEMD160 + + @@ -161,9 +244,55 @@ - + + + RSA + DSA + ECDSA + + + DSA + RSA + ECDSA + + + SHA1 + SHA224 + SHA256 + SHA384 + SHA512 + SHA3-224 + SHA3-256 + SHA3-384 + SHA3-512 + RIPEMD160 + + - + + + RSA + DSA + ECDSA + + + DSA + RSA + ECDSA + + + SHA1 + SHA224 + SHA256 + SHA384 + SHA512 + SHA3-224 + SHA3-256 + SHA3-384 + SHA3-512 + RIPEMD160 + + @@ -171,7 +300,6 @@ - - - - - - - - + - + @@ -247,7 +432,30 @@ - + + + RSA + DSA + ECDSA + + + DSA + RSA + ECDSA + + + SHA1 + SHA224 + SHA256 + SHA384 + SHA512 + SHA3-224 + SHA3-256 + SHA3-384 + SHA3-512 + RIPEMD160 + + @@ -257,85 +465,62 @@ - + + + RSA + DSA + ECDSA + + + DSA + RSA + ECDSA + + + SHA1 + SHA224 + SHA256 + SHA384 + SHA512 + SHA3-224 + SHA3-256 + SHA3-384 + SHA3-512 + RIPEMD160 + + - + + + RSA + DSA + ECDSA + + + DSA + RSA + ECDSA + + + SHA1 + SHA224 + SHA256 + SHA384 + SHA512 + SHA3-224 + SHA3-256 + SHA3-384 + SHA3-512 + RIPEMD160 + + - - - RSA - DSA - ECDSA - PLAIN-ECDSA - - - - DSA - RSA - ECDSA - PLAIN-ECDSA - - - - MD2 - MD5 - SHA1 - SHA224 - SHA256 - SHA384 - SHA512 - SHA3-224 - SHA3-256 - SHA3-384 - SHA3-512 - RIPEMD160 - WHIRLPOOL - - - - MD2 - MD5 - SHA1 - SHA224 - SHA256 - SHA384 - SHA512 - SHA3-224 - SHA3-256 - SHA3-384 - SHA3-512 - RIPEMD160 - WHIRLPOOL - - - DSA - DSA - DSA - DSA - RSA - RSA - RSA - RSA - ECDSA - ECDSA - ECDSA - ECDSA - ECDSA - ECDSA - PLAIN-ECDSA - PLAIN-ECDSA - PLAIN-ECDSA - PLAIN-ECDSA - PLAIN-ECDSA - PLAIN-ECDSA - - - - - - - + + diff --git a/src/main/resources/policy/custom-constraint.xml b/src/main/resources/policy/custom-constraint.xml index 8abc6ae46..9c24dd1b4 100644 --- a/src/main/resources/policy/custom-constraint.xml +++ b/src/main/resources/policy/custom-constraint.xml @@ -19,6 +19,7 @@ application/vnd.etsi.asic-e+zip + @@ -35,7 +36,7 @@ - + @@ -54,8 +55,8 @@ - - + + nonRepudiation @@ -97,7 +98,7 @@ - + @@ -152,6 +153,8 @@ + + @@ -176,7 +179,7 @@ - + @@ -195,8 +198,8 @@ - - + + nonRepudiation @@ -238,7 +241,7 @@ - + @@ -311,20 +314,21 @@ - + + - + - + @@ -358,7 +362,7 @@ - + @@ -413,7 +417,7 @@ - + @@ -425,7 +429,7 @@ - + @@ -458,7 +462,7 @@ - + @@ -520,9 +524,9 @@ - + - + diff --git a/src/main/resources/self_signed_tsa.p12 b/src/main/resources/self_signed_tsa.p12 new file mode 100644 index 000000000..626dc9de3 Binary files /dev/null and b/src/main/resources/self_signed_tsa.p12 differ diff --git a/src/main/resources/static/css/app.css b/src/main/resources/static/css/app.css index 0f93cd45d..7019e7c32 100644 --- a/src/main/resources/static/css/app.css +++ b/src/main/resources/static/css/app.css @@ -1,3 +1,5 @@ +@import 'flags.css'; + @font-face { font-family: 'FontAwesome'; src: url('/webjars/font-awesome/5.15.2/webfonts/fa-solid-900.woff') format('woff'), @@ -72,7 +74,7 @@ pre { } :not(section) > textarea::placeholder { - background-color: #ff8f9e; + background-color: #ffeeba; color: black !important; } @@ -181,10 +183,6 @@ code { margin-top: 10px; } -.nav-item { - margin-right: 5px; -} - .loader { border: 5px solid #f3f3f3; -webkit-animation: spin 1s linear infinite; @@ -550,6 +548,11 @@ input:checked + .slider:before { max-width: 60px; } +.scrollbar-lite { + scrollbar-width: none; + overflow-y:scroll; +} + .scrollbar-lite::-webkit-scrollbar { width: 5px; background-color: transparent; @@ -912,6 +915,17 @@ height: 100%; border-bottom : 1px solid #000000; } + +.nav-item.ws-tab { + margin-bottom: -1px; + margin-right: 5px; + border-bottom : 1px solid #000000; +} + +.nav-item.ws-tab.active { + border-bottom : 1px solid #e2e3e5; +} + .nav-tabs .nav-link { color: #6c757d; border-color: #6c757d !important; @@ -919,7 +933,7 @@ height: 100%; /*background-color: #dee2e6;*/ } -.nav-tabs .nav-link.current { +.nav-link.current { color: black; border-color: #000 #000 #e2e3e5 #000 !important; @@ -1178,7 +1192,7 @@ textarea:placeholder-shown.required-field { .fixed-action-btns { position: fixed; - right: 50px; + right: 1vw; bottom: 80px; margin-bottom: 0; z-index: 6; @@ -1378,6 +1392,10 @@ input:focus, textarea:focus, select:focus { display: none; } +.stampAnnotation:hover { + border: 1px solid green !important; +} + .bg-striped { background-image: linear-gradient(135deg, #8a4848 25%, #474747 25%, #474747 50%, #8a4848 50%, #8a4848 75%, #474747 75%, #474747 100%); background-size: 28.28px 28.28px; @@ -1572,7 +1590,7 @@ input:focus, textarea:focus, select:focus { display: inline !important; } .d-xxl-table-cell { - display: table-cell!important; + display: table-cell !important; } .d-xxl-block { display: block !important; @@ -1585,6 +1603,11 @@ input:focus, textarea:focus, select:focus { } } +@media (min-width: 1600px) { + .d-xxxl-table-cell { + display: table-cell !important; + } +} .ss-single-selected { vertical-align: middle !important; margin: auto !important; diff --git a/src/main/resources/static/css/flags.css b/src/main/resources/static/css/flags.css new file mode 100644 index 000000000..26b2a6490 --- /dev/null +++ b/src/main/resources/static/css/flags.css @@ -0,0 +1,149 @@ + +.small_flag { + display: block; + width: 32px; + height : 24px; + float: left; + border: 1px solid #ececec; + margin-right: 5px; +} + +.flag { + display: block; + width: 64px; + height : 48px; + border: 1px solid #ececec; +} + +.flag_AT { + background: url(../images/flags/at.svg); + background-size: contain; +} +.flag_BG { + background: url(../images/flags/bg.svg); + background-size: contain; +} +.flag_CZ { + background: url(../images/flags/cz.svg); + background-size: contain; +} +.flag_DK { + background: url(../images/flags/dk.svg); + background-size: contain; +} +.flag_EL { + background: url(../images/flags/el.svg); + background-size: contain; +} +.flag_EU { + background: url(../images/flags/eu.svg); + background-size: contain; +} +.flag_FR { + background: url(../images/flags/fr.svg); + background-size: contain; +} +.flag_HU { + background: url(../images/flags/hu.svg); + background-size: contain; +} +.flag_IS { + background: url(../images/flags/is.svg); + background-size: contain; +} +.flag_LI { + background: url(../images/flags/li.svg); + background-size: contain; +} +.flag_LU { + background: url(../images/flags/lu.svg); + background-size: contain; +} +.flag_MT { + background: url(../images/flags/mt.svg); + background-size: contain; +} +.flag_NO { + background: url(../images/flags/no.svg); + background-size: contain; +} +.flag_PT { + background: url(../images/flags/pt.svg); + background-size: contain; +} +.flag_SE { + background: url(../images/flags/se.svg); + background-size: contain; +} +.flag_SK { + background: url(../images/flags/sk.svg); + background-size: contain; +} +.flag_BE { + background: url(../images/flags/be.svg); + background-size: contain; +} +.flag_CY { + background: url(../images/flags/cy.svg); + background-size: contain; +} +.flag_DE { + background: url(../images/flags/de.svg); + background-size: contain; +} +.flag_EE { + background: url(../images/flags/ee.svg); + background-size: contain; +} +.flag_ES { + background: url(../images/flags/es.svg); + background-size: contain; +} +.flag_FI { + background: url(../images/flags/fi.svg); + background-size: contain; +} +.flag_HR { + background: url(../images/flags/hr.svg); + background-size: contain; +} +.flag_IE { + background: url(../images/flags/ie.svg); + background-size: contain; +} +.flag_IT { + background: url(../images/flags/it.svg); + background-size: contain; +} +.flag_LT { + background: url(../images/flags/lt.svg); + background-size: contain; +} +.flag_LV { + background: url(../images/flags/lv.svg); + background-size: contain; +} +.flag_NL { + background: url(../images/flags/nl.svg); + background-size: contain; +} +.flag_PL { + background: url(../images/flags/pl.svg); + background-size: contain; +} +.flag_RO { + background: url(../images/flags/ro.svg); + background-size: contain; +} +.flag_SI { + background: url(../images/flags/si.svg); + background-size: contain; +} +.flag_UK { + background: url(../images/flags/uk.svg); + background-size: contain; +} +.flag_no_country { + background: url(../images/flags/no_country.svg); + background-size: contain; +} \ No newline at end of file diff --git a/src/main/resources/static/images/flags/at.svg b/src/main/resources/static/images/flags/at.svg new file mode 100644 index 000000000..38dd0ecef --- /dev/null +++ b/src/main/resources/static/images/flags/at.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/main/resources/static/images/flags/be.svg b/src/main/resources/static/images/flags/be.svg new file mode 100644 index 000000000..44a0aed26 --- /dev/null +++ b/src/main/resources/static/images/flags/be.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/images/flags/bg.svg b/src/main/resources/static/images/flags/bg.svg new file mode 100644 index 000000000..d0501130c --- /dev/null +++ b/src/main/resources/static/images/flags/bg.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/images/flags/cy.svg b/src/main/resources/static/images/flags/cy.svg new file mode 100644 index 000000000..f21a4477d --- /dev/null +++ b/src/main/resources/static/images/flags/cy.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/main/resources/static/images/flags/cz.svg b/src/main/resources/static/images/flags/cz.svg new file mode 100644 index 000000000..d27a0d5ba --- /dev/null +++ b/src/main/resources/static/images/flags/cz.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/de.svg b/src/main/resources/static/images/flags/de.svg new file mode 100644 index 000000000..089f99952 --- /dev/null +++ b/src/main/resources/static/images/flags/de.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/images/flags/dk.svg b/src/main/resources/static/images/flags/dk.svg new file mode 100644 index 000000000..031d2032a --- /dev/null +++ b/src/main/resources/static/images/flags/dk.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/static/images/flags/ee.svg b/src/main/resources/static/images/flags/ee.svg new file mode 100644 index 000000000..56724db64 --- /dev/null +++ b/src/main/resources/static/images/flags/ee.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/images/flags/el.svg b/src/main/resources/static/images/flags/el.svg new file mode 100644 index 000000000..441181301 --- /dev/null +++ b/src/main/resources/static/images/flags/el.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/es.svg b/src/main/resources/static/images/flags/es.svg new file mode 100644 index 000000000..67b456a6d --- /dev/null +++ b/src/main/resources/static/images/flags/es.svg @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/eu.svg b/src/main/resources/static/images/flags/eu.svg new file mode 100644 index 000000000..572a8e698 --- /dev/null +++ b/src/main/resources/static/images/flags/eu.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/fi.svg b/src/main/resources/static/images/flags/fi.svg new file mode 100644 index 000000000..a5518b733 --- /dev/null +++ b/src/main/resources/static/images/flags/fi.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/static/images/flags/fr.svg b/src/main/resources/static/images/flags/fr.svg new file mode 100644 index 000000000..cb3a021a7 --- /dev/null +++ b/src/main/resources/static/images/flags/fr.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/images/flags/hr.svg b/src/main/resources/static/images/flags/hr.svg new file mode 100644 index 000000000..7a8ad0977 --- /dev/null +++ b/src/main/resources/static/images/flags/hr.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/hu.svg b/src/main/resources/static/images/flags/hu.svg new file mode 100644 index 000000000..785e9be8a --- /dev/null +++ b/src/main/resources/static/images/flags/hu.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/images/flags/ie.svg b/src/main/resources/static/images/flags/ie.svg new file mode 100644 index 000000000..bd0b654f9 --- /dev/null +++ b/src/main/resources/static/images/flags/ie.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/images/flags/is.svg b/src/main/resources/static/images/flags/is.svg new file mode 100644 index 000000000..3adce8853 --- /dev/null +++ b/src/main/resources/static/images/flags/is.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/src/main/resources/static/images/flags/it.svg b/src/main/resources/static/images/flags/it.svg new file mode 100644 index 000000000..060927841 --- /dev/null +++ b/src/main/resources/static/images/flags/it.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/images/flags/li.svg b/src/main/resources/static/images/flags/li.svg new file mode 100644 index 000000000..1d00f1f50 --- /dev/null +++ b/src/main/resources/static/images/flags/li.svg @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/lt.svg b/src/main/resources/static/images/flags/lt.svg new file mode 100644 index 000000000..75c1c7a6a --- /dev/null +++ b/src/main/resources/static/images/flags/lt.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/images/flags/lu.svg b/src/main/resources/static/images/flags/lu.svg new file mode 100644 index 000000000..80c2270fc --- /dev/null +++ b/src/main/resources/static/images/flags/lu.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/static/images/flags/lv.svg b/src/main/resources/static/images/flags/lv.svg new file mode 100644 index 000000000..65ff5decc --- /dev/null +++ b/src/main/resources/static/images/flags/lv.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/main/resources/static/images/flags/mt.svg b/src/main/resources/static/images/flags/mt.svg new file mode 100644 index 000000000..6333fa64f --- /dev/null +++ b/src/main/resources/static/images/flags/mt.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/nl.svg b/src/main/resources/static/images/flags/nl.svg new file mode 100644 index 000000000..7dfbd4152 --- /dev/null +++ b/src/main/resources/static/images/flags/nl.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/images/flags/no.svg b/src/main/resources/static/images/flags/no.svg new file mode 100644 index 000000000..490f80d57 --- /dev/null +++ b/src/main/resources/static/images/flags/no.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/no_country.svg b/src/main/resources/static/images/flags/no_country.svg new file mode 100644 index 000000000..42fbbca84 --- /dev/null +++ b/src/main/resources/static/images/flags/no_country.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/pl.svg b/src/main/resources/static/images/flags/pl.svg new file mode 100644 index 000000000..f32275a30 --- /dev/null +++ b/src/main/resources/static/images/flags/pl.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/main/resources/static/images/flags/pt.svg b/src/main/resources/static/images/flags/pt.svg new file mode 100644 index 000000000..53a6dcfb6 --- /dev/null +++ b/src/main/resources/static/images/flags/pt.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/ro.svg b/src/main/resources/static/images/flags/ro.svg new file mode 100644 index 000000000..b5d3e8a56 --- /dev/null +++ b/src/main/resources/static/images/flags/ro.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/images/flags/se.svg b/src/main/resources/static/images/flags/se.svg new file mode 100644 index 000000000..bff128b27 --- /dev/null +++ b/src/main/resources/static/images/flags/se.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/si.svg b/src/main/resources/static/images/flags/si.svg new file mode 100644 index 000000000..2a84bc194 --- /dev/null +++ b/src/main/resources/static/images/flags/si.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/images/flags/sk.svg b/src/main/resources/static/images/flags/sk.svg new file mode 100644 index 000000000..f3dd1ab0d --- /dev/null +++ b/src/main/resources/static/images/flags/sk.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/main/resources/static/images/flags/uk.svg b/src/main/resources/static/images/flags/uk.svg new file mode 100644 index 000000000..64d7c8171 --- /dev/null +++ b/src/main/resources/static/images/flags/uk.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/js/modules/ui/GlobalUi.js b/src/main/resources/static/js/modules/ui/GlobalUi.js index 651c975cf..fe88dff68 100644 --- a/src/main/resources/static/js/modules/ui/GlobalUi.js +++ b/src/main/resources/static/js/modules/ui/GlobalUi.js @@ -1,5 +1,4 @@ import {default as SelectUser} from "../utils/SelectUser.js"; -import {SseSubscribe} from "../utils/SseSubscribe.js"; import {CsrfToken} from "../../prototypes/CsrfToken.js"; import {WizUi} from "./WizUi.js"; @@ -21,10 +20,6 @@ export class GlobalUi { this.autoHide = $('.auto-hide'); this.markAsReadButtons = $('button[id^="markAsReadButton_"]'); this.markHelpAsReadButtons = $('button[id^="markHelpAsReadButton_"]'); - if(authUserEppn != null) { - sessionStorage.setItem("sseId", this.csrf.token) - this.sseSubscribe = new SseSubscribe(this.csrf.token); - } this.initListeners(); this.initBootBox(); this.initSideBar(); @@ -239,6 +234,7 @@ export class GlobalUi { if(!url.match("/user/users+[\\w\\W]+") && !url.match("/user/users") && !url.match("/admin/+[\\w\\W]+") + && !url.match("/manager/+[\\w\\W]+") && !url.match("^/user/$") && !url.match("^/user/signrequests$") && !url.match("/user/signrequests/+[\\w\\W]+")) { diff --git a/src/main/resources/static/js/modules/ui/forms/FormUi.js b/src/main/resources/static/js/modules/ui/forms/FormUi.js index c5fb1af60..a46b62d1f 100644 --- a/src/main/resources/static/js/modules/ui/forms/FormUi.js +++ b/src/main/resources/static/js/modules/ui/forms/FormUi.js @@ -1,16 +1,17 @@ -import {SseDispatcher} from "../../utils/SseDispatcher.js"; import {Message} from "../../../prototypes/Message.js"; +import Toast from "../Toast.js"; export default class FormUi { - constructor(formId, prefillTypes) { + constructor(domain, formId, prefillTypes) { console.info("Starting Form UI for " + formId); + this.toast = new Toast(); this.formId = formId; this.btnAddField = $('#btn-add-field'); this.btnRemove = $('#btn-remove'); this.btnSaveFields = $('#saveButton'); - this.sseDispatcher = new SseDispatcher(); this.prefillTypes = prefillTypes; + this.domain = domain; this.initListeners(); } @@ -97,7 +98,6 @@ export default class FormUi { message.type = "info"; message.text = "Enregistrement en cours"; message.object = null; - this.sseDispatcher.dispatchEvent("user", message); let self = this; let fieldsUpdates = $('form[name^="field-update"]'); let i = 1; @@ -106,7 +106,7 @@ export default class FormUi { console.log(fd.get("_csrf")); $.ajax({ type: "POST", - url: "/admin/forms/field/" + $(this).attr('id') + "/update?_csrf=" + fd.get("_csrf"), + url: "/" + self.domain + "/forms/field/" + $(this).attr('id') + "/update?_csrf=" + fd.get("_csrf"), data: fd, processData: false, contentType: false, @@ -116,7 +116,7 @@ export default class FormUi { message.type = "success"; message.text = "Modifications enregistrées"; message.object = null; - self.sseDispatcher.dispatchEvent("user", message); + self.toast.launch(message); } i++; }, @@ -125,7 +125,7 @@ export default class FormUi { message.type = "error"; message.text = "Problème lors de l'enregistrement"; message.object = null; - this.sseDispatcher.dispatchEvent("user", message); + self.toast.launch(message); }, }); }); diff --git a/src/main/resources/static/js/modules/ui/signrequests/Nexu.js b/src/main/resources/static/js/modules/ui/signrequests/Nexu.js index 8df679c5a..f4db4c503 100644 --- a/src/main/resources/static/js/modules/ui/signrequests/Nexu.js +++ b/src/main/resources/static/js/modules/ui/signrequests/Nexu.js @@ -1,30 +1,31 @@ export class Nexu { - constructor(nexuUrl, nexuVersion, rootUrl, addExtra, id) { - this.nexuUrl = nexuUrl; - this.nexuVersion = nexuVersion; - Nexu.rootUrl = rootUrl; + constructor(addExtra, id) { + this.globalProperties = JSON.parse(sessionStorage.getItem("globalProperties")); + this.nexuUrl = this.globalProperties.nexuUrl; + this.nexuVersion = this.globalProperties.nexuVersion; + Nexu.rootUrl = this.globalProperties.rootUrl; Nexu.addExtra = addExtra; Nexu.id = id; this.tokenId = null; this.keyId = null; - this.checkNexuClient(); + this.bindingPorts = "9795, 9886, 9887, 9888"; + this.detectedPort = ""; this.successDiv = $("#success"); this.successDiv.hide(); - } - - getCertificates() { - Nexu.updateProgressBar("Chargement des certificats", "25%"); - try { - nexu_get_certificates(Nexu.getDataToSign, Nexu.error); - } - catch(e) { - console.error(e); - const merror = { - errorMessage: "Problème avec l'application NexU" - }; - error(Object.create(merror)); - } + $("#warning-text").html("NexU not detected or not started ! "); + $("#nexu_missing_alert").show(); + $("#signFormConfirm").hide(); + let self = this; + this.checkNexuClient().then(function (){ + console.warn("NexU detected"); + $("#warning-text").html(""); + $("#nexu_missing_alert").hide(); + $("#signFormConfirm").show(); + if(id != null) { + self.loadScript(); + } + }); } static getDataToSign(certificateData) { @@ -105,28 +106,35 @@ export class Nexu { } checkNexuClient() { - console.log("Start checking NexU"); - $.ajax({ - type: "GET", - url: this.nexuUrl + "/nexu-info", - crossDomain: true, - dataType: "json", - context : this, - success: data => this.checkNexu(data) - }).fail(function (error) { - console.warn("NexU not detected or not started ! " + JSON.stringify(error)); - $("#warning-text").html("NexU not detected or not started ! "); - $("#nexu_missing_alert").show(); - $("#signFormConfirm").hide(); + return new Promise((resolve, reject) => { + console.log("Start checking NexU"); + let ports = this.bindingPorts.split(","); + let detectNexu = false; + let self = this; + ports.forEach(function (port){ + let url = "http://localhost:" + port.trim() + "/nexu-info"; + console.info("check " + url); + $.ajax({ + type: "GET", + url: url, + crossDomain: true, + dataType: "json", + context : this, + success: function (data) { + console.info("nexu detected on " + url); + detectNexu = true; + self.detectedPort = port.trim(); + self.checkNexu(data); + resolve("nexu detected"); + } + }); + }); }); - } checkNexu(data) { console.log("Check NexU"); - if(data.version.startsWith(this.nexuVersion) || data.version.startsWith("1.23") || data.version.startsWith("1.22")) { - console.log("Loading script..."); - this.loadScript(); + if(data.version.startsWith(this.nexuVersion) || data.version.startsWith("1.23") || data.version.startsWith("1.22") || data.version.startsWith("1.8")) { $("#nexu_ready_alert").show(); $("#submit-button").prop('disabled', false); } else { @@ -137,14 +145,11 @@ export class Nexu { } loadScript() { - let xhrObj = new XMLHttpRequest(); - xhrObj.open('GET', this.nexuUrl + "/nexu.js"); - xhrObj.send(null); - let se = document.createElement('script'); - se.type = "text/javascript"; - se.text = xhrObj.responseText; - document.getElementsByTagName('head')[0].appendChild(se); - console.log("NexU script loaded"); + let url = "http://localhost:" + this.detectedPort + "/nexu.js"; + console.info("loading nexu script : " + url); + $.getScript(url, function() { + nexu_get_certificates(Nexu.getDataToSign, Nexu.error); + }); } } \ No newline at end of file diff --git a/src/main/resources/static/js/modules/ui/signrequests/SignPosition.js b/src/main/resources/static/js/modules/ui/signrequests/SignPosition.js index d54f3a096..0d8926571 100644 --- a/src/main/resources/static/js/modules/ui/signrequests/SignPosition.js +++ b/src/main/resources/static/js/modules/ui/signrequests/SignPosition.js @@ -29,12 +29,17 @@ export class SignPosition extends EventFactory { signRequestParams.signImageNumber = signImageNumber; } if (this.signImages != null && this.signImages.length > 0) { - if (currentSignRequestParams[i].xPos > -1 && currentSignRequestParams[i].yPos > -1) { - signRequestParams.xPos = currentSignRequestParams[i].xPos; - signRequestParams.yPos = currentSignRequestParams[i].yPos; - signRequestParams.signPageNumber = currentSignRequestParams[i].signPageNumber; + if (currentSignRequestParams[i] != null) { + if (currentSignRequestParams[i].xPos > -1 && currentSignRequestParams[i].yPos > -1) { + signRequestParams.xPos = currentSignRequestParams[i].xPos; + signRequestParams.yPos = currentSignRequestParams[i].yPos; + signRequestParams.signPageNumber = currentSignRequestParams[i].signPageNumber; + } } } + if(localStorage.getItem('addWatermark') != null) { + signRequestParams.addWatermark = localStorage.getItem('addWatermark') === 'true'; + } this.signRequestParamses.set(i + "", signRequestParams); } } else { @@ -71,7 +76,11 @@ export class SignPosition extends EventFactory { this.cross.attr("data-current", "true"); this.cross.css("position", "fixed"); this.cross.css("margin-left", "270px"); - this.cross.css("margin-top", "180px"); + if($("#ws-tabs").length) { + this.cross.css("margin-top", "222px"); + } else { + this.cross.css("margin-top", "180px"); + } this.cross.css("left", "0px"); this.cross.css("top", "0px"); } @@ -82,21 +91,29 @@ export class SignPosition extends EventFactory { } if (this.signType === "visa" || this.signType === "hiddenVisa") { - this.toggleWatermark(); + if(!this.getCurrentSignParams().addWatermark) this.toggleWatermark(); this.toggleExtraInfos(); this.visualActive = false; + } else { + if(this.getCurrentSignParams().addWatermark) { + this.getCurrentSignParams().addWatermark = false; + this.toggleWatermark(); + } } if (this.signType === "visa") { this.toggleVisual(); $("#visualButton").remove(); } - if(this.signType === "nexuSign") { + if(this.signType === "nexuSign" || this.signType === "certSign") { $("#visualButton").removeClass("d-none"); } this.initListeners(); this.borders.addClass("anim-border"); this.borders.removeClass("static-border"); this.faImages = ["check-solid", "times-solid", "circle-regular", "minus-solid"]; + if(localStorage.getItem("zoom") != null) { + this.updateSignZoom(parseFloat(localStorage.getItem("zoom"))); + } } initListeners() { @@ -143,7 +160,9 @@ export class SignPosition extends EventFactory { } this.signExtraButton.on('click', e => this.toggleExtraInfos()); this.signExtraOnTopButton.on('click', e => this.toggleExtraPosition()); - this.displayMoreToolsButton.show(); + if(this.signType !== "visa" && this.signType !== "hiddenVisa") { + this.displayMoreToolsButton.show(); + } this.displayMoreToolsButton.on('click', e => this.displayMoreTools()); this.hideMoreToolsButton.on('click', e => this.hideMoreTools()); this.watermarkButton.on('click', e => this.toggleWatermark()); @@ -229,7 +248,6 @@ export class SignPosition extends EventFactory { let signRequestParams; if(this.signRequestParamses.get(currentSign) == null) { signRequestParams = new SignRequestParams(); - signRequestParams.xPos = -1; signRequestParams.yPos = -1; signRequestParams.signPageNumber = this.getCurrentSignParams().signPageNumber; @@ -348,6 +366,11 @@ export class SignPosition extends EventFactory { this.hideMoreTools(); this.initCrossToolsListeners(); this.dragSignature(); + let textExtra = $("#textExtra_" + this.currentSign); + textExtra.on("input", e => this.refreshExtraText(e)); + textExtra.on("click mouseup mousedown", function (e){ + e.stopPropagation(); + }); } lockCurrentSign() { @@ -398,12 +421,12 @@ export class SignPosition extends EventFactory { } changeSignSize(result) { - if(this.signImages[this.getCurrentSignParams().signImageNumber] != null) { + // if(this.signImages[this.getCurrentSignParams().signImageNumber] != null) { this.getCurrentSignParams().signWidth = Math.round((result.w + this.getCurrentSignParams().extraWidth) * this.getCurrentSignParams().signScale * this.fixRatio); this.getCurrentSignParams().signHeight = Math.round((result.h + this.getCurrentSignParams().extraHeight) * this.getCurrentSignParams().signScale * this.fixRatio); this.changeSignColor(Color.rgbToHex(this.getCurrentSignParams().red, this.getCurrentSignParams().green, this.getCurrentSignParams().blue)); this.updateSignSize(); - } + // } } getImageDimensions(file) { @@ -457,12 +480,16 @@ export class SignPosition extends EventFactory { signZoomOut(e) { e.stopPropagation(); - this.updateSignZoom(this.getCurrentSignParams().signScale - 0.1); + let zoom = this.getCurrentSignParams().signScale - 0.1; + this.updateSignZoom(zoom); + localStorage.setItem("zoom", Math.round(zoom * 10) / 10); } signZoomIn(e) { e.stopPropagation(); - this.updateSignZoom(this.getCurrentSignParams().signScale + 0.1); + let zoom = this.getCurrentSignParams().signScale + 0.1; + this.updateSignZoom(zoom); + localStorage.setItem("zoom", Math.round(zoom * 10) / 10); } resetSign() { @@ -659,7 +686,7 @@ export class SignPosition extends EventFactory { this.borders.css("height", 150); this.getCurrentSignParams().signWidth = 150; this.getCurrentSignParams().signHeight = 75; - $("#displayMoreTools_0").hide(); + this.displayMoreToolsButton.hide(); $("#signUndo_0").hide(); } } @@ -692,7 +719,9 @@ export class SignPosition extends EventFactory { } this.getCurrentSignParams().addWatermark = true; } - + if(this.signType !== "visa" && this.signType !== "hiddenVisa") { + localStorage.setItem('addWatermark', this.getCurrentSignParams().addWatermark); + } } toggleExtraInfos() { @@ -815,12 +844,14 @@ export class SignPosition extends EventFactory { this.getCurrentSignParams().green = rgb[1]; this.getCurrentSignParams().blue = rgb[2]; - let img = "data:image/jpeg;charset=utf-8;base64" + - ", " + this.signImages[this.getCurrentSignParams().signImageNumber]; let cross = this.cross; - Color.changeColInUri(img, "#000000", color).then(function (e) { - cross.css("background-image", "url('" + e + "')"); - }) + if (this.signImages[this.getCurrentSignParams().signImageNumber] != null) { + let img = "data:image/jpeg;charset=utf-8;base64" + + ", " + this.signImages[this.getCurrentSignParams().signImageNumber]; + Color.changeColInUri(img, "#000000", color).then(function (e) { + cross.css("background-image", "url('" + e + "')"); + }) + } let textExtra = $("#textExtra_" + this.currentSign); textExtra.css({"color" : color + ""}); } @@ -853,7 +884,6 @@ export class SignPosition extends EventFactory { addCheckImage() { this.addSign(); this.changeToFaImage(1); - this.forceRemoveExtra(); } addTimesImage() { diff --git a/src/main/resources/static/js/modules/ui/signrequests/SignUi.js b/src/main/resources/static/js/modules/ui/signrequests/SignUi.js index e79b74286..a58722c14 100644 --- a/src/main/resources/static/js/modules/ui/signrequests/SignUi.js +++ b/src/main/resources/static/js/modules/ui/signrequests/SignUi.js @@ -4,13 +4,13 @@ import {Step} from "../../../prototypes/Step.js"; export class SignUi { - constructor(id, dataId, formId, currentSignRequestParams, signImageNumber, currentSignType, signable, postits, isPdf, currentStepNumber, currentStepId, currentStepMultiSign, workflow, signImages, userName, csrf, fields, stepRepeatable, status, profile, action) { + constructor(id, dataId, formId, currentSignRequestParams, signImageNumber, currentSignType, signable, postits, isPdf, currentStepNumber, currentStepId, currentStepMultiSign, workflow, signImages, userName, csrf, fields, stepRepeatable, status, action, nbSignRequests) { console.info("Starting sign UI"); + this.globalProperties = JSON.parse(sessionStorage.getItem("globalProperties")); this.signRequestId = id; this.percent = 0; this.getProgressTimer = null; this.wait = $('#wait'); - this.passwordError = document.getElementById("passwordError"); this.workspace = null; this.signForm = document.getElementById("signForm"); this.csrf = new CsrfToken(csrf); @@ -22,8 +22,10 @@ export class SignUi { this.stepRepeatable = stepRepeatable; this.currentStepNumber = currentStepNumber; this.gotoNext = false; - this.profile = profile; + this.certTypeSelect = $("#certType"); + this.nbSignRequests = nbSignRequests; this.initListeners(); + this.initReportModal(); } initListeners() { @@ -37,8 +39,44 @@ export class SignUi { $("#launchNoInfiniteSignButton").click(); } }); + if(this.certTypeSelect) { + this.certTypeSelect.on("change", e => this.togglePasswordField()); + } + $("#copyButton").on('click', e => this.copy()); - document.addEventListener("sign", e => this.updateWaitModal(e)); + // document.addEventListener("sign", e => this.updateWaitModal(e)); + } + + initReportModal() { + let self = this; + $.ajax({ + url: "/user/validation/short/" + self.signRequestId, + type: 'GET', + success: function (data, textStatus, xhr) { + let modal = "" + + "" + + "" + + "" + + data + + ""; + $("body").append(modal); + $('#reportModal').on('hidden.bs.modal', function () { + $("div[id^='report_']").each(function() { + $(this).show(); + }); + }) + $("#reportModalBtn").removeClass("d-none"); + } + }); + } + + togglePasswordField(){ + let value = $("#certType").val(); + if(value === "etab") { + $("#password").hide(); + } else { + $("#password").show(); + } } launchNoInfiniteSign() { @@ -91,7 +129,8 @@ export class SignUi { } if(this.workspace != null) { this.signRequestUrlParams = { - 'password' : document.getElementById("password").value, + 'password' : $("#password").val(), + 'certType' : $("#certType").val(), 'signRequestParams' : JSON.stringify(Array.from(this.workspace.signPosition.signRequestParamses.values())), 'visual' : this.workspace.signPosition.visualActive, 'comment' : this.signComment.val(), @@ -113,59 +152,37 @@ export class SignUi { url: "/user/signrequests/sign/" + this.signRequestId + "/?" + self.csrf.parameterName + "=" + self.csrf.token, type: 'POST', data: signRequestUrlParams, - error: function(e) { - bootbox.alert("La signature s'est terminée, d'une façon inattendue. La page va s'actualiser", function() { - document.location.reload(); - }); - } - }); - } - - updateWaitModal(e) { - console.info("update wait modal"); - let message = e.detail - console.info(message); - this.percent = this.percent + 5; - if(message.type === "sign_system_error" || message.type === "not_authorized") { - console.error("sign error : system error"); - document.getElementById("signError").style.display = "block"; - document.getElementById("signError").innerHTML =" Erreur du système de signature : " + message.text; - document.getElementById("closeModal").style.display = "block"; - document.getElementById("bar").classList.remove("progress-bar-animated"); - } else if(message.type === "initNexu") { - console.info("redirect to NexU sign proccess"); - document.location.href="/user/nexu-sign/" + this.signRequestId; - }else if(message.type === "end") { - console.info("sign end"); - document.getElementById("bar-text").innerHTML = ""; - document.getElementById("bar").classList.remove("progress-bar-animated"); - document.getElementById("bar-text").innerHTML = message.text; - document.getElementById("bar").style.width = 100 + "%"; - if (this.gotoNext) { - document.location.href = $("#nextSignRequestButton").attr('href'); - } else { - if(this.profile != null && this.profile === "dev") { - document.location.href = "/user/signrequests/" + this.signRequestId; + success: function(data, textStatus, xhr) { + if(self.gotoNext) { + document.location.href = $("#nextSignRequestButton").attr('href'); } else { - document.location.href = "/user/"; + if(self.nbSignRequests > 1 || !self.globalProperties.returnToHomeAfterSign) { + document.location.href = "/user/signrequests/" + self.signRequestId; + } else { + document.location.href = "/user/"; + } + } + }, + error: function(data, textStatus, xhr) { + if(data.responseText === "initNexu") { + document.location.href="/user/nexu-sign/" + self.signRequestId; + } else { + $("#signSpinner").hide(); + console.error("sign error : " + data.responseText); + document.getElementById("signError").style.display = "block"; + document.getElementById("signError").innerHTML = " Erreur du système de signature : " + data.responseText; + document.getElementById("closeModal").style.display = "block"; } } - } else { - console.debug("update bar"); - document.getElementById("bar").style.display = "block"; - document.getElementById("bar").style.width = this.percent + "%"; - document.getElementById("bar-text").innerHTML = message.text; - } + }); } reset() { this.percent = 0; - this.passwordError.style.display = "none"; + $("#signSpinner").show(); document.getElementById("signError").style.display = "none"; document.getElementById("closeModal").style.display = "none"; document.getElementById("validModal").style.display = "none"; - document.getElementById("bar").style.display = "none"; - document.getElementById("bar").classList.add("progress-bar-animated"); } redirect() { diff --git a/src/main/resources/static/js/modules/ui/signrequests/WorkspacePdf.js b/src/main/resources/static/js/modules/ui/signrequests/WorkspacePdf.js index 2aff5a867..996d69512 100644 --- a/src/main/resources/static/js/modules/ui/signrequests/WorkspacePdf.js +++ b/src/main/resources/static/js/modules/ui/signrequests/WorkspacePdf.js @@ -2,7 +2,6 @@ import {PdfViewer} from "../../utils/PdfViewer.js"; import {SignPosition} from "./SignPosition.js"; import {WheelDetector} from "../../utils/WheelDetector.js"; import {Message} from "../../../prototypes/Message.js"; -import {SseDispatcher} from "../../utils/SseDispatcher.js"; export class WorkspacePdf { @@ -32,7 +31,7 @@ export class WorkspacePdf { } } if (this.isPdf) { - this.pdfViewer = new PdfViewer('/user/signrequests/get-last-file/' + id, signable, currentStepNumber, currentStepId, this.forcePageNum, fields); + this.pdfViewer = new PdfViewer('/user/signrequests/get-last-file/' + id, signable, currentStepNumber, currentStepId, this.forcePageNum, fields, false); } this.signPosition = new SignPosition( signType, @@ -42,7 +41,6 @@ export class WorkspacePdf { userName, signable, this.forcePageNum); this.mode = 'sign'; this.wheelDetector = new WheelDetector(); - this.sseDispatcher = new SseDispatcher(); this.signLaunchButton = $("#signLaunchButton"); this.addSpotEnabled = false; this.addCommentEnabled = false; @@ -54,7 +52,12 @@ export class WorkspacePdf { this.initDataFields(fields); if ((formId == null && workflow == null) || (currentStepMultiSign !== null && currentStepMultiSign)) { $("#second-tools").toggleClass("d-none d-flex"); - $("#workspace").css("margin-top", "170px"); + if($("#ws-tabs").length) { + $("#workspace").css("margin-top", "212px"); + } else { + $("#workspace").css("margin-top", "170px"); + } + } } @@ -169,6 +172,9 @@ export class WorkspacePdf { this.pdfViewer.adjustZoom(); this.initLaunchButtons(); this.pdfViewer.removeEventListener('ready'); + if(this.signPosition.signImages.length === 0 && this.signType !== "visa" && this.signType !== "hiddenVisa") { + this.signPosition.toggleVisual(); + } } initLaunchButtons() { @@ -220,7 +226,6 @@ export class WorkspacePdf { message.type = "success"; message.text = "Modifications enregistrées"; message.object = null; - // self.sseDispatcher.dispatchEvent("user", message); dataId.val(response); if (redirect) { location.href = "/user/datas/" + response + "/update"; @@ -260,7 +265,7 @@ export class WorkspacePdf { if ((self.signPosition.cross.css("position") === 'fixed' || self.signPosition.getCurrentSignParams().xPos === -1) && self.signPosition.visualActive) { bootbox.alert("Merci de placer la signature", function () { self.pdfViewer.initSavedValues(); - if (self.currentSignRequestParams != null) { + if (self.currentSignRequestParams != null && self.currentSignRequestParams[0] != null) { self.pdfViewer.renderPage(self.currentSignRequestParams[0].signPageNumber); } self.signPosition.firstDrag = true; @@ -614,7 +619,7 @@ export class WorkspacePdf { this.signPosition.cross.removeClass('d-none'); } this.pdfViewer.rotation = 0; - if (this.currentSignRequestParams != null && this.currentSignRequestParams.length > 0) { + if (this.currentSignRequestParams != null && this.currentSignRequestParams.length > 0 && this.currentSignRequestParams[0] != null) { if (!this.forcePageNum) { this.pdfViewer.renderPage(1); let signPage = this.currentSignRequestParams[0].signPageNumber; diff --git a/src/main/resources/static/js/modules/utils/PdfViewer.js b/src/main/resources/static/js/modules/utils/PdfViewer.js index b9dfc53c4..0e5802779 100644 --- a/src/main/resources/static/js/modules/utils/PdfViewer.js +++ b/src/main/resources/static/js/modules/utils/PdfViewer.js @@ -367,16 +367,18 @@ export class PdfViewer extends EventFactory { let datePickerIndex = 40; console.debug("rending pdfForm items with fields" + items); let signFieldNumber = 0; + let self = this; for (let i = 0; i < items.length; i++) { if(items[i].fieldType === undefined) { if(items[i].title && items[i].title.toLowerCase().includes('sign')) { signFieldNumber = signFieldNumber + 1; $('.popupWrapper').remove(); let signField = $('section[data-annotation-id=' + items[i].id + '] > div'); + signField.addClass("sign-field") signField.append('Champ signature ' + signFieldNumber + ''); - signField.addClass("sign-field"); // signField.addClass("d-none"); // signField.parent().remove(); + } continue; } @@ -607,7 +609,7 @@ export class PdfViewer extends EventFactory { break; } } - return (isIncludeCurrentStep || (this.currentStepNumber === 0 && dataField.stepZero)) && this.signable + return (isIncludeCurrentStep || (this.currentStepNumber === 0 && dataField.stepZero));// && this.signable } renderPdfForm(items) { @@ -617,15 +619,27 @@ export class PdfViewer extends EventFactory { console.debug(">>Start compute item"); if(items[i].fieldType === undefined) { console.log(items[i]); - // if(items[i].title && items[i].title.toLowerCase().includes('sign')) { - // signFieldNumber = signFieldNumber + 1; - // $('.popupWrapper').remove(); - // let signField = $('section[data-annotation-id=' + items[i].id + '] > div'); - // signField.append('Champ signature ' + signFieldNumber + ''); - // signField.addClass("sign-field"); - // // signField.addClass("d-none"); - // // signField.parent().remove(); - // } + if(items[i].title && items[i].title.toLowerCase().includes('sign')) { + signFieldNumber = signFieldNumber + 1; + $('.popupWrapper').remove(); + let section = $('section[data-annotation-id=' + items[i].id +']'); + let signField = $('section[data-annotation-id=' + items[i].id + '] > div'); + signField.addClass("sign-field"); + signField.unbind(); + section.unbind(); + section.attr("id", signFieldNumber); + section.on('click', function () { + $("#reportModal").modal("show"); + $("div[id^='report_']").each(function() { + $(this).hide(); + }); + $("#report_" + $(this).attr("id")).show(); + }) + // signField.attr("data-toggle", "modal"); + // signField.attr("data-target", "#sign_" + self.signRequestId); + // signField.addClass("d-none"); + // signField.parent().remove(); + } continue; } let inputName = items[i].fieldName.split(/\$|#|!/)[0]; diff --git a/src/main/resources/static/js/modules/utils/SseDispatcher.js b/src/main/resources/static/js/modules/utils/SseDispatcher.js deleted file mode 100644 index 623506c11..000000000 --- a/src/main/resources/static/js/modules/utils/SseDispatcher.js +++ /dev/null @@ -1,13 +0,0 @@ -export class SseDispatcher { - - constructor() { - } - - dispatchEvent(type, message) { - console.info("dispatch event : " + type + " " + message); - let event = new CustomEvent(type); - event.initCustomEvent(type, false, false, message); - document.dispatchEvent(event); - } - -} \ No newline at end of file diff --git a/src/main/resources/static/js/modules/utils/SseSubscribe.js b/src/main/resources/static/js/modules/utils/SseSubscribe.js deleted file mode 100644 index 900eb33cb..000000000 --- a/src/main/resources/static/js/modules/utils/SseSubscribe.js +++ /dev/null @@ -1,53 +0,0 @@ -import {Message} from "../../prototypes/Message.js"; -import {EventFactory} from "./EventFactory.js"; -import {SseDispatcher} from "./SseDispatcher.js"; - -export class SseSubscribe extends EventFactory { - - constructor(sseId) { - console.info("Start SSE"); - super(); - this.sseId = sseId; - this.initSse(); - this.listenToEvent(); - this.sseDispatcher = new SseDispatcher(); - } - - initSse() { - console.info("connect to sse"); - let self = this; - this.eventSource = new EventSource('/sse/' + this.sseId); - this.eventSource.onopen = function(e) { - console.info("refresh sse : " + self.sseId); - } - window.onbeforeunload = function(e) { - console.info("close sse : " + self.sseId); - self.eventSource.close(); - }; - - } - - listenToEvent() { - console.info("subscribe to events"); - this.eventSource.addEventListener("global", response => { - console.info("receive global event"); - let message = new Message(JSON.parse(response.data)); - this.sseDispatcher.dispatchEvent("global", message); - }, false); - this.eventSource.addEventListener("user", response => { - console.info("receive user event"); - let message = new Message(JSON.parse(response.data)); - this.sseDispatcher.dispatchEvent("user", message); - }, false); - this.eventSource.addEventListener("sign", response => { - console.info("receive sign event"); - let message = new Message(JSON.parse(response.data)); - this.sseDispatcher.dispatchEvent("sign", message); - }, false); - this.eventSource.addEventListener("massSign", response => { - console.info("receive mass-sign event"); - let message = new Message(JSON.parse(response.data)); - this.sseDispatcher.dispatchEvent("massSign", message); - }, false); - } -} \ No newline at end of file diff --git a/src/main/resources/templates/admin/certificats/list.html b/src/main/resources/templates/admin/certificats/list.html new file mode 100644 index 000000000..0bce96d46 --- /dev/null +++ b/src/main/resources/templates/admin/certificats/list.html @@ -0,0 +1,93 @@ + + + + + + + + + + + + Logs + + + + + + + + + Certificats + + + + Nom + Date d'expiration + Roles + Actions + + + + + + + + + + + + + + + + + + + + + + + Ajouter un certificat + + + + + + + + Keystore au format PKCS12 + + + + Choisir un fichier + + + + + Nom du role autorisé à acceder au formulaire + + + + + + + + Mot de passe du keystore + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/admin/currentsessions.html b/src/main/resources/templates/admin/currentsessions.html index 5209ff900..7e0d24df0 100644 --- a/src/main/resources/templates/admin/currentsessions.html +++ b/src/main/resources/templates/admin/currentsessions.html @@ -6,7 +6,7 @@ - + Sessions courantes diff --git a/src/main/resources/templates/admin/dss/lotl-info.html b/src/main/resources/templates/admin/dss/lotl-info.html index 04b699a6c..be17aea96 100644 --- a/src/main/resources/templates/admin/dss/lotl-info.html +++ b/src/main/resources/templates/admin/dss/lotl-info.html @@ -1,28 +1,41 @@ - - - - - - - No info found for this LOTL - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + DSS List Of Trusted Lists + + + + + No info found for this LOTL + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/templates/admin/dss/oj-certificates.html b/src/main/resources/templates/admin/dss/oj-certificates.html deleted file mode 100644 index ee0c2d0f7..000000000 --- a/src/main/resources/templates/admin/dss/oj-certificates.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - DSS Trusted Certificats - - - - - - - - - - - - - - - - link - - - - - Custom certificats - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/templates/admin/dss/pivot-changes.html b/src/main/resources/templates/admin/dss/pivot-changes.html index 596e988dc..7e9f5b7b0 100644 --- a/src/main/resources/templates/admin/dss/pivot-changes.html +++ b/src/main/resources/templates/admin/dss/pivot-changes.html @@ -1,99 +1,131 @@ - - - - - - - - - - - - This page contains the information about evolution of the original keystore by provided pivots. - The following notations are used: - - Copied certificate from the previous source; - Added certificate to the source by the pivot; - Removed certificate from the source by the pivot; - The signing certificate of the LOTL. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + DSS List Of Trusted Lists + + + + + + + + This page contains the information about evolution of the original keystore by provided + pivots. + The following notations are used: + + Copied certificate from the previous source; + + Added certificate to the source by the pivot; + + Removed certificate from the source by the pivot; + + The signing certificate of the LOTL. + + + The initial LOTL-signing certificates can be found on the + page. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + - + - - - - - + - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + +
No info found for this LOTL
- - link -
This page contains the information about evolution of the original keystore by provided pivots.
The following notations are used:
This page contains the information about evolution of the original keystore by provided + pivots.
The initial LOTL-signing certificates can be found on the + page.