xref: /trunk/test/odf-validate/fixtures/encrypted/make.py (revision 0e16a31d78a652c56c5c0fc79c752f48b9048df9)
1*0e16a31dSJim Jagielski#**************************************************************
2*0e16a31dSJim Jagielski#
3*0e16a31dSJim Jagielski#  Licensed to the Apache Software Foundation (ASF) under one
4*0e16a31dSJim Jagielski#  or more contributor license agreements.  See the NOTICE file
5*0e16a31dSJim Jagielski#  distributed with this work for additional information
6*0e16a31dSJim Jagielski#  regarding copyright ownership.  The ASF licenses this file
7*0e16a31dSJim Jagielski#  to you under the Apache License, Version 2.0 (the
8*0e16a31dSJim Jagielski#  "License"); you may not use this file except in compliance
9*0e16a31dSJim Jagielski#  with the License.  You may obtain a copy of the License at
10*0e16a31dSJim Jagielski#
11*0e16a31dSJim Jagielski#    http://www.apache.org/licenses/LICENSE-2.0
12*0e16a31dSJim Jagielski#
13*0e16a31dSJim Jagielski#  Unless required by applicable law or agreed to in writing,
14*0e16a31dSJim Jagielski#  software distributed under the License is distributed on an
15*0e16a31dSJim Jagielski#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*0e16a31dSJim Jagielski#  KIND, either express or implied.  See the License for the
17*0e16a31dSJim Jagielski#  specific language governing permissions and limitations
18*0e16a31dSJim Jagielski#  under the License.
19*0e16a31dSJim Jagielski#
20*0e16a31dSJim Jagielski#**************************************************************
21*0e16a31dSJim Jagielski
22*0e16a31dSJim Jagielski# usage: runpy.sh fixtures/encrypted/make.py <port> <outdir> [<twindir>]   (fixtures/encrypted/run.sh drives it)
23*0e16a31dSJim Jagielski# Saves password-protected packages with the office's configured ODF version and UseSHA1InODF12 /
24*0e16a31dSJim Jagielski# UseBlowfishInODF12 values; <twindir> gets the same documents without a password.
25*0e16a31dSJim Jagielskiimport sys, os, zlib, struct, hashlib, uno
26*0e16a31dSJim Jagielskifrom com.sun.star.awt import Point, Size
27*0e16a31dSJim Jagielskifrom com.sun.star.table import CellRangeAddress
28*0e16a31dSJim Jagielskifrom unohelp import connect, desktop, pv, FILTERS
29*0e16a31dSJim Jagielski
30*0e16a31dSJim JagielskiPASSWORD = "t12-Password"
31*0e16a31dSJim Jagielskiport, outdir = int(sys.argv[1]), os.path.abspath(sys.argv[2])
32*0e16a31dSJim Jagielskitwindir = os.path.abspath(sys.argv[3]) if len(sys.argv) > 3 else None
33*0e16a31dSJim Jagielskictx = connect(port)
34*0e16a31dSJim Jagielskid = desktop(ctx)
35*0e16a31dSJim Jagielskios.makedirs(outdir, exist_ok=True)
36*0e16a31dSJim Jagielskiif twindir:
37*0e16a31dSJim Jagielski    os.makedirs(twindir, exist_ok=True)
38*0e16a31dSJim Jagielski
39*0e16a31dSJim Jagielski
40*0e16a31dSJim Jagielskidef png(path):
41*0e16a31dSJim Jagielski    raw = b"".join(b"\x00" + b"".join(bytes((x * 16, y * 16, 128)) for x in range(16)) for y in range(16))
42*0e16a31dSJim Jagielski
43*0e16a31dSJim Jagielski    def chunk(t, b):
44*0e16a31dSJim Jagielski        c = struct.pack(">I", len(b)) + t + b
45*0e16a31dSJim Jagielski        return c + struct.pack(">I", zlib.crc32(t + b) & 0xFFFFFFFF)
46*0e16a31dSJim Jagielski    with open(path, "wb") as f:
47*0e16a31dSJim Jagielski        f.write(b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", 16, 16, 8, 2, 0, 0, 0))
48*0e16a31dSJim Jagielski                + chunk(b"IDAT", zlib.compress(raw)) + chunk(b"IEND", b""))
49*0e16a31dSJim Jagielski
50*0e16a31dSJim Jagielski
51*0e16a31dSJim Jagielskidef algs_in_use():
52*0e16a31dSJim Jagielski    cp = ctx.ServiceManager.createInstanceWithContext("com.sun.star.configuration.ConfigurationProvider", ctx)
53*0e16a31dSJim Jagielski    ca = cp.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess",
54*0e16a31dSJim Jagielski                                        (pv("nodepath", "/org.openoffice.Office.Common/Save/ODF"),))
55*0e16a31dSJim Jagielski    return {(True, True): "", (False, False): "-aes", (True, False): "-sha1-aes",
56*0e16a31dSJim Jagielski            (False, True): "-sha256-blowfish"}[(ca.getByName("UseSHA1InODF12"), ca.getByName("UseBlowfishInODF12"))]
57*0e16a31dSJim Jagielski
58*0e16a31dSJim Jagielski
59*0e16a31dSJim Jagielskidef graphic(url):
60*0e16a31dSJim Jagielski    gp = ctx.ServiceManager.createInstanceWithContext("com.sun.star.graphic.GraphicProvider", ctx)
61*0e16a31dSJim Jagielski    return gp.queryGraphic((pv("URL", url),))
62*0e16a31dSJim Jagielski
63*0e16a31dSJim Jagielski
64*0e16a31dSJim Jagielskidef new(kind):
65*0e16a31dSJim Jagielski    url = {"odt": "swriter", "ods": "scalc", "odp": "simpress", "odg": "sdraw"}[kind]
66*0e16a31dSJim Jagielski    return d.loadComponentFromURL("private:factory/" + url, "_blank", 0, (pv("Hidden", True),))
67*0e16a31dSJim Jagielski
68*0e16a31dSJim Jagielski
69*0e16a31dSJim Jagielskidef pic(doc, page, url, x, y):
70*0e16a31dSJim Jagielski    g = doc.createInstance("com.sun.star.drawing.GraphicObjectShape")
71*0e16a31dSJim Jagielski    page.add(g)
72*0e16a31dSJim Jagielski    g.Graphic = graphic(url)
73*0e16a31dSJim Jagielski    g.Position = Point(x, y)
74*0e16a31dSJim Jagielski    g.Size = Size(4000, 4000)
75*0e16a31dSJim Jagielski
76*0e16a31dSJim Jagielski
77*0e16a31dSJim Jagielskidef shape(doc, page, svc, x, y, w, h, text=None):
78*0e16a31dSJim Jagielski    s = doc.createInstance("com.sun.star.drawing." + svc)
79*0e16a31dSJim Jagielski    page.add(s)
80*0e16a31dSJim Jagielski    s.Position = Point(x, y)
81*0e16a31dSJim Jagielski    s.Size = Size(w, h)
82*0e16a31dSJim Jagielski    if text:
83*0e16a31dSJim Jagielski        s.String = text
84*0e16a31dSJim Jagielski    return s
85*0e16a31dSJim Jagielski
86*0e16a31dSJim Jagielski
87*0e16a31dSJim Jagielskidef writer(doc, img, objects):
88*0e16a31dSJim Jagielski    text = doc.Text
89*0e16a31dSJim Jagielski    cur = text.createTextCursor()
90*0e16a31dSJim Jagielski    text.insertString(cur, "Encrypted text document. \u00c4\u00f6\u00fc \u20ac \u4e2d\u6587\n", False)
91*0e16a31dSJim Jagielski    text.insertString(cur, "Second paragraph with enough words to make the content stream longer. " * 40, False)
92*0e16a31dSJim Jagielski    if img:
93*0e16a31dSJim Jagielski        g = doc.createInstance("com.sun.star.text.TextGraphicObject")
94*0e16a31dSJim Jagielski        g.Graphic = graphic(img)
95*0e16a31dSJim Jagielski        g.Width, g.Height = 4000, 4000
96*0e16a31dSJim Jagielski        text.insertTextContent(cur, g, False)
97*0e16a31dSJim Jagielski    if objects:
98*0e16a31dSJim Jagielski        for clsid, name in (("12dcae26-281f-416f-a234-c3086127382e", "Chart1"),
99*0e16a31dSJim Jagielski                            ("078B7ABA-54FC-457F-8551-6147e776a997", "Formula1")):
100*0e16a31dSJim Jagielski            o = doc.createInstance("com.sun.star.text.TextEmbeddedObject")
101*0e16a31dSJim Jagielski            o.CLSID = clsid
102*0e16a31dSJim Jagielski            o.Name = name
103*0e16a31dSJim Jagielski            o.Width, o.Height = 8000, 6000
104*0e16a31dSJim Jagielski            text.insertTextContent(cur, o, False)
105*0e16a31dSJim Jagielski            if name == "Formula1":
106*0e16a31dSJim Jagielski                o.Model.Formula = "a + b over c"
107*0e16a31dSJim Jagielski
108*0e16a31dSJim Jagielski
109*0e16a31dSJim Jagielskidef calc(doc, img, objects):
110*0e16a31dSJim Jagielski    sh = doc.Sheets.getByIndex(0)
111*0e16a31dSJim Jagielski    for r in range(10):
112*0e16a31dSJim Jagielski        sh.getCellByPosition(0, r).Value = r + 1
113*0e16a31dSJim Jagielski        sh.getCellByPosition(1, r).Value = (r + 1) * 3.5
114*0e16a31dSJim Jagielski        sh.getCellByPosition(2, r).String = "row %d \u00e9" % r
115*0e16a31dSJim Jagielski    sh.getCellByPosition(3, 0).Formula = "=SUM(A1:A10)"
116*0e16a31dSJim Jagielski    if objects:
117*0e16a31dSJim Jagielski        ra = CellRangeAddress()
118*0e16a31dSJim Jagielski        ra.Sheet, ra.StartColumn, ra.StartRow, ra.EndColumn, ra.EndRow = 0, 0, 0, 1, 9
119*0e16a31dSJim Jagielski        sh.Charts.addNewByName("C1", uno.createUnoStruct("com.sun.star.awt.Rectangle", 8000, 1000, 8000, 6000), (ra,), True, True)
120*0e16a31dSJim Jagielski    if img:
121*0e16a31dSJim Jagielski        pic(doc, sh.DrawPage, img, 1000, 12000)
122*0e16a31dSJim Jagielski
123*0e16a31dSJim Jagielski
124*0e16a31dSJim Jagielskidef impress(doc, img, objects):
125*0e16a31dSJim Jagielski    p = doc.DrawPages.getByIndex(0)
126*0e16a31dSJim Jagielski    shape(doc, p, "TextShape", 2000, 2000, 10000, 2000, "Encrypted slide one")
127*0e16a31dSJim Jagielski    shape(doc, p, "RectangleShape", 2000, 6000, 5000, 3000, "box")
128*0e16a31dSJim Jagielski    if img:
129*0e16a31dSJim Jagielski        pic(doc, p, img, 14000, 6000)
130*0e16a31dSJim Jagielski    p2 = doc.DrawPages.insertNewByIndex(1)
131*0e16a31dSJim Jagielski    shape(doc, p2, "EllipseShape", 3000, 3000, 6000, 4000, "slide two")
132*0e16a31dSJim Jagielski
133*0e16a31dSJim Jagielski
134*0e16a31dSJim Jagielskidef draw(doc, img, objects):
135*0e16a31dSJim Jagielski    p = doc.DrawPages.getByIndex(0)
136*0e16a31dSJim Jagielski    shape(doc, p, "RectangleShape", 2000, 2000, 6000, 3000, "rect")
137*0e16a31dSJim Jagielski    shape(doc, p, "TextShape", 2000, 7000, 8000, 2000, "Encrypted drawing \u00e4")
138*0e16a31dSJim Jagielski    if img:
139*0e16a31dSJim Jagielski        pic(doc, p, img, 12000, 2000)
140*0e16a31dSJim Jagielski
141*0e16a31dSJim Jagielski
142*0e16a31dSJim JagielskiFILL = {"odt": writer, "ods": calc, "odp": impress, "odg": draw}
143*0e16a31dSJim JagielskiTAG = {"odt": "text", "ods": "calc", "odp": "impress", "odg": "draw"}
144*0e16a31dSJim Jagielski
145*0e16a31dSJim Jagielski
146*0e16a31dSJim Jagielskidef modify_info(password):
147*0e16a31dSJim Jagielski    salt = os.urandom(16)
148*0e16a31dSJim Jagielski    h = hashlib.pbkdf2_hmac("sha1", password.encode("utf-8"), salt, 1024, 16)
149*0e16a31dSJim Jagielski    return uno.Any("[]com.sun.star.beans.PropertyValue",
150*0e16a31dSJim Jagielski                   (pv("algorithm-name", "PBKDF2"), pv("salt", uno.ByteSequence(salt)),
151*0e16a31dSJim Jagielski                    pv("iteration-count", 1024), pv("hash", uno.ByteSequence(h))))
152*0e16a31dSJim Jagielski
153*0e16a31dSJim Jagielski
154*0e16a31dSJim Jagielskidef make(kind, suffix, img, objects, tag, encrypt=True, modify=False):
155*0e16a31dSJim Jagielski    doc = new(kind)
156*0e16a31dSJim Jagielski    FILL[kind](doc, img, objects)
157*0e16a31dSJim Jagielski    name = "encrypted-%s%s.%s" % (tag, suffix, kind)
158*0e16a31dSJim Jagielski    props = [pv("FilterName", FILTERS[kind])]
159*0e16a31dSJim Jagielski    if encrypt:
160*0e16a31dSJim Jagielski        props.append(pv("Password", PASSWORD))
161*0e16a31dSJim Jagielski    if modify:
162*0e16a31dSJim Jagielski        props.append(pv("ModifyPasswordInfo", modify_info(PASSWORD)))
163*0e16a31dSJim Jagielski    doc.storeToURL(uno.systemPathToFileUrl(os.path.join(outdir, name)), tuple(props))
164*0e16a31dSJim Jagielski    if twindir:
165*0e16a31dSJim Jagielski        doc.storeToURL(uno.systemPathToFileUrl(os.path.join(twindir, name)), (pv("FilterName", FILTERS[kind]),))
166*0e16a31dSJim Jagielski    doc.close(True)
167*0e16a31dSJim Jagielski    print(name)
168*0e16a31dSJim Jagielski
169*0e16a31dSJim Jagielski
170*0e16a31dSJim Jagielskiimg = os.path.join(os.path.dirname(outdir), "pic.png")
171*0e16a31dSJim Jagielskipng(img)
172*0e16a31dSJim Jagielskiimgurl = uno.systemPathToFileUrl(img)
173*0e16a31dSJim Jagielskisuffix = algs_in_use()
174*0e16a31dSJim Jagielskiprint("algorithms:", suffix or "default")
175*0e16a31dSJim Jagielskifor kind in FILL if suffix in ("", "-aes") else ("odt",):
176*0e16a31dSJim Jagielski    make(kind, suffix, None, False, TAG[kind])
177*0e16a31dSJim Jagielski    make(kind, suffix, imgurl, kind in ("odt", "ods"), TAG[kind] + "-objects")
178*0e16a31dSJim Jagielskiif not suffix:
179*0e16a31dSJim Jagielski    for kind in ("odt", "ods"):
180*0e16a31dSJim Jagielski        make(kind, suffix, None, False, TAG[kind] + "-modifyonly", encrypt=False, modify=True)
181*0e16a31dSJim Jagielski        make(kind, suffix, None, False, TAG[kind] + "-modify", modify=True)
182