mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-09-03 21:00:27 +00:00
Fixes #10077 Clipboard read confirmations would immediately show a sheet which grabbed focus. This could be used for a bunch of dumb reasons, including DoS attacks. But, it also caused focus/sheet loops for programs that did OSC52 on focus changes (which was seen via some Neovim configs!). Now, if a surface is unfocused, we bell the surface and show the confirmation request on next focus. If the surface is not focused or another request comes in, we cancel the prior one. This also fixes some memory management issues around clipboard requests that were likely small leaks (didn't verify the old bug, but verified the new code, and eyeballed the old).
61 lines
1.9 KiB
Swift
61 lines
1.9 KiB
Swift
import Foundation
|
|
import Cocoa
|
|
import SwiftUI
|
|
|
|
/// This initializes a clipboard confirmation warning window. The window itself
|
|
/// WILL NOT show automatically and the caller must show the window via
|
|
/// showWindow, beginSheet, etc.
|
|
class ClipboardConfirmationController: NSWindowController {
|
|
override var windowNibName: NSNib.Name? { "ClipboardConfirmation" }
|
|
|
|
private(set) var confirmation: Ghostty.ClipboardConfirmationRequest
|
|
weak private var delegate: ClipboardConfirmationViewDelegate?
|
|
|
|
init(
|
|
confirmation: Ghostty.ClipboardConfirmationRequest,
|
|
delegate: ClipboardConfirmationViewDelegate
|
|
) {
|
|
self.confirmation = confirmation
|
|
self.delegate = delegate
|
|
super.init(window: nil)
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) is not supported for this view")
|
|
}
|
|
|
|
/// Replace the request represented by the visible sheet without changing
|
|
/// the sheet's focus state. The previous request is cancelled by its
|
|
/// SurfaceView before this method is called.
|
|
func replaceConfirmation(with confirmation: Ghostty.ClipboardConfirmationRequest) {
|
|
guard self.confirmation !== confirmation else { return }
|
|
self.confirmation = confirmation
|
|
|
|
guard isWindowLoaded, let window else { return }
|
|
configure(window)
|
|
}
|
|
|
|
// MARK: - NSWindowController
|
|
|
|
override func windowDidLoad() {
|
|
guard let window = window else { return }
|
|
|
|
configure(window)
|
|
}
|
|
|
|
private func configure(_ window: NSWindow) {
|
|
switch confirmation.kind {
|
|
case .paste:
|
|
window.title = "Warning: Potentially Unsafe Paste"
|
|
case .osc_52_read, .osc_52_write:
|
|
window.title = "Authorize Clipboard Access"
|
|
}
|
|
|
|
window.contentView = NSHostingView(rootView: ClipboardConfirmationView(
|
|
contents: confirmation.contents,
|
|
request: confirmation.kind,
|
|
delegate: delegate
|
|
))
|
|
}
|
|
}
|