From 03f323c5936e0ec239ccef57a517d58d5d329cbd Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 15 Apr 2014 10:06:56 -0400 Subject: [PATCH] Hooked up support for a Griffin Powermate. If you have access to one and run the program with --powermate=/dev/whatever, 1pass will accept button presses on the Powermate as if you hit the magic key combo. Also, it will toggle the light on the device to pulse when the keychain is unlocked. --- 1pass.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1pass.lua | 7 ++++ 2 files changed, 114 insertions(+), 3 deletions(-) diff --git a/1pass.c b/1pass.c index ee7e9e4..54d44b5 100644 --- a/1pass.c +++ b/1pass.c @@ -1,7 +1,12 @@ +#include +#include #include #include #include #include +#include +#include + #include "lua.h" #include "lauxlib.h" #include "lualib.h" @@ -14,6 +19,87 @@ #define STATICARRAYLEN(x) ( (sizeof ((x))) / (sizeof ((x)[0])) ) +// plug in a Griffin Powermate, make sure you have access to it, and run with +// --powermate=/dev/input/eventX +static int powermate_fd = -1; +static int pumpPowermate(void) +{ + struct input_event buf[32]; + int pressed = 0; + ssize_t br; + + if (powermate_fd == -1) + return 0; // nothing to do. + + while ((br = read(powermate_fd, buf, sizeof (buf))) > 0) + { + ssize_t i; + br /= sizeof (buf[0]); + for (i = 0; i < br; i++) + { + struct input_event *ev = &buf[i]; + if ((ev->type == EV_KEY) && (ev->code == BTN_0) && (ev->value)) + pressed = 1; + } // for + } // while + + return pressed; +} + +static void setPowermateLED(const int enable) +{ + struct input_event ev; + const int brightness = enable ? 255 : 0; + const int pulse_speed = 255; + const int pulse_table = 0; + const int pulse_awake = enable ? 1 : 0; + const int pulse_asleep = 0; + + if (powermate_fd == -1) + return; + + memset(&ev, '\0', sizeof (ev)); + ev.type = EV_MSC; + ev.code = MSC_PULSELED; + ev.value = brightness | (pulse_speed << 8) | (pulse_table << 17) | (pulse_asleep << 19) | (pulse_awake << 20); + + if (write(powermate_fd, &ev, sizeof (ev)) != sizeof (ev)) + fprintf(stderr, "WARNING: tried to set Powermate LED and failed: %s\n", strerror(errno)); +} // setPowermateLED + + +static void initPowermate(int *_argc, char **argv) +{ + const char *arg = "--powermate="; + const size_t arglen = strlen(arg); + int argc = *_argc; + int i; + + for (i = 1; i < argc; i++) + { + const char *thisarg = argv[i]; + if (strncmp(thisarg, arg, arglen) != 0) + continue; + + thisarg += arglen; + powermate_fd = open(thisarg, O_RDWR); + if (powermate_fd == -1) + fprintf(stderr, "WARNING: couldn't open Powermate at %s: %s\n", thisarg, strerror(errno)); + else + { + const int flags = fcntl(powermate_fd, F_GETFL, 0) | O_NONBLOCK; + fcntl(powermate_fd, F_SETFL, flags); + } // else + + // eliminate this command line. + memmove(&argv[i], &argv[i+1], (argc-i) * sizeof (char *)); + argc--; + } // for + + *_argc = argc; +} // initPowermate + + static lua_State *luaState = NULL; static const uint8_t zero16[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static const char saltprefix[] = { 'S', 'a', 'l', 't', 'e', 'd', '_', '_' }; @@ -289,6 +375,14 @@ static int popupGuiMenu(lua_State *L) } // popupGuiMenu +static int setPowermateLED_Lua(lua_State *L) +{ + const int enable = lua_toboolean(L, 1); + setPowermateLED(enable); + return 0; +} // setPowermateLED_Lua + + static void keyhookPressed(void) { lua_getglobal(luaState, "keyhookPressed"); @@ -300,6 +394,9 @@ static gboolean keyhookPumper(void *arg) { if (pumpKeyHook()) keyhookPressed(); + else if (pumpPowermate()) + keyhookPressed(); + return TRUE; // keep firing timer } // keyhookPumper @@ -375,15 +472,21 @@ static int initLua(const int argc, char **argv) luaSetCFunc(luaState, giveControlToGui, "giveControlToGui"); luaSetCFunc(luaState, runGuiPasswordPrompt, "runGuiPasswordPrompt"); luaSetCFunc(luaState, copyToClipboard, "copyToClipboard"); + luaSetCFunc(luaState, setPowermateLED_Lua, "setPowermateLED"); // Set up argv table... lua_newtable(luaState); int i; + int luai = 1; for (i = 0; i < argc; i++) { - lua_pushinteger(luaState, i+1); - lua_pushstring(luaState, argv[i]); - lua_settable(luaState, -3); + if (argv[i]) + { + lua_pushinteger(luaState, luai); + lua_pushstring(luaState, argv[i]); + lua_settable(luaState, -3); + luai++; + } // if } // for lua_setglobal(luaState, "argv"); @@ -397,6 +500,7 @@ static int initLua(const int argc, char **argv) int main(int argc, char **argv) { + initPowermate(&argc, argv); gtk_init(&argc, &argv); if (!initLua(argc, argv)) // this will move control to 1pass.lua diff --git a/1pass.lua b/1pass.lua index df58ab2..e13e2fc 100644 --- a/1pass.lua +++ b/1pass.lua @@ -289,11 +289,15 @@ function keyhookPressed() -- not local! Called from C! keyhookRunning = true + -- !!! FIXME: this should lose the key in RAM and turn off the Powermate + -- !!! FIXME: LED when the time expires instead of if the time has + -- !!! FIXME: expired when the user is trying to get at the keychain. if passwordUnlockTime ~= nil then local now = os.time() local maxTime = (15 * 60) -- !!! FIXME: don't hardcode. if os.difftime(now, passwordUnlockTime) > maxTime then -- lose the existing password and key, prompt user again. + setPowermateLED(false) password = argv[2] -- might be nil, don't reset if on command line. keys["SL5"] = nil end @@ -314,6 +318,7 @@ function keyhookPressed() -- not local! Called from C! end else passwordUnlockTime = os.time() + setPowermateLED(true) end end @@ -326,6 +331,7 @@ function keyhookPressed() -- not local! Called from C! keys["SL5"] = nil passwordUnlockTime = nil keyhookRunning = false + setPowermateLED(false) end appendGuiMenuItem(topmenu, "Lock keychain", lock_callback) @@ -360,6 +366,7 @@ end -- !!! FIXME: message box, exit if basedir is wack. -- !!! FIXME: this can probably happen in C now (the Lua mainline is basically gone now). +setPowermateLED(false) -- off by default print("Now waiting for the magic key combo (probably Alt-Meta-\\) ...") giveControlToGui()