Merge remote-tracking branch 'origin/pr/3'

master
n1trux 4 years ago
commit 43a3dd81ac

@ -38,12 +38,10 @@ RUN mkdir -p /var/run/sshd
# expose SSH port
EXPOSE 22
ENV TILDE_CONF="/app/data/applicationsconfig.ini"
#COPY config/environment /app/user/.ssh/environment
RUN mkdir /app/user/.ssh
RUN echo TILDE_CONF=$TILDE_CONF > /app/user/.ssh/environment
RUN touch /app/data/applications.sqlite
RUN touch /app/data/applications.log
# Doesnt work, @TODO why
#RUN setfacl -R -m u:tilde:rwx /app/data/
RUN chown -R tilde /app/data
CMD ["/usr/sbin/sshd", "-D"]
RUN mkdir /app/user/.ssh
CMD ["sh", "-c", " echo TILDE_CONF=$TILDE_CONF > /app/user/.ssh/environment && /usr/sbin/sshd -D"]

@ -4,16 +4,20 @@ import configparser, logging, sqlite3, argparse, pwd
import os
import subprocess
# Clear shell
def clear():
os.system('cls' if os.name == 'nt' else 'clear')
# create dictionary out of sqlite results
def dict_factory(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
# prints command(but doesnt execute them)
# need this for work, just convenience
def debugExec(commands):
@ -24,38 +28,38 @@ def debugExec(commands):
# @TODO hardcoded config?
cwd = os.environ.get('TILDE_CONF')
if cwd is None:
cwd=os.getcwd()+"/applicationsconfig.ini"
cwd = os.getcwd() + "/applicationsconfig.ini"
else:
if os.path.isfile(cwd) is False:
cwd=os.getcwd()+"/applicationsconfig.ini"
cwd = os.getcwd() + "/applicationsconfig.ini"
# cwd is now either cwd/applicationsconfig or $TILDE_CONF
argparser = argparse.ArgumentParser(description = 'interactive registration formular for tilde platforms')
argparser.add_argument('-c', '--config', default = cwd,
type = str, help = 'Path to configuration file', required = False)
argparser = argparse.ArgumentParser(description='interactive registration formular for tilde platforms')
argparser.add_argument('-c', '--config', default=cwd,
type=str, help='Path to configuration file', required=False)
args = argparser.parse_args()
CONF_FILE = args.config
config = configparser.ConfigParser()
config.read(CONF_FILE)
logging.basicConfig(format="%(asctime)s: %(message)s",
level = int(config['LOG_LEVEL']['log_level'])
level=int(config['LOG_LEVEL']['log_level'])
)
del(cwd)
del cwd
REG_FILE = config['DEFAULT']['applications_db']
# Does everything related to applicants, i.e. creating, manipulations...
class applicants():
class Applicants:
# User identifier
identifier = "username"
# SQLite DB Path
sourceDB = ""
# another sqlite to batch-recreate users
differentDB = ""
def __init__(self, lident, sourceDB=REG_FILE):
def __init__(self, lident, sourcedb=REG_FILE):
self.identifier = lident
self.sourceDB = sourceDB
self.sourceDB = sourcedb
self.__connectToDB__("source")
# all results shall be done with dict_factory! Makes everything so much simpler
self.sdbCursor.row_factory = dict_factory
@ -75,58 +79,61 @@ class applicants():
self.ddbCursor = self.ddbConnection.cursor()
def __closeDB__(self, which):
if(which == "source"):
if which == "source":
try:
self.sdbConnection.close()
except sqlite3.Error as e:
logging.exception("Couldn't close database! Error: %s" % e) # @TODO: Dump full db with query or just the executed querys to file
logging.exception(
"Couldn't close database! Error: %s" % e)
# @TODO: Dump full db with query or just the executed querys to file
else:
self.ddbConnection.close() # @TODO: Evaluate getting rid of ddb(differentDB)?
# get List of all applications(not accepted yet)
def getApplicationsList(self):
def getapplicationslist(self):
query = "SELECT * FROM `applications` WHERE `status` = '0'"
try:
self.sdbCursor.execute(query)
rows = self.sdbCursor.fetchall()
except sqlite3.Error as e:
logging.exception("Database Error: %s" % e)
rows=[]
rows = []
return rows
def getApprovedApplicantsList(self):
def getapprovedapplicantslist(self):
query = "SELECT * From `applications` WHERE `status` = '1'"
try:
self.sdbCursor.execute(query)
rows = self.sdbCursor.fetchall()
except sqlite3.Error as e:
logging.exception("Database Error: %s" % e)
rows=[]
rows = []
return rows
# edit aproved users
def editApprovedApplicant(self, term, updaterow):
def editapprovedapplicants(self, term):
try:
# the fuck did i try here?
self.sdbCursor.execute(
"UPDATE `applications` SET ? WHERE id=?",
( str(term), )
"UPDATE `applications` WHERE id=?", (str(term),)
)
self.sdbConnection.commit()
except sqlite3.Error as e:
logging.exception("Database Error: %s" % e)
# set user to aproved
def setApprovedApplication(self, selectterm):
query = "SELECT `username` FROM `applications` WHERE `username` = `{0!s}`".format(selectterm)
def setapprovedapplication(self, selectterm):
# query = "SELECT `username` FROM `applications` WHERE `username` = `{0!s}`".format(selectterm)
pass
# get applicants data
def getApplicantsData(self, term):
def getapplicantsdata(self, term):
# @TODO: Use shorthand if for the correct query, directly into sqlite
if self.identifier == "id":
try:
self.sdbCursor.execute(
"SELECT * FROM `applications` WHERE id = ?",
( str(term), )
(str(term),)
)
except sqlite3.Error as e:
logging.exception("Database Error: %s" % e)
@ -134,26 +141,26 @@ class applicants():
else:
self.sdbCursor.execute(
"SELECT * FROM `applications` WHERE username = ?",
( str(term), )
(str(term),)
)
result = self.sdbCursor.fetchone()
return result
# @TODO: migrade just approved users to some new/another sqlitedb
def migrateApprovedData(self, different_db):
def migrateapproveddata(self, different_db):
pass
# @TODO: delete migrated data
def deleteMigratedDataSet(self, selectterm):
def deletemigrateddata(self, selectterm):
pass
# Applicants whom doesnt got approved should get removed
def removeApplicant(self, term):
def removeapplicant(self, term):
if self.identifier == "id":
try:
self.sdbCursor.execute(
"DELETE FROM `applications` WHERE id = ?",
( str(term), )
(str(term),)
)
self.sdbConnection.commit()
except sqlite3.Error as e:
@ -161,25 +168,26 @@ class applicants():
else:
self.sdbCursor.execute(
"DELETE FROM `applications` WHERE username = ?",
( str(term), )
'DELETE FROM `applications` WHERE username = ?',
(str(term),)
)
self.sdbConnection.commit()
#@TODO: Possibility to work without passing users manually
def selectedUser(userid, username = False):
# @TODO: Possibility to work without passing users manually
def selecteduser(userid, username=False):
pass
# Print out a list of aprovable users
def printApprovableUsers(self, users):
i=0
def printapprovableusers(self, users):
i = 0
for user in users:
print("ID: {0!s}, Status: {0!s}, Name: {0!s}".format(i, user["status"], user["username"]))
i += 1
return i
# Get List of users
def userPrint(self, fetched, userid):
@staticmethod
def userprint(fetched, userid):
print("ID: {0!s}".format(fetched[int(userid)]["id"]))
print("Username: {0!s}".format(fetched[int(userid)]["username"]))
print("Mail: {0!s}".format(fetched[int(userid)]["email"]))
@ -187,8 +195,8 @@ class applicants():
print("Registrated time: {0!s}".format(fetched[int(userid)]["timestamp"]))
# Approve an applicant. Handles everything related, like create home dir, set flags blabla
def approveApplicant(self, term):
user = self.getApplicantsData(term)
def approveapplicant(self, term):
user = self.getapplicantsdata(term)
ret = self.__execScript(user)
if ret[0] != 0: # @DEBUG: Change to == 0
print("Something went wrong in the user creation! Exiting without deleting users record in database!")
@ -199,7 +207,7 @@ class applicants():
try:
self.sdbCursor.execute(
"UPDATE `applications` SET `status`=1 WHERE `id`=?",
( str(term), )
(str(term),)
)
self.sdbConnection.commit()
except sqlite3.Error as e:
@ -207,172 +215,170 @@ class applicants():
else:
self.sdbCursor.execute(
"UPDATE `applications` SET `status`=1 WHERE `username`=?"
( str(term), )
"UPDATE `applications` SET `status`=1 WHERE `username`=?",
(str(term), )
)
self.sdbConnection.commit()
# Script execution, handles everything done with the shell/commands themselves
def __execScript(self, user):
@staticmethod
def __execScript(user):
# @TODO: omfg just write some wrapper-class/lib... sucks hard!
username=user["username"]
homeDir="/home/"+username+"/"
sshDir=homeDir+".ssh/"
executed=[]
username = user["username"]
home_dir = "/home/" + username + "/"
ssh_dir = home_dir + ".ssh/"
executed = []
executed.append(["useradd", "-m", username])
rcode = subprocess.call(executed[0])
if rcode != 0:
return [rcode,executed,]
returncode = subprocess.call(executed[0])
if returncode != 0:
return [returncode, executed, ]
executed.append(["usermod", "--lock", username])
rcode = subprocess.call(executed[1]) #empty pw
if rcode != 0:
return [rcode,executed,]
returncode = subprocess.call(executed[1]) # empty pw
if returncode != 0:
return [returncode, executed, ]
executed.append(["usermod", "-a", "-G", "tilde", username])
rcode = subprocess.call(executed[2]) # add to usergroup
if rcode != 0:
return [rcode,executed,]
returncode = subprocess.call(executed[2]) # add to usergroup
if returncode != 0:
return [returncode, executed, ]
executed.append(["mkdir", sshDir])
executed.append(["mkdir", ssh_dir])
try:
# @TODO: use config variable(chmodPerms)
ret = os.mkdir(sshDir, 0o777) #create sshdir
rcode = 0
os.mkdir(ssh_dir, 0o777) # create sshdir
returncode = 0
except OSError as e:
logging.exception(e.strerror)
rcode = e.errno # False, couldn't create.
return [rcode,executed,]
returncode = e.errno # False, couldn't create.
return [returncode, executed, ]
executed.append(["write(sshkey) to", sshDir+"authorized_keys"])
with open(sshDir+"authorized_keys", "w") as f:
executed.append(["write(sshkey) to", ssh_dir + "authorized_keys"])
with open(ssh_dir + "authorized_keys", "w") as f:
f.write(user["pubkey"])
if f.closed != True:
if not f.closed:
logging.exception("Could'nt write to authorized_keys!")
return [rcode,executed,]
return [returncode, executed, ]
executed.append(["chmod", "-Rv", "700", sshDir])
executed.append(["chmod", "-Rv", "700", ssh_dir])
try:
os.chmod(sshDir+"authorized_keys", 0o700) # directory is already 700
rcode = 0
os.chmod(ssh_dir + "authorized_keys", 0o700) # directory is already 700
returncode = 0
except OSError as e:
logging.exception(e.strerror)
rcode = e.errno
return [rcode, executed,]
returncode = e.errno
return [returncode, executed, ]
try:
executed.append(["chown", "-Rv", username+":"+username, sshDir])
os.chown(sshDir, pwd.getpwnam(username)[2], pwd.getpwnam(username)[3]) #2=>uid, 3=>gid
executed.append(["chown", "-v", username+":"+username, sshDir+"authorized_keys"])
os.chown(sshDir+"authorized_keys", pwd.getpwnam(username)[2], pwd.getpwnam(username)[3])
rcode = 0
executed.append(["chown", "-Rv", username + ":" + username, ssh_dir])
os.chown(ssh_dir, pwd.getpwnam(username)[2], pwd.getpwnam(username)[3]) # 2=>uid, 3=>gid
executed.append(["chown", "-v", username + ":" + username, ssh_dir + "authorized_keys"])
os.chown(ssh_dir + "authorized_keys", pwd.getpwnam(username)[2], pwd.getpwnam(username)[3])
returncode = 0
except OSError as e:
logging.exception(e.strerror) # @TODO: maybe append strerror to executed instead of printing it
rcode = e.errno
return [rcode, executed,]
return [rcode,executed,]
"""
{'id': 7, 'username': 'testuser47', 'email': '47test@testmail.com', 'name':
'test Name', 'pubkey': 'ssh-rsa [...]', 'timestamp': '2018-08-22 13:31:16', 'status': 0}
returncode = e.errno
return [returncode, executed, ]
"""
return [returncode, executed, ]
# {'id': 7, 'username': 'testuser47', 'email': '47test@testmail.com', 'name':
# 'test Name', 'pubkey': 'ssh-rsa [...]', 'timestamp': '2018-08-22 13:31:16', 'status': 0}
def main():
# how many times the Seperator/Delimiter?
# how many times the Separator/Delimiter?
delcount = 40
# The seperator for the menu
Seperator = "="*delcount
Menu = Seperator+"\n\t\t Main-Menu:\n\n" \
"\t 1) list and edit pending users\n"\
"\t 2) list applicants\n"\
"\t 3) edit applicant\n"\
"\t 4) quit\n"+Seperator+"\n"
# The separator for the menu
separator = "=" * delcount
menu = separator + "\n\t\t Main-Menu:\n\n" \
"\t 1) list and edit pending users\n" \
"\t 2) list applicants\n" \
"\t 3) edit applicant\n" \
"\t 4) quit\n" + separator + "\n"
# Identify by ID
applications = applicants(lident = "id")
applications = Applicants(lident="id")
while 1 != 0:
print(Menu)
print(menu)
command = input("Please select, what you want to do: \n -> ")
# User shouldnt be able to type something in that isnt a number
# User shouldn't be able to type something in that isnt a number
if command.isalpha() or command == '':
clear()
print("!!! invalid input, please try again. !!!")
continue
# convert
command=int(command)
command = int(command)
if command == 4 or command == "q":
exit(0)
# Edit and list pending users/applicants @TODO Wording: Users or applicants?
elif command == 1:
users = applications.getApplicationsList()
i=applications.printApprovableUsers(users)
users = applications.getapplicationslist()
i = applications.printapprovableusers(users)
if i == 0 :
if i == 0:
print("No pending users")
# giving some time to aknowledge that something WRONG happened
# giving some time to acknowledge that something WRONG happened
input("Continue with Keypress...")
clear()
continue
usersel = 0
UserMax = i
user_selection = 0
user_max = i
print("Menu:\n r=>return to main")
# Edit Menue
while 1 != 0 or usersel != "r":
i = applications.printApprovableUsers(users)
if usersel == "r":
# Edit Menu
while 1 != 0 or user_selection != "r":
i = applications.printapprovableusers(users)
if user_selection == "r":
break # break when user presses r
usersel = input("Which user( ID ) do you want to change? ->")
if len(usersel) > 1 or usersel.isalpha():
usersel = ""
user_selection = input("Which user( ID ) do you want to change? ->")
if len(user_selection) > 1 or user_selection.isalpha():
user_selection = ""
# convert to int if input isnt an r
usersel = int(usersel) if usersel != '' and usersel != 'r' else 0
if usersel > UserMax - 1:
print("User {0!s} doesn't exist!".format(usersel))
user_selection = int(user_selection) if user_selection != '' and user_selection != 'r' else 0
if user_selection > user_max - 1:
print("User {0!s} doesn't exist!".format(user_selection))
continue
# Show the user his chosen user and ask what to do
applications.userPrint(users, usersel)
print("You chosed ID No. {0!s}, what do you like to do?".format(usersel))
chosenUser = usersel
usersel = ""
# Finally down the edit menue!
while usersel != "e":
usersel = input("User: {0!s}\n \t\t(A)ctivate \n\t\t(R)emove \n\t\tR(e)turn\n -> ".format(chosenUser))
if usersel == "A":
applications.approveApplicant(users[chosenUser]['id'])
print("User {0!s} has been successfully approved!".format(users[chosenUser]['username']))
applications.userprint(users, user_selection)
print("You chosed ID No. {0!s}, what do you like to do?".format(user_selection))
chosen_user = user_selection
user_selection = ""
# Finally down the edit menu!
while user_selection != "e":
user_selection = input(
"User: {0!s}\n \t\t(A)ctivate \n\t\t(R)emove \n\t\tR(e)turn\n -> ".format(chosen_user))
if user_selection == "A":
applications.approveapplicant(users[chosen_user]['id'])
print("User {0!s} has been successfully approved!".format(users[chosen_user]['username']))
input("waiting for input...")
clear()
usersel="e" # remove for being able to continue editing?
user_selection = "e" # remove for being able to continue editing?
continue
elif usersel == "R":
applications.removeApplicant(users[chosenUser]['id'])
print("User {0!s} successfully deleted!".format(user[chosenUser]['username']))
elif user_selection == "R":
applications.removeapplicant(users[chosen_user]['id'])
print("User {0!s} successfully deleted!".format(user[chosen_user]['username']))
input("waiting for input...")
clear()
continue
elif usersel == "e":
elif user_selection == "e":
clear()
continue
elif int(command) == 2:
users = applications.getApprovedApplicantsList()
users = applications.getapprovedapplicantslist()
if users == []:
if not users:
print("no activate users yet!")
i=0
i = 0
for user in users:
print("ID: {0!s}, Status: {1!s}, Name: {2!s}".format(user["id"], user["status"], user["username"]))
continue
@ -381,11 +387,12 @@ def main():
else:
exit(0)
if __name__ == "__main__":
try:
main()
exit(0)
except KeyboardInterrupt:
pass
#print("Exception occured. View log file for details.")
#logging.exception("Some exception occured")
# print("Exception occured. View log file for details.")
# logging.exception("Some exception occured")

@ -14,62 +14,69 @@ try:
else:
if ospath.isfile(cwd) is False:
cwd=getcwd()+"/applicationsconfig.ini"
# cwd is now either cwd/applicationsconfig or $TILDE_CONF
# cwd is now either cwd/applicationsconfig or $TILDE_CONF
argparser = argparse.ArgumentParser(description='interactive registration formular for tilde platforms')
argparser.add_argument('-c', '--config', default=cwd, type=str, help='Config file', required=False)
args = argparser.parse_args()
CONF_FILE=args.config
CONF_FILE = args.config
except:
# intended broad, @TODO check them all for errors instead of everything in one
logging.exception("Argumentparser-Exception: ")
exit(0)
try:
config = configparser.ConfigParser()
config.read(CONF_FILE)
logging.basicConfig(format="%(asctime)s: %(message)s", filename=config['DEFAULT']['log_file'],level=int(config['LOG_LEVEL']['log_level']))
del(cwd)
REG_FILE=config['DEFAULT']['applications_db']
logging.basicConfig(format="%(asctime)s: %(message)s", filename=config['DEFAULT']['log_file'],
level=int(config['LOG_LEVEL']['log_level']))
REG_FILE = config['DEFAULT']['applications_db']
except:
# intended broad, @TODO check them all for errors instead of everything in one
logging.exception("logging or configparser-Exception: ")
exit(0)
VALID_SSH=False
VALID_USER=False
VALID_SSH = False
VALID_USER = False
def __createTable(cursor, connection):
try:
cursor.execute(
"CREATE TABLE IF NOT EXISTS applications(" \
"id INTEGER PRIMARY KEY AUTOINCREMENT,"\
"username TEXT NOT NULL, email TEXT NOT NULL,"\
"name TEXT NOT NULL, pubkey TEXT NOT NULL,"\
"CREATE TABLE IF NOT EXISTS applications("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"username TEXT NOT NULL, email TEXT NOT NULL,"
"name TEXT NOT NULL, pubkey TEXT NOT NULL,"
"timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, status INTEGER NOT NULL DEFAULT 0);")
connection.commit()
except:
logging.exception("Couldn't create needed SQLite Table!")
except sqlite3.Error as e:
logging.exception("Couldn't create needed SQLite Table! Exception: %s" % e)
def addtotable(cursor, connection, username, name, email, pubkey):
try:
cursor.execute("INSERT INTO 'applications'(username, name, email, pubkey)VALUES("\
cursor.execute("INSERT INTO 'applications'(username, name, email, pubkey)VALUES("
"?,?,?,?)", [username, name, email, pubkey])
connection.commit()
except:
logging.exception("Couldn't insert user into the db")
except sqlite3.Error as e:
logging.exception("Couldn't insert user into the db: %s" % e)
# check if sqlite file does exists or already and has our structure
def __checkSQLite(cursor, connection):
#SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}';
# SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}';
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='applications'")
res=cursor.fetchall()
res = cursor.fetchall()
if res== []:
if not res:
try:
__createTable(cursor, connection)
except:
logging.exception("couldn't create table on given database. Exception: ")
except sqlite3.Error as e:
logging.exception("couldn't create table on given database. Exception: %s" % e)
else:
pass
return True
def check_username(value):
global VALID_USER
if len(value) < 3:
@ -78,9 +85,10 @@ def check_username(value):
try:
from pwd import getpwnam
getpwnam(value)
VALID_USER=False
except:
VALID_USER=True
VALID_USER = False
# intended broad
except Exception:
VALID_USER = True
return True
return False
@ -111,38 +119,34 @@ def validate_pubkey(value):
return True
def main():
print(" ▗▀▖ \n▗▖▖ ▐ ▌ ▌▛▀▖\n▘▝▗▖▜▀ ▌ ▌▌ ▌\n ▝▘▐ ▝▀▘▘ ▘")
username = input("Welcome to the ~.fun user application form!\n\nWhat is your desired username? [a-z0-9] allowed:\n")
while (not re.match("[a-z]+[a-z0-9]", username)) or (not check_username(username)):
username = input("Invalid Username, maybe it exists already?\nValid characters are only a-z and 0-9.\nMake sure your username starts with a character and not a number." \
username = input("Invalid Username, maybe it exists already?\nValid characters are only a-z and 0-9."
"\nMake sure your username starts with a character and not a number."
"\nWhat is your desired username? [a-z0-9] allowed:\n")
fullname = input("\nPlease enter your full name:\n")
while not re.match("\w+\s*\w*", username):
fullname = input("\nThat is not your real name.\nPlease enter your full name:\n")
email = input("\nPlease enter your email address:\n")
while not re.match("(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", email):
email = input("\nThat is not a valid mail address.\nPlease enter your email address:\n")
pubkey = input("\nPlease paste your ssh public key:\n")
while (not re.match("ssh-(\w)+\s(\w+)(\s*)([a-zA-Z0-9@]*)", pubkey)) or (not validate_pubkey(pubkey)):
pubkey = input("\nPlease enter a valid public key. You can show it with ssh-keygen -f .ssh/id_rsa -y on your local machine.\nPlease enter your pubkey:\n")
pubkey = input("\nPlease enter a valid public key. You can show it with ssh-keygen -f .ssh/id_rsa -y on your "
"local machine.\nPlease enter your pubkey:\n")
validate_pubkey(pubkey)
print("\nUsername: {0!s}".format(username))
print("Full Name: {0!s}".format(fullname))
print("Email: {0!s}".format(email))
print("Public {0!s}".format(pubkey))
validation = input("\nIs this information correct? [y/N]")
while not re.match("[yYnN\n]", validation):
print("Please answer y for yes or n for no")
@ -156,13 +160,16 @@ def main():
addtotable(cursor, connection, username, fullname, email, pubkey)
connection.commit()
connection.close()
except:
logging.exception("Database {0!s} couldnt be accessed or created. Exception:".format(config['DEFAULT']['applications_db']))
except sqlite3.Error as e:
logging.exception("Database {0!s} couldnt be accessed or created. Exception: {0!s}".
format(config['DEFAULT']['applications_db'], e))
if connection:
connection.close()
exit(1)
pass
return 0
if __name__ == "__main__":
try:
main()

Loading…
Cancel
Save