fix(macos): launch service with stable privacy identity

This commit is contained in:
dh
2026-09-11 20:59:56 +02:00
parent d77187e9ec
commit 0e2aa3830f
6 changed files with 160 additions and 0 deletions
+24
View File
@@ -30,6 +30,10 @@
<MacOsMeetingIntegrationsSource>$(MSBuildProjectDirectory)/Native/MacOsMeetingIntegrations/main.swift</MacOsMeetingIntegrationsSource>
<MacOsMeetingIntegrationsInfoPlist>$(MSBuildProjectDirectory)/Native/MacOsMeetingIntegrations/Info.plist</MacOsMeetingIntegrationsInfoPlist>
<MacOsMeetingIntegrationsOutputPath>Native/macos-meeting-integrations</MacOsMeetingIntegrationsOutputPath>
<MacOsLauncherSource>$(MSBuildProjectDirectory)/Native/MacOsLauncher/main.swift</MacOsLauncherSource>
<MacOsLauncherInfoPlist>$(MSBuildProjectDirectory)/Native/MacOsLauncher/Info.plist</MacOsLauncherInfoPlist>
<MacOsLauncherOutputPath>Native/macos-meeting-assistant-launcher</MacOsLauncherOutputPath>
<MacOsApplicationBundlePath>MeetingAssistant.app</MacOsApplicationBundlePath>
</PropertyGroup>
<ItemGroup>
@@ -90,6 +94,26 @@
<Exec Command="/usr/bin/codesign --force --deep --sign - &quot;$(TargetDir)$(MacOsAudioCaptureBundlePath)&quot;" />
<Exec Command="/usr/bin/xcrun swiftc -parse-as-library -O -target $(MacOsAudioCaptureArchitecture)-apple-macos13.0 -framework AppKit -framework Carbon -framework WebKit &quot;$(MacOsDesktopControlsSource)&quot; -o &quot;$(TargetDir)$(MacOsDesktopControlsOutputPath)&quot;" />
<Exec Command="/usr/bin/xcrun swiftc -parse-as-library -O -target $(MacOsAudioCaptureArchitecture)-apple-macos13.0 -framework AppKit -framework CoreGraphics -framework EventKit -framework ImageIO -framework UniformTypeIdentifiers -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __info_plist -Xlinker &quot;$(MacOsMeetingIntegrationsInfoPlist)&quot; &quot;$(MacOsMeetingIntegrationsSource)&quot; -o &quot;$(TargetDir)$(MacOsMeetingIntegrationsOutputPath)&quot;" />
<Exec Command="/usr/bin/xcrun swiftc -parse-as-library -O -target $(MacOsAudioCaptureArchitecture)-apple-macos13.0 &quot;$(MacOsLauncherSource)&quot; -o &quot;$(TargetDir)$(MacOsLauncherOutputPath)&quot;" />
</Target>
<Target
Name="PackageMacOsApplication"
AfterTargets="Publish"
DependsOnTargets="CopyMeetingAssistantConfigToPublishRoot;CopyMacOsNativeHelpersToPublish"
Condition="'$(MacOsNativeHelpersEnabled)' == 'true'">
<RemoveDir Directories="$(PublishDir)$(MacOsApplicationBundlePath)" />
<MakeDir Directories="$(PublishDir)$(MacOsApplicationBundlePath)/Contents/MacOS" />
<MakeDir Directories="$(PublishDir)$(MacOsApplicationBundlePath)/Contents/Resources/app" />
<ItemGroup>
<MacOsPublishedRuntimeFiles Include="$(PublishDir)**/*" Exclude="$(PublishDir)$(MacOsApplicationBundlePath)/**/*" />
</ItemGroup>
<Copy
SourceFiles="@(MacOsPublishedRuntimeFiles)"
DestinationFiles="@(MacOsPublishedRuntimeFiles->'$(PublishDir)$(MacOsApplicationBundlePath)/Contents/Resources/app/%(RecursiveDir)%(Filename)%(Extension)')" />
<Copy SourceFiles="$(TargetDir)$(MacOsLauncherOutputPath)" DestinationFiles="$(PublishDir)$(MacOsApplicationBundlePath)/Contents/MacOS/MeetingAssistant" />
<Copy SourceFiles="$(MacOsLauncherInfoPlist)" DestinationFiles="$(PublishDir)$(MacOsApplicationBundlePath)/Contents/Info.plist" />
<Exec Command="/usr/bin/codesign --force --deep --sign - --requirements '=designated =&gt; identifier &quot;cloud.schweigert.meeting-assistant&quot;' &quot;$(PublishDir)$(MacOsApplicationBundlePath)&quot;" />
</Target>
<Target
@@ -0,0 +1,24 @@
<?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>CFBundleExecutable</key>
<string>MeetingAssistant</string>
<key>CFBundleIdentifier</key>
<string>cloud.schweigert.meeting-assistant</string>
<key>CFBundleName</key>
<string>Meeting Assistant</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSUIElement</key>
<true/>
<key>NSCalendarsFullAccessUsageDescription</key>
<string>Meeting Assistant reads calendar metadata for meeting notes and recording prompts.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Meeting Assistant records microphone audio for live meeting transcription.</string>
</dict>
</plist>
@@ -0,0 +1,70 @@
import Darwin
import Dispatch
import Foundation
@main
private struct MeetingAssistantLauncher {
private static let serviceDirectoryName = "MeetingAssistant"
static func main() {
let runtimeDirectory = Bundle.main.bundleURL
.appendingPathComponent("Contents/Resources/app", isDirectory: true)
let assemblyPath = runtimeDirectory.appendingPathComponent("MeetingAssistant.dll").path
let environmentFile = FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent("Library/Application Support")
.appendingPathComponent(serviceDirectoryName)
.appendingPathComponent("config/meeting-assistant.env")
guard FileManager.default.fileExists(atPath: assemblyPath) else {
fail("Meeting Assistant runtime not found at \(assemblyPath)")
}
guard FileManager.default.fileExists(atPath: environmentFile.path) else {
fail("Meeting Assistant environment file not found at \(environmentFile.path)")
}
let process = Process()
process.executableURL = URL(fileURLWithPath: "/bin/zsh")
process.arguments = [
"-c",
"set -a; source \"$1\"; set +a; exec /usr/local/share/dotnet/dotnet \"$2\" --contentRoot \"$3\"",
"meeting-assistant-launcher",
environmentFile.path,
assemblyPath,
runtimeDirectory.path
]
process.currentDirectoryURL = runtimeDirectory
signal(SIGTERM, SIG_IGN)
signal(SIGINT, SIG_IGN)
let terminationSignal = DispatchSource.makeSignalSource(signal: SIGTERM, queue: .global())
terminationSignal.setEventHandler {
if process.isRunning {
process.terminate()
}
}
terminationSignal.resume()
let interruptSignal = DispatchSource.makeSignalSource(signal: SIGINT, queue: .global())
interruptSignal.setEventHandler {
if process.isRunning {
kill(process.processIdentifier, SIGINT)
}
}
interruptSignal.resume()
do {
try process.run()
process.waitUntilExit()
Darwin.exit(process.terminationStatus)
} catch {
fail("Meeting Assistant launcher failed: \(error)")
}
}
private static func fail(_ message: String) -> Never {
FileHandle.standardError.write(Data("\(message)\n".utf8))
Darwin.exit(1)
}
}