Skip to content

Instantly share code, notes, and snippets.

@brettowe
Created May 4, 2022 21:28
Show Gist options
  • Save brettowe/592d2652acc7a3277678a576eef53c0b to your computer and use it in GitHub Desktop.
Save brettowe/592d2652acc7a3277678a576eef53c0b to your computer and use it in GitHub Desktop.
script that uses a yubikey on headless machines without a power button to initialize shutdown
#!/usr/bin/env python3
# this script listens for a yubikey to be plugged into a device and shutdown if the button is pressed on it
# handy for headless devices that have no power buttons but need to be shutdown
# no verification is done to see if its an authorized yubi key
# changelog
# 20220504 - initial release
import functools
import os.path
import pyudev
import subprocess
from fido2.hid import CtapHidDevice
from fido2.client import Fido2Client
from fido2.server import Fido2Server
try:
from fido2.pcsc import CtapPcscDevice
except ImportError:
CtapPcscDevice = None
def touchKey():
uv = "discouraged"
dev = next(CtapHidDevice.list_devices(), None)
# Set up a FIDO 2 client using the origin https://example.com
client = Fido2Client(dev, "https://localhost.com")
# Prefer UV if supported and configured
if client.info.options.get("uv"):
uv = "preferred"
print("Authenticator supports User Verification")
server = Fido2Server({"id": "localhost.com", "name": "Fido Shutdown"}, attestation="direct")
user = {"id": b"user_id", "name": "A. User"}
# Prepare parameters for makeCredential
create_options, state = server.register_begin(
user, user_verification=uv, authenticator_attachment="cross-platform"
)
try:
# Create a credential
# (really just touch the device we don't care beyond that)
result = client.make_credential(create_options["publicKey"])
# touched
return True
except:
# no touch or removed
return False
def main():
BASE_PATH = os.path.abspath(os.path.dirname(__file__))
path = functools.partial(os.path.join, BASE_PATH)
call = lambda x, *args: subprocess.call([path(x)] + list(args))
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by(subsystem='usb') # Remove this line to listen for all devices.
monitor.start()
for device in iter(monitor.poll, None):
if device.get('ID_MODEL_ID') == '0407' and device.get('ID_VENDOR_ID') == '1050':
try:
l_status = touchKey()
except:
l_status = False
if l_status:
print ("shutdown")
subprocess.run(["/usr/bin/shutdown", "-h", "now"])
else:
print ("no shutdown")
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment