Password entry or time stealers



I don’t know about you, but during the day I often have to leave the workplace and block the poppy. In order not to make a few clicks of the mouse, I “hung up” my poppy on the “shift + cmd + l” keys, but upon arrival at the workplace I again had to enter a password (which is not so simple due to my paranoidness). And now, having made a mistake in a hurry once again when entering it, I thought about automating the lock / unlock process. Since all the doors of our office open on the map, I decided to hang it on the RFID tag (it still hangs around my neck all the time) and this function. So, the task in words looked like this: logging in once at the beginning of the working day to be able to lock / unlock the poppy by RFID tag, while all the functions of checking the validity of the tag, etc. should occur on the poppy side.

The beginning is already half the battle, and the stand based on the Arduino UNO was just freed up at hand.

In the process, I decided to supplement the functionality: the label will be read only when the yellow button in the photo above is pressed (I don’t know why such complications - apparently, paranoia affects again). So, the general process should look like this:

  • The entire functional part will be on the poppy side, while the Arduino will only transmit the tag code and “blink LEDs”;
  • Hold the button - the yellow ready LED lights up;
  • If we apply an incorrect label, the red LED lights up;
  • Attach the correct label - the green LED lights up and the poppy locks / unlocks.

Having bought an RFID module at 125 kHz, I assembled a prototype device on a breadboard.

Sketch and code for Arduino


#include 
// "Распиновка"
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 = "";
}


The most interesting, in my opinion, is happening not on the Adruino side, but on the poppy side. So, Node.js with the SerialPort module will communicate with the stand . But for starters, I would like to solve the issue of storing the unlock password (I really did not want to keep it open in the body of the script, although FileVault is turned on by default). To do this, I decided to use the standard "key keeper" OS X - Keychain Access.

How to add a password to the key holder?
We call Keychain Access (Spotlight Search to help you)


Add a new password ...


In the Account Name field, specify an adequate name - we will contact it later from the script

Do not forget to access the key:
security find-generic-password -ga my password


image
Confirm access to the key for the console security program

Well, you can start the script itself on Node.js. To do this, create the “RFIDUnLock” folder on the desktop, the script itself will be referred to as “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');
		}
	});
}


Next, save the code for calling the Node.js script as a program (using the Script Editor ):

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

More if you can ...
We call the Script Editor (Spotlight Search to help you) We


write the code ...


Export ...


Save it as Application

You can also add a key that informs about the launch of the program in the background mode. To do this, in the “info.plist” file (available when viewing the contents of the program folder: ctrl + click on the file and selecting “Show Package Contents”), you need to add “”: before closing tags:

LSBackgroundOnly


... And add the launch of our program at boot
image

PS: After playing a couple of days with the prototype, I decided that he "has the right to live" - ​​it remains to solder it into the case, using the smaller brother Arduino Nano.

NB: In the 21st century there will be many wills containing passwords.

Also popular now: