Skip to content

Commit 39b8313

Browse files
committed
Add extend Container validity method
IB-8265 Signed-off-by: Raul Metsma <raul@metsma.ee>
1 parent 7198fed commit 39b8313

12 files changed

Lines changed: 231 additions & 149 deletions

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: 77 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@
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;
3634
using namespace std;
3735

36+
#define STR_VIEW_FMT(str) int(str.size()), str.data()
37+
3838
class ASiC_E::Private
3939
{
4040
public:
@@ -51,21 +51,83 @@ class ASiC_E::Private
5151
/**
5252
* Initialize BDOC container.
5353
*/
54-
ASiC_E::ASiC_E()
55-
: ASiContainer(MIMETYPE_ASIC_E)
54+
ASiC_E::ASiC_E(const string &path, bool create) try
55+
: ASiContainer(path, MIMETYPE_ASIC_E)
5656
, d(make_unique<Private>())
5757
{
58-
}
58+
if(create)
59+
return;
60+
auto z = load(true, {MIMETYPE_ASIC_E, MIMETYPE_ADOC});
61+
auto doc = XMLDocument::open(z.read("META-INF/manifest.xml"), {"manifest", MANIFEST_NS});
62+
doc.validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_manifest_v1_2.xsd"));
63+
64+
set<string_view> manifestFiles;
65+
bool mimeFound = false;
66+
for(auto file = doc/"file-entry"; file; file++)
67+
{
68+
auto full_path = file[{"full-path", MANIFEST_NS}];
69+
auto media_type = file[{"media-type", MANIFEST_NS}];
70+
DEBUG("full_path = '%.*s', media_type = '%.*s'", STR_VIEW_FMT(full_path), STR_VIEW_FMT(media_type));
5971

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

71133
ASiC_E::~ASiC_E()
@@ -110,9 +172,7 @@ void ASiC_E::save(const ZipSerialize &s)
110172
unique_ptr<Container> ASiC_E::createInternal(const string &path)
111173
{
112174
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;
175+
return unique_ptr<Container>(new ASiC_E(path, true));
116176
}
117177

118178
/**
@@ -146,7 +206,7 @@ void ASiC_E::canSave()
146206
unique_ptr<Container> ASiC_E::openInternal(const string &path)
147207
{
148208
DEBUG("ASiC_E::openInternal(%s)", path.c_str());
149-
return unique_ptr<Container>(new ASiC_E(path));
209+
return unique_ptr<Container>(new ASiC_E(path, false));
150210
}
151211

152212
void ASiC_E::loadSignatures(XMLDocument &&doc, const string &file)
@@ -157,92 +217,6 @@ void ASiC_E::loadSignatures(XMLDocument &&doc, const string &file)
157217
addSignature(make_unique<SignatureXAdES_LTA>(signatures, s, this));
158218
}
159219

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-
246220
Signature* ASiC_E::prepareSignature(Signer *signer)
247221
{
248222
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;

src/ASiContainer.cpp

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,9 @@ using namespace digidoc;
3636
using namespace digidoc::util;
3737
using namespace std;
3838

39-
class ASiContainer::Private
39+
struct ASiContainer::Private
4040
{
41-
public:
42-
string mimetype, path;
41+
string path, mimetype;
4342
vector<DataFile*> documents;
4443
vector<Signature*> signatures;
4544
map<string, ZipSerialize::Properties, std::less<>> properties;
@@ -48,11 +47,9 @@ class ASiContainer::Private
4847
/**
4948
* Initialize Container.
5049
*/
51-
ASiContainer::ASiContainer(string_view mimetype)
52-
: d(make_unique<Private>())
53-
{
54-
d->mimetype = string(mimetype);
55-
}
50+
ASiContainer::ASiContainer(const string &path, string_view mimetype)
51+
: d(make_unique<Private>(path, string(mimetype)))
52+
{}
5653

5754
XMLDocument ASiContainer::createManifest() const
5855
{
@@ -78,10 +75,10 @@ XMLDocument ASiContainer::createManifest() const
7875
* @param supported supported mimetypes.
7976
* @return returns zip serializer for the container.
8077
*/
81-
ZipSerialize ASiContainer::load(const string &path, bool mimetypeRequired, const set<string_view> &supported)
78+
ZipSerialize ASiContainer::load(bool mimetypeRequired, const set<string_view> &supported)
8279
{
83-
DEBUG("ASiContainer::ASiContainer(path = '%s')", path.c_str());
84-
ZipSerialize z(d->path = path, false);
80+
DEBUG("ASiContainer::ASiContainer(path = '%s')", d->path.c_str());
81+
ZipSerialize z(d->path, false);
8582
vector<string> list = z.list();
8683

8784
// ETSI TS 102 918: mimetype has to be the first in the archive
@@ -247,8 +244,8 @@ void ASiContainer::save(const string &path)
247244
THROW("Can not save, container is empty.");
248245
canSave();
249246
if(!path.empty())
250-
zpath(path);
251-
ZipSerialize s(zpath(), true);
247+
d->path = path;
248+
ZipSerialize s(d->path, true);
252249
s.addFile("mimetype", zproperty("mimetype"), false)(mediaType());
253250

254251
array<char,10240> buf{};
@@ -269,12 +266,7 @@ void ASiContainer::save(const string &path)
269266
save(s);
270267
}
271268

272-
void ASiContainer::zpath(const string &file)
273-
{
274-
d->path = file;
275-
}
276-
277-
string ASiContainer::zpath() const
269+
const string& ASiContainer::path() const
278270
{
279271
return d->path;
280272
}

0 commit comments

Comments
 (0)