import os
import random
import getpass
import pickle

# 유저 정보를 저장하는 Dictionary 변수를 불러오기 위한 pickle
with open("data/user_info.pkl", "rb") as fr:
    user = pickle.loads(fr.read())
# 메인 스트림을 분기를 조정하는 스위칭 변수
controller = "main"
# 현재 접속한 인원에 대한 정보, 딱히 쓸모는 없는 상태.
current_id = ""


def encoding_pw(pw):
    """
    받은 문자열을 암호화 해주는 함수
    :param pw: str, 비밀번호 문자열
    :return en_pw: str, 암호화된 비밀번호 문자열
    """
    en_pw = ""
    range_1 = list(range(33, 39)) + list(range(48, 58))
    range_2 = list(range(65, 91)) + list(range(97, 122))
    for idx, ch in enumerate(pw):
        if random.random() >= 0.5:
            add_pw = chr(random.choice(range_1))
            new_i = chr(ord(ch) + (idx % 3) * 2 + 1)
        else:
            add_pw = chr(random.choice(range_2))
            new_i = chr(ord(ch) - (idx % 3) * 2 - 1)
        en_pw += add_pw
        en_pw += new_i
    if random.random() >= 0.5:
        en_pw += chr(random.choice(range_1 + range_2))
    return en_pw


def decoding_pw(en_pw):
    """
    암호화된 비밀번호를 복화화하여 원상복구 시키는 함수
    :param en_pw: str, 암호화된 비밀번호
    :return pw: str, 복화화된 비밀번호
    """
    pw = ""
    for idx, ch in enumerate(en_pw):
        if idx % 2 == 1:
            if ord(en_pw[idx - 1]) < 65:
                de_i = chr(ord(ch) - ((idx//2) % 3)*2 - 1)
            else:
                de_i = chr(ord(ch) + ((idx // 2) % 3) * 2 + 1)
            pw += de_i
    return pw


def print_main_menu():
    """
    메인화면을 UI 출력 함수
    :return: None
    """
    # print(user)
    # print(encoding_pw("1q2w3e"))
    print("1. 로그인\n2. 회원가입\n0. 종료")


def main_stream():
    """
    메인화면에서의 흐름을 통제하는 함수
    :return controller: str, 전체 흐름의 분기를 관장하는 변수
    """
    while True:
        os.system("cls")
        print_main_menu()
        usr_in = input("입력 : ")
        if "1" in usr_in:
            return "sign in"
        elif "2" in usr_in:
            return "sign up"
        elif "0" in usr_in:
            return "exit"
        else:
            os.system("cls")
            input("잘못 입력했습니다!")


def sign_in_stream():
    """
    로그인에서의 흐름을 통제하는 함수

    :return controller: str, 전체 흐름의 분기를 관장하는 변수
    :return tmp_user_info : tuple, 로그인한 대상의 정보를 전달해주는 tuple
    """
    while True:
        os.system("cls")
        id_in = input("아이디 입력 : ")
        if id_in == "exit":
            return "main", None
        pw_in = getpass.getpass("비밀번호 입력 : ")
        if pw_in == "exit":
            return "main", None
        if user.get(id_in) is not None:
            if decoding_pw(user.get(id_in)[0]) == pw_in:
                tmp_user_info = (id_in, user[id_in][1])
                return "sign in success", tmp_user_info
            else:
                os.system("cls")
                input("아이디 혹은 비밀번호가 틀렸습니다!")


def print_sign_up(id_="", pw="", name=""):
    """
    회원가입에서 현재 입력한 값을 보여주는 UI 출력 함수
    :param id_: str, 현재 입력 받은 ID문자열, default=""
    :param pw: str, 현재 입력 받은 비밀번호 문자열, default=""
    :param name: str, 현재 입력 받은 이름 문자열, default=""
    :return: None
    """
    os.system("cls")
    if not id_:
        id_ = "---------"
    if not pw:
        pw = "---------"
    if not name:
        name = "---------"
    print(f"  I  D  : {id_}")
    if pw != "---------":
        print(f"Password: {len(pw)*'*'}")
    else:
        print(f"Password: {pw}")
    print(f"N a m e : {name}")


def sign_up_stream():
    """
    회원가입에서의 흐름을 통제하는 함수
    :return controller: str, 전체 흐름의 분기를 관장하는 변수
    """
    id_ = id_check()
    if id_ == "exit":
        return "main"
    pw = pw_check(id_)
    if pw == "exit":
        return "main"
    name = name_check(id_, pw)
    if name == "exit":
        return "main"
    user[id_] = [encoding_pw(pw), name]
    print_sign_up(id_, pw, name)
    input("회원가입이 완료됬습니다!")
    return "main"


def id_check():
    """
    생성할 아이디를 입력받고 확인한 후 입력을 승인해주는 함수
    :return usr_input: str, 입력받은 문자열 or 종료를 위한 'exit'문자열
    """
    while True:
        print_sign_up()
        usr_input = input("생성할 아이디 입력 : ")
        if usr_input == "exit":
            return "exit"
        if usr_input.isdigit():
            os.system("cls")
            input(f"'{usr_input}'은/는 숫자로만 이루어져 생성할 수 없습니다!")
        elif usr_input in user.keys():
            os.system("cls")
            input(f"'{usr_input}'은/는 이미 존재합니다!")
        else:
            return usr_input


def pw_check(id_):
    """
    생성할 비밀번호를 입력받고 확인한 후 입력을 승인해주는 함수
    :param id_: str, 현재 입력값 출력을 위한 ID 변수
    :return usr_input: str, 입력받은 문자열 or 종료를 위한 'exit'문자열
    """
    switch_ = False
    while not switch_:
        print_sign_up(id_)
        usr_input = getpass.getpass("새로운 비밀번호 입력 : ")
        if usr_input == "exit":
            return "exit"
        switch_, msg = pw_make_check(id_, usr_input)
        if not switch_:
            os.system("cls")
            input(msg)
            continue
        print_sign_up(id_, usr_input)
        pw_recheck = getpass.getpass("비밀번호 확인 입력 : ")
        if pw_recheck == "exit":
            return "exit"
        if usr_input != pw_recheck:
            switch_ = False
            os.system("cls")
            input("비밀번호가 틀립니다!")
            continue
        return usr_input


def pw_make_check(id_, tmp_pw):
    """
    비밀번호 입력시 세부적인 조건을 따로 분류한 함수
    :param id_: str, ID에 대한 비교를 하기 위한 ID 변수
    :param tmp_pw: str, 입력을 허가하기 전의 비밀번호
    :return T/F: bool, 허용 가능한 비밀번혼지 아닌지 반환
    :return msg: str, 반환 값에 대한 메세지
    """
    uppers, lowers, numbers = False, False, False
    repeat_module = ["", 0]
    if not (8 <= len(tmp_pw) <= 15):
        return False, "비밀번호는 최대 15글자, 최소 8글자여야 합니다."
    if (id_ in tmp_pw) or (tmp_pw in id_):
        return False, "비밀번호에 아이디값을 사용할 수 없습니다."
    for i in tmp_pw:
        if 48 <= ord(i) <= 57:
            numbers = True
        elif 65 <= ord(i) <= 90:
            uppers = True
        elif 97 <= ord(i) <= 122:
            lowers = True

        if not repeat_module[0] or repeat_module[0] != i:
            repeat_module[0] = i
            repeat_module[1] = 1
        elif repeat_module[0] == i:
            repeat_module[1] += 1
            if repeat_module[1] == 3:
                return False, "3번 연속되는 숫자는 사용할 수 없습니다."
    if numbers and uppers and lowers:
        return True, "done"
    else:
        return False, "적어도 1개 이상의 소문자, 대문자 숫자가 포함되어야 합니다."


def name_check(id_, pw):
    """
    생성할 비밀번호를 입력받고 확인한 후 입력을 승인해주는 함수
    :param id_: str, 현재 입력값 출력을 위한 ID 변수
    :param pw: str, 현재 입력값 출력을 위한 비밀번호 변수
    :return: str, 입력받은 문자열 or 종료를 위한 'exit'문자열
    """
    while True:
        print_sign_up(id_, pw)
        usr_input = input("이름 입력 : ")
        if usr_input == "exit":
            return "exit"
        if not (2 <= len(usr_input) <= 15):
            os.system("cls")
            input("이름은 최소 2글자, 최대 15글자여야합니다.")
        return usr_input


while True:
    """
    메인 스트림
    """
    if controller == "main":
        controller = main_stream()
    elif controller == "sign in":
        controller, user_info = sign_in_stream()
        if controller == "sign in success":
            current_id = user_info[0]
            input(f"{user_info[1]}님 로그인 성공!")
            controller = "main"
    elif controller == "sign up":
        controller = sign_up_stream()
    elif controller == "exit":
        os.system("cls")
        input("프로그램을 종료합니다!")
        exit()
    with open("data/user_info.pkl", "wb") as fw:
        fw.write(pickle.dumps(user))

 

 

감사합니다.

+ Recent posts