mirror of
https://github.com/oxen-io/lokinet
synced 2023-12-14 06:53:00 +01:00
Working signed macOS GUI build
This commit is contained in:
parent
496c1d274c
commit
2b7b1fcc79
15 changed files with 361 additions and 231 deletions
|
@ -32,7 +32,7 @@ project(lokinet
|
|||
if(APPLE)
|
||||
# Apple build number: must be incremented to submit a new build for the same lokinet version,
|
||||
# should be reset to 0 when the lokinet version increments.
|
||||
set(LOKINET_APPLE_BUILD 0)
|
||||
set(LOKINET_APPLE_BUILD 1)
|
||||
endif()
|
||||
|
||||
set(RELEASE_MOTTO "Gluten Free Edition" CACHE STRING "Release motto")
|
||||
|
@ -106,6 +106,7 @@ endif()
|
|||
|
||||
include(cmake/solaris.cmake)
|
||||
include(cmake/win32.cmake)
|
||||
include(cmake/macos.cmake)
|
||||
|
||||
# No in-source building
|
||||
include(MacroEnsureOutOfSourceBuild)
|
||||
|
@ -302,6 +303,10 @@ add_subdirectory(docs)
|
|||
|
||||
include(cmake/gui.cmake)
|
||||
|
||||
if(APPLE)
|
||||
macos_target_setup()
|
||||
endif()
|
||||
|
||||
# uninstall target
|
||||
if(NOT TARGET uninstall)
|
||||
configure_file(
|
||||
|
|
|
@ -18,20 +18,34 @@ if (BUILD_GUI)
|
|||
|
||||
find_program(YARN NAMES yarn yarnpkg REQUIRED)
|
||||
message(STATUS "Building lokinet-gui with yarn ${YARN}, target ${GUI_YARN_TARGET}")
|
||||
set(wine_env)
|
||||
if(WIN32)
|
||||
set(wine_env WINEDEBUG=-all "WINEPREFIX=${PROJECT_BINARY_DIR}/wineprefix")
|
||||
endif()
|
||||
|
||||
add_custom_target(lokinet-gui
|
||||
COMMAND ${YARN} install --frozen-lockfile &&
|
||||
WINEDEBUG=-all "WINEPREFIX=${PROJECT_BINARY_DIR}/wineprefix" ${YARN} ${GUI_YARN_EXTRA_OPTS} ${GUI_YARN_TARGET}
|
||||
${wine_env} ${YARN} ${GUI_YARN_EXTRA_OPTS} ${GUI_YARN_TARGET}
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/gui")
|
||||
|
||||
if(APPLE)
|
||||
add_custom_target(copy_gui ALL
|
||||
DEPENDS lokinet lokinet-extension lokinet-gui
|
||||
# FIXME: we really shouldn't be building inside the source directory but this is npm...
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${PROJECT_SOURCE_DIR}/lokinet-gui/release/mac/lokinet-gui.app
|
||||
$<TARGET_BUNDLE_DIR:lokinet>
|
||||
add_custom_target(assemble_gui ALL
|
||||
DEPENDS assemble lokinet-gui
|
||||
COMMAND mkdir "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Helpers"
|
||||
COMMAND cp -a "${PROJECT_SOURCE_DIR}/gui/release/mac/Lokinet-GUI.app" "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Helpers/"
|
||||
COMMAND mkdir -p "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Resources/en.lproj"
|
||||
COMMAND cp "${PROJECT_SOURCE_DIR}/contrib/macos/InfoPlist.strings" "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Resources/en.lproj/"
|
||||
COMMAND cp "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Resources/icon.icns" "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Helpers/Lokinet-GUI.app/Contents/Resources/icon.icns"
|
||||
COMMAND cp "${PROJECT_SOURCE_DIR}/contrib/macos/InfoPlist.strings" "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Helpers/Lokinet-GUI.app/Contents/Resources/en.lproj/"
|
||||
COMMAND /usr/libexec/PlistBuddy
|
||||
-c "Delete :CFBundleDisplayName"
|
||||
-c "Add :LSHasLocalizedDisplayName bool true"
|
||||
-c "Add :CFBundleDevelopmentRegion string en"
|
||||
-c "Set :CFBundleShortVersionString ${lokinet_VERSION}"
|
||||
-c "Set :CFBundleVersion ${lokinet_VERSION}.${LOKINET_APPLE_BUILD}"
|
||||
"${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Helpers/Lokinet-GUI.app/Contents/Info.plist"
|
||||
)
|
||||
add_dependencies(assemble copy_gui)
|
||||
|
||||
elseif(WIN32)
|
||||
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/gui")
|
||||
add_custom_target(copy_gui ALL
|
||||
|
|
176
cmake/macos.cmake
Normal file
176
cmake/macos.cmake
Normal file
|
@ -0,0 +1,176 @@
|
|||
if(NOT APPLE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
option(MACOS_SYSTEM_EXTENSION
|
||||
"Build the network extension as a system extension rather than a plugin. This must be ON for non-app store release builds, and must be OFF for dev builds and Mac App Store distribution builds"
|
||||
OFF)
|
||||
option(CODESIGN "codesign the resulting app and extension" ON)
|
||||
set(CODESIGN_ID "" CACHE STRING "codesign the macos app using this key identity; if empty we'll try to guess")
|
||||
set(default_profile_type "dev")
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(default_profile_type "release")
|
||||
endif()
|
||||
set(CODESIGN_PROFILE "${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.${default_profile_type}.provisionprofile" CACHE FILEPATH
|
||||
"Path to a .provisionprofile to use for the main app")
|
||||
|
||||
if(CODESIGN AND NOT CODESIGN_ID)
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(codesign_cert_pattern "Developer ID Application")
|
||||
else()
|
||||
set(codesign_cert_pattern "Apple Development")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND security find-identity -v -p codesigning
|
||||
COMMAND sed -n "s/^ *[0-9][0-9]*) *\\([A-F0-9]\\{40\\}\\) *\"\\(${codesign_cert_pattern}.*\\)\"\$/\\1 \\2/p"
|
||||
RESULT_VARIABLE find_id_exit_code
|
||||
OUTPUT_VARIABLE find_id_output)
|
||||
if(NOT find_id_exit_code EQUAL 0)
|
||||
message(FATAL_ERROR "Finding signing identities with security find-identity failed; try specifying an id using -DCODESIGN_ID=...")
|
||||
endif()
|
||||
|
||||
string(REGEX MATCHALL "(^|\n)[0-9A-F]+" find_id_sign_id "${find_id_output}")
|
||||
if(NOT find_id_sign_id)
|
||||
message(FATAL_ERROR "Did not find any \"${codesign_cert_pattern}\" identity; try specifying an id using -DCODESIGN_ID=...")
|
||||
endif()
|
||||
if (find_id_sign_id MATCHES ";")
|
||||
message(FATAL_ERROR "Found multiple \"${codesign_cert_pattern}\" identities:\n${find_id_output}\nSpecify an identify using -DCODESIGN_ID=...")
|
||||
endif()
|
||||
set(CODESIGN_ID "${find_id_sign_id}" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if(CODESIGN)
|
||||
message(STATUS "Codesigning using ${CODESIGN_ID}")
|
||||
|
||||
if (NOT MACOS_NOTARIZE_USER AND NOT MACOS_NOTARIZE_PASS AND NOT MACOS_NOTARIZE_ASC AND EXISTS "$ENV{HOME}/.notarization.cmake")
|
||||
message(STATUS "Loading notarization info from ~/.notarization.cmake")
|
||||
include("$ENV{HOME}/.notarization.cmake")
|
||||
endif()
|
||||
|
||||
if (MACOS_NOTARIZE_USER AND MACOS_NOTARIZE_PASS AND MACOS_NOTARIZE_ASC)
|
||||
message(STATUS "Enabling notarization with account ${MACOS_NOTARIZE_ASC}/${MACOS_NOTARIZE_USER}")
|
||||
else()
|
||||
message(WARNING "You have not set one or more of MACOS_NOTARIZE_USER, MACOS_NOTARIZE_PASS, MACOS_NOTARIZE_ASC: notarization will fail; see contrib/macos/README.txt")
|
||||
endif()
|
||||
|
||||
else()
|
||||
message(WARNING "Codesigning disabled; the resulting build will not run on most macOS systems")
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT CODESIGN_PROFILE)
|
||||
message(WARNING "Missing a CODESIGN_PROFILE provisioning profile: Apple will most likely log an uninformative error message to the system log and then kill harmless kittens if you try to run the result")
|
||||
endif()
|
||||
if(NOT EXISTS "${CODESIGN_PROFILE}")
|
||||
message(FATAL_ERROR "Provisioning profile ${CODESIGN_PROFILE} does not exist; fix your -DCODESIGN_PROFILE path")
|
||||
endif()
|
||||
message(STATUS "Using ${CODESIGN_PROFILE} provisioning profile")
|
||||
|
||||
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(lokinet_ext_dir Contents/Library/SystemExtensions)
|
||||
else()
|
||||
set(lokinet_ext_dir Contents/PlugIns)
|
||||
endif()
|
||||
|
||||
if(CODESIGN)
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(LOKINET_ENTITLEMENTS_TYPE sysext)
|
||||
set(notarize_py_is_sysext True)
|
||||
else()
|
||||
set(LOKINET_ENTITLEMENTS_TYPE plugin)
|
||||
set(notarize_py_is_sysext False)
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in"
|
||||
"${PROJECT_BINARY_DIR}/sign.sh"
|
||||
@ONLY)
|
||||
|
||||
add_custom_target(
|
||||
sign
|
||||
DEPENDS "${PROJECT_BINARY_DIR}/sign.sh"
|
||||
COMMAND "${PROJECT_BINARY_DIR}/sign.sh"
|
||||
)
|
||||
|
||||
if(MACOS_NOTARIZE_USER AND MACOS_NOTARIZE_PASS AND MACOS_NOTARIZE_ASC)
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/contrib/macos/notarize.py.in"
|
||||
"${PROJECT_BINARY_DIR}/notarize.py"
|
||||
@ONLY)
|
||||
add_custom_target(
|
||||
notarize
|
||||
DEPENDS "${PROJECT_BINARY_DIR}/notarize.py" sign
|
||||
COMMAND "${PROJECT_BINARY_DIR}/notarize.py"
|
||||
)
|
||||
else()
|
||||
message(WARNING "You have not set one or more of MACOS_NOTARIZE_USER, MACOS_NOTARIZE_PASS, MACOS_NOTARIZE_ASC: notarization disabled")
|
||||
endif()
|
||||
else()
|
||||
add_custom_target(sign COMMAND "true")
|
||||
add_custom_target(notarize DEPENDS sign COMMAND "true")
|
||||
endif()
|
||||
|
||||
|
||||
# Called later to set things up, after the main lokinet targets are set up
|
||||
function(macos_target_setup)
|
||||
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
target_compile_definitions(lokinet PRIVATE MACOS_SYSTEM_EXTENSION)
|
||||
endif()
|
||||
|
||||
set_target_properties(lokinet
|
||||
PROPERTIES
|
||||
OUTPUT_NAME Lokinet
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "Lokinet"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${lokinet_VERSION}"
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "${lokinet_VERSION}"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.lokinet"
|
||||
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.Info.plist.in"
|
||||
MACOSX_BUNDLE_COPYRIGHT "© 2022, The Oxen Project"
|
||||
)
|
||||
|
||||
add_custom_target(copy_bootstrap
|
||||
DEPENDS lokinet-extension
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/bootstrap/mainnet.signed
|
||||
$<TARGET_BUNDLE_DIR:lokinet-extension>/Contents/Resources/bootstrap.signed
|
||||
)
|
||||
|
||||
set(mac_icon ${PROJECT_BINARY_DIR}/lokinet.icns)
|
||||
add_custom_command(OUTPUT ${mac_icon}
|
||||
COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet-mac.svg ${mac_icon}
|
||||
DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh)
|
||||
add_custom_target(icon DEPENDS ${mac_icon})
|
||||
|
||||
|
||||
add_dependencies(lokinet lokinet-extension icon)
|
||||
|
||||
|
||||
if(CODESIGN_PROFILE)
|
||||
add_custom_target(copy_prov_prof
|
||||
DEPENDS lokinet
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CODESIGN_PROFILE}
|
||||
$<TARGET_BUNDLE_DIR:lokinet>/Contents/embedded.provisionprofile
|
||||
)
|
||||
else()
|
||||
add_custom_target(copy_prov_prof COMMAND true)
|
||||
endif()
|
||||
|
||||
add_custom_target(assemble ALL
|
||||
DEPENDS lokinet lokinet-extension icon copy_prov_prof copy_bootstrap
|
||||
COMMAND rm -rf "${PROJECT_BINARY_DIR}/Lokinet.app"
|
||||
COMMAND cp -a $<TARGET_BUNDLE_DIR:lokinet> "${PROJECT_BINARY_DIR}/Lokinet.app"
|
||||
COMMAND mkdir -p "${PROJECT_BINARY_DIR}/Lokinet.app/${lokinet_ext_dir}"
|
||||
COMMAND cp -a $<TARGET_BUNDLE_DIR:lokinet-extension> "${PROJECT_BINARY_DIR}/Lokinet.app/${lokinet_ext_dir}/"
|
||||
COMMAND mkdir -p "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Resources"
|
||||
COMMAND cp -a "${mac_icon}" "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Resources/icon.icns"
|
||||
)
|
||||
|
||||
if(CODESIGN)
|
||||
add_dependencies(sign assemble)
|
||||
endif()
|
||||
endfunction()
|
21
contrib/lokinet-mac.svg
Normal file
21
contrib/lokinet-mac.svg
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1024 1024" style="enable-background:new 0 0 1024 1024;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M897.5,1024H126.5C56.6,1024,0,967.4,0,897.5V126.5C0,56.6,56.6,0,126.5,0h771.1C967.4,0,1024,56.6,1024,126.5
|
||||
v771.1C1024,967.4,967.4,1024,897.5,1024z"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon points="585.2,658.9 512,732.1 438.8,658.9 365.1,732.1 512,879 658.9,732.1 "/>
|
||||
<polygon points="658.9,585.2 732.1,512 658.9,438.8 732.1,365.1 879,512 732.1,658.9 "/>
|
||||
<polygon points="365.1,438.8 291.9,512 365.1,585.2 291.9,658.9 145,512 291.9,365.1 "/>
|
||||
<polygon points="438.8,365.1 512,291.9 585.2,365.1 658.9,291.9 512,145 365.1,291.9 "/>
|
||||
<rect x="533.4" y="533.3" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -242.3375 585.3179)" width="103.9" height="103.9"/>
|
||||
<rect x="386.7" y="386.9" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -181.837 438.6521)" width="103.9" height="103.9"/>
|
||||
<rect x="533.2" y="386.7" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -138.7545 542.2352)" width="103.9" height="103.9"/>
|
||||
<rect x="386.9" y="533.5" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -285.4199 481.7348)" width="103.9" height="103.9"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -20,6 +20,7 @@ cmake \
|
|||
-DBUILD_STATIC_DEPS=ON \
|
||||
-DBUILD_LIBLOKINET=OFF \
|
||||
-DWITH_TESTS=OFF \
|
||||
-DWITH_BOOTSTRAP=OFF \
|
||||
-DNATIVE_BUILD=OFF \
|
||||
-DWITH_LTO=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
|
|
BIN
contrib/macos/InfoPlist.strings
Normal file
BIN
contrib/macos/InfoPlist.strings
Normal file
Binary file not shown.
|
@ -5,11 +5,8 @@
|
|||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Lokinet</string>
|
||||
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>lokinet-gui</string>
|
||||
<string>Lokinet</string>
|
||||
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.lokinet</string>
|
||||
|
@ -20,6 +17,9 @@
|
|||
<key>CFBundleName</key>
|
||||
<string>Lokinet</string>
|
||||
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>icon.icns</string>
|
||||
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
|
||||
|
@ -32,8 +32,14 @@
|
|||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.15</string>
|
||||
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2022 The Oxen Project, licensed under GPLv3-or-later</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2022 The Oxen Project, licensed under GPLv3-or-later</string>
|
||||
|
||||
</dict>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
|
||||
<key>LSHasLocalizedDisplayName</key>
|
||||
<true/>
|
||||
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -14,7 +14,7 @@ done
|
|||
mv "${outdir}/icon_1024x1024.png" "${outdir}/icon_512x512@2x.png"
|
||||
for size in 16 32 128 256; do
|
||||
double=$((size * 2))
|
||||
cp "${outdir}/icon_${double}x${double}.png" "${outdir}/icon_${size}x${size}@2x.png"
|
||||
ln -f "${outdir}/icon_${double}x${double}.png" "${outdir}/icon_${size}x${size}@2x.png"
|
||||
done
|
||||
|
||||
iconutil -c icns "${outdir}"
|
||||
|
|
|
@ -1,26 +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>Label</key>
|
||||
<string>network.loki.lokinet.daemon</string>
|
||||
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/var/lib/lokinet/lokinet_macos_daemon_script.sh</string>
|
||||
</array>
|
||||
|
||||
<!-- Keep Lokinet alive unless magic file exists -->
|
||||
<key>KeepAlive</key>
|
||||
<dict>
|
||||
<key>PathState</key>
|
||||
<dict>
|
||||
<key>/var/lib/lokinet/suspend-launchd-service</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>/var/log/lokinet.log</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -24,11 +24,11 @@ if not all(("@MACOS_NOTARIZE_USER@", "@MACOS_NOTARIZE_PASS@", "@MACOS_NOTARIZE_A
|
|||
|
||||
os.chdir("@PROJECT_BINARY_DIR@")
|
||||
app = "Lokinet.app"
|
||||
zipfile = "Lokinet.app.notarize.zip"
|
||||
print(f"Creating lokinet.app.notarize.zip from lokinet.app")
|
||||
zipfile = f"{app}.notarize.zip"
|
||||
print(f"Creating {zipfile} from {app}")
|
||||
if os.path.exists(zipfile):
|
||||
os.remove(zipfile)
|
||||
subprocess.run(['zip', '-r', zipfile, app])
|
||||
subprocess.run(['ditto', '-v', '-c', '-k', '--sequesterRsrc', '--keepParent', app, zipfile])
|
||||
|
||||
userpass = ('--username', "@MACOS_NOTARIZE_USER@", '--password', "@MACOS_NOTARIZE_PASS@")
|
||||
print("Submitting {} for notarization; this may take a minute...".format(zipfile))
|
||||
|
|
|
@ -2,24 +2,71 @@
|
|||
|
||||
set -e
|
||||
|
||||
if [ -z "@CODESIGN" ]; then
|
||||
if [ "@CODESIGN@" != "ON" ]; then
|
||||
echo "Cannot codesign: this build was not configured with codesigning" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
signit() {
|
||||
target="$1"
|
||||
entitlements="$2"
|
||||
echo -e "\n\e[33;1mSigning ${target/*\/Lokinet.app/Lokinet.app}...\e[0m" >&2
|
||||
codesign \
|
||||
--verbose=4 \
|
||||
--force \
|
||||
-s "@CODESIGN_ID@" \
|
||||
--entitlements "$entitlements" \
|
||||
--strict \
|
||||
--timestamp \
|
||||
--options=runtime \
|
||||
"$target"
|
||||
}
|
||||
|
||||
gui_entitlements="@PROJECT_SOURCE_DIR@/gui/node_modules/app-builder-lib/templates/entitlements.mac.plist"
|
||||
ext_entitlements="@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-extension.@LOKINET_ENTITLEMENTS_TYPE@.entitlements.plist"
|
||||
app_entitlements="@PROJECT_SOURCE_DIR@/contrib/macos/lokinet.@LOKINET_ENTITLEMENTS_TYPE@.entitlements.plist"
|
||||
|
||||
SIGN_TARGET="@PROJECT_BINARY_DIR@/Lokinet.app"
|
||||
|
||||
for ext in systemextension appex; do
|
||||
netext="@lokinet_ext_dir@/org.lokinet.network-extension.$ext"
|
||||
if [ -e "@SIGN_TARGET@/$netext" ]; then
|
||||
echo -e "\n\e[33;1mSigning $netext...\e[0m\n" >&2
|
||||
codesign --verbose=4 --force -s "@CODESIGN_ID@" \
|
||||
--entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-extension.@LOKINET_ENTITLEMENTS_TYPE@.entitlements.plist" \
|
||||
--deep --strict --timestamp --options=runtime "@SIGN_TARGET@/$netext"
|
||||
netext="$SIGN_TARGET/@lokinet_ext_dir@/org.lokinet.network-extension.$ext"
|
||||
if [ -e "$netext" ]; then
|
||||
signit "$netext" "$ext_entitlements"
|
||||
fi
|
||||
done
|
||||
|
||||
for sub in "/Contents/MacOS/Lokinet" "" ; do
|
||||
echo -e "\n\e[33;1mSigning $(basename @SIGN_TARGET@)$sub...\e[0m\n" >&2
|
||||
codesign --verbose=4 --force -s "@CODESIGN_ID@" \
|
||||
--entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet.@LOKINET_ENTITLEMENTS_TYPE@.entitlements.plist" \
|
||||
--deep --strict --timestamp --options=runtime "@SIGN_TARGET@$sub"
|
||||
done
|
||||
if [ "@BUILD_GUI@" == "ON" ]; then
|
||||
gui_app="$SIGN_TARGET"/Contents/Helpers/Lokinet-GUI.app
|
||||
gui_sign_targets=()
|
||||
for bundle in \
|
||||
"$gui_app"/Contents/Frameworks/*.framework \
|
||||
"$gui_app"/Contents/Frameworks/*.app
|
||||
do
|
||||
|
||||
if [ -d "$bundle/Libraries" ]; then
|
||||
gui_sign_targets+=("$bundle"/Libraries/*.dylib)
|
||||
fi
|
||||
if [ -d "$bundle/Helpers" ]; then
|
||||
gui_sign_targets+=("$bundle"/Helpers/*)
|
||||
fi
|
||||
if [ -d "$bundle/Resources" ]; then
|
||||
for f in "$bundle/Resources"/*; do
|
||||
if [[ -f "$f" && -x "$f" && "$(file -b "$f")" == Mach-O* ]]; then
|
||||
gui_sign_targets+=("$f")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
gui_sign_targets+=("$bundle")
|
||||
done
|
||||
|
||||
gui_sign_targets+=("$gui_app")
|
||||
|
||||
for target in "${gui_sign_targets[@]}"; do
|
||||
signit "$target" "$gui_entitlements"
|
||||
done
|
||||
|
||||
signit "$SIGN_TARGET"/Contents/MacOS/Lokinet "$app_entitlements"
|
||||
fi
|
||||
|
||||
signit "$SIGN_TARGET" "$app_entitlements"
|
||||
|
|
|
@ -67,171 +67,6 @@ foreach(exe ${exetargets})
|
|||
endif()
|
||||
endforeach()
|
||||
|
||||
if(APPLE)
|
||||
option(MACOS_SYSTEM_EXTENSION
|
||||
"Build the network extension as a system extension rather than a plugin. This must be ON for non-app store release builds, and must be OFF for dev builds and Mac App Store distribution builds"
|
||||
OFF)
|
||||
option(CODESIGN "codesign the resulting app and extension" ON)
|
||||
set(CODESIGN_ID "" CACHE STRING "codesign the macos app using this key identity; if empty we'll try to guess")
|
||||
set(default_profile_type "dev")
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(default_profile_type "release")
|
||||
endif()
|
||||
set(CODESIGN_PROFILE "${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.${default_profile_type}.provisionprofile" CACHE FILEPATH
|
||||
"Path to a .provisionprofile to use for the main app")
|
||||
set(CODESIGN_EXT_PROFILE "${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.${default_profile_type}.provisionprofile" CACHE FILEPATH
|
||||
"Path to a .provisionprofile to use for the extension")
|
||||
|
||||
if(CODESIGN AND NOT CODESIGN_ID)
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(codesign_cert_pattern "Developer ID Application")
|
||||
else()
|
||||
set(codesign_cert_pattern "Apple Development")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND security find-identity -v -p codesigning
|
||||
COMMAND sed -n "s/^ *[0-9][0-9]*) *\\([A-F0-9]\\{40\\}\\) *\"\\(${codesign_cert_pattern}.*\\)\"\$/\\1 \\2/p"
|
||||
RESULT_VARIABLE find_id_exit_code
|
||||
OUTPUT_VARIABLE find_id_output)
|
||||
if(NOT find_id_exit_code EQUAL 0)
|
||||
message(FATAL_ERROR "Finding signing identities with security find-identity failed; try specifying an id using -DCODESIGN_ID=...")
|
||||
endif()
|
||||
|
||||
string(REGEX MATCHALL "(^|\n)[0-9A-F]+" find_id_sign_id "${find_id_output}")
|
||||
if(NOT find_id_sign_id)
|
||||
message(FATAL_ERROR "Did not find any \"${codesign_cert_pattern}\" identity; try specifying an id using -DCODESIGN_ID=...")
|
||||
endif()
|
||||
if (find_id_sign_id MATCHES ";")
|
||||
message(FATAL_ERROR "Found multiple \"${codesign_cert_pattern}\" identities:\n${find_id_output}\nSpecify an identify using -DCODESIGN_ID=...")
|
||||
endif()
|
||||
set(CODESIGN_ID "${find_id_sign_id}" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if(CODESIGN)
|
||||
message(STATUS "Codesigning using ${CODESIGN_ID}")
|
||||
else()
|
||||
message(WARNING "Codesigning disabled; the resulting build will not run on most macOS systems")
|
||||
endif()
|
||||
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(lokinet_ext_dir Contents/Library/SystemExtensions)
|
||||
target_compile_definitions(lokinet PRIVATE MACOS_SYSTEM_EXTENSION)
|
||||
if (NOT MACOS_NOTARIZE_USER AND NOT MACOS_NOTARIZE_PASS AND NOT MACOS_NOTARIZE_ASC AND EXISTS "$ENV{HOME}/.notarization.cmake")
|
||||
message(STATUS "Loading notarization info from ~/.notarization.cmake")
|
||||
include("$ENV{HOME}/.notarization.cmake")
|
||||
endif()
|
||||
if (MACOS_NOTARIZE_USER AND MACOS_NOTARIZE_PASS AND MACOS_NOTARIZE_ASC)
|
||||
message(STATUS "Enabling notarization with account ${MACOS_NOTARIZE_ASC}/${MACOS_NOTARIZE_USER}")
|
||||
else()
|
||||
message(WARNING "You have not set one or more of MACOS_NOTARIZE_USER, MACOS_NOTARIZE_PASS, MACOS_NOTARIZE_ASC: notarization will fail; see contrib/macos/README.txt")
|
||||
endif()
|
||||
else()
|
||||
set(lokinet_ext_dir Contents/PlugIns)
|
||||
endif()
|
||||
|
||||
foreach(var CODESIGN_PROFILE CODESIGN_EXT_PROFILE)
|
||||
if(NOT ${var})
|
||||
message(WARNING "Missing a ${var} provisioning profile, and not building a system extension: Apple will most likely log an uninformative error message to the system log and then kill harmless kittens if you try to run the result")
|
||||
endif()
|
||||
if(NOT EXISTS "${${var}}")
|
||||
message(FATAL_ERROR "Provisioning profile ${${var}} does not exist; fix your -D${var} path")
|
||||
endif()
|
||||
endforeach()
|
||||
message(STATUS "Using ${CODESIGN_PROFILE} provisioning profile")
|
||||
message(STATUS "Using ${CODESIGN_EXT_PROFILE} extension provisioning profile")
|
||||
|
||||
set(mac_icon ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns)
|
||||
add_custom_command(OUTPUT ${mac_icon}
|
||||
COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${mac_icon}
|
||||
DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh)
|
||||
add_custom_target(icons DEPENDS ${mac_icon})
|
||||
add_dependencies(lokinet icons lokinet-extension)
|
||||
set(post_build_pp)
|
||||
if(CODESIGN AND CODESIGN_PROFILE)
|
||||
set(post_build_pp COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CODESIGN_PROFILE}
|
||||
$<TARGET_BUNDLE_DIR:lokinet>/Contents/embedded.provisionprofile)
|
||||
endif()
|
||||
|
||||
set_target_properties(lokinet
|
||||
PROPERTIES
|
||||
OUTPUT_NAME Lokinet
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "Lokinet"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${lokinet_VERSION}"
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "${lokinet_VERSION}"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.lokinet"
|
||||
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.Info.plist.in"
|
||||
MACOSX_BUNDLE_ICON_FILE "${mac_icon}"
|
||||
MACOSX_BUNDLE_COPYRIGHT "© 2022, The Oxen Project"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
add_custom_target(assemble
|
||||
DEPENDS lokinet lokinet-extension
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/bootstrap/mainnet.signed
|
||||
$<TARGET_BUNDLE_DIR:lokinet-extension>/Contents/Resources/bootstrap.signed
|
||||
COMMAND mkdir -p $<TARGET_BUNDLE_DIR:lokinet>/${lokinet_ext_dir}
|
||||
COMMAND cp -a $<TARGET_BUNDLE_DIR:lokinet-extension> $<TARGET_BUNDLE_DIR:lokinet>/${lokinet_ext_dir}
|
||||
${post_build_pp})
|
||||
|
||||
if(TARGET lokinet-gui)
|
||||
add_custom_target(copy_gui
|
||||
DEPENDS lokinet lokinet-extension lokinet-gui
|
||||
# FIXME: we really shouldn't be building inside the source directory but this is npm...
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/lokinet-gui/release/mac/lokinet-gui.app $<TARGET_BUNDLE_DIR:lokinet>
|
||||
)
|
||||
add_dependencies(assemble copy_gui)
|
||||
endif()
|
||||
|
||||
if(NOT CODESIGN)
|
||||
message(STATUS "codesigning disabled")
|
||||
add_custom_target(
|
||||
sign
|
||||
DEPENDS assemble
|
||||
COMMAND "true")
|
||||
|
||||
elseif(CODESIGN)
|
||||
set(SIGN_TARGET "${PROJECT_BINARY_DIR}/Lokinet.app")
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(LOKINET_ENTITLEMENTS_TYPE sysext)
|
||||
else()
|
||||
set(LOKINET_ENTITLEMENTS_TYPE plugin)
|
||||
endif()
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in"
|
||||
"${PROJECT_BINARY_DIR}/sign.sh"
|
||||
@ONLY)
|
||||
add_custom_target(
|
||||
sign
|
||||
DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" assemble
|
||||
COMMAND "${PROJECT_BINARY_DIR}/sign.sh"
|
||||
)
|
||||
|
||||
if(NOT (MACOS_NOTARIZE_USER AND MACOS_NOTARIZE_PASS AND MACOS_NOTARIZE_ASC))
|
||||
message(WARNING "You have not set one or more of MACOS_NOTARIZE_USER, MACOS_NOTARIZE_PASS, MACOS_NOTARIZE_ASC: notarization disabled")
|
||||
endif()
|
||||
if (MACOS_SYSTEM_EXTENSION)
|
||||
set(notarize_py_is_sysext True)
|
||||
else()
|
||||
set(notarize_py_is_sysext False)
|
||||
endif()
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/contrib/macos/notarize.py.in"
|
||||
"${PROJECT_BINARY_DIR}/notarize.py"
|
||||
@ONLY)
|
||||
add_custom_target(
|
||||
notarize
|
||||
DEPENDS "${PROJECT_BINARY_DIR}/notarize.py" sign
|
||||
COMMAND "${PROJECT_BINARY_DIR}/notarize.py"
|
||||
)
|
||||
|
||||
else()
|
||||
message(FATAL_ERROR "CODESIGN_APP (=${CODESIGN_APP}) and/or CODESIGN_EXT (=${CODESIGN_EXT}) are not set. To disable code signing use -DCODESIGN=OFF")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SETCAP)
|
||||
install(CODE "execute_process(COMMAND ${SETCAP} cap_net_admin,cap_net_bind_service=+eip ${CMAKE_INSTALL_PREFIX}/bin/lokinet)")
|
||||
endif()
|
||||
|
|
|
@ -8,7 +8,7 @@ let app = NSApplication.shared
|
|||
let START = "--start"
|
||||
let STOP = "--stop"
|
||||
|
||||
let HELP_STRING = "usage: lokinet [--start|--stop]"
|
||||
let HELP_STRING = "usage: lokinet {--start|--stop}"
|
||||
|
||||
class LokinetMain: NSObject, NSApplicationDelegate {
|
||||
var vpnManager = NETunnelProviderManager()
|
||||
|
@ -46,9 +46,8 @@ class LokinetMain: NSObject, NSApplicationDelegate {
|
|||
if let savedManagers = savedManagers {
|
||||
for manager in savedManagers {
|
||||
if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.netextBundleId {
|
||||
manager.isEnabled = false
|
||||
manager.connection.stopVPNTunnel()
|
||||
self.result(msg: "Lokinet Down")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,6 +154,7 @@ class LokinetMain: NSObject, NSApplicationDelegate {
|
|||
|
||||
func request(_: OSSystemExtensionRequest, didFailWithError error: Error) {
|
||||
NSLog("System extension request failed: %@", error.localizedDescription)
|
||||
self.bail()
|
||||
}
|
||||
|
||||
func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) {
|
||||
|
@ -174,9 +174,60 @@ class LokinetMain: NSObject, NSApplicationDelegate {
|
|||
|
||||
let args = CommandLine.arguments
|
||||
|
||||
if args.count <= 2 {
|
||||
// If we are invoked with no arguments then exec the gui. This is dumb, but there doesn't seem to
|
||||
// be a nicer way to do this on Apple's half-baked platform because:
|
||||
// - we have three "bundles" we need to manage: the GUI app, the system extension, and the Lokinet
|
||||
// app (this file) which loads the system extension.
|
||||
// - if we embed the system extension directly inside the GUI then it fails to launch because the
|
||||
// electron GUI's requirements (needed for JIT) conflict with the ability to load a system
|
||||
// extensions.
|
||||
// - if we embed Lokinet.app inside Lokinet-GUI.app and then the system extension inside Lokinet.app
|
||||
// then it works, but macos loses track of the system extension and doesn't remove it when you
|
||||
// remove the application. (It breaks your system, leaving an impossible-to-remove system
|
||||
// extension, in just the same way it breaks if you don't use Finder to remove the Application.
|
||||
// Apple used to say (around 2 years ago as of writing) that they would fix this situation "soon",
|
||||
// but hasn't, and has stopped saying anything about it.)
|
||||
// - if we try to use multiple executables (one to launch the system extension, one simple shell
|
||||
// script to execs the embedded GUI app) inside the Lokinet.app and make the GUI the default for
|
||||
// the application then Lokinet gets killed by gatekeeper because code signing only applies the
|
||||
// (required-for-system-extensions) provisioningprofile to the main binary in the app.
|
||||
//
|
||||
// So we are left needing *one* single binary that isn't the GUI but has to do double-duty for both
|
||||
// exec'ing the binary and loading lokinet, depending on how it is called.
|
||||
//
|
||||
// But of course there is no way to specify command-line arguments to the default binary macOS runs,
|
||||
// so we can't use a `--gui` flag or anything so abhorrent to macos purity, thus this nasty
|
||||
// solution:
|
||||
// - no args -- exec the GUI
|
||||
// - `--start` -- load the system extension and start lokinet
|
||||
// - `--stop` -- stop lokinet
|
||||
//
|
||||
// macOS: land of half-baked implementations and nasty hacks to make anything work.
|
||||
|
||||
if args.count == 1 {
|
||||
let gui_path = Bundle.main.resourcePath! + "/../Helpers/Lokinet-GUI.app"
|
||||
if !FileManager.default.fileExists(atPath: gui_path) {
|
||||
NSLog("Could not find gui app at %@", gui_path)
|
||||
exit(1)
|
||||
}
|
||||
let gui_url = URL(fileURLWithPath: gui_path, isDirectory: false)
|
||||
let gui_app_conf = NSWorkspace.OpenConfiguration()
|
||||
let group = DispatchGroup()
|
||||
group.enter()
|
||||
NSWorkspace.shared.openApplication(at: gui_url, configuration: gui_app_conf,
|
||||
completionHandler: { (app, error) in
|
||||
if error != nil {
|
||||
NSLog("Error launching gui: %@", error!.localizedDescription)
|
||||
} else {
|
||||
NSLog("Lauched GUI");
|
||||
}
|
||||
group.leave()
|
||||
})
|
||||
group.wait()
|
||||
|
||||
} else if args.count == 2 {
|
||||
let delegate = LokinetMain()
|
||||
delegate.mode = args.count > 1 ? args[1] : START
|
||||
delegate.mode = args[1]
|
||||
app.delegate = delegate
|
||||
app.run()
|
||||
} else {
|
||||
|
|
2
gui
2
gui
|
@ -1 +1 @@
|
|||
Subproject commit 4861da59c3f1251a002199e185cc8a638845e692
|
||||
Subproject commit abcd94814e261ffd88104357e3946201d0d2c8e0
|
|
@ -3,7 +3,7 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
if (BUILD_SHARED_LIBS OR NOT BUILD_STATIC_DEPS OR NOT STATIC_LINK)
|
||||
message(FATAL_ERROR "macOS builds require a full static build; perhaps use the contrib/macos.sh script to build?")
|
||||
message(FATAL_ERROR "macOS builds require a full static build; perhaps use the contrib/mac.sh script to build?")
|
||||
endif()
|
||||
|
||||
# god (steve jobs) made apple so that man may suffer
|
||||
|
|
Loading…
Reference in a new issue