1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
#!/usr/bin/python
# Generate bundles for brandable Bitmask Lite.
# (c) LEAP Encryption Access Project
# (c) Kali Kaneko 2018-2019
import json
import os
import os.path
import shutil
import stat
from string import Template
here = os.path.split(os.path.abspath(__file__))[0]
ENTRYPOINT = 'bitmask-vpn'
HELPER = 'bitmask-helper'
OPENVPN = 'openvpn-osx'
TEMPLATE_INFO = 'template-info.plist'
TEMPLATE_HELPER = 'template-helper.plist'
TEMPLATE_PREINSTALL = 'template-preinstall'
TEMPLATE_POSTINSTALL = 'template-postinstall'
data = json.load(open(os.path.join(here, 'data.json')))
APPNAME = data.get('applicationName')
VERSION = data.get('version', 'unknown')
APP_PATH = os.path.abspath(here + '/../dist/' + APPNAME + ".app")
STAGING = os.path.abspath(here + '/../staging/')
ASSETS = os.path.abspath(here + '/../assets/')
ICON = os.path.join(ASSETS, 'icon.icns')
SCRIPTS = os.path.join(os.path.abspath(here), 'scripts')
INFO_PLIST = APP_PATH + '/Contents/Info.plist'
HELPER_PLIST = os.path.join(SCRIPTS, 'se.leap.bitmask-helper.plist')
PREINSTALL = os.path.join(SCRIPTS, 'preinstall')
POSTINSTALL = os.path.join(SCRIPTS, 'postinstall')
RULEFILE = os.path.join(here, 'bitmask.pf.conf')
VPN_UP = os.path.join(here, 'client.up.sh')
VPN_DOWN = os.path.join(here, 'client.down.sh')
try:
os.makedirs(APP_PATH + "/Contents/MacOS")
except Exception:
pass
try:
os.makedirs(APP_PATH + "/Contents/Resources")
except Exception:
pass
try:
os.makedirs(APP_PATH + "/Contents/helper")
except Exception:
pass
data['entrypoint'] = ENTRYPOINT
data['info_string'] = APPNAME + " " + VERSION
data['bundle_identifier'] = 'se.leap.' + data['applicationNameLower']
data['bundle_name'] = APPNAME
# utils
def copy_payload(filename, destfile=None):
if destfile is None:
destfile = APP_PATH + "/Contents/MacOS/" + filename
else:
destfile = APP_PATH + destfile
shutil.copyfile(STAGING + '/' + filename, destfile)
cmode = os.stat(destfile).st_mode
os.chmod(destfile, cmode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
def generate_from_template(template, dest, data):
print("[+] File written from template to", dest)
template = Template(open(template).read())
with open(dest, 'w') as output:
output.write(template.substitute(data))
# 1. Generation of the Bundle Info.plist
# --------------------------------------
generate_from_template(TEMPLATE_INFO, INFO_PLIST, data)
# 2. Generate PkgInfo
# -------------------------------------------
with open(APP_PATH + "/Contents/PkgInfo", "w") as f:
# is this enough? See what PyInstaller does.
f.write("APPL????")
# 3. Copy the binary payloads
# --------------------------------------------
copy_payload(ENTRYPOINT)
copy_payload(HELPER)
copy_payload(OPENVPN, destfile='/Contents/Resources/openvpn.leap')
# 4. Copy the app icon from the assets folder
# -----------------------------------------------
shutil.copyfile(ICON, APP_PATH + '/Contents/Resources/app.icns')
# 5. Generate the scripts for the installer
# -----------------------------------------------
# Watch out that, for now, all the brandings are sharing the same helper name.
# This is intentional: I prefer not to have too many root helpers laying around
# until we consolidate a way of uninstalling and/or updating them.
# This also means that only one of the derivatives will work at a given time
# (ie, uninstall bitmask legacy to use riseupvpn).
# If this bothers you, and it should, let's work on improving uninstall and
# updates.
generate_from_template(TEMPLATE_HELPER, HELPER_PLIST, data)
generate_from_template(TEMPLATE_PREINSTALL, PREINSTALL, data)
generate_from_template(TEMPLATE_POSTINSTALL, POSTINSTALL, data)
# 6. Copy helper pf rule file
# ------------------------------------------------
shutil.copy(RULEFILE, APP_PATH + '/Contents/helper/')
# 7. Copy openvpn up/down scripts
# ------------------------------------------------
shutil.copy(VPN_UP, APP_PATH + '/Contents/helper/')
shutil.copy(VPN_DOWN, APP_PATH + '/Contents/helper/')
# 8. Generate uninstall script
# -----------------------------------------------
# TODO copy the uninstaller script from bitmask-dev
# TODO substitute vars
# this is a bit weak procedure for now.
# To begin with, this assumes everything is hardcoded into
# /Applications/APPNAME.app
# We could consider moving the helpers into /usr/local/sbin,
# so that the plist files always reference there.
# We're all set!
# -----------------------------------------------
print("[+] Output written to build/{provider}/dist/{appname}.app".format(
provider=data['name'].lower(),
appname=APPNAME))
|