- a/Tools/ChangeLog +16 lines
Lines 1-3 a/Tools/ChangeLog_sec1
1
2022-02-21  Sam Sneddon  <gsnedders@apple.com>
2
3
        Rewrite run-webkit-archive to allow spawning other binaries
4
        https://bugs.webkit.org/show_bug.cgi?id=236968
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        This provides a CLI to run-webkit-archive, to allow a custom
9
        binary to be launched. It also provides feedback when binaries
10
        within the archive are still quarantined.
11
12
        The most notable option is --minibrowser, which will run the
13
        MiniBrowser.app within the archive.
14
15
        * WebKitArchiveSupport/run-webkit-archive:
16
1
2022-02-20  Sihui Liu  <sihui_liu@apple.com>
17
2022-02-20  Sihui Liu  <sihui_liu@apple.com>
2
18
3
        Origin file may not be created after migrating data to general storage directory
19
        Origin file may not be created after migrating data to general storage directory
- a/Tools/WebKitArchiveSupport/run-webkit-archive -35 / +208 lines
Lines 1-4 a/Tools/WebKitArchiveSupport/run-webkit-archive_sec1
1
#!/usr/bin/env python
1
#!/usr/bin/env xcrun python3
2
2
3
# Copyright (C) 2017 Apple Inc. All rights reserved.
3
# Copyright (C) 2017 Apple Inc. All rights reserved.
4
#
4
#
Lines 7-19 a/Tools/WebKitArchiveSupport/run-webkit-archive_sec2
7
# are met:
7
# are met:
8
#
8
#
9
# 1.  Redistributions of source code must retain the above copyright
9
# 1.  Redistributions of source code must retain the above copyright
10
#     notice, this list of conditions and the following disclaimer. 
10
#     notice, this list of conditions and the following disclaimer.
11
# 2.  Redistributions in binary form must reproduce the above copyright
11
# 2.  Redistributions in binary form must reproduce the above copyright
12
#     notice, this list of conditions and the following disclaimer in the
12
#     notice, this list of conditions and the following disclaimer in the
13
#     documentation and/or other materials provided with the distribution. 
13
#     documentation and/or other materials provided with the distribution.
14
# 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14
# 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15
#     its contributors may be used to endorse or promote products derived
15
#     its contributors may be used to endorse or promote products derived
16
#     from this software without specific prior written permission. 
16
#     from this software without specific prior written permission.
17
#
17
#
18
# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18
# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Lines 26-69 a/Tools/WebKitArchiveSupport/run-webkit-archive_sec3
26
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
28
29
import os, platform, subprocess
29
import argparse
30
import ctypes
31
import ctypes.util
32
import errno
33
import os
34
import platform
35
import textwrap
36
import subprocess
30
37
31
SAFARI_FOR_WEBKIT_DEVELOPMENT='/Applications/Safari.app/Contents/MacOS/SafariForWebKitDevelopment'
32
38
33
def check_for_valid_platform():
39
libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True)
34
    if 'Darwin' not in platform.system():
40
35
        print('Unsupported OS, exiting.')
41
SAFARI_FOR_WEBKIT_DEVELOPMENT = (
42
    "/Applications/Safari.app/Contents/MacOS/SafariForWebKitDevelopment"
43
)
44
45
46
def hasxattr(path, attribute):
47
    """returns True if path has xattr attribute"""
48
    bpath = os.fsencode(path)
49
    battr = attribute.encode("utf-8")  # on macOS, xattr names are always UTF-8
50
    r = libc.getxattr(ctypes.c_char_p(bpath), ctypes.c_char_p(battr), None, 0, 0, 0)
51
52
    # the call succeeded, we have the xattr
53
    if r >= 0:
54
        return True
55
56
    err = ctypes.get_errno()
57
58
    # the attribute doesn't exist
59
    if err == errno.ENOATTR:
60
        return False
61
62
    # or we have a real error
63
    raise OSError(err, errno.errorcode.get(err), path)
64
65
66
def removexattr(path, attribute):
67
    """remove xattr attribute from path"""
68
    bpath = os.fsencode(path)
69
    battr = attribute.encode("utf-8")  # on macOS, xattr names are always UTF-8
70
    r = libc.removexattr(ctypes.c_char_p(bpath), ctypes.c_char_p(battr), 0)
71
72
    if r == 0:
73
        return None
74
75
    assert r == -1
76
    err = ctypes.get_errno()
77
    raise OSError(err, errno.errorcode.get(err), path)
78
79
80
def find_build_path(search_dir=None, config="auto"):
81
    if search_dir is None:
82
        search_dir = os.path.dirname(os.path.abspath(__file__))
83
84
    opts = []
85
    if config in ("auto", "debug"):
86
        opts.append(os.path.join(search_dir, "Debug"))
87
88
    if config in ("auto", "release"):
89
        opts.append(os.path.join(search_dir, "Release"))
90
91
    for p in opts:
92
        if os.path.isdir(p):
93
            return p
94
    else:
95
        return None
96
97
98
def find_potentially_quarantined(path):
99
    exts = (".app", ".bundle", ".dylib", ".framework", ".xpc")
100
    with os.scandir(path) as it:
101
        return [entry.path for entry in it if entry.name.endswith(exts)]
102
103
104
def check_paths_for_quarantine(paths):
105
    errors = []
106
    for path in paths:
107
        if hasxattr(path, "com.apple.quarantine"):
108
            errors.append(f"ERROR: {path} is quarantined")
109
    return errors
110
111
112
def scary_warning():
113
    msg = (
114
        "By opening this app, you will be overriding system security which can "
115
        + "expose your computer and personal information to malware that may "
116
        + "harm your Mac or compromise your privacy."
117
    )
118
    print(textwrap.fill(msg))
119
120
    i = input("Do you want to continue? yes/no... ")
121
    if i.strip() == "yes":
122
        return True
123
    else:
124
        print("Didn't receive a 'yes'.")
125
        return False
126
127
128
def remove_from_quarantine(paths):
129
    for path in paths:
130
        try:
131
            removexattr(path, "com.apple.quarantine")
132
        except OSError as e:
133
            if e.errno != errno.ENOATTR:
134
                raise e
135
136
137
def set_dyld_framework_path(new_env, dyld_path):
138
    print(f"Setting DYLD FRAMEWORK and LIBRARY paths to {dyld_path}")
139
    new_env["DYLD_FRAMEWORK_PATH"] = dyld_path
140
    new_env["DYLD_LIBRARY_PATH"] = dyld_path
141
142
143
def parse_args(*args, **kwargs):
144
    parser = argparse.ArgumentParser(description="launch a WebKit archive")
145
146
    parser.add_argument(
147
        "--override-system-security",
148
        action="store_true",
149
        help="override system security settings",
150
    )
151
152
    group = parser.add_mutually_exclusive_group()
153
    group.add_argument(
154
        "--binary",
155
        action="store",
156
        default=SAFARI_FOR_WEBKIT_DEVELOPMENT,
157
        metavar="PATH",
158
        help="path to the binary to run [default: SafariForWebKitDevelopment]",
159
    )
160
    group.add_argument(
161
        "--minibrowser",
162
        action="store_true",
163
        dest="binary_minibrowser",  # use a flag, for we don't know the path.
164
        help="set the binary to MiniBrowser.app",
165
    )
166
    group.add_argument(
167
        "--safariforwebkitdevelopment",
168
        action="store_const",
169
        const=SAFARI_FOR_WEBKIT_DEVELOPMENT,
170
        dest="binary",
171
        help="set the binary to SafariForWebKitDevelopment",
172
    )
173
174
    group = parser.add_mutually_exclusive_group()
175
    group.add_argument(
176
        "--debug",
177
        action="store_const",
178
        const="debug",
179
        dest="config",
180
        default="auto",
181
        help="run a debug build [default: auto-selected]",
182
    )
183
    group.add_argument(
184
        "--release",
185
        action="store_const",
186
        const="release",
187
        dest="config",
188
        default="auto",
189
        help="run a release build [default: auto-selected]",
190
    )
191
192
    args = parser.parse_args(*args, **kwargs)
193
    return args
194
195
196
def main():
197
    script_dir = os.path.dirname(os.path.abspath(__file__))
198
    args = parse_args()
199
200
    if "Darwin" not in platform.system():
201
        print("Unsupported OS, exiting.")
202
        exit(1)
203
204
    if args.override_system_security:
205
        if not scary_warning():
206
            exit(1)
207
208
    build_path = find_build_path(script_dir, args.config)
209
    if build_path is None:
210
        print(
211
            "No Release or Debug framework directories found in the current folder, exiting."
212
        )
36
        exit(1)
213
        exit(1)
37
214
38
def find_dyld_framework_path(script_path):
215
    if args.binary_minibrowser:
39
    current_directory = os.path.dirname(script_path)
216
        binary = f"{build_path}/MiniBrowser.app/Contents/MacOS/MiniBrowser"
40
    sub_directories = [name for name in os.listdir(current_directory) if os.path.isdir(name)]
41
    if 'Debug' in sub_directories:
42
        return current_directory + '/Debug'
43
    elif 'Release' in sub_directories:
44
        return current_directory + '/Release'
45
    else:
217
    else:
46
        print('No Release or Debug framework directories found in the current folder, exiting.')
218
        binary = os.path.abspath(args.binary)
219
220
    paths = find_potentially_quarantined(build_path)
221
222
    if args.override_system_security:
223
        remove_from_quarantine(paths)
224
225
    errors = check_paths_for_quarantine(paths)
226
    if errors:
227
        for error in errors:
228
            print(error)
47
        exit(1)
229
        exit(1)
48
230
49
def run_safari_for_webkit_development():
231
    os.chdir(script_dir)
50
    subprocess.call(SAFARI_FOR_WEBKIT_DEVELOPMENT)
232
    new_env = os.environ.copy()
233
    set_dyld_framework_path(new_env, build_path)
51
234
52
def set_dyld_framework_path(script_path):
235
    os.execle(binary, binary, new_env)
53
    dyld_path = find_dyld_framework_path(script_path)
236
54
    print('Setting DYLD FRAMEWORK and LIBRARY paths to {}'.format(dyld_path))
237
55
    os.environ['DYLD_FRAMEWORK_PATH'] = dyld_path
238
if __name__ == "__main__":
56
    os.environ['DYLD_LIBRARY_PATH'] = dyld_path
57
    
58
def main():
59
    check_for_valid_platform()
60
    script_path = os.path.abspath(__file__)
61
    os.chdir(os.path.dirname(script_path))
62
    set_dyld_framework_path(script_path)
63
    run_safari_for_webkit_development()
64
    
65
if __name__ == '__main__':
66
    try:
239
    try:
67
        main()    
240
        main()
68
    except KeyboardInterrupt:
241
    except KeyboardInterrupt:
69
        exit("Aborting.")
242
        exit("Aborting.")

Return to Bug 236968