diff options
| -rw-r--r-- | Makefile | 3 | ||||
| -rwxr-xr-x | pkg/osx/installer/Bitmask.pkgproj | 755 | ||||
| -rw-r--r-- | pkg/osx/installer/README.rst | 2 | ||||
| -rwxr-xr-x | pkg/osx/quickpkg | 557 | ||||
| -rwxr-xr-x | pkg/osx/scripts/postinstall (renamed from pkg/osx/installer/post-inst.sh) | 2 | ||||
| -rwxr-xr-x | pkg/osx/scripts/preinstall (renamed from pkg/osx/installer/pre-inst.sh) | 4 | ||||
| -rw-r--r-- | pkg/osx/scripts/se.leap.bitmask-helper.plist (renamed from pkg/osx/installer/se.leap.bitmask-helper.plist) | 0 | ||||
| -rw-r--r-- | pkg/pyinst/build.mk | 2 | 
8 files changed, 566 insertions, 759 deletions
| @@ -69,6 +69,9 @@ bundle_in_docker:  docker_container:  	cd pkg/docker_bundle && docker build -t mybundle . +osx_pkg: +	pkg/osx/quickpkg --output dist/Bitmask-$(NEXT_VERSION).pkg --scripts pkg/osx/scripts/ dist/Bitmask.app/ +  cleanpkg:  	rm -rf dist build diff --git a/pkg/osx/installer/Bitmask.pkgproj b/pkg/osx/installer/Bitmask.pkgproj deleted file mode 100755 index f42ffc87..00000000 --- a/pkg/osx/installer/Bitmask.pkgproj +++ /dev/null @@ -1,755 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> -	<key>PROJECT</key> -	<dict> -		<key>PACKAGE_FILES</key> -		<dict> -			<key>DEFAULT_INSTALL_LOCATION</key> -			<string>/Applications</string> -			<key>HIERARCHY</key> -			<dict> -				<key>CHILDREN</key> -				<array> -					<dict> -						<key>CHILDREN</key> -						<array> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>80</integer> -								<key>PATH</key> -								<string>Bitmask.app</string> -								<key>PATH_TYPE</key> -								<integer>3</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>3</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>80</integer> -								<key>PATH</key> -								<string>Utilities</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -						</array> -						<key>GID</key> -						<integer>80</integer> -						<key>PATH</key> -						<string>Applications</string> -						<key>PATH_TYPE</key> -						<integer>0</integer> -						<key>PERMISSIONS</key> -						<integer>509</integer> -						<key>TYPE</key> -						<integer>1</integer> -						<key>UID</key> -						<integer>0</integer> -					</dict> -					<dict> -						<key>CHILDREN</key> -						<array> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>80</integer> -								<key>PATH</key> -								<string>Application Support</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Automator</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Documentation</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Filesystems</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Frameworks</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Input Methods</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Internet Plug-Ins</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>LaunchAgents</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>LaunchDaemons</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>PreferencePanes</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Preferences</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>80</integer> -								<key>PATH</key> -								<string>Printers</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>PrivilegedHelperTools</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>QuickLook</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>QuickTime</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Screen Savers</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Scripts</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Services</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Widgets</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -						</array> -						<key>GID</key> -						<integer>0</integer> -						<key>PATH</key> -						<string>Library</string> -						<key>PATH_TYPE</key> -						<integer>0</integer> -						<key>PERMISSIONS</key> -						<integer>493</integer> -						<key>TYPE</key> -						<integer>1</integer> -						<key>UID</key> -						<integer>0</integer> -					</dict> -					<dict> -						<key>CHILDREN</key> -						<array> -							<dict> -								<key>CHILDREN</key> -								<array> -									<dict> -										<key>CHILDREN</key> -										<array/> -										<key>GID</key> -										<integer>0</integer> -										<key>PATH</key> -										<string>Extensions</string> -										<key>PATH_TYPE</key> -										<integer>0</integer> -										<key>PERMISSIONS</key> -										<integer>493</integer> -										<key>TYPE</key> -										<integer>1</integer> -										<key>UID</key> -										<integer>0</integer> -									</dict> -								</array> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Library</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>493</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -						</array> -						<key>GID</key> -						<integer>0</integer> -						<key>PATH</key> -						<string>System</string> -						<key>PATH_TYPE</key> -						<integer>0</integer> -						<key>PERMISSIONS</key> -						<integer>493</integer> -						<key>TYPE</key> -						<integer>1</integer> -						<key>UID</key> -						<integer>0</integer> -					</dict> -					<dict> -						<key>CHILDREN</key> -						<array> -							<dict> -								<key>CHILDREN</key> -								<array/> -								<key>GID</key> -								<integer>0</integer> -								<key>PATH</key> -								<string>Shared</string> -								<key>PATH_TYPE</key> -								<integer>0</integer> -								<key>PERMISSIONS</key> -								<integer>1023</integer> -								<key>TYPE</key> -								<integer>1</integer> -								<key>UID</key> -								<integer>0</integer> -							</dict> -						</array> -						<key>GID</key> -						<integer>80</integer> -						<key>PATH</key> -						<string>Users</string> -						<key>PATH_TYPE</key> -						<integer>0</integer> -						<key>PERMISSIONS</key> -						<integer>493</integer> -						<key>TYPE</key> -						<integer>1</integer> -						<key>UID</key> -						<integer>0</integer> -					</dict> -				</array> -				<key>GID</key> -				<integer>0</integer> -				<key>PATH</key> -				<string>/</string> -				<key>PATH_TYPE</key> -				<integer>0</integer> -				<key>PERMISSIONS</key> -				<integer>493</integer> -				<key>TYPE</key> -				<integer>1</integer> -				<key>UID</key> -				<integer>0</integer> -			</dict> -			<key>PAYLOAD_TYPE</key> -			<integer>0</integer> -			<key>VERSION</key> -			<integer>3</integer> -		</dict> -		<key>PACKAGE_SCRIPTS</key> -		<dict> -			<key>POSTINSTALL_PATH</key> -			<dict> -				<key>PATH</key> -				<string>../../bitmask-dev/pkg/osx/installer/post-inst.sh</string> -				<key>PATH_TYPE</key> -				<integer>3</integer> -			</dict> -			<key>PREINSTALL_PATH</key> -			<dict> -				<key>PATH</key> -				<string>../pkg/osx/installer/pre-inst.sh</string> -				<key>PATH_TYPE</key> -				<integer>3</integer> -			</dict> -			<key>RESOURCES</key> -			<array> -				<dict> -					<key>CHILDREN</key> -					<array/> -					<key>GID</key> -					<integer>0</integer> -					<key>PATH</key> -					<string>se.leap.bitmask-helper.plist</string> -					<key>PATH_TYPE</key> -					<integer>1</integer> -					<key>PERMISSIONS</key> -					<integer>420</integer> -					<key>TYPE</key> -					<integer>3</integer> -					<key>UID</key> -					<integer>0</integer> -				</dict> -			</array> -		</dict> -		<key>PACKAGE_SETTINGS</key> -		<dict> -			<key>AUTHENTICATION</key> -			<integer>1</integer> -			<key>CONCLUSION_ACTION</key> -			<integer>0</integer> -			<key>IDENTIFIER</key> -			<string>se.leap.pkg.Bitmask</string> -			<key>OVERWRITE_PERMISSIONS</key> -			<false/> -			<key>RELOCATABLE</key> -			<true/> -			<key>USE_HFS+_COMPRESSION</key> -			<true/> -			<key>VERSION</key> -			<string>0.10a1</string> -		</dict> -		<key>PROJECT_COMMENTS</key> -		<dict> -			<key>NOTES</key> -			<data> -			PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBIVE1M -			IDQuMDEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQv -			c3RyaWN0LmR0ZCI+CjxodG1sPgo8aGVhZD4KPG1ldGEgaHR0cC1l -			cXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7 -			IGNoYXJzZXQ9VVRGLTgiPgo8bWV0YSBodHRwLWVxdWl2PSJDb250 -			ZW50LVN0eWxlLVR5cGUiIGNvbnRlbnQ9InRleHQvY3NzIj4KPHRp -			dGxlPjwvdGl0bGU+CjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29u -			dGVudD0iQ29jb2EgSFRNTCBXcml0ZXIiPgo8bWV0YSBuYW1lPSJD -			b2NvYVZlcnNpb24iIGNvbnRlbnQ9IjEyNjUuMjEiPgo8c3R5bGUg -			dHlwZT0idGV4dC9jc3MiPgpwLnAxIHttYXJnaW46IDAuMHB4IDAu -			MHB4IDAuMHB4IDAuMHB4OyBmb250OiAxMi4wcHggSGVsdmV0aWNh -			fQo8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5Pgo8cCBjbGFzcz0icDEi -			Pk1heSB0aGUgT1NYIGJ1bmRsZXMgYmUgd2l0aCB5b3U8L3A+Cjwv -			Ym9keT4KPC9odG1sPgo= -			</data> -		</dict> -		<key>PROJECT_SETTINGS</key> -		<dict> -			<key>BUILD_PATH</key> -			<dict> -				<key>PATH</key> -				<string>../../../../../Bitmask/build</string> -				<key>PATH_TYPE</key> -				<integer>1</integer> -			</dict> -			<key>CERTIFICATE</key> -			<dict> -				<key>NAME</key> -				<string>Developer ID Installer: LEAP Encryption Access Project (SB5RR8K33W)</string> -				<key>PATH</key> -				<string>/Users/user/Library/Keychains/login.keychain</string> -			</dict> -			<key>EXCLUDED_FILES</key> -			<array> -				<dict> -					<key>PATTERNS_ARRAY</key> -					<array> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>.DS_Store</string> -							<key>TYPE</key> -							<integer>0</integer> -						</dict> -					</array> -					<key>PROTECTED</key> -					<true/> -					<key>PROXY_NAME</key> -					<string>Remove .DS_Store files</string> -					<key>PROXY_TOOLTIP</key> -					<string>Remove ".DS_Store" files created by the Finder.</string> -					<key>STATE</key> -					<true/> -				</dict> -				<dict> -					<key>PATTERNS_ARRAY</key> -					<array> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>.pbdevelopment</string> -							<key>TYPE</key> -							<integer>0</integer> -						</dict> -					</array> -					<key>PROTECTED</key> -					<true/> -					<key>PROXY_NAME</key> -					<string>Remove .pbdevelopment files</string> -					<key>PROXY_TOOLTIP</key> -					<string>Remove ".pbdevelopment" files created by ProjectBuilder or Xcode.</string> -					<key>STATE</key> -					<true/> -				</dict> -				<dict> -					<key>PATTERNS_ARRAY</key> -					<array> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>CVS</string> -							<key>TYPE</key> -							<integer>1</integer> -						</dict> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>.cvsignore</string> -							<key>TYPE</key> -							<integer>0</integer> -						</dict> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>.cvspass</string> -							<key>TYPE</key> -							<integer>0</integer> -						</dict> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>.svn</string> -							<key>TYPE</key> -							<integer>1</integer> -						</dict> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>.git</string> -							<key>TYPE</key> -							<integer>1</integer> -						</dict> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>.gitignore</string> -							<key>TYPE</key> -							<integer>0</integer> -						</dict> -					</array> -					<key>PROTECTED</key> -					<true/> -					<key>PROXY_NAME</key> -					<string>Remove SCM metadata</string> -					<key>PROXY_TOOLTIP</key> -					<string>Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems.</string> -					<key>STATE</key> -					<true/> -				</dict> -				<dict> -					<key>PATTERNS_ARRAY</key> -					<array> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>classes.nib</string> -							<key>TYPE</key> -							<integer>0</integer> -						</dict> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>designable.db</string> -							<key>TYPE</key> -							<integer>0</integer> -						</dict> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>info.nib</string> -							<key>TYPE</key> -							<integer>0</integer> -						</dict> -					</array> -					<key>PROTECTED</key> -					<true/> -					<key>PROXY_NAME</key> -					<string>Optimize nib files</string> -					<key>PROXY_TOOLTIP</key> -					<string>Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles.</string> -					<key>STATE</key> -					<true/> -				</dict> -				<dict> -					<key>PATTERNS_ARRAY</key> -					<array> -						<dict> -							<key>REGULAR_EXPRESSION</key> -							<false/> -							<key>STRING</key> -							<string>Resources Disabled</string> -							<key>TYPE</key> -							<integer>1</integer> -						</dict> -					</array> -					<key>PROTECTED</key> -					<true/> -					<key>PROXY_NAME</key> -					<string>Remove Resources Disabled folders</string> -					<key>PROXY_TOOLTIP</key> -					<string>Remove "Resources Disabled" folders.</string> -					<key>STATE</key> -					<true/> -				</dict> -				<dict> -					<key>SEPARATOR</key> -					<true/> -				</dict> -			</array> -			<key>NAME</key> -			<string>Bitmask</string> -			<key>REFERENCE_FOLDER_PATH</key> -			<string>/Users/user/leap/bitmask-dev/dist</string> -		</dict> -	</dict> -	<key>TYPE</key> -	<integer>1</integer> -	<key>VERSION</key> -	<integer>2</integer> -</dict> -</plist> diff --git a/pkg/osx/installer/README.rst b/pkg/osx/installer/README.rst deleted file mode 100644 index ff5676e3..00000000 --- a/pkg/osx/installer/README.rst +++ /dev/null @@ -1,2 +0,0 @@ -This is a project to generate Bitmask.pgk, using the program 'Packages'. -That will sign the installer with LEAP's developer certificates. diff --git a/pkg/osx/quickpkg b/pkg/osx/quickpkg new file mode 100755 index 00000000..a8d04982 --- /dev/null +++ b/pkg/osx/quickpkg @@ -0,0 +1,557 @@ +#!/usr/bin/python + +import argparse +import string +import os +import subprocess +import tempfile +import shutil +import stat + +# includes FoundationPlist since some apps store their Info.plist +# as binary PropertyLists + +# FoundationPlist: + +# Copyright 2009-2014 Greg Neagle. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +#      http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""FoundationPlist.py -- a tool to generate and parse MacOSX .plist files. + +This is intended as a drop-in replacement for Python's included plistlib, +with a few caveats: +    - readPlist() and writePlist() operate only on a filepath, +        not a file object. +    - there is no support for the deprecated functions: +        readPlistFromResource() +        writePlistToResource() +    - there is no support for the deprecated Plist class. + +The Property List (.plist) file format is a simple XML pickle supporting +basic object types, like dictionaries, lists, numbers and strings. +Usually the top level object is a dictionary. + +To write out a plist file, use the writePlist(rootObject, filepath) +function. 'rootObject' is the top level object, 'filepath' is a +filename. + +To parse a plist from a file, use the readPlist(filepath) function, +with a file name. It returns the top level object (again, usually a +dictionary). + +To work with plist data in strings, you can use readPlistFromString() +and writePlistToString(). +""" + +from Foundation import NSData, \ +                       NSPropertyListSerialization, \ +                       NSPropertyListMutableContainersAndLeaves, \ +                       NSPropertyListXMLFormat_v1_0 + + +class FoundationPlistException(Exception): +    '''Base error for this module''' +    pass + + +class NSPropertyListSerializationException(FoundationPlistException): +    '''Read error for this module''' +    pass + + +class NSPropertyListWriteException(FoundationPlistException): +    '''Write error for this module''' +    pass + + +# private functions +def _dataToPlist(data): +    '''low-level function that parses a data object into a propertyList object''' +    darwin_vers = int(os.uname()[2].split('.')[0]) +    if darwin_vers > 10: +        (plistObject, plistFormat, error) = ( +            NSPropertyListSerialization.propertyListWithData_options_format_error_( +                data, NSPropertyListMutableContainersAndLeaves, None, None)) +    else: +        # 10.5 doesn't support propertyListWithData:options:format:error: +        # 10.6's PyObjC wrapper for propertyListWithData:options:format:error: +        #        is broken +        # so use the older NSPropertyListSerialization function +        (plistObject, plistFormat, error) = ( +            NSPropertyListSerialization.propertyListFromData_mutabilityOption_format_errorDescription_( +                         data, NSPropertyListMutableContainersAndLeaves, None, None)) +    if plistObject is None: +        if error is None: +            error = "Plist data is invalid and could not be deserialized." +        raise NSPropertyListSerializationException(error) +    else: +        return plistObject + + +def _plistToData(plistObject): +    '''low-level function that creates NSData from a plist object''' +    darwin_vers = int(os.uname()[2].split('.')[0]) +    if darwin_vers > 10: +        (data, error) = ( +            NSPropertyListSerialization.dataWithPropertyList_format_options_error_( +                plistObject, NSPropertyListXMLFormat_v1_0, 0, None)) +    else: +        # use the older NSPropertyListSerialization function on 10.6 and 10.5 +        (data, error) = ( +            NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( +                plistObject, NSPropertyListXMLFormat_v1_0, None)) +    if data is None: +        if error is None: +            error = "Property list invalid for format." +        raise NSPropertyListSerializationException(error) +    return data + + +# public functions +def readPlist(filepath): +    '''Read a .plist file from filepath.  Return the unpacked root object +    (which is usually a dictionary).''' +    try: +        data = NSData.dataWithContentsOfFile_(filepath) +    except NSPropertyListSerializationException, error: +        # insert filepath info into error message +        errmsg = (u'%s in %s' % (error, filepath)) +        raise NSPropertyListSerializationException(errmsg) +    return _dataToPlist(data) + + +def readPlistFromString(aString): +    '''Read a plist data from a string. Return the root object.''' +    data = buffer(aString) +    return _dataToPlist(data) + + +def writePlist(plistObject, filepath): +    '''Write 'plistObject' as a plist to filepath.''' +    plistData = _plistToData(plistObject) +    if plistData.writeToFile_atomically_(filepath, True): +        return +    else: +        raise NSPropertyListWriteException( +            u"Failed to write plist data to %s" % filepath) + + +def writePlistToString(plistObject): +    '''Create a plist-formatted string from plistObject.''' +    return str(_plistToData(plistObject)) + + +#  +# quickpkg +#  + + +quickpkg_version = '0.5' +supported_extensions = ['dmg', 'app', 'zip'] + + +# modeled after munkiimport but to build a pkg + + +def logger(log, v=0): +    if args.verbosity >= v: +        print log + + +def cmdexec(command, stdin=''): +    """Execute a command.""" +    # if 'command' is a string, split the string into components +    if isinstance(command, str): +        command = command.split() + +    proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) +    (stdout, stderr) = proc.communicate(stdin) + +    logger("cmdexec: %s, result: %s, error: %s" % (command, stdout, stderr), 3) + +    # strip trailing whitespace, which would mess with string comparisons +    return {"return_code": proc.returncode, "stderr": stderr.rstrip(), "stdout": stdout.rstrip()} + + +# from munkicommons.py +def getFirstPlist(textString): +    """Gets the next plist from a text string that may contain one or +    more text-style plists. +    Returns a tuple - the first plist (if any) and the remaining +    string after the plist""" +    plist_header = '<?xml version' +    plist_footer = '</plist>' +    plist_start_index = textString.find(plist_header) +    if plist_start_index == -1: +        # not found +        return ("", textString) +    plist_end_index = textString.find( +        plist_footer, plist_start_index + len(plist_header)) +    if plist_end_index == -1: +        # not found +        return ("", textString) +    # adjust end value +    plist_end_index = plist_end_index + len(plist_footer) +    return (textString[plist_start_index:plist_end_index], +            textString[plist_end_index:]) + + +def dmg_has_sla(dmgpath): +    has_sla = False +    imageinfo_cmd = ['/usr/bin/hdiutil', 'imageinfo', dmgpath, '-plist'] +    result = cmdexec(imageinfo_cmd) +    if result["return_code"] != 0: +        print "error getting imageinfo! %s, %s" % (result["return_code"], result["stderr"]) +        return False +    result_plist = result["stdout"] +    imageinfo_dict = readPlistFromString(result_plist) +    properties = imageinfo_dict.get('Properties') +    if properties is not None: +        has_sla = properties.get('Software License Agreement', False) +    return has_sla + + +def attachdmg(dmgpath): +    global dmg_was_mounted +    info_cmd = ["hdiutil", "info", "-plist"] +    info_result = cmdexec(info_cmd) +    if info_result["return_code"] == 0: +        # parse the plist output +        (theplist, alltext) = getFirstPlist(info_result["stdout"]) +        info_dict = readPlistFromString(theplist) +        volpaths = [] +        if "images" in info_dict.keys(): +            for y in info_dict["images"]: +                if "image-path" in y.keys(): +                    if os.path.samefile(y["image-path"], dmgpath): +                        for x in y.get("system-entities"): +                            if "mount-point" in x.keys(): +                                volpaths.append(x["mount-point"]) +                                dmg_was_mounted = True +                        return volpaths +    else: +        print "error getting hdiutil info" +        print "(%d, %s)" % (info_result["returncode"], info_result["stderr"]) +        cleanup_and_exit(1) + +    attachcmd = ["/usr/bin/hdiutil", +                 "attach", +                 dmgpath, +                 "-mountrandom", +                 "/private/tmp", +                 "-plist", +                 "-nobrowse"] +    if dmg_has_sla(dmgpath): +        stdin = "Y\n" +        print "NOTE: Disk image %s has a license agreement!" % dmgpath +    else: +        stdin = '' +    result = cmdexec(attachcmd, stdin) +    if result["return_code"] == 0: +        # parse the plist output +        (theplist, alltext) = getFirstPlist(result["stdout"]) +        resultdict = readPlistFromString(theplist) +        volpaths = [] +        for x in resultdict["system-entities"]: +            if x["potentially-mountable"]: +                if x["volume-kind"] == 'hfs': +                    volpaths.append(x["mount-point"]) +        # return the paths to mounted volume +        return volpaths +    else: +        print "error mounting disk image" +        print "(%d, %s)" % (result["returncode"], result["stderr"]) +        cleanup_and_exit(1) + + +def detachpaths(volpaths): +    for x in volpaths: +        if os.path.exists(x): +            if os.path.ismount(x): +                detachcmd = ["/usr/bin/hdiutil", "detach", x] +                cmdexec(detachcmd) + + +def finditemswithextension(dirpath, item_extension): +    foundapps = [] +    if os.path.exists(dirpath): +        for x in os.listdir(dirpath): +            (item_basename, item_extension) = os.path.splitext(x) +            item_extension = string.lstrip(item_extension, '.') +            if item_extension == 'app': +                foundapps.append(os.path.join(dirpath, x)) +    else: +        print "path %s does not exist" % dirpath +        cleanup_and_exit(1) +    return foundapps + + +def appNameAndVersion(app_path): +    info_path = os.path.join(app_path, "Contents/Info.plist") +    if not os.path.exists(info_path): +        print "Application at path %s does not have Info.plist" % app_path +        # TODO: cleanup volumes here +        cleanup_and_exit(1) +    info_plist = readPlist(info_path) +    app_name = info_plist.get("CFBundleName") +    if app_name is None: +        app_name = info_plist.get("CFBundleDisplayName") +        if app_name is None: +            (app_name, app_ext) = os.path.splitext(os.path.basename(app_path)) +    app_identifier = info_plist.get("CFBundleIdentifier") +    app_version = info_plist.get("CFBundleShortVersionString") +    if app_version is None: +        app_version = info_plist.get("CFBundleVersion") +    return (app_name, app_identifier, app_version) + + +def cleanup_and_exit(returncode): +    global dmgvolumepaths +    global dmg_was_mounted +    global tmp_path +     +    if args.clean: +        if not dmg_was_mounted: +            detachpaths(dmgvolumepaths) +        if tmp_path is not None: +            shutil.rmtree(tmp_path) +    exit(returncode) + + +if __name__ == "__main__": + +    parser = argparse.ArgumentParser(description="""Attempts to build a pkg from the input. +                                                 Installer item can be a dmg, zip, or app.""", +                                     epilog="""Example: quickpkg /path/to/installer_item""") + +    # takes a path as input +    parser.add_argument('item_path', help="path to the installer item") + +    scripts_group = parser.add_argument_group('Installation Scripts', +        '''These options will set the installation scripts. You pass an entire folder of scripts, +            just like the option of `pkgbuild` or you can give a file for the preinstall or postinstall +            scripts respectively. If you give both the --scripts and either one or both of --preinstall +            and --postinstall, quickpkg will attempt to merge, but throw an error if it cannot.''') +    scripts_group.add_argument('--scripts', help="path to a folder with scripts") +    scripts_group.add_argument('--preinstall', '--pre', help="path to the preinstall script") +    scripts_group.add_argument('--postinstall', '--post', help="path to the postinstall script") + +    parser.add_argument('--ownership', choices=['recommended', 'preserve', 'preserve-other'], +                        help="will be passed through to pkgbuild") +    parser.add_argument('--output', '--out', '-o', +        help='''path where the package file will be created. If you give the full filename +                then you can use '{name}', '{version}' and '{identifier}' as placeholders. +                If this is a directory, then the +                package will be created with the default filename {name}-{version}.pkg''') + +    parser.add_argument('--clean', dest='clean', action='store_true', help="clean up temp files (DEFAULT)") +    parser.add_argument('--no-clean', dest='clean', action='store_false', help=" do NOT clean up temp files") +    parser.set_defaults(clean=True) + +    parser.add_argument('--relocatable', dest='relocatable', action='store_true', +                        help="sets BundleIsRelocatable in the PackageInfo to true") +    parser.add_argument('--no-relocatable', dest='relocatable', action='store_false', +                        help="sets BundleIsRelocatable in the PackageInfo (DEFAULT is false)") +    parser.set_defaults(relocatable=False) + + +    parser.add_argument("-v", "--verbosity", action="count", default=0, help="controls amount of logging output (max -vvv)") +    parser.add_argument('--version', help='prints the version', action='version', version=quickpkg_version) + +    args = parser.parse_args() + +    # remove trailing '/' from path +    item_path = string.rstrip(args.item_path, '/') + +    if item_path.startswith('~'): +        item_path = os.path.expanduser(item_path) +    item_path = os.path.abspath(item_path) + +    # get file extension +    (item_basename, item_extension) = os.path.splitext(item_path) +    item_extension = string.lstrip(item_extension, '.') + +    # is extension supported +    if item_extension not in supported_extensions: +        print ".%s is not a supported extension!" % item_extension +        exit(1) + +    foundapps = [] + +    # if item is an app, just pass it on +    if item_extension == 'app': +        if not os.path.exists(item_path): +            print "This does not seem to be an Application!" +            exit(1) +        foundapps.append(item_path) + +    dmgvolumepaths = [] +    tmp_path = None +    dmg_was_mounted = False +    tmp_scripts_path = None +    tmp_path = tempfile.mkdtemp() +    payload_path = os.path.join(tmp_path, "payload") +    os.makedirs(payload_path) + +    # if item is a dmg, mount it and find useful contents +    if item_extension == 'dmg': +        dmgvolumepaths = attachdmg(item_path) +        for x in dmgvolumepaths: +            moreapps = finditemswithextension(x, 'app') +            foundapps.extend(moreapps) +        if len(foundapps) == 0: +            print "Could not find an application!" +            cleanup_and_exit(1) +        elif len(foundapps) > 1: +            print "Found too many Applications! Can't decide!" +            print foundapps +            cleanup_and_exit(1) +         +    # if item is zip, unzip to tmp location and find useful contents +    if item_extension == 'zip': +        unarchive_path = os.path.join(tmp_path, "unarchive") +        unzip_cmd = ["/usr/bin/unzip", "-d", unarchive_path, item_path] +        result = cmdexec(unzip_cmd) +        if result["return_code"] != 0: +            print "An error occured while unzipping:" +            print "%d, %s" % (result["return_code"], result["stderr"]) +            cleanup_and_exit(1) +        foundapps = finditemswithextension(unarchive_path, 'app') +        if len(foundapps) == 0: +            print "Could not find an application!" +            cleanup_and_exit(1) +        elif len(foundapps) > 1: +            print "Found too many Applications! Can't decide!" +            print foundapps +            cleanup_and_exit(1) + +    logger("Found application: %s" % foundapps[0], 1) + +    # copy found app to payload folder +    app_name = os.path.basename(foundapps[0]) +    app_path = os.path.join(payload_path, app_name) +    shutil.copytree(foundapps[0], app_path)         + +    # extract version and other metadata +    (app_name, app_identifier, app_version) = appNameAndVersion(app_path) + +    logger("Name: %s, ID: %s, Version: %s" % (app_name, app_identifier, app_version), 1) + +    # create the component plist +    component_plist = os.path.join(tmp_path, app_identifier) + ".plist" +    analyzecmd = ["/usr/bin/pkgbuild", +                  "--analyze", +                  "--root", payload_path, +                  "--identifier", app_identifier, +                  "--version", app_version, +                  "--install-location", "/Applications", +                  component_plist] +    result = cmdexec(analyzecmd) + +    logger(result["stdout"], 1) +    if result["return_code"] != 0: +        print "Error Code: %d " % result["return_code"] +        print result["stderr"] +        cleanup_and_exit(1) +     +    if not args.relocatable: +        # read and change component plist +        components = readPlist(component_plist) +        # component plist is an array of components +        for bundle in components: +            if "BundleIsRelocatable" in bundle.keys(): +                bundle["BundleIsRelocatable"] = False +        writePlist(components, component_plist) +     +    pkg_name = "{name}-{version}.pkg" +    if args.output: +        if os.path.isdir(args.output): +            pkg_path = os.path.join(args.output, pkg_name) +        else: +            pkg_path = args.output +    else: +        pkg_path = pkg_name +    nospace_app_name = app_name.replace(' ', '')  # remove spaces +    pkg_path = pkg_path.format(name=nospace_app_name, version=app_version, identifier=app_identifier) + +    if not pkg_path.endswith('pkg'): +        pkg_path += '.pkg' + +    # run pkgutil to build result +    pkgcmd = ["/usr/bin/pkgbuild", +              "--root", payload_path, +              "--component-plist", component_plist, +              "--identifier", app_identifier, +              "--version", app_version, +              "--install-location", "/Applications", +              pkg_path] + +    if args.scripts and not os.path.exists(args.scripts): +        print "scripts folder %s does not exist!" % args.scripts +        cleanup_and_exit(1) + +    if args.postinstall or args.preinstall: +        tmp_scripts_path = os.path.join(tmp_dir, "scripts") +        os.makedirs(tmp_scripts_path) +         +        if args.scripts: +            logger("copying %s to tmp scripts folder %s" % (args.scripts, tmp_scripts_path), 1) +            shutil.rmtree(tmp_scripts_path) +            shutil.copytree(args.scripts, tmp_scripts_path) +        if args.postinstall: +            if not os.path.exists(args.postinstall): +                print "postinstall file %s does not exist!" % args.postinstall +                cleanup_and_exit(1) +            postinstall_path = os.path.join(tmp_scripts_path, "postinstall") +            if os.path.exists(postinstall_path): +                print "postinstall script already exists in %s" % args.scripts +                cleanup_and_exit(1) +            logger("copying %s to %s" % (args.postinstall, postinstall_path), 1) +            shutil.copy2(args.postinstall, postinstall_path) +            os.chmod(postinstall_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | +                                       stat.S_IRGRP | stat.S_IXGRP | +                                       stat.S_IROTH | stat.S_IXOTH) +        if args.preinstall: +            if not os.path.exists(args.preinstall): +                print "preinstall file %s does not exist!" % args.preinstall +                cleanup_and_exit(1) +            preinstall_path = os.path.join(tmp_scripts_path, "preinstall") +            if os.path.exists(preinstall_path): +                print "preinstall script already exists in %s" % args.scripts +                cleanup_and_exit(1) +            logger("copying %s to %s" % (args.preinstall, preinstall_path), 1) +            shutil.copy2(args.preinstall, preinstall_path) +            os.chmod(preinstall_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | +                                      stat.S_IRGRP | stat.S_IXGRP | +                                      stat.S_IROTH | stat.S_IXOTH) + +    if tmp_scripts_path: +        logger("scripts path: %s" % tmp_scripts_path, 1) +        pkgcmd.extend(["--scripts", tmp_scripts_path]) +    elif args.scripts: +        logger("scripts path: %s" % args.scripts, 1) +        pkgcmd.extend(["--scripts", args.scripts]) + +    if args.ownership: +        pkgcmd.extend(["--ownership", args.ownership]) + +    result = cmdexec(pkgcmd) + +    logger(result["stdout"], 1) +    if result["return_code"] != 0: +        print "Error Code: %d " % result["return_code"] +        print result["stderr"] +    else: +        print pkg_path + +    cleanup_and_exit(0) diff --git a/pkg/osx/installer/post-inst.sh b/pkg/osx/scripts/postinstall index 0202323a..9c2176b2 100755 --- a/pkg/osx/installer/post-inst.sh +++ b/pkg/osx/scripts/postinstall @@ -2,3 +2,5 @@  # Bitmask Post-Instalation script  cp se.leap.bitmask-helper.plist /Library/LaunchDaemons/  launchctl load /Library/LaunchDaemons/se.leap.bitmask-helper.plist || echo "Already loaded, skipping..." +echo `date` "::Bitmask post-installation script succeeded." >> /tmp/bitmask-install.log +exit 0 diff --git a/pkg/osx/installer/pre-inst.sh b/pkg/osx/scripts/preinstall index 1651a221..222922cf 100755 --- a/pkg/osx/installer/pre-inst.sh +++ b/pkg/osx/scripts/preinstall @@ -1,3 +1,5 @@  #!/bin/sh -# Bitmask Post-Instalation script +# Bitmask Pre-Instalation script  [[ -f /Library/LaunchDaemons/se.leap.bitmask-helper.plist ]] && launchctl unload /Library/LaunchDaemons/se.leap.bitmask-helper.plist +echo `date` "::Bitmask pre-installation script succeeded." >> /tmp/bitmask-install.log +exit 0 diff --git a/pkg/osx/installer/se.leap.bitmask-helper.plist b/pkg/osx/scripts/se.leap.bitmask-helper.plist index 4428f131..4428f131 100644 --- a/pkg/osx/installer/se.leap.bitmask-helper.plist +++ b/pkg/osx/scripts/se.leap.bitmask-helper.plist diff --git a/pkg/pyinst/build.mk b/pkg/pyinst/build.mk index b6dea151..2ad224b4 100644 --- a/pkg/pyinst/build.mk +++ b/pkg/pyinst/build.mk @@ -47,7 +47,7 @@ bundle_osx_helpers:  	mkdir -p $(DIST_VERSION)/apps/helpers  	cp src/leap/bitmask/vpn/helpers/osx/bitmask-helper $(DIST_VERSION)/apps/helpers/  	cp src/leap/bitmask/vpn/helpers/osx/bitmask.pf.conf $(DIST_VERSION)/apps/helpers/ -	cp pkg/osx/installer/se.leap.bitmask-helper.plist $(DIST_VERSION)/apps/helpers/ +	cp pkg/osx/scripts/se.leap.bitmask-helper.plist $(DIST_VERSION)/apps/helpers/  	cp -r pkg/osx/daemon $(DIST_VERSION)/apps/helpers/  	cp -r pkg/osx/openvpn $(DIST_VERSION)/apps/helpers/ | 
