xref: /trunk/test/odf-validate/make-pkg-controls.py (revision 0e16a31d78a652c56c5c0fc79c752f48b9048df9)
1#**************************************************************
2#
3#  Licensed to the Apache Software Foundation (ASF) under one
4#  or more contributor license agreements.  See the NOTICE file
5#  distributed with this work for additional information
6#  regarding copyright ownership.  The ASF licenses this file
7#  to you under the Apache License, Version 2.0 (the
8#  "License"); you may not use this file except in compliance
9#  with the License.  You may obtain a copy of the License at
10#
11#    http://www.apache.org/licenses/LICENSE-2.0
12#
13#  Unless required by applicable law or agreed to in writing,
14#  software distributed under the License is distributed on an
15#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16#  KIND, either express or implied.  See the License for the
17#  specific language governing permissions and limitations
18#  under the License.
19#
20#**************************************************************
21
22# usage: make-pkg-controls.py -- (re)generate pkgcheck.py's negative-control packages in fixtures/control-pkg/
23# .expected.json maps each package to the (level, rule) pairs pkgcheck.py must report, exactly.
24import json, os, shutil, warnings, zipfile
25
26C = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures", "control-pkg")
27MIME = "application/vnd.oasis.opendocument.text"
28S, Z = zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED
29SIG = ('<?xml version="1.0" encoding="UTF-8"?>\n<dsig:document-signatures xmlns:dsig="urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0" '
30       'dsig:version="%s" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:Signature Id="s1"/></dsig:document-signatures>\n')
31ENC = ('<manifest:encryption-data manifest:checksum-type="SHA1/1K" manifest:checksum="AAAA">'
32       '<manifest:algorithm manifest:algorithm-name="Blowfish CFB" manifest:initialisation-vector="AAAA"/>'
33       '<manifest:key-derivation manifest:key-derivation-name="PBKDF2" manifest:key-size="16" manifest:iteration-count="1024" manifest:salt="AAAA"/>'
34       '</manifest:encryption-data>')
35
36
37def entry(path, mt="text/xml", inner="", **attrs):
38    a = "".join(' manifest:%s="%s"' % kv for kv in attrs.items())
39    return '<manifest:file-entry manifest:full-path="%s" manifest:media-type="%s"%s>%s</manifest:file-entry>' % (path, mt, a, inner)
40
41
42def manifest(*entries, root="manifest:manifest"):
43    return ('<?xml version="1.0" encoding="UTF-8"?>\n<%s xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">%s</%s>\n'
44            % (root, "".join(entries), root))
45
46
47ROOT = entry("/", MIME, version="1.2")
48CONTENT = entry("content.xml")
49GOOD_MANI = manifest(ROOT, CONTENT)
50EXPECTED = {}
51
52
53def build(name, files, expect=()):
54    """files: (zip name, data, method[, extra]) in physical order."""
55    with zipfile.ZipFile(os.path.join(C, name + ".odt"), "w") as z, warnings.catch_warnings():
56        warnings.simplefilter("ignore")
57        for f in files:
58            zi = zipfile.ZipInfo(f[0])
59            if len(f) > 3:
60                zi.extra = f[3]
61            z.writestr(zi, f[1], compress_type=f[2])
62    EXPECTED[name + ".odt"] = sorted(expect)
63
64
65def std(mani=GOOD_MANI, mime=MIME, extra=()):
66    return [("mimetype", mime, S), ("content.xml", "<c/>", Z)] + list(extra) + [("META-INF/manifest.xml", mani, Z)]
67
68
69shutil.rmtree(C, ignore_errors=True)
70os.makedirs(C)
71build("good", std())
72sub = [("Object 1/content.xml", "<c/>", Z), ("Pictures/a.png", "x", S), ("secret.xml", "0123456789", S),
73       ("META-INF/documentsignatures.xml", SIG % "1.2", Z)]
74build("good-full", std(manifest(ROOT, CONTENT, entry("Object 1/", MIME, version="1.2"), entry("Object 1/content.xml"),
75                                entry("Pictures/a.png", "image/png"), entry("secret.xml", inner=ENC, size="10")), extra=sub))
76build("mime-deflated", [("mimetype", MIME, Z), ("content.xml", "<c/>", Z), ("META-INF/manifest.xml", GOOD_MANI, Z)], [("shall", "mimetype-compressed")])
77build("mime-extra", [("mimetype", MIME, S, b"\xfe\xca\x00\x00"), ("content.xml", "<c/>", Z), ("META-INF/manifest.xml", GOOD_MANI, Z)], [("shall", "mimetype-extra")])
78build("mime-notfirst", [("content.xml", "<c/>", Z), ("mimetype", MIME, S), ("META-INF/manifest.xml", GOOD_MANI, Z)], [("shall", "mimetype-first")])
79build("mime-mismatch", std(mime="application/x-bogus"), [("shall", "mimetype-mismatch")])
80build("mime-nonascii", std(mime=MIME + "é"), [("shall", "mimetype-ascii")])
81build("mime-missing", std()[1:], [("should", "mimetype-missing"), ("shall", "mimetype-missing")])
82build("mime-missing-noroot", std(manifest(CONTENT))[1:], [("should", "mimetype-missing")])
83build("no-root-entry", std(manifest(CONTENT)), [("shall", "manifest-root-entry")])
84build("uncovered", std(extra=[("extra.xml", "<e/>", Z)]), [("shall", "manifest-coverage")])
85build("dup-entry", std(manifest(ROOT, CONTENT, CONTENT)), [("shall", "manifest-duplicate")])
86build("self-entry", std(manifest(ROOT, CONTENT, entry("mimetype", "text/plain"))), [("shall", "manifest-self")])
87build("dangling", std(manifest(ROOT, CONTENT, entry("gone.xml"))), [("should", "manifest-dangling")])
88build("dir-entry-manifest", std(manifest(ROOT, CONTENT, entry("Configurations2/", "application/vnd.sun.xml.ui.configuration"))), [("should", "manifest-dir-entry")])
89build("stray-meta-inf", std(extra=[("META-INF/foo.xml", "<f/>", Z)]), [("shall", "meta-inf-file")])
90build("no-manifest", [("mimetype", MIME, S), ("content.xml", "<c/>", Z)], [("shall", "manifest-missing")])
91build("manifest-malformed", std("<manifest:manifest"), [("shall", "manifest-malformed")])
92build("manifest-wrongroot", std(manifest(root="manifest:other")), [("shall", "manifest-root")])
93build("zip-bzip2", std(extra=[("b.xml", "<b/>", zipfile.ZIP_BZIP2)], mani=manifest(ROOT, CONTENT, entry("b.xml"))), [("shall", "zip-method")])
94build("zip-dup-name", std(extra=[("content.xml", "<d/>", Z)]), [("shall", "zip-duplicate")])
95build("zip-dir-entry", std(extra=[("Pictures/", "", S)]), [("should", "zip-dir-entry")])
96build("enc-nosize", std(manifest(ROOT, CONTENT, entry("secret.xml", inner=ENC)), extra=[("secret.xml", "0123456789", S)]), [("shall", "encrypted-size")])
97build("enc-deflated", std(manifest(ROOT, CONTENT, entry("secret.xml", inner=ENC, size="10")), extra=[("secret.xml", "0123456789", Z)]), [("shall", "encrypted-method")])
98build("sig-malformed", std(extra=[("META-INF/documentsignatures.xml", "<dsig", Z)]), [("shall", "signature-malformed")])
99build("sig-wrongroot", std(extra=[("META-INF/documentsignatures.xml", "<a/>", Z)]), [("shall", "signature-root")])
100build("sig-badversion", std(extra=[("META-INF/documentsignatures.xml", SIG % "1.1", Z)]), [("shall", "signature-schema")])
101json.dump(EXPECTED, open(os.path.join(C, ".expected.json"), "w"), indent=1)
102