diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1e45146e1..19d21193c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -105,7 +105,7 @@ jobs: container: ${{ matrix.container }} strategy: matrix: - container: ['ubuntu:20.04', 'ubuntu:22.04', 'ubuntu:23.04', 'ubuntu:23.10'] + container: ['ubuntu:20.04', 'ubuntu:22.04', 'ubuntu:23.10'] env: DEBIAN_FRONTEND: noninteractive DEBFULLNAME: github-actions diff --git a/examples/DigiDocCSharp/DigiDocCSharp.csproj b/examples/DigiDocCSharp/DigiDocCSharp.csproj index 9ed490dbe..69d7450e0 100644 --- a/examples/DigiDocCSharp/DigiDocCSharp.csproj +++ b/examples/DigiDocCSharp/DigiDocCSharp.csproj @@ -2,38 +2,34 @@ Debug - x86 - 8.0.30703 - 2.0 + x64 {DDEE2029-EA2A-49D2-80CB-F0E2E396B005} Exe Properties DigiDocCSharp DigiDocCSharp - v4.0 - Client + v4.7.2 512 - - x86 + + AnyCPU true full - false bin\Debug\ DEBUG;TRACE prompt - 4 true + false - - x86 + + AnyCPU pdbonly true bin\Release\ TRACE prompt - 4 true + false _WINDOWS diff --git a/examples/DigiDocCSharp/DigiDocCSharp.sln b/examples/DigiDocCSharp/DigiDocCSharp.sln index 7cdf7b5e2..dca8f622b 100644 --- a/examples/DigiDocCSharp/DigiDocCSharp.sln +++ b/examples/DigiDocCSharp/DigiDocCSharp.sln @@ -1,20 +1,25 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual C# Express 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34009.444 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DigiDocCSharp", "DigiDocCSharp.csproj", "{DDEE2029-EA2A-49D2-80CB-F0E2E396B005}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Debug|x86.ActiveCfg = Debug|x86 - {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Debug|x86.Build.0 = Debug|x86 - {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Release|x86.ActiveCfg = Release|x86 - {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Release|x86.Build.0 = Release|x86 + {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DDEE2029-EA2A-49D2-80CB-F0E2E396B005}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7D43E58D-0FD9-4023-A18F-D69EE6A229E1} + EndGlobalSection EndGlobal diff --git a/examples/DigiDocCSharp/Program.cs b/examples/DigiDocCSharp/Program.cs index 731d69af5..ed3accb6b 100644 --- a/examples/DigiDocCSharp/Program.cs +++ b/examples/DigiDocCSharp/Program.cs @@ -124,10 +124,10 @@ private static void Sign(string[] args) b.addDataFile(args[i], "application/octet-stream"); } #if _WINDOWS - using (WinSigner signer = new WinSigner()) + using (var signer = new WinSigner()) { #else - using (PKCS11Signer signer = new PKCS11Signer()) + using (var signer = new PKCS11Signer()) { signer.setPin(args[1]); #endif @@ -184,7 +184,8 @@ private static void Verify(string file) try { Console.WriteLine("Opening file: " + file); - Container b = Container.open(file); + var cb = new ContainerOpen(); + Container b = Container.open(file, cb); Console.WriteLine("Files:"); foreach (DataFile d in b.dataFiles()) @@ -226,4 +227,9 @@ private static void Version() " libdigidocpp " + digidoc.digidoc.version()); } } + + class ContainerOpen : ContainerOpenCB + { + override public bool validateOnline() { return true; } + } } diff --git a/examples/java/README.md b/examples/java/README.md index 0aeebec8f..62857a779 100644 --- a/examples/java/README.md +++ b/examples/java/README.md @@ -6,4 +6,4 @@ ## Run - java -Djava.library.path=/Library/libdigidocpp/lib -jar build/libs/libdigidoc.jar \ No newline at end of file + java -Djava.library.path=/some/path/lib -jar build/libs/libdigidoc.jar \ No newline at end of file diff --git a/examples/java/gradle/wrapper/gradle-wrapper.jar b/examples/java/gradle/wrapper/gradle-wrapper.jar index ccebba771..7f93135c4 100644 Binary files a/examples/java/gradle/wrapper/gradle-wrapper.jar and b/examples/java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/java/gradle/wrapper/gradle-wrapper.properties b/examples/java/gradle/wrapper/gradle-wrapper.properties index c30b486a8..3fa8f862f 100644 --- a/examples/java/gradle/wrapper/gradle-wrapper.properties +++ b/examples/java/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/examples/java/gradlew b/examples/java/gradlew index 79a61d421..0adc8e1a5 100755 --- a/examples/java/gradlew +++ b/examples/java/gradlew @@ -83,10 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +131,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -197,6 +198,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java b/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java index 5fdabd498..5ff995e76 100644 --- a/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java +++ b/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java @@ -133,7 +133,8 @@ static void verify(String file) { try { System.out.println("Opening file: " + file); - Container b = Container.open(file); + ContainerOpen cb = new ContainerOpen(); + Container b = Container.open(file, cb); assert b != null; System.out.println("Files:"); @@ -200,4 +201,10 @@ static byte[] fromHex(String s) { } return data; } + + static private class ContainerOpen extends ContainerOpenCB + { + @Override + public boolean validateOnline() { return true; } + } } diff --git a/examples/python/main.py b/examples/python/main.py index 05e4249bb..68e687eaf 100644 --- a/examples/python/main.py +++ b/examples/python/main.py @@ -2,6 +2,13 @@ import sys import os +class ContainerOpenCB(digidoc.ContainerOpenCB): + + def __init__(self): + digidoc.ContainerOpenCB.__init__(self) + + def validateOnline(self): + return True class Program: digidoc.initialize() @@ -78,7 +85,8 @@ def sign(self, args): def verify(self, file): print("Opening file: " + file) - doc = digidoc.Container.open(file) + cb = ContainerOpenCB() + doc = digidoc.Container.open(file, cb) print("Files:") for d in doc.dataFiles(): diff --git a/libdigidocpp.dox b/libdigidocpp.dox index 9375cb6d5..031ec80f1 100644 --- a/libdigidocpp.dox +++ b/libdigidocpp.dox @@ -1380,6 +1380,8 @@ Signature Validation Policy Default POLv2 http://open-eid.github.io/SiVa/siva/appendix/validation_policy/ +\-\-offline Optional +open container offline (eg. Don't send to SiVa) \-\-warnings= (ignore, warning, error) Optional diff --git a/libdigidocpp.i b/libdigidocpp.i index f265c3322..f64ba3ee0 100644 --- a/libdigidocpp.i +++ b/libdigidocpp.i @@ -19,7 +19,7 @@ // digidocpp.i - SWIG interface for libdigidocpp library -%module digidoc +%module(directors="1") digidoc %begin %{ #ifdef _MSC_VER @@ -231,6 +231,8 @@ extern "C" %newobject digidoc::Container::open; %newobject digidoc::Container::create; +%feature("director") digidoc::ContainerOpenCB; + %typemap(javacode) digidoc::Conf %{ public Conf transfer() { swigCMemOwn = false; @@ -318,16 +320,21 @@ namespace std { } } %extend digidoc::Container { + static digidoc::Container* open(const std::string &path, digidoc::ContainerOpenCB *cb) + { + return digidoc::Container::openPtr(path, cb).release(); + } + digidoc::Signature* prepareWebSignature(const std::vector &cert, const std::string &profile = {}, const std::vector &roles = {}, const std::string &city = {}, const std::string &state = {}, const std::string &postalCode = {}, const std::string &country = {}) { - class : public digidoc::Signer + class final: public digidoc::Signer { public: - digidoc::X509Cert cert() const override { return _cert; } - std::vector sign(const std::string &, const std::vector &) const override + digidoc::X509Cert cert() const final { return _cert; } + std::vector sign(const std::string &, const std::vector &) const final { THROW("Not implemented"); } diff --git a/src/ASiC_S.cpp b/src/ASiC_S.cpp index f7c7e6fec..04dea735b 100644 --- a/src/ASiC_S.cpp +++ b/src/ASiC_S.cpp @@ -102,7 +102,7 @@ void ASiC_S::addAdESSignature(istream & /*signature*/) THROW("Not implemented."); } -unique_ptr ASiC_S::openInternal(const string &path) +unique_ptr ASiC_S::openInternal(const string &path, ContainerOpenCB * /*cb*/) { if (!isContainerSimpleFormat(path)) return {}; @@ -130,11 +130,9 @@ Signature *ASiC_S::sign(Signer * /*signer*/) bool ASiC_S::isContainerSimpleFormat(const string &path) { DEBUG("isContainerSimpleFormat(path = '%s')", path.c_str()); - const auto extension = util::File::fileExtension(path); - if(extension == ASICE_EXTENSION || extension == ASICE_EXTENSION_ABBR || - extension == BDOC_EXTENSION) + if(util::File::fileExtension(path, {"asice", "sce", "bdoc"})) return false; - if(extension == ASICS_EXTENSION || extension == ASICS_EXTENSION_ABBR) + if(util::File::fileExtension(path, {"asics", "scs"})) return true; DEBUG("Check if ASiC/zip containter"); try diff --git a/src/ASiC_S.h b/src/ASiC_S.h index 95c9483ef..3af245268 100644 --- a/src/ASiC_S.h +++ b/src/ASiC_S.h @@ -41,7 +41,7 @@ namespace digidoc Signature* sign(Signer* signer) override; static std::unique_ptr createInternal(const std::string &path); - static std::unique_ptr openInternal(const std::string &path); + static std::unique_ptr openInternal(const std::string &path, ContainerOpenCB *cb); private: ASiC_S(); diff --git a/src/ASiContainer.cpp b/src/ASiContainer.cpp index 2a6440482..6efcd1ffb 100644 --- a/src/ASiContainer.cpp +++ b/src/ASiContainer.cpp @@ -48,12 +48,6 @@ class ASiContainer::Private map properties; }; -const string_view ASiContainer::ASICE_EXTENSION = "asice"; -const string_view ASiContainer::ASICE_EXTENSION_ABBR = "sce"; -const string_view ASiContainer::ASICS_EXTENSION = "asics"; -const string_view ASiContainer::ASICS_EXTENSION_ABBR = "scs"; -const string_view ASiContainer::BDOC_EXTENSION = "bdoc"; - const string ASiContainer::MIMETYPE_ASIC_E = "application/vnd.etsi.asic-e+zip"; const string ASiContainer::MIMETYPE_ASIC_S = "application/vnd.etsi.asic-s+zip"; //https://signa.mitsoft.lt/static/signa-web/webResources/docs/ADOC_specification_approved20090907_EN.pdf diff --git a/src/ASiContainer.h b/src/ASiContainer.h index 73ddfb3c2..bb7487738 100644 --- a/src/ASiContainer.h +++ b/src/ASiContainer.h @@ -38,12 +38,6 @@ namespace digidoc class ASiContainer: public Container { public: - static const std::string_view ASICE_EXTENSION; - static const std::string_view ASICE_EXTENSION_ABBR; - static const std::string_view ASICS_EXTENSION; - static const std::string_view ASICS_EXTENSION_ABBR; - static const std::string_view BDOC_EXTENSION; - static const std::string MIMETYPE_ASIC_E; static const std::string MIMETYPE_ASIC_S; static const std::string MIMETYPE_ADOC; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c55e19fb4..0d257c71a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -271,13 +271,11 @@ if(SWIG_FOUND) target_include_directories(digidoc_java PRIVATE ${JAVA_INCLUDE_PATH} $<$:${JAVA_INCLUDE_PATH2}>) target_compile_definitions(digidoc_java PRIVATE TARGET_NAME="$") target_link_libraries(digidoc_java digidocpp digidocpp_util digidocpp_ver) - set_property(TARGET digidoc_java PROPERTY SWIG_COMPILE_DEFINITIONS $<$:SWIGWIN>) - if(APPLE) - set_target_properties(digidoc_java PROPERTIES MACOSX_RPATH YES INSTALL_RPATH /Library/Frameworks) - install(TARGETS digidoc_java DESTINATION /Library/Java/Extensions) - else() - install(TARGETS digidoc_java DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif() + set_target_properties(digidoc_java PROPERTIES + INSTALL_RPATH $<$:/Library/Frameworks> + SWIG_COMPILE_DEFINITIONS $<$:SWIGWIN> + ) + install(TARGETS digidoc_java DESTINATION $,/Library/Java/Extensions,${CMAKE_INSTALL_LIBDIR}>) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/java/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ee/ria/libdigidocpp FILES_MATCHING PATTERN "*.java") if(WIN32) install(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) @@ -289,7 +287,6 @@ if(SWIG_FOUND) swig_add_library(digidoc_python LANGUAGE python SOURCES ../libdigidocpp.i) target_compile_definitions(digidoc_python PRIVATE TARGET_NAME="$") target_link_libraries(digidoc_python digidocpp digidocpp_util digidocpp_ver Python3::Module) - set_property(TARGET digidoc_python PROPERTY SWIG_COMPILE_DEFINITIONS $<$:SWIGWIN>) #configure_file(setup.py.cmake setup.py) #install(CODE "execute_process(COMMAND python3 ${CMAKE_CURRENT_BINARY_DIR}/setup.py install)") if(NOT Python3_SITELIB) @@ -303,6 +300,10 @@ if(SWIG_FOUND) else() set_target_properties(digidoc_python PROPERTIES SUFFIX .so) endif() + set_target_properties(digidoc_python PROPERTIES + INSTALL_RPATH $<$:/Library/Frameworks> + SWIG_COMPILE_DEFINITIONS $<$:SWIGWIN> + ) install(TARGETS digidoc_python DESTINATION ${Python3_SITELIB}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/digidoc.py DESTINATION ${Python3_SITELIB}) endif() diff --git a/src/Container.cpp b/src/Container.cpp index d8bca3069..8592a5d35 100644 --- a/src/Container.cpp +++ b/src/Container.cpp @@ -68,7 +68,8 @@ namespace digidoc static string m_appName = "libdigidocpp"; static string m_userAgent = "libdigidocpp"; static vector m_createList {}; -static vector m_openList {}; +using OpenCB = std::unique_ptr (*)(const std::string &path, ContainerOpenCB *cb); +static vector m_openList {}; } /** @@ -96,14 +97,7 @@ string digidoc::userAgent() { return m_userAgent; } * Returns libdigidocpp library version */ string digidoc::version() { - string ver = FILE_VER_STR; -#if defined(DYNAMIC_LIBDIGIDOC) || defined(LINKED_LIBDIGIDOC) - ver += "_ddoc"; -#endif -#ifdef PDF_SUPPORT - ver += "_siva"; -#endif - return ver; + return FILE_VER_STR; } /** @@ -348,10 +342,22 @@ Container* Container::open(const string &path) * @throws Exception */ unique_ptr Container::openPtr(const string &path) +{ + return openPtr(path, {}); +} + +/** + * Opens container from a file + * + * @param path + * @param cb Callback called when needed + * @throws Exception + */ +unique_ptr Container::openPtr(const string &path, ContainerOpenCB *cb) { for(auto open: m_openList) { - if(unique_ptr container = open(path)) + if(unique_ptr container = open(path, cb)) return container; } return ASiC_E::openInternal(path); @@ -417,7 +423,7 @@ unique_ptr Container::openPtr(const string &path) * * It must contain static members: * * static Container* createInternal(const std::string &path); - * * static Container* openInternal(const std::string &path); + * * static Container* openInternal(const std::string &path, digidoc::ContainerOpenCB *cb); * * @see Container::create, Container::open */ diff --git a/src/Container.h b/src/Container.h index c2f9ac6d7..92655e978 100644 --- a/src/Container.h +++ b/src/Container.h @@ -40,6 +40,11 @@ DIGIDOCPP_EXPORT void terminate(); DIGIDOCPP_EXPORT std::string userAgent(); DIGIDOCPP_EXPORT std::string version(); +struct ContainerOpenCB { + virtual ~ContainerOpenCB() = default; + virtual bool validateOnline() const { return true; } +}; + class DIGIDOCPP_EXPORT Container { public: @@ -66,6 +71,7 @@ class DIGIDOCPP_EXPORT Container static std::unique_ptr createPtr(const std::string &path); DIGIDOCPP_DEPRECATED static Container* open(const std::string &path); static std::unique_ptr openPtr(const std::string &path); + static std::unique_ptr openPtr(const std::string &path, digidoc::ContainerOpenCB *cb); template static void addContainerImplementation(); diff --git a/src/SiVaContainer.cpp b/src/SiVaContainer.cpp index 180612146..5ed0e9181 100644 --- a/src/SiVaContainer.cpp +++ b/src/SiVaContainer.cpp @@ -144,29 +144,28 @@ void SignatureSiVa::validate(const string &policy) const } -SiVaContainer::SiVaContainer(const string &path, bool useHashCode) +SiVaContainer::SiVaContainer(const string &path, ContainerOpenCB *cb, bool useHashCode) : d(make_unique()) { - string ext = File::fileExtension(path); - DEBUG("SiVaContainer::SiVaContainer(%s, %s, %d)", path.c_str(), ext.c_str(), useHashCode); + DEBUG("SiVaContainer::SiVaContainer(%s, %d)", path.c_str(), useHashCode); unique_ptr ifs = make_unique(File::encodeName(d->path = path), ifstream::binary); auto fileName = File::fileName(path); istream *is = ifs.get(); - static const array asic {"asice", "sce", "asics", "scs"}; - if(ext == "ddoc") + if(File::fileExtension(path, {"ddoc"})) { d->mediaType = "application/x-ddoc"; d->ddoc = std::move(ifs); ifs = parseDDoc(useHashCode); is = ifs.get(); } - else if(ext == "pdf") + else if(File::fileExtension(path, {"pdf"})) { d->mediaType = "application/pdf"; d->dataFiles.push_back(new DataFilePrivate(std::move(ifs), fileName, "application/pdf")); } - else if(find(asic.cbegin(), asic.cend(), ext) != asic.cend()) + else if(File::fileExtension(path, {"asice", "sce", "asics", "scs"})) { + static const string_view metaInf = "META-INF/"; ZipSerialize z(path, false); vector list = z.list(); if(list.empty() || list.front() != "mimetype") @@ -174,13 +173,14 @@ SiVaContainer::SiVaContainer(const string &path, bool useHashCode) if(d->mediaType = ASiContainer::readMimetype(z); d->mediaType != ASiContainer::MIMETYPE_ASIC_E && d->mediaType != ASiContainer::MIMETYPE_ASIC_S) THROW("Unknown file"); - if(none_of(list.cbegin(), list.cend(), [](const string &file) { return file.find("p7s") != string::npos; })) + if(none_of(list.cbegin(), list.cend(), [](const string &file) { + return file.rfind(metaInf, 0) == 0 && util::File::fileExtension(file, {"p7s"}); + })) THROW("Unknown file"); - static const string metaInf = "META-INF/"; for(const string &file: list) { - if(file == "mimetype" || file.substr(0, metaInf.size()) == metaInf) + if(file == "mimetype" || file.rfind(metaInf, 0) == 0) continue; const auto directory = File::directory(file); if(directory.empty() || directory == "/" || directory == "./") @@ -194,6 +194,9 @@ SiVaContainer::SiVaContainer(const string &path, bool useHashCode) else THROW("Unknown file"); + if(cb && !cb->validateOnline()) + THROW("Online validation disabled"); + array buf{}; string b64; is->clear(); @@ -220,6 +223,7 @@ SiVaContainer::SiVaContainer(const string &path, bool useHashCode) Connect::Result r = Connect(CONF(verifyServiceUri), "POST", 0, CONF(verifyServiceCerts)).exec({ {"Content-Type", "application/json;charset=UTF-8"} }, (const unsigned char*)req.c_str(), req.size()); + req.clear(); if(!r.isOK() && !r.isStatusCode("400")) THROW("Failed to send request to SiVa"); @@ -287,7 +291,7 @@ SiVaContainer::SiVaContainer(const string &path, bool useHashCode) for(const json &error: signature.value("errors", {})) { string message = error["content"]; - if(message.find("Bad digest for DataFile") == 0 && useHashCode) + if(message.find("Bad digest for DataFile", 0) != string::npos && useHashCode) THROW("%s", message.c_str()); s->_exceptions.emplace_back(EXCEPTION_PARAMS("%s", message.c_str())); } @@ -298,7 +302,7 @@ SiVaContainer::SiVaContainer(const string &path, bool useHashCode) if(message == "X509IssuerName has none or invalid namespace: null" || message == "X509SerialNumber has none or invalid namespace: null") ex.setCode(Exception::IssuerNameSpaceWarning); - else if(message.find("Bad digest for DataFile") == 0) + else if(message.find("Bad digest for DataFile") != string::npos) ex.setCode(Exception::DataFileNameSpaceWarning); else if(message == "Old and unsupported format: SK-XML version: 1.0") continue; @@ -344,15 +348,15 @@ vector SiVaContainer::dataFiles() const return d->dataFiles; } -unique_ptr SiVaContainer::openInternal(const string &path) +unique_ptr SiVaContainer::openInternal(const string &path, ContainerOpenCB *cb) { try { - return unique_ptr(new SiVaContainer(path, true)); + return unique_ptr(new SiVaContainer(path, cb, true)); } catch(const Exception &e) { - if(e.msg().find("Bad digest for DataFile") == 0) - return unique_ptr(new SiVaContainer(path, false)); + if(e.msg().find("Bad digest for DataFile") != string::npos) + return unique_ptr(new SiVaContainer(path, cb, false)); if(e.msg() == "Unknown file") - return {}; + return {}; throw; } } diff --git a/src/SiVaContainer.h b/src/SiVaContainer.h index ce93edff7..9624771ff 100644 --- a/src/SiVaContainer.h +++ b/src/SiVaContainer.h @@ -99,13 +99,13 @@ class SiVaContainer final: public Container Signature* sign(Signer* signer) final; static std::unique_ptr createInternal(const std::string &path); - static std::unique_ptr openInternal(const std::string &path); + static std::unique_ptr openInternal(const std::string &path, ContainerOpenCB *cb); private: - SiVaContainer(const std::string &path, bool useHashCode); + SiVaContainer(const std::string &path, ContainerOpenCB *cb, bool useHashCode); DISABLE_COPY(SiVaContainer); - std::unique_ptr parseDDoc(bool useHashCode); + std::unique_ptr parseDDoc(bool useHashCode); class Private; std::unique_ptr d; diff --git a/src/digidoc-tool.1.cmake b/src/digidoc-tool.1.cmake index 79c2b5844..857a9e18d 100644 --- a/src/digidoc-tool.1.cmake +++ b/src/digidoc-tool.1.cmake @@ -27,6 +27,7 @@ Command open: http://open-eid.github.io/SiVa/siva/appendix/validation_policy/ --extractAll[=path] - extracts documents without validating signatures (to path when provided) --validateOnExtract - validates container before extracting files + --offline - open container offline (eg. Don't send to SiVa) Command add: Example: digidoc-tool add --file=file1.txt container-file.asice diff --git a/src/digidoc-tool.cpp b/src/digidoc-tool.cpp index 70e496f49..dd67d56b4 100644 --- a/src/digidoc-tool.cpp +++ b/src/digidoc-tool.cpp @@ -326,6 +326,7 @@ static int printUsage(const char *executable) << " http://open-eid.github.io/SiVa/siva/appendix/validation_policy/" << endl << " --extractAll[=path] - extracts documents without validating signatures (to path when provided)" << endl << " --validateOnExtract - validates container before extracting files" << endl << endl + << " --offline - open container offline (eg. Don't send to SiVa)" << endl << endl << " Command add:" << endl << " Example: " << executable << " add --file=file1.txt container-file.asice" << endl << " Available options:" << endl @@ -539,6 +540,11 @@ static int open(int argc, char* argv[]) fs::path extractPath; bool validateOnExtract = false; int returnCode = EXIT_SUCCESS; + struct OpenCB final: public ContainerOpenCB + { + bool online = true; + bool validateOnline() const final { return online; } + } cb; // Parse command line arguments. for(int i = 2; i < argc; i++) @@ -566,6 +572,8 @@ static int open(int argc, char* argv[]) validateOnExtract = true; else if(arg.find("--policy=") == 0) policy = arg.substr(9); + else if(arg.find("--offline") == 0) + cb.online = false; else path = arg; } @@ -575,7 +583,7 @@ static int open(int argc, char* argv[]) unique_ptr doc; try { - doc = Container::openPtr(path); + doc = Container::openPtr(path, &cb); } catch(const Exception &e) { cout << "Failed to parse container" << endl; cout << " Exception:" << endl << e; diff --git a/src/util/File.cpp b/src/util/File.cpp index 4827e9abd..bf5c93682 100644 --- a/src/util/File.cpp +++ b/src/util/File.cpp @@ -133,14 +133,17 @@ void File::updateModifiedTime(const string &path, time_t time) THROW("Failed to update file modified time."); } -string File::fileExtension(const string &path) +bool File::fileExtension(string_view path, initializer_list list) { size_t pos = path.find_last_of('.'); if(pos == string::npos) - return {}; - string ext = path.substr(pos + 1); - transform(ext.begin(), ext.end(), ext.begin(), ::tolower); - return ext; + return false; + string_view ext = path.substr(pos + 1); + return any_of(list.begin(), list.end(), [ext](string_view exp) { + return equal(ext.cbegin(), ext.cend(), exp.cbegin(), exp.cend(), [](auto a, auto b) { + return tolower(a) == tolower(b); + }); + }); } /** diff --git a/src/util/File.h b/src/util/File.h index a2aa2130f..3861ef395 100644 --- a/src/util/File.h +++ b/src/util/File.h @@ -41,7 +41,7 @@ namespace digidoc static time_t modifiedTime(const std::string &path); static void updateModifiedTime(const std::string &path, time_t time); static bool fileExists(const std::string& path); - static std::string fileExtension(const std::string &path); + static bool fileExtension(std::string_view path, std::initializer_list list); static unsigned long fileSize(const std::string &path); static std::string fileName(const std::string& path); static std::string directory(const std::string& path);