Ввод пароля или похитители времени



Не знаю, как вам, но мне в течении дня приходится часто отходить от рабочего места и блокировать мак. Чтобы не совершать несколько кликов мышкой, блокировку своего мака я «повесил» на клавиши «shift + cmd + l», но по приходу к рабочему месту опять же приходилось вводить пароль (который в силу моей параноидальности не так-то прост). И вот, ошибившись в спешке в очередной раз при его вводе, задумался автоматизировать процесс блокировки/разблокировки. Так как все двери нашего офиса открываются по карте, решил повесить на RFID-метку (всё равно всё время болтается на шее) и эту функцию. Итак, задача на словах выглядела так: авторизовавшись единожды в начале рабочего дня иметь возможность блокировки/разблокировки мака по RFID-метке, при этом все функции проверки валидности метки и т.п. должны происходить на стороне мака.

Начало — уже половина дела, да и как раз под рукой освободился стенд на базе Arduino UNO.

В процессе работы решил дополнить функционал: считывание метки будет происходить только при нажатой кнопке жёлтого цвета на фото выше (уж не знаю, зачем такие усложнения — видимо, опять параноя сказывается). Итак, общий процесс должен будет выглядеть следующим образом:

  • Функциональная часть вся будет на стороне мака, а Arduino будет только передавать код метки и «мигать светодиодами»;
  • Зажимаем кнопку — загорается жёлтый светодиод готовности;
  • Если прикладываем некорректную метку — загорается красный светодиод;
  • Прикладываем правильную метку — загорается зелёный светодиод и происходит блокировка/разблокировка мака.

Докупив модуль RFID на 125 кГц, собрал на макетной плате прототип устройства.

Скетч и код для Arduino


#include <SoftwareSerial.h>

// "Распиновка"
int buttonPin = 2;
int ledGreenPin = 13;
int ledYellowPin = 12;
int ledRedPin = 11;

// Модуль RFID и переменны для него
SoftwareSerial RFID(6, 7);

String inputString = "";
int rfidData;
String rfidNumber = "";
String rfidNumberLast = "";
boolean startPressButton = false;

void setup() {
  Serial.begin(115200);
  RFID.begin(9600);

  pinMode(buttonPin, INPUT);

  pinMode(ledGreenPin, OUTPUT);
  pinMode(ledYellowPin, OUTPUT);
  pinMode(ledRedPin, OUTPUT);

  digitalWrite(ledGreenPin, LOW);
  digitalWrite(ledYellowPin, LOW);
  digitalWrite(ledRedPin, LOW);
}

void loop() {
  listenButton();
}

/* Слушаем кнопку. Если нажата - слушаем RFID */
void listenButton() {
  if (digitalRead(buttonPin) == HIGH) {
    if (!startPressButton) {
      startPressButton = true;
      clearRFID();
    }
    digitalWrite(ledYellowPin, HIGH);
    listenRFID();
  } else {
    startPressButton = false;
    digitalWrite(ledYellowPin, LOW);
  }
}

/* Слушаем RFID. Если получен номер метки - кидаем его в поток */
void listenRFID() {
  if (RFID.available()) {
    delay(100);
    rfidNumber = "";
    for (int i = 0; i < 14; i++) {
      rfidData = RFID.read();
      if (rfidData < 16) rfidNumber += '0';
      rfidNumber += rfidData;
    }
    RFID.flush();
    sendRDIFNumber();
  }
}

/* Кидаем номер метки в поток */
void sendRDIFNumber() {
  if (rfidNumber != "" and rfidNumberLast != rfidNumber) {
    Serial.print("S");
    Serial.print(rfidNumber);
    Serial.print("E");
    rfidNumberLast = rfidNumber;
    rfidNumber = "";
  }
}

/* Слушаем поток на предмет комманд для Arduino */
void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    inputString += inChar;
    if (inputString == "M1F") {
      Serial.flush();
      inputString = "";
      logInOutProcess();
    }
    if (inputString == "M0F") {
      Serial.flush();
      inputString = "";
      logInOutFail();
    }
  }
}

/* Проверка на стороне мака прошла успешно - зелёный цвет */
void logInOutProcess() {
  clearRFID();
  digitalWrite(ledGreenPin, HIGH);
  digitalWrite(ledYellowPin, LOW);
  digitalWrite(ledRedPin, LOW);
  delay(1000);
  digitalWrite(ledGreenPin, LOW);
  digitalWrite(ledYellowPin, LOW);
  digitalWrite(ledRedPin, LOW);
}

/* Проверка на стороне мака не прошла - красный цвет */
void logInOutFail() {
  clearRFID();
  digitalWrite(ledGreenPin, LOW);
  digitalWrite(ledYellowPin, LOW);
  digitalWrite(ledRedPin, HIGH);
  delay(1000);
  digitalWrite(ledGreenPin, LOW);
  digitalWrite(ledYellowPin, LOW);
  digitalWrite(ledRedPin, LOW);
}

/* Чистка выдачи RFID-модуля */
void clearRFID() {
  RFID.flush();
  rfidNumberLast = "";
  rfidNumber = "";
}


Самое интересное, на мой взгляд, происходит не на стороне Adruino, а на стороне мака. Итак, общаться со стендом будет Node.js с модулем SerialPort. Но для начала хотелось бы решить вопрос с хранением пароля разблокировки (очень уж не хотелось держать его открытым в теле скрипта, хоть и FileVault по-умолчанию включён). Для этого решил воспользоваться стандартной «ключницей» OS X — Keychain Access.

Как добавить пароль в ключницу?
Вызываем Keychain Access (Spotlight Search Вам в помощь)


Добавляем новый пароль...


В поле Account Name прописываем адекватное имя — позже к нему будем обращаться из скрипта

Не забываем получить доступ к ключу:
security find-generic-password -ga my password


image
Подтверждаем доступ к ключу для консольной программы security

Ну вот, можно приступить к самому скрипту на Node.js. Для этого на рабочем столе создаём папку «RFIDUnLock», сам скрипт будет именоваться как «rfid.js»:

var inputString = "";
var serialport = require('serialport');
var SerialPort = serialport.SerialPort;
var sp = new SerialPort('/dev/tty.usbmodem20331', { // подсмотреть "путь" девайса можно в "Tools/Serial Port" программы Arduino
	baudrate: 115200
});
var exec = require('child_process').exec;
sp.on('open', function() {
	/* Читаем поток */
	sp.on('data', function(data) {
		inputString += data.toString("utf8");
		/* Берём из потока нужные данные по "маркерам" */
		var cardCode = inputString.match(/S([0-9]+)E/i);
		if (cardCode && cardCode[1] != 'undefined') {
			checkCardNumber(cardCode[1]);
			inputString = '';
		}
	});
});
function checkCardNumber(cardCode) {
	sp.flush(function() {
		/* Если метка та, что нужно... */
		if (cardCode == '0211111111111111111111111103') {
			/* ...отправляем команду Arduino "мигнуть зелёным" */
			sp.write('M1F');
			/* проверяем: запущен ли "скрин сейвер"? */
			exec('ps aux | grep -c ScreenSaverEngine.app | grep -v grep', function (error, stdout, stderr) {
				/* если запущен - берём пароль из Kaychain и "печатаем" в поле ввода пароля */
				if (parseInt(stdout) > 2) {
					exec("security 2>&1 >/dev/null find-generic-password -ga mypassword | ruby -e 'print $1 if STDIN.gets =~ /^password: \"(.*)\"$/'", function (error, stdout, stderr) {
					if (error !== null) return;
						var appleScript = 'osascript -e \'tell application "System Events"\' -e \'key code 56\' -e \'delay 0.5\' -e \'keystroke "' + stdout + '"\' -e \'key code 36\' -e \'end tell\'';
						exec(appleScript);
					});
				/* ...если "скрин север" не запущен - запускаем */
				} else {
					exec('open -a /System/Library/Frameworks/ScreenSaver.framework/Versions/Current/Resources/ScreenSaverEngine.app');
				}
			});
		/* Метка не корректна - отправляем команду Arduino "мигнуть красным" */
		} else {
			sp.write('M0F');
		}
	});
}


Далее сохраняем как программу (с помощью Script Editor) код вызова Node.js скрипта:

do shell script "/usr/local/bin/node ~/Desktop/RFIDUnLock/rfid.js"

Подробнее, если можно...
Вызываем Script Editor (Spotlight Search Вам в помощь)


Прописываем код...


Экспортируем...


Сохраняем как Application

Можно так же добавить ключ, сообщающий о запуске программы в background-режиме. Для этого в файле «info.plist» (доступен при просмоте содержимого папки программы: ctrl + click на файле и выбор «Show Package Contents») необходимо дописать перед закрывающими тегами "</dict></plist>":

<key>LSBackgroundOnly</key>
</true>


...И добавляем запуск нашей программы при загрузке системы
image

P.S.: Поигравшись пару дней с прототипом, решил, что он «имеет право жить» — осталось спаять его в корпус, с использованием меньшего брата Arduino Nano.

N.B.: В XXI веке будет много завещаний, содержащих пароли.
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 51

    +2
    Системные настройки — Рабочий стол и заставка — Заставка — Активные углы — Левый верхний = «Включить заставку».

    Достаточно, уходя, просто провести по тачпаду по диагонали и включается заставка с паролем.
      +2
      Только это не решает задачу со входом обратно без ввода пароля.
        0
        Согласен, не решает. Но позволяет заблокировать не глядя не то что на клавиатуру, но и на сам ноутбук.

        Ждем сканер отпечатков :)
          –1
          На фото Mac Pro. Там обычно нет тачпада.
            –1
            image
              0
              Там обычно нет тачпада.

              Не всегда он есть, а покупать тачпад ради блокировки экрана — уж извините.
                +2
                Мышку тоже быстро в угол экрана задвинуть.
                  0
                  Не знаю как вы, но я достаточно часто случайно завожу мышку в углы. У меня на них сейчас назначены такие функции как показать все окна и рабочий стол. Сейчас при случайном срабатывании — это не проблема, просто еще раз в этот угол нужно мышку затащить, делается почти мгновенно. А вот если при этом будет включаться заставка — это уже вариант по хуже.
                  0
                  Ну не знаю. Тачпад не удобен только для дизайна. А вот для другой работы очень даже не плох.
                  Все маководы, с которыми я общаюсь, имеют тачпад. И у всех, ко всему прочему, ноутбуки.

                  Да и как писал grishkaa, мышку тоже можно использовать для этих же целей. Так что тачпад в данном случае = мышке.
            +2
            Вот такой цепляйте seeedstudio.com/wiki/Grove_-_Finger_Print_Sensor_V1.0 :)
              +1
              в linux есть решение — pam-usb или pam-blue.Позволяют на основе данных наличия\отсутсвия конкретного устройства автоматически выполнять действия, например разблокировку\блокировку ноута
              0
              btw, по дефолту это действие и так висит на хоткее: cmd+shift+eject (cmd+shift+fn+power на mbp retina).
                +1
                Вот только чтобы нажать это сочетание надо две руки. А с заставкой — одного пальца и можно даже не смотреть :)
                  0
                  Мое сообщение, больше посыл к упоминанию автора о том, что он привязал это действие к cmd+shift+l. И да, тут имхо, дело вкуса, мне как человеку, у которого обычно обе руки на клавиатуре, и дефолтный хоткей удобен. Единственная проблема, с которой я сталкивался — о нем написано чуть больше, чем нигде, именно поэтому многие перевешивают его сторонними средствами.
                    0
                    Согласен что это дело вкуса.
                    У меня тоже руки постоянно на клавиатуре — пока еще это лучший способ писать код. Но бывает так, что встаешь к коллеге. А потом чтобы заблокировать компьютер — надо обойти стол и нажать комбинацию. А с активными углами я тянусь одной рукой, пара движений (два — для верности :) и можно идти.
                    Надо рассматривать это не как замену, а как дополнение.
                      0
                      К сожалению, я «тракторист», то бишь любитель Hot Keys. Гораздо проще нажать комбинацию клавиш нежели совершать лишние движения мышью. Хотя активный угол у меня тоже настроен — нижний правый для Launchpad.
                +4
                Вот чуть менее гиковское, но чуть более элегантное решение проблемы автора:
                www.knocktounlock.com/
                  0
                  не, по карте круче)
                    +1
                    Без допзащиты недостаточно секьюрно, RFID скопировать не просто, а очень просто. Хорошо бы к карте хотя бы пин.
                      0
                      Для активации режима карты необходима авторизация в системе (для запуска программы считывания метки), поэтому это решение можно применять при кратковременном «отходе» от мака…
                      0
                      (удалено, не в ту ветку)
                      0
                      Добра тебе, человек. Много добра!
                        0
                        под другие ОСи не встречали подобного приложения? Ubuntu + Android, к примеру…
                          0
                          под линуха давно есть, правда без стука — просто по удалению девайса от компа/ноута.
                          Сам когда-то пользовался, но потом отказался в пользу Fingerprint
                            0
                            огромное спасибо за направление
                            немного покатал, но под Ubuntu Unity 14.04 странно себя повел: окошко настройками один раз появилось и больше не показывалось, непрерывно запрашивалось подтверждение сопряжения
                            решил, что не стоит засорять рабочую ОСь непонятным ПО
                        –3
                        Пользуясь случаем, поделюсь самописным скринсейвером с часами: скачать.

                        Написал, когда не нашел ни одного адекватного скринсейвера с простыми часами. Для работы нужен шрифт Myriad Pro.
                          +3
                          Вы бы его хотя бы в исходных кодах рядом с бинарником выложили, а то предложили скачать запускаемый файл на Хабре…
                            –2
                            Исходник выкладывать стыдно, если честно, там не самый лучший код. Но если действительно интересно, могу в личку кинуть.
                              +3
                              Дело не в вашем коде как таковом, а в том, что мы все тут параноики и не запускаем не собранные лично из сырцов после тщательной проверки бинарники :)
                          0
                          Интересно, что Мак можно разблокировать программно. Винду, как я понимаю, нельзя из принципа. Хотя может и получится, если драйвер клавиатуры написать.

                          Кстати интересный вариант. Сделать девайс в формате USB-флешки, имитирующий HID-клавиатуру, после определения в системе просто вводит пароль. Но пароль придется ранить в устройстве, а извлечь его оттуда проще простого.
                            0
                            Надо встроить в этот usb-девайс сканер отпечатка пальца.
                              0
                              Со сканером отпечатка пальца винду и так можно разблокировать, я так и делаю на своем Lenovo x230. Сейчас почитал, у винды вроде как есть интерфейсы, позволяющие прикручивать альтернативные механизмы авторизации, типа отпечатков пальцев и всяких токенов. Вероятно таким образом можно провернуть разблокировку.
                              0
                              Когда-то давно, еще во времена Windows XP, игрался с Rohos Logon Key. Принцип тот же, вставляешь флешку — пароль вводится программой и выполняется вход в систему. Судя по всему используется программная эмуляция клавиатуры. Плюс можно было использовать двухфакторную авторизацию USB-флешка + PIN-код.
                              Disclaimer: Программа платная (может быть есть триал/бесплатная ограниченная версия). Я никак не связан с разработчиком этой программы, так что не сочтите за рекламу.
                                0
                                Вообще, ввод пароля через USB ключ напрямую — это с т.з. безопасности небезопасно, простите за каламбур. Логичнее было бы применить какую-нибудь криптографию.

                                Иначе получается примерно как выписанные на бумажку пароли (или в тетрадочку). Допустим, потерял, а кто-то нашел… или подсмотрел через плечо
                                0
                                Все уже давно придумано до вас.
                                  0
                                  Круто! Но я особо и не сомневался, что кто-то придумал это раньше. Особенно понравилось управление через Caps Lock, остроумно.
                                  0
                                  Насколько знаю, нужен не драйвер клавиатуры, а Credential Provider (будет работать на Vista+). На XP был вариант с GINA dll.
                                  http://msdn.microsoft.com/en-us/library/windows/desktop/bb648647(v=vs.85).aspx
                                    0
                                    Ага, я это уже тоже понял. Так гораздо правильнее.
                                  0
                                  Есть еще один интересный способ — разблокировать компьютер когда в указанном радиусе появляется определенное блютуз устройство (телефон), радиус можно определять по уровню сигнала, для секъюрности еще можно сохранить в телефон некий приватный ключ. Аналогично, компьютер может сам блокироваться если устройства нету рядом.

                                  Подход известный — сходу гуглится куча приложений реализующих эту идею.
                                    0
                                    По уровню сигнала ненадёжно — положил телефон в карман, уровень сигнала понизился, компьютер заблокировался :)
                                    Или вышел в туалет, который прямо за стеной, компьютер разблокировался.
                                      0
                                      1. Можно отключить автоматическую блокировку и блокировать самому лично, а разблокировку настроить так чтобы она срабатывала только при приближении устройства вплотную. С ноутбуком должно быть удобно.
                                        0
                                        2. Лично мне было бы удобно на работе и так — я всегда кладу телефон на стол возле компьютера практически в одно и тоже место, а когда отхожу — беру с собой. И туалета за стенкой нету :)
                                      0
                                      Я это как-то делал простеньким скриптом на баше. Спариваешь устройство в «Маком», а потом проверяешь на доступность что-от там из /dev (не помню точно что), спишь секунду, проверяешь ещё раз.
                                      +2
                                      Я такую игрушку когда-то тоже захотел, реализовал на PIC18F2550, ибо их было много. USB HID эмуляция клавиатуры. Приходишь — втыкаешь флешку в фронтальный разъем и эмулировалось нажатие ESC-Ctrl-Alt-Del-Пароль.
                                      Так же хотел привязать к 433Мгц передатчику, который бы раз в 15-20сек слал бы пачку в эфир, опрашивая. Но руки не дошли. Этот же свисток можно использовать для ввода пароля на ресурсах, имея пару кнопок
                                        0
                                        Ну так teensy же умеет притворяться клавиатурой. pjrc.com.
                                          0
                                          Дороговато, да и нужен папа-юсб на борту, всё же.
                                            0
                                            16 баксов разве дорого? Что касаемо USB, мы же на Хабре. Всё равно корпус под плату делать — можно и переходник вставить.

                                            Я себе как-то давно купил две 2++ версии контроллера и нарадоваться на них не могу. Очень полезные ардуинки.

                                            Правда, стоит отметить, что за доставку тоже придётся заплатить. Это да.
                                              0
                                              Да, дорого. Не вижу смысла столько платить, если есть такое. Конечно есть 3.0, но это все равно не stm32f103
                                                0
                                                Нуууу. Я вот вот миди контроллеры на тинси делаю. Нужно много входов. По ссылке их совсем мало.
                                        +1
                                        Жёстко. А ведь можно просто юзать yubikey.
                                          0
                                          Для Убунты есть Bluetooth решение BlueProximity, которое блокирует и разблокирует ориентируясь на расстояние до телефона. Может его и на мак можно прикрутить.

                                          Only users with full accounts can post comments. Log in, please.