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