パスワードを条件付きランダム生成(PySide2, QML) GUI-第2章

まえがき

この記事ではGUIのインターフェースから各種条件を受け取ってパスワードを実際に生成するクラスを実装を取り上げていく、そんな素敵な記事なんです。

全体の機能をちょっと整理すると以下の3つに分けられる。

  1. GUIインターフェース:ビュー
  2. GUIとのやり取り:コントローラー
  3. パスワード生成クラス:コントローラーから値もらう

GUI部分は今後記事にしていくが、QMLとPySideとで繋がり具合を調べていてふと、「そういえばパスワードそのものを生成する機能ってふわっとしたイメージしかないな」と思い、なんやかんやでこちらを先に完成させることになった。

変更履歴

2020/04/05: 新規作成

この記事の環境

バージョン: Python 3.8.1

IDE: Spacemacs

環境構築: pyenv、pyenv-virtualenv

OS: macOS

パスワード生成クラスの作成

まずパスワード生成クラスの機能の詳細を明らかにしたい。今回は生成機能を1つのクラスにする。シンプルな機能なのでPySide2を使うコントローラー役の内部に書いても良かったが、これも勉強とゆうことでできるだけ多くの言語機能を使うことにした。

機能詳細

パスワード生成の条件は4種類。3つは複数の選択肢のうち1つのみ選択可能だが、残り1つは重複して選択できる。

  1. 文字数
  2. 文字の始まりの指定
  3. 形式指定
  4. 含める文字種類(重複可)

この4つの指定を受け取りパスワードを生成して文字列として返す。

今回やったこと

  1. 生成クラスと定数クラスの2つを作った。
  2. DocstringをNumPyスタイルで記述した。
  3. パッケージ管理用の特殊変数も使ったよ。(__version__, __autor__)
  4. お決まりの__name__ == "main"を使ったよ。
  5. 定数クラスを作ってインポートしただよ。

パスワード生成モジュール:ソースコード

__version__, __author__などはPythonのライブラリに入っているので真似して入れてみた。ただsetup.pyなるものがあるとモジュールに__version__を書く必要はないのかもしれない。

まだまだ改良の余地、修正の余地があるがとりあえずこんなもんでいいだろう。

# -*- coding: utf-8 -*-
"""\
パスワード生成モジュール
    英字(大文字、小文字)、記号、数字の中から抽出。
    条件は、文字数、含める文字種、始まりの文字指定、パスワード形式指定
"""

__version__ = "0.1"
__author__ = "Hideo Tsujisaki"

import random
import string

import constants as const


class PwRandomizer(object):
    """\
    パスワード生成機能。
    英字(大文字、小文字)、記号、数字の中から抽出。
    条件は、文字数、含める文字種、始まりの文字指定、パスワード形式指定。

    Attributes
    ----------
    char_lim : integer
    condition : string
    start_con : string
    style : string, default None

    Rturns
    ------
    pass_word : string
    """

	const.START_COND_MOJI = "moji"
	const.START_COND_KIGO = "kigo"
	const.START_COND_NUMB = "numb"
	const.PASSWORD_STYLE_HYPHEN = "pyhe"
	const.PASSWORD_STYLE_DOTTS = "dott"

    cond = ""

    def __init__(self, char_lim, condition, start_con, style=None):
        self.lower_case = string.ascii_lowercase
        self.upper_case = string.ascii_uppercase
        self.digits = string.digits
        self.kigou = string.punctuation

        self.char_lim = char_lim
        self.condition = condition
        self.staert_con = start_con
        self.style = style

        self.pw_builder()

    if __name__ == "main":

        def pw_builder(self):

            self.cond_setter()

            # パスワード生成部
            pass_word = ""

            if self.s_con == const.TART_COND_MOJI:
                pass_word += random.choise(self.lower_case)

            if self.s_con == const.START_COND_KIGO:
                pass_word += random.coise(self.kigou)

            if self.s_con == const.START_COND_NUMB:
                pass_word += random.choice(self.digits)

            build_counter = 2
            for build_counter in range(self.num):
                pass_word += random.choice(self.cond)

            # パスワード整形部
            cep_type = ""
            if self.styles == const.PASSWORD_STYLE_HYPHEN:
                cep_type = "-"

            if self.styles == const.PASSWORD_STYLE_DOTTS:
                cep_type = "."

            if self.styles is not None:
                if self.num == 8:
                    pass_word.replace(pass_word[2], cep_type)
                    pass_word.replace(pass_word[5], cep_type)

                if self.num == 16:
                    pass_word.replace(pass_word[7], cep_type)
                    pass_word.replace(pass_word[12], cep_type)

                if self.num == 32:
                    pass_word.replace(pass_word[9], cep_type)
                    pass_word.replace(pass_word[16], cep_type)
                    pass_word.replace(pass_word[23], cep_type)
                    pass_word.replace(pass_word[30], cep_type)

                return pass_word

        def cond_setter(self):
            """\
            含める文字の設定(複数同時指定可能)
            Return: String ex."ab", "ac"
            condition: 大文字=a、記号=b、数字=c
			"""
            cond = self.lower_case

            if "a" in self.condition:
                cond += self.upper_case

            if "b" in self.condition:
                cond += self.kigou

            if "c" in self.condition:
                cond += self.digits

定数モジュール:ソースコード

Pythonには定数が言語機能として実装されていないということで、定数クラスを作ろうと思った。最初は定数クラスに値を入れてタプルとしてあればいいかと思った。しかし少し調べてみるともっと良い方法が見つかったのでこれにした。

使う側で変数を定義して使うが、1度値を代入すると2回目以降は代入できない。エラーが出る。まさに定数。ほぼマルパクリ。パクリもと。

# -*- coding: utf-8 -*-
"""\
定数モジュール
"""

__version__ = "0.1"
__author__ = "Hideo Tsujisaki"


class _Constants(object):
    class ConstError(TypeError):
        pass

    def __repr__(self):
        return "定数型の定義。"

    def __setattr__(self, const_name, value):
        if const_name in self.__dict__:
            raise self.ConstError("定数には再代入できません。 (%s)" % const_name)
        self.__dict__[const_name] = value

    def __del__(self):
        self.__dict__.clear()

むすび

とりあえずこんなところでよしとして次はPySide2を使ったコントローラーとQMLもビューを完成させたい。最終的な動作テストをした後で色々と仕様変更なり修正なりがあるだろうから完成品まではままだ時間がかかると思われる。

コメントする