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