1
\$\begingroup\$

I am making an user class which I could inherit and use in the future.
(recently started learning Python and OOP)

import mysql.connector as mycon
class user:
    host = "localhost"
    user = "root"
    password = "pass"
    database = "USERS"
    table = "UserData"

    def __init__(self,firstName,lastName,userName,email):
        self.firstName = firstName
        self.lastName = lastName
        self.userName = userName
        self.fullName = firstName + " " + lastName
        self.email = email

    @classmethod
    def login(cls,userName,password):
        db = mycon.connect(host = cls.host,user = cls.user,password = cls.password,database = cls.database)
        cursor = db.cursor()
        r=cursor.execute("SELECT * FROM {} WHERE UserName = '{}';".format(cls.table,userName))
        userInfo = cursor.fetchone()
        if(userInfo!=None):
            if(userInfo[2]==password):
                print("Login Successful")
                return cls(userInfo[0],userInfo[1],userInfo[3],userInfo[4])
            else:
                print("INVALID PASSWORD",password,userInfo[2])
        else:
            print("USER DOES NOT EXIST")
        db.close()

    @classmethod
    def register(cls,firstName,lastName,password,userName,email):
        db = mycon.connect(host = cls.host,user = cls.user,password = cls.password,database = cls.database)
        cursor = db.cursor()
        r=cursor.execute("Insert into {} values('{}','{}','{}','{}','{}');".format(cls.table,firstName,lastName,password,userName,email))
        db.commit()
        db.close()

with a table UserData with description

enter image description here

\$\endgroup\$
1
  • \$\begingroup\$ Welcome to CodeReview@SE. Not claiming being new to DB programming, better don your asbestos. (Nah. Everything should be meant constructive, even if not praise.) \$\endgroup\$
    – greybeard
    Commented Feb 11, 2020 at 10:23

1 Answer 1

0
\$\begingroup\$

One of the most important things to take care of when writing a database application is to prevent unwanted access. This means that you always want to make sure that there is no user (and the programmer, i.e. you should be included in that) can supply an input that can escape the query and e.g. delete your whole database. This attack vector is called SQL injection and is very common. Avoiding it is relatively easy, thankfully, although you cannot do it for the table name:

@classmethod
def login(cls, user_name, password):
    db = mycon.connect(host=cls.host, user=cls.user, password=cls.password,
                       database=cls.database)
    cursor = db.cursor()
    query = f"SELECT firstName, lastName, password, UserName, email FROM {cls.table} WHERE UserName = %s;"
    r = cursor.execute(query, (user_name,))
    user_info = cursor.fetchone()
    if user_info is not None:
        if user_info[2] == password:
            print("Login Successful")
            return cls(user_info[0],user_info[1],user_info[3],user_info[4])
        else:
            print(f"INVALID PASSWORD {password} {user_info[2]}")
    else:
        print("USER DOES NOT EXIST")
    db.close()

Note that I followed Python's official style-guide, PEP8, which recommends using lower_case for variables and functions, spaces after commas and around = when using it as an assignment, but no space around the = when using it for keyword arguments.

Comparisons to None should always be done with is or is not and if conditions don't require parenthesis, since it is a keyword.

I also explicitly named the column names (they might be called differently, judging by UserName, so you would have to fix that), to ensure that you can change the table structure, as long as these names stay the same.

And I used an f-string for easy formatting in case of an invalid password. Note that in this case you do reveal the actual password (I guess this is just for testing, just make sure you don't forget to remove that information later). In a similar vein, you should not store passwords in plaintext. Hash them with a good hashing algorithm and ideally add a salt.

You could also use the mysql.cursor.MySQLCursorNamedTuple cursor, so you can say user_info.password instead of user_info[2]. Just use cursor = db.cursor(named_tuple=True).

You should do yourself a favor and add a docstring to every method you write, to explain what the method does, what its arguments are and what it returns.

\$\endgroup\$
3
  • \$\begingroup\$ How to prevent revealing the password \$\endgroup\$ Commented Feb 11, 2020 at 11:52
  • \$\begingroup\$ @VISHALAGRAWAL Just don't print the password that was input and the real password, print("INVALID PASSWORD"). \$\endgroup\$
    – Graipher
    Commented Feb 11, 2020 at 12:23
  • \$\begingroup\$ Oh forgot to remove those thanks for help man \$\endgroup\$ Commented Feb 11, 2020 at 14:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.