Skip to content

Commit 8d90771

Browse files
committed
Add extend Container validity method
IB-8265 Signed-off-by: Raul Metsma <raul@metsma.ee>
1 parent 426562d commit 8d90771

14 files changed

Lines changed: 314 additions & 149 deletions

‎libdigidocpp.dox‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,9 @@ You change the default behaviour in the configuration file with the following pa
758758
\tableofcontents
759759
Note that Libdigidocpp uses internal memory buffers in case of all the operations, so that intermediary data is not written to temporary files on the disk. Also, the data files to be added to a DigiDoc container can be read from a data stream and later extracted from the container to a stream so that the data can be kept in memory.
760760

761+
\subsection string-encoding String encoding
762+
All <tt>std::string</tt> values passed to or returned from the API are UTF-8 encoded. This applies to file paths, media types, and all other string parameters and return values throughout the library.
763+
761764
\subsection initialization Initialization
762765
Libdigidocpp's initialization method conducts the following operations:
763766
1. initializes dependent libraries (see also \ref libraries)

‎libdigidocpp.i‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,11 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
214214
// std::unique_ptr is since swig 4.1
215215
%ignore digidoc::Container::createPtr;
216216
%ignore digidoc::Container::openPtr;
217+
%ignore digidoc::Container::extendContainerValidity;
217218

218219
%newobject digidoc::Container::open;
219220
%newobject digidoc::Container::create;
221+
%newobject digidoc::Container::extendContainerValidity;
220222

221223
%immutable digidoc::TSAInfo::cert;
222224
%immutable digidoc::TSAInfo::time;
@@ -280,7 +282,14 @@ def transfer(self):
280282
%template(Signatures) std::vector<digidoc::Signature*>;
281283
%template(TSAInfos) std::vector<digidoc::TSAInfo>;
282284

285+
%rename("%s") digidoc::Container::extendContainerValidity;
286+
283287
%extend digidoc::Container {
288+
static Container* extendContainerValidity(Container &doc, Signer *signer)
289+
{
290+
return digidoc::Container::extendContainerValidity(doc, signer).release();
291+
}
292+
284293
static digidoc::Container* open(const std::string &path, digidoc::ContainerOpenCB *cb)
285294
{
286295
return digidoc::Container::openPtr(path, cb).release();

‎src/ASiC_E.cpp‎

Lines changed: 75 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@
2323
#include "DataFile_p.h"
2424
#include "SignatureXAdES_LTA.h"
2525
#include "XMLDocument.h"
26-
#include "crypto/Digest.h"
2726
#include "crypto/Signer.h"
2827
#include "util/File.h"
2928

3029
#include <algorithm>
3130
#include <set>
32-
#include <sstream>
3331

3432
using namespace digidoc;
3533
using namespace digidoc::util;
@@ -51,21 +49,83 @@ class ASiC_E::Private
5149
/**
5250
* Initialize BDOC container.
5351
*/
54-
ASiC_E::ASiC_E()
55-
: ASiContainer(MIMETYPE_ASIC_E)
52+
ASiC_E::ASiC_E(const string &path, bool create) try
53+
: ASiContainer(path, MIMETYPE_ASIC_E)
5654
, d(make_unique<Private>())
5755
{
58-
}
56+
if(create)
57+
return;
58+
auto z = load(true, {MIMETYPE_ASIC_E, MIMETYPE_ADOC});
59+
auto doc = XMLDocument::open(z.read("META-INF/manifest.xml"), {"manifest", MANIFEST_NS});
60+
doc.validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_manifest_v1_2.xsd"));
61+
62+
set<string_view> manifestFiles;
63+
bool mimeFound = false;
64+
for(auto file = doc/"file-entry"; file; file++)
65+
{
66+
auto full_path = file[{"full-path", MANIFEST_NS}];
67+
auto media_type = file[{"media-type", MANIFEST_NS}];
68+
DEBUG("full_path = '%.*s', media_type = '%.*s'", STR_VIEW_FMT(full_path), STR_VIEW_FMT(media_type));
5969

60-
/**
61-
* Opens ASiC container from a file
62-
*/
63-
ASiC_E::ASiC_E(const string &path)
64-
: ASiContainer(MIMETYPE_ASIC_E)
65-
, d(make_unique<Private>())
70+
// ODF does not specify that mimetype should be first in manifest
71+
if(full_path == "/")
72+
{
73+
if(mimeFound)
74+
THROW("Manifest multiple entries defined for file '/'.");
75+
if(mediaType() != media_type)
76+
THROW("Manifest has incorrect container media type defined '%.*s', expecting '%s'.", STR_VIEW_FMT(media_type), mediaType().c_str());
77+
mimeFound = true;
78+
continue;
79+
}
80+
if(full_path.back() == '/') // Skip Directory entries
81+
continue;
82+
83+
if(const auto &[pos, inserted] = manifestFiles.insert(full_path); !inserted)
84+
THROW("Manifest multiple entries defined for file '%.*s'.", STR_VIEW_FMT(full_path));
85+
if(mediaType() == MIMETYPE_ADOC &&
86+
(full_path.starts_with("META-INF/") || full_path.starts_with("metadata/")))
87+
d->metadata.push_back(new DataFilePrivate(z, string(full_path), string(media_type)));
88+
else
89+
addDataFilePrivate(new DataFilePrivate(z, string(full_path), string(media_type)));
90+
}
91+
if(!mimeFound)
92+
THROW("Manifest is missing mediatype file entry.");
93+
94+
for(const string &file: z.list())
95+
{
96+
/**
97+
* http://www.etsi.org/deliver/etsi_ts/102900_102999/102918/01.03.01_60/ts_102918v010301p.pdf
98+
* 6.2.2 Contents of Container
99+
* 3) The root element of each "*signatures*.xml" content shall be either:
100+
*/
101+
if(file.starts_with("META-INF/") && file.contains("signatures"))
102+
{
103+
try
104+
{
105+
loadSignatures(XMLDocument::open(z.read(file)), file);
106+
}
107+
catch(const Exception &e)
108+
{
109+
THROW_CAUSE(e, "Failed to parse signature '%s'.", file.c_str());
110+
}
111+
continue;
112+
}
113+
114+
if(file == "mimetype" || file.starts_with("META-INF"))
115+
continue;
116+
if(manifestFiles.erase(file) == 0)
117+
THROW("File '%s' found in container is not described in manifest.", file.c_str());
118+
}
119+
if(!manifestFiles.empty())
120+
THROW("Manifest describes files that are not found in container.");
121+
}
122+
catch(const Exception &e)
66123
{
67-
auto zip = load(path, true, {MIMETYPE_ASIC_E, MIMETYPE_ADOC});
68-
parseManifestAndLoadFiles(zip);
124+
THROW_CAUSE(e, "Failed to parse manifest");
125+
}
126+
catch(...)
127+
{
128+
THROW("Failed to parse manifest XML: Unknown exception");
69129
}
70130

71131
ASiC_E::~ASiC_E()
@@ -110,9 +170,7 @@ void ASiC_E::save(const ZipSerialize &s)
110170
unique_ptr<Container> ASiC_E::createInternal(const string &path)
111171
{
112172
DEBUG("ASiC_E::createInternal(%s)", path.c_str());
113-
unique_ptr<ASiC_E> doc = unique_ptr<ASiC_E>(new ASiC_E);
114-
doc->zpath(path);
115-
return doc;
173+
return unique_ptr<Container>(new ASiC_E(path, true));
116174
}
117175

118176
/**
@@ -146,7 +204,7 @@ void ASiC_E::canSave()
146204
unique_ptr<Container> ASiC_E::openInternal(const string &path)
147205
{
148206
DEBUG("ASiC_E::openInternal(%s)", path.c_str());
149-
return unique_ptr<Container>(new ASiC_E(path));
207+
return unique_ptr<Container>(new ASiC_E(path, false));
150208
}
151209

152210
void ASiC_E::loadSignatures(XMLDocument &&doc, const string &file)
@@ -157,92 +215,6 @@ void ASiC_E::loadSignatures(XMLDocument &&doc, const string &file)
157215
addSignature(make_unique<SignatureXAdES_LTA>(signatures, s, this));
158216
}
159217

160-
/**
161-
* Parses manifest file and checks that files described in manifest exist, also
162-
* checks that no extra file do exist that are not described in manifest.xml.
163-
*
164-
* @param path directory on disk of the BDOC container.
165-
* @throws Exception exception is thrown if the manifest.xml file parsing failed.
166-
*/
167-
void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
168-
{
169-
DEBUG("ASiC_E::readManifest()");
170-
171-
try
172-
{
173-
auto doc = XMLDocument::open(z.read("META-INF/manifest.xml"), {"manifest", MANIFEST_NS});
174-
doc.validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_manifest_v1_2.xsd"));
175-
176-
set<string_view> manifestFiles;
177-
bool mimeFound = false;
178-
for(auto file = doc/"file-entry"; file; file++)
179-
{
180-
auto full_path = file[{"full-path", MANIFEST_NS}];
181-
auto media_type = file[{"media-type", MANIFEST_NS}];
182-
DEBUG("full_path = '%s', media_type = '%s'", full_path.data(), media_type.data());
183-
184-
if(manifestFiles.contains(full_path))
185-
THROW("Manifest multiple entries defined for file '%s'.", full_path.data());
186-
187-
// ODF does not specify that mimetype should be first in manifest
188-
if(full_path == "/")
189-
{
190-
if(mediaType() != media_type)
191-
THROW("Manifest has incorrect container media type defined '%s', expecting '%s'.", media_type.data(), mediaType().c_str());
192-
mimeFound = true;
193-
continue;
194-
}
195-
if(full_path.back() == '/') // Skip Directory entries
196-
continue;
197-
198-
manifestFiles.insert(full_path);
199-
if(mediaType() == MIMETYPE_ADOC &&
200-
(full_path.starts_with("META-INF/") ||
201-
full_path.starts_with("metadata/")))
202-
d->metadata.push_back(new DataFilePrivate(z, string(full_path), string(media_type)));
203-
else
204-
addDataFilePrivate(new DataFilePrivate(z, string(full_path), string(media_type)));
205-
}
206-
if(!mimeFound)
207-
THROW("Manifest is missing mediatype file entry.");
208-
209-
for(const string &file: z.list())
210-
{
211-
/**
212-
* http://www.etsi.org/deliver/etsi_ts/102900_102999/102918/01.03.01_60/ts_102918v010301p.pdf
213-
* 6.2.2 Contents of Container
214-
* 3) The root element of each "*signatures*.xml" content shall be either:
215-
*/
216-
if(file.starts_with("META-INF/") &&
217-
file.find("signatures") != string::npos)
218-
{
219-
try
220-
{
221-
loadSignatures(XMLDocument::open(z.read(file)), file);
222-
}
223-
catch(const Exception &e)
224-
{
225-
THROW_CAUSE(e, "Failed to parse signature '%s'.", file.c_str());
226-
}
227-
continue;
228-
}
229-
230-
if(file == "mimetype" || file.starts_with("META-INF"))
231-
continue;
232-
if(!manifestFiles.contains(file))
233-
THROW("File '%s' found in container is not described in manifest.", file.c_str());
234-
}
235-
}
236-
catch(const Exception &e)
237-
{
238-
THROW_CAUSE(e, "Failed to parse manifest");
239-
}
240-
catch(...)
241-
{
242-
THROW("Failed to parse manifest XML: Unknown exception");
243-
}
244-
}
245-
246218
Signature* ASiC_E::prepareSignature(Signer *signer)
247219
{
248220
if(mediaType() != MIMETYPE_ASIC_E)

‎src/ASiC_E.h‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,10 @@ namespace digidoc
5050
static std::unique_ptr<Container> openInternal(const std::string &path);
5151

5252
private:
53-
ASiC_E();
54-
ASiC_E(const std::string &path);
53+
ASiC_E(const std::string &path, bool create);
5554
DISABLE_COPY(ASiC_E);
5655
void canSave() final;
5756
void loadSignatures(XMLDocument &&doc, const std::string &file);
58-
void parseManifestAndLoadFiles(const ZipSerialize &z);
5957
void save(const ZipSerialize &s) final;
6058

6159
class Private;

‎src/ASiC_S.cpp‎

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,26 +27,19 @@
2727
#include "util/File.h"
2828
#include "util/log.h"
2929

30-
#include <sstream>
31-
3230
using namespace digidoc;
3331
using namespace digidoc::util;
3432
using namespace std;
3533

3634
/**
3735
* Initialize ASiCS container.
3836
*/
39-
ASiC_S::ASiC_S()
40-
: ASiContainer(MIMETYPE_ASIC_S)
41-
{}
42-
43-
/**
44-
* Opens ASiC-S container from a file
45-
*/
46-
ASiC_S::ASiC_S(const string &path)
47-
: ASiContainer(MIMETYPE_ASIC_S)
37+
ASiC_S::ASiC_S(const string &path, bool create)
38+
: ASiContainer(path, MIMETYPE_ASIC_S)
4839
{
49-
auto z = load(path, false, {mediaType()});
40+
if(create)
41+
return;
42+
auto z = load(false, {mediaType()});
5043
bool foundTimestamp = false;
5144
bool foundManifest = false;
5245
for(const string &file: z.list())
@@ -108,9 +101,7 @@ unique_ptr<Container> ASiC_S::createInternal(const string &path)
108101
if(!util::File::fileExtension(path, {"asics", "scs"}))
109102
return {};
110103
DEBUG("ASiC_S::createInternal(%s)", path.c_str());
111-
auto doc = unique_ptr<ASiC_S>(new ASiC_S());
112-
doc->zpath(path);
113-
return doc;
104+
return unique_ptr<Container>(new ASiC_S(path, true));
114105
}
115106

116107
void ASiC_S::addAdESSignature(istream & /*signature*/)
@@ -131,7 +122,7 @@ unique_ptr<Container> ASiC_S::openInternal(const string &path, ContainerOpenCB *
131122
{
132123
if(util::File::fileExtension(path, {"asice", "sce", "bdoc"}))
133124
return {};
134-
return unique_ptr<Container>(new ASiC_S(path));
125+
return unique_ptr<Container>(new ASiC_S(path, false));
135126
}
136127
catch(const Exception &)
137128
{

‎src/ASiC_S.h‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ namespace digidoc
4141
static std::unique_ptr<Container> openInternal(const std::string &path, ContainerOpenCB *cb);
4242

4343
private:
44-
ASiC_S();
45-
ASiC_S(const std::string &path);
44+
ASiC_S(const std::string &path, bool create);
4645
DISABLE_COPY(ASiC_S);
4746

4847
void addDataFileChecks(const std::string &path, const std::string &mediaType) override;

0 commit comments

Comments
 (0)