ときどきZIPファイルにパスワードを設定しなければならない時がある

## PPAPは使わないのが基本ですが

最近はファイルのやり取りを行う場合、メールにファイルを添付することは少なくなったと思います。

かつてはセキュリティを考慮したつもりでいわゆる鍵付きZIPファイルにする事が多かったんですが、それだとウイルスチェックができないとかいろいろと問題点も指摘されて最近はファイル共有サービス等を利用することが一般的になりました。

が、ファイル共有サービスでファイル送付後に時々「オタクが使ってるファイル共有サービスのURLは、うちのセキュリティポリシーでアクセスできないんですけど」などと言う連絡が来たりして、改めて鍵付きZIPファイルで送ることになる事態に時々陥ります。

まあ事前にパスワードを決めとけよっていう話なんですが、時々しかやり取りしない場合はそんなこともしてないし、初めてやり取りする相手だとそもそも無理だし。

で、そんな時パスワードを設定するにしても「あなたのシグネチャに書いてあった携帯番号の下四桁です」とか「あなたのメールアドレスの@からあとの文字列です」とかいうとちょっとかっちょ悪い。とはいってもかっちょいい（予測しづらい）パスワードを毎回考え出すのもめんどくさい。なので、昨日まではpythonでパスワード自動生成スクリプトを書いてそれを使ったりしてました。ただし毎回イチから書くのはめんどくさいから、Google Colaboratryで書いたコードをGithubに保存して、使いたいときには毎回Githubから読み出して使ってましたが、それもやっぱめんどくさい。

ということで、そんなパスワードを生成するちょっとした処理をstreamlit cloud環境で動くようにしてみたよってのが今回のメインテーマです。

## さっそく画面

サービスにアクセスするとこんな画面が出てきます。

![スクリーンショット 2023-10-24 21.34.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739706/c7273e18-76ea-f0df-af62-0411369a1f0b.png)

作成ボタンをクリックすると指定した文字種類と文字数でパスワードが生成されます。

パスワード表示エリアはcode()で表示させているので、表示されたパスワードを簡単にコピー出来るようになっています。

![スクリーンショット 2023-10-24 22.03.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739706/ad9fa4c7-f10a-96cc-7e68-a621bfe5ae38.png)


### 主な仕様（というほど大げさなものではない）

パスワードで使う文字もアルファベット、数字、記号の組み合わせをどうするか選ぶことができます。

何も指定しないと英文字（大文字小文字）と数字の組み合わせとしています。

パスワードの長さも指定可です。デフォルトは１２桁とし、あまりに短いと意味がないし、あまりに長いと作成時やたらめったら時間がかかる（10,000桁を試したらずっと動き続けてた)ので８桁以上２０桁以下としています。

streamlitを使う中で、ラジオボタンなどは一般的で特に迷うこともなかったのですが、今回はパスワードの桁数指定のための数字入力をテーマに掲げ、streamlitのドキュメントでその実現方法を調べてみた結果、number_input()というウィジットを見つけたのでそれを使ってサービスを立ち上げることとしました。

またnumber_input()ウィジットはエンターキーを押せば処理が動くんですが、そうじゃなくて「いまパスワードをつくってますよ」っていう意識付けのためにform_submit_button()というのを使って、ボタンをクリックすることで処理が実行されたように見えるようちょっとだけ工夫しました。（使い方が正しいかどうかはよくわかってないけど）

まあそんなわけで、パスワードを作成する部分も、単純にsecrets関数をつかって文字列からランダムに指定された数の文字を拾って、そいつを並べたってだけですのでメイン処理には特に工夫はありません。

そんな工夫のないソースコードは以下の通り。

```
import streamlit as st
import string
import secrets

### パスワード発生関数

def pass_gen(size=12,txt=2):
    if txt == 0:
        chars = string.ascii_letters + string.digits + '%&$#()'
    elif txt == 1:
        chars = string.ascii_letters + string.digits + string.punctuation
    else:
        chars = string.ascii_letters + string.digits

    return ''.join(secrets.choice(chars) for _ in range(size))

### ここから画面制御

st.subheader('パスワードを作成')

### st.form_submit_button()が効く範囲はwith st.form()の中です

with st.form("my_form"):
    text = st.radio(
        "パスワードを構成する文字種類を選択してください。指定がない場合は 普通 です",
        ["複雑", "より複雑", "普通"],
        captions = ["Alphabet + 数字 + %&$#()", "Alphabet + 数字 + 記号", "Alphabet + 数字"],
        index=2
        )

    if text == "複雑":
        txt = 0
    elif text == "より複雑":
        txt = 1
    elif text ==  "普通":
        txt = 2

    st.write(' ')

    number = st.number_input("パスワードの桁数(8桁以上 最大20桁)を入力してください　指定がない場合は12桁です", value=12, placeholder="桁数入力")

    submitted = st.form_submit_button(label="作成")

    st.write(' ')
    st.write('パスワード')
    if submitted:
        if number <= 20 and number >= 8:
            st.code(pass_gen(number,txt)) #コピペして使いたいのでcode関数を使ってます
        else:
            st.write('注意！ 指定した桁数を確認してください 8桁以上20桁以内です')
    else:
        st.write("＊＊＊＊＊")

st.text('作成されたパスワードは表示エリアの右端をクリックするとコピーできます ')

```
もう少しきれいに書けるかもしれないけれど、動いているならオーケー主義ですので、まずはこれにて終了。
ソースコードには試行錯誤のあとも残ってたりするので、まあそこはご愛嬌ってことでよろしくお願いします。

実際に使ってみたい人は以下のリンクをクリックして使ってみてください。ちゃんと動くはずです。

" https://make-password.streamlit.app/ "


注意点としてはzipファイルをつくったあとパスワードをメモをとらないままもう一度作成ボタンをクリックしてしまったら、二度と同じパスワードは生成されないってことです。

連続してボタンを押した場合はせめてその履歴が画面表示できないかといろいろ考えたのですが、今の私のStreamlit力では実現出来ませんでした。なので、こいつは今後の課題として残しておきます。

今回はここまで。