概要
子供がPCをやめない。。。お昼の時間になっても、寝る時間になっても、ずっとネットサーフィンをしていて、返してもらえないし、PCを離さない。これでは取り上げることもできない。
というような経験はありませんか?私のおとーとが今まさにそんな感じなんですけど、PCを遠隔でロックするアプリを作ってみました。
ブラウザで当該アプリにアクセスすると
このような画面が出てきて、彼のアカウントをロック/アンロックしたり、彼のPCをシャットダウンさせたりできます。
残念だったな、おとーとよ、お兄ちゃんはITに詳しいんだ!!!
システム構成
おとーとのPCはLinux Mintです(ポンコツPCだったのでLinuxにしちゃいました)。
本アプリはPythonで書かれていて、Flaskを動かしています。Flaskが提供するサーバーにPOSTメソッドでリクエストを送ると、本アプリが彼のアカウントをロック/アンロックしたり、PCをシャットダウンしたりします。
家族が使うので、これらの操作をGUIで行えるよう、専用のWebページをGETメソッドで送信します。
本アプリはデーモンとして動作しているので、PCが起動されたら自動的に起動されます。おとーとのPCには、私のアカウント(管理者ユーザー)と彼のアカウント(一般ユーザー)があり、私のアカウントから本アプリを管理しています。
※本アプリのソースファイルなどは彼のアカウントからは見えないようにパーミッションを設定しています。また、デーモンは管理者ユーザーじゃない限り操作できないので、セキュリティ的にも大丈夫だと思います。
実装
実装する上で色々勉強したので、そのメモをここに置きます。
1. Pythonを自動起動
このようなファイルを書いて
[Unit]
Description=Remote management of ototo user.
[Service]
ExecStart=python3 /<python-script-path>
[Install]
WantedBy=multi-user.target
/etc/systemd/system
に入れて
sudo systemctl enable ototo
で自動起動にする。
sudo systemctl start ototo
で今すぐ起動する。
Pythonは、ユーザーが手動で起動させた際とSystemdが起動させた際とで、モジュールの探索パスが異なる場合があります。Systemdが起動させた際に予期せぬインポートエラーが起きるのを防ぐために、
- 動作する上で必要なモジュールは別途新しく作ったフォルダに入れる(e.g.
/home/onichan/PythonModule
)。 - Pythonスクリプトでは、モジュールをインポートする前に以下のようなコードを動かす。
import sys
sys.path.append("/home/onichan/PythonModule")
などをするといいです。
2. ユーザーをロック/アンロックするLinuxコマンド
sudo passwd -u <username>
sudo passwd -l <username>
3. sudoを一発で実行したい
ユーザーをロック/アンロックするコマンドをPythonから実行したいのですが、、、sudoを含むコマンドをPythonから実行しようとすると困ったことがあります。
sudo <command>
パスワード: ←どうやってPythonから入力するん???
対話形式でパスワードを求められると、Pythonだと自動化するのに苦労します。
ですが、以下のような書き方をすると、sudoにパスワードを与え、コマンドを実行するところまで一発でできます。
echo <password> | sudo -S <command>
パスワードをベタ書きしてしまうのは、ちょっと危ないかも。
4. Pythonからコマンドを実行
from subprocess import PIPE, run
def run_shell(prompt):
return run(prompt, stdout=PIPE, shell=True)
せっかくなのでsudoでコマンドを実行するメソッドも作っておきます。
def run_sudo(supassword, prompt):
return run_shell(f"echo {supassword} | sudo -S {prompt}")
5. JavaScriptでPostメソッドを投げる
今回はエントリーポイント1つに1つのコマンドを割り振るという形で実装します。例えば、PCをシャットダウンさせたかったら、<PCのIPアドレス>:<ポート番号>/shutdown
という所にPOSTメソッドを送ればOK。
POSTメソッドを送る操作は、Webページから行うようにします(Flaskのrender_template
機能でHTMLページを送信している)。そのWebページ内でのPOSTメソッドの送信は以下のように実装しました。
const r = new XMLHttpRequest()
r.open("POST","/shutdown")
r.send()
まとめ
これ結構便利なんで、実戦投入します。同じようなお悩みを抱えている方、是非実践してみてください。
ところで、ログイン画面に戻すのってどうやってやるんでしょうね。
xflock4
は現在のユーザーからログイン画面に遷移する機能なので、Systemctlから起動している本アプリがこのコマンドを実行しても、おとーとのアカウントからログイン画面に遷移させることができないのです。
xfce4-session-logout -u
も試してみましたが、Systemctlから起動している時に限りエラーが出てできませんでした。
本当なら、シャットダウンさせる機能よりログイン画面に戻す機能の方が実装したいんですけどね。。。