LoginSignup
1
2

Python+Flaskで、子供のPCを遠隔でロック&アンロックするデーモンを作る

Last updated at Posted at 2023-05-18

概要

子供がPCをやめない。。。お昼の時間になっても、寝る時間になっても、ずっとネットサーフィンをしていて、返してもらえないし、PCを離さない。これでは取り上げることもできない。

というような経験はありませんか?私のおとーとが今まさにそんな感じなんですけど、PCを遠隔でロックするアプリを作ってみました。

ブラウザで当該アプリにアクセスすると

image.png

このような画面が出てきて、彼のアカウントをロック/アンロックしたり、彼のPCをシャットダウンさせたりできます。

残念だったな、おとーとよ、お兄ちゃんはITに詳しいんだ!!!

システム構成

note.png

おとーとのPCはLinux Mintです(ポンコツPCだったのでLinuxにしちゃいました)。
本アプリはPythonで書かれていて、Flaskを動かしています。Flaskが提供するサーバーにPOSTメソッドでリクエストを送ると、本アプリが彼のアカウントをロック/アンロックしたり、PCをシャットダウンしたりします。
家族が使うので、これらの操作をGUIで行えるよう、専用のWebページをGETメソッドで送信します。
本アプリはデーモンとして動作しているので、PCが起動されたら自動的に起動されます。おとーとのPCには、私のアカウント(管理者ユーザー)と彼のアカウント(一般ユーザー)があり、私のアカウントから本アプリを管理しています。

※本アプリのソースファイルなどは彼のアカウントからは見えないようにパーミッションを設定しています。また、デーモンは管理者ユーザーじゃない限り操作できないので、セキュリティ的にも大丈夫だと思います。

実装

実装する上で色々勉強したので、そのメモをここに置きます。

1. Pythonを自動起動

このようなファイルを書いて

ototo.service
[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が起動させた際に予期せぬインポートエラーが起きるのを防ぐために、

  1. 動作する上で必要なモジュールは別途新しく作ったフォルダに入れる(e.g. /home/onichan/PythonModule)。
  2. Pythonスクリプトでは、モジュールをインポートする前に以下のようなコードを動かす。
init_syspath.py
import sys
sys.path.append("/home/onichan/PythonModule")

などをするといいです。

2. ユーザーをロック/アンロックするLinuxコマンド

ロック
sudo passwd -u <username>
アンロック
sudo passwd -l <username>

3. sudoを一発で実行したい

ユーザーをロック/アンロックするコマンドをPythonから実行したいのですが、、、sudoを含むコマンドをPythonから実行しようとすると困ったことがあります。

Before
sudo <command>
パスワード: ←どうやってPythonから入力するん???

対話形式でパスワードを求められると、Pythonだと自動化するのに苦労します。

ですが、以下のような書き方をすると、sudoにパスワードを与え、コマンドを実行するところまで一発でできます。

After
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から起動している時に限りエラーが出てできませんでした。
本当なら、シャットダウンさせる機能よりログイン画面に戻す機能の方が実装したいんですけどね。。。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2