make the smart speaker smarter 18

12/07

モルモット

Index

Let me login to my pc AUTOMATICALLY

ちょっとスマートスピーカのネタから外れるのだが久々に更新。
先日、PASORIをラズパイにつないで、Felicaのカードを
置いたら、主人が帰ってきたことを認識するって仕組みを作った。

おかえりなさい

みたいなのをGoogle Home miniから喋らせて
それまで人感センサで電気をつけていたのを
ストップさせたりといった仕組み。

せっかくなので、家の私のPCのログイン画面の入力も
省略したいなと思い始めた。

なので、オートログインの仕組みをちょっと調べてみた。

Specs

その前に私のPCのスペックを。

No Name Value
0 PC Dellのなんか古いやつ
1 OS Debian GNU/Linux 10.0
2 X-Window System xorg 7.7
3 Display Manager lightdm 1.10.3

別にハード的なことに制約はないので
OSとミドルだけ知ってほしかったのでこんなもんかな。

んでね。このlightdmってのが割と何も考えずに
普段のDesktop Managerとして選択しちゃって
もう2年ぐらい常用しているのだが
こやつの自動ログインの仕組みを調べたら
割と簡単な仕組みで実現できることがわかった。

How to auto-login

自動ログインの仕組みは、以下のディレクトリにファイルを作る。
私の環境はディレクトリがなかったので作った。

/etc/lightdm/lightdm.conf.d/10_autologin.conf1

$ sudo mkdir -p /etc/lightdm/lightdm.conf.d
$ sudo vi /etc/lightdm/lightdm.conf.d/10_autologin.conf

以下の内容を保存しておくと。

[SeatDefaults]
autologin-user={AUTOLOGIN_USERNAME}
autologin-user-timeout=0

{AUTOLOGIN_USERNAME}には自分が普段使っているユーザアカウント名に
置き換える。これで再起動すると、自動でログインできる仕組み。

If I put on my card, then let me login

例えばスマートカードでのログインだとPCにカードを挿したり置いたりしたら
ログインされるってのはあるけどそれをラズパイにつながっている
PASORIにカードを置いたことをトリガーにそれをできるようにするって話。

Is my master ON?

ラズパイではご主人が帰ってきたことを認識したらDBに保存している。
それをJudgeクラスから呼び出せば、ご主人様のいるかをtrue/falseで
わかるようにしているので、それを外部からもわかるようにする。

LAN内通信なので大したセキュリティは用意しない。ラズパイ側には
IPフィルタがあるのでPCからのアクセス許可をするぐらい。

んで、APIを用意する。
本気で作るならJSONでやりとりして
認証とかもtlsかなんかでやっちゃうんだろうけど
インターネットに晒すわけでもないのでここでは簡便にする。

以前から動かしているapi.jsに主人いますかAPIを用意する。
以下抜粋。

const jdg=require('Judge');

app.get('/loginauth/get/', (req, res) => {
let loginCheck=async ()=>{
let j=await new jdg();
let ret=await j.isMasterOn();
res.header('Content-Type', 'text/html; charset=utf-8');
res.status(200).send(ret);
}
loginCheck();
});

JudgeクラスのisMasterOnメゾッドを呼べばtrue/falseで
返ってくるので、それをそのままクライアントに返す。

URLは

http://raspberrypi:50880/loginauth/get/

みたいなのにしてみる。

PC側はこのAPIを定期的に叩いてtrueであれば
自動ログイン処理をスタートさせることに。

autologin.sh

今回cron+bash scriptで実現してみる。
仕組みは単純。

sequenceDiagram
    participant sh as PC
    participant api as raspberrypi
    participant db as DB

    alt flag file exists?
        Note over sh : Quit
    else
        Note over sh : Run next step
    end
    
    sh->>+api : Get result
    api->>+db : Get record set
    db-->>-api : Send res
    api-->>-sh : Send result

    alt is master on
        Note over sh : Call function
    else
        Note over sh : Quit
    end

こんな感じ。
最終的に関数を呼んでいるのだが(Call functionのとこ)、
そこは以下のことをしている。

  • 自動ログインのファイルを生成する
  • lightdmを再起動する
  • フラグファイルを作る
  • 自動ログイン後は自動ログインのファイルを削除する

最後のフラグファイルはログイン後にも間違って動かないようにするためのやつ。
自動ログイン後は毎回自動ログインファイルを削除することで
次の再起動時にはログイン画面を表示させるため。
フラグファイルは再起動したら消えるように/tmpに生成する。

んで、このスクリプトを1分間隔で実行する。

はいできあがり。

ではスクリプトを作ってみる。

/srv/loginauth/checkmaster.sh

ここに作る。

#!/bin/bash
SYSNAME=autologin
AUTHURL=http://raspberrypi:50880/loginauth/get/
DMSERVICE=lightdm
SYSCTL=$(which systemctl)
CURL=$(which curl)
AUTHEVI=/tmp/loggedin.stat
AUTOLOGINFILE=/etc/lightdm/lightdm.conf.d/10_autologin.conf
USERNAME=friedbiscuit

if [ "x${SYSCTL}" == "x" -o "x${CURL}" == "x" ];
then
_e "some command[s] was/were not found"
exit 1
fi

if [ ! -d $(dirname $AUTOLOGINFILE) ];
then
mkdir -p $(dirname $AUTOLOGINFILE)
fi

if [ -f $AUTOLOGINFILE ];
then
rm -f $AUTOLOGINFILE
fi

function _e {
logger -t $SYSNAME "${1}"
}

function checking {
ret=$(${CURL} -s ${AUTHURL})
if [ "x$ret" == "xtrue" ];
then
_e "found master is on"
fi
echo $ret
}

function autologin {
ret=$($SYSCTL status $DMSERVICE |grep "running" >/dev/null && echo -n "OK")
if [ "x$ret" == "xOK" ];
then
_e "${DMSERVICE} is running now"
cat <<EOF >$AUTOLOGINFILE
[SeatDefaults]
autologin-user=${USERNAME}
autologin-user-timeout=0
EOF
$SYSCTL restart $DMSERVICE >/dev/null && _e "auto login start"
fi
}


function main {
if [ -f $AUTHEVI ];
then
exit
fi
ret=$(checking)
if [ "x$ret" == "xtrue" ];
then
autologin
sleep 5
_e "auto login evidence"
echo 1 > $AUTHEVI
rm -f $AUTOLOGINFILE
fi
}

main

あとはrootのcrontabに以下を追加

* * * * /srv/loginauth/checkmaster.sh >/dev/null

これで1分間隔でチェックさせる。

Did I have a good exprerience?

今のところ便利。以下の課題があるけど
特に解決しなくてもいいかな。

  • 自分の部屋なので、マルチユーザには対応していない。
  • 厳密にログインしたかを判断していない。
  • 本当はデーモンとして動くクロスプラットフォーム化プログラムとしてちゃんと管理してみたい。

コメント: