Merge branch 'macos-secure-keyboard-entry' of https://github.com/multi/kitty
This is the usual Apple security theatre. Prevent key loggers from reading key events from the OS, but those same key events are written to the unsecured tty device from where the keylogger could read them anyway. But, since I dont want to have to explain why this is simply security theatre to every rando on the internet, merging anyway. It only costs one line in the application menu and maybe it will make some people that click on it *feel* more secure.
This commit is contained in:
commit
084b028eac
@ -561,6 +561,133 @@ translateKeyToModifierFlag(uint32_t key)
|
|||||||
static const NSRange kEmptyRange = { NSNotFound, 0 };
|
static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||||
|
|
||||||
|
|
||||||
|
// SecureKeyboardEntryController {{{
|
||||||
|
@interface SecureKeyboardEntryController : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, readonly) BOOL isDesired;
|
||||||
|
@property (nonatomic, readonly, getter=isEnabled) BOOL enabled;
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance;
|
||||||
|
|
||||||
|
- (void)toggle;
|
||||||
|
- (void)update;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation SecureKeyboardEntryController {
|
||||||
|
int _count;
|
||||||
|
BOOL _desired;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance {
|
||||||
|
static id instance;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
instance = [[self alloc] init];
|
||||||
|
});
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_desired = false;
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(applicationDidResignActive:)
|
||||||
|
name:NSApplicationDidResignActiveNotification
|
||||||
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(applicationDidBecomeActive:)
|
||||||
|
name:NSApplicationDidBecomeActiveNotification
|
||||||
|
object:nil];
|
||||||
|
if ([NSApp isActive]) {
|
||||||
|
[self update];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - API
|
||||||
|
|
||||||
|
- (void)toggle {
|
||||||
|
// Set _desired to the opposite of the current state.
|
||||||
|
_desired = !_desired;
|
||||||
|
debug_key(@"toggle called. Setting desired to %@", @(_desired));
|
||||||
|
|
||||||
|
// Try to set the system's state of secure input to the desired state.
|
||||||
|
[self update];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEnabled {
|
||||||
|
return !!IsSecureEventInputEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isDesired {
|
||||||
|
return _desired;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Notifications
|
||||||
|
|
||||||
|
- (void)applicationDidResignActive:(NSNotification *)notification {
|
||||||
|
if (_count > 0) {
|
||||||
|
debug_key(@"Application resigning active.");
|
||||||
|
[self update];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidBecomeActive:(NSNotification *)notification {
|
||||||
|
if (self.isDesired) {
|
||||||
|
debug_key(@"Application became active.");
|
||||||
|
[self update];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (BOOL)allowed {
|
||||||
|
return [NSApp isActive];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)update {
|
||||||
|
debug_key(@"Update secure keyboard entry. desired=%@ active=%@",
|
||||||
|
@(self.isDesired), @([NSApp isActive]));
|
||||||
|
const BOOL secure = self.isDesired && [self allowed];
|
||||||
|
|
||||||
|
if (secure && _count > 0) {
|
||||||
|
debug_key(@"Want to turn on secure input but it's already on");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!secure && _count == 0) {
|
||||||
|
debug_key(@"Want to turn off secure input but it's already off");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_key(@"Before: IsSecureEventInputEnabled returns %d", (int)self.isEnabled);
|
||||||
|
if (secure) {
|
||||||
|
OSErr err = EnableSecureEventInput();
|
||||||
|
debug_key(@"EnableSecureEventInput err=%d", (int)err);
|
||||||
|
if (err) {
|
||||||
|
debug_key(@"EnableSecureEventInput failed with error %d", (int)err);
|
||||||
|
} else {
|
||||||
|
_count += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
OSErr err = DisableSecureEventInput();
|
||||||
|
debug_key(@"DisableSecureEventInput err=%d", (int)err);
|
||||||
|
if (err) {
|
||||||
|
debug_key(@"DisableSecureEventInput failed with error %d", (int)err);
|
||||||
|
} else {
|
||||||
|
_count -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_key(@"After: IsSecureEventInputEnabled returns %d", (int)self.isEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
// }}}
|
||||||
|
|
||||||
// Delegate for window related notifications {{{
|
// Delegate for window related notifications {{{
|
||||||
|
|
||||||
@interface GLFWWindowDelegate : NSObject
|
@interface GLFWWindowDelegate : NSObject
|
||||||
@ -1401,6 +1528,19 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev) {
|
|||||||
|
|
||||||
- (BOOL)validateMenuItem:(NSMenuItem *)item {
|
- (BOOL)validateMenuItem:(NSMenuItem *)item {
|
||||||
if (item.action == @selector(performMiniaturize:)) return YES;
|
if (item.action == @selector(performMiniaturize:)) return YES;
|
||||||
|
if (item.action == @selector(toggleSecureInput:)) {
|
||||||
|
SecureKeyboardEntryController *controller = [SecureKeyboardEntryController sharedInstance];
|
||||||
|
if (controller.isEnabled) {
|
||||||
|
if (controller.isDesired) {
|
||||||
|
item.state = NSControlStateValueOn;
|
||||||
|
} else {
|
||||||
|
item.state = NSControlStateValueMixed;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.state = controller.isDesired ? NSControlStateValueOn : NSControlStateValueOff;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
return [super validateMenuItem:item];
|
return [super validateMenuItem:item];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1410,6 +1550,10 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev) {
|
|||||||
else [super performMiniaturize:sender];
|
else [super performMiniaturize:sender];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)toggleSecureInput:(id)sender {
|
||||||
|
[[SecureKeyboardEntryController sharedInstance] toggle];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)canBecomeKeyWindow
|
- (BOOL)canBecomeKeyWindow
|
||||||
{
|
{
|
||||||
// Required for NSWindowStyleMaskBorderless windows
|
// Required for NSWindowStyleMaskBorderless windows
|
||||||
|
|||||||
@ -89,7 +89,7 @@ def init_env(env: Env, pkg_config: Callable, pkg_version: Callable, at_least_ver
|
|||||||
|
|
||||||
elif module == 'cocoa':
|
elif module == 'cocoa':
|
||||||
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
|
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
|
||||||
for f_ in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
|
for f_ in 'Cocoa Carbon IOKit CoreFoundation CoreVideo'.split():
|
||||||
ans.ldpaths.extend(('-framework', f_))
|
ans.ldpaths.extend(('-framework', f_))
|
||||||
|
|
||||||
elif module == 'wayland':
|
elif module == 'wayland':
|
||||||
|
|||||||
@ -397,6 +397,12 @@ cocoa_create_global_menu(void) {
|
|||||||
|
|
||||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
|
||||||
|
[[appMenu addItemWithTitle:@"Secure Keyboard Entry"
|
||||||
|
action:@selector(toggleSecureInput:)
|
||||||
|
keyEquivalent:@"s"]
|
||||||
|
setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
|
||||||
|
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
|
||||||
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", app_name]
|
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", app_name]
|
||||||
action:@selector(terminate:)
|
action:@selector(terminate:)
|
||||||
keyEquivalent:@"q"];
|
keyEquivalent:@"q"];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user