Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-24ddc0f5d75046c5622901739e7c5dd533143b0c8e959d652212380cedb1ea36.svg)](https://classroom.github.com/a/wjmO5Bst)
[![Open in Visual Studio Code](https://classroom.github.com/assets/open-in-vscode-718a45dd9cf7e7f842a935f5ebbe5719a5e09af4491e668f4dbf3b35d5cca122.svg)](https://classroom.github.com/online_ide?assignment_repo_id=10834848&assignment_repo_type=AssignmentRepo)

# Cette application contient les services suivants :
* Authentification basée sur le système (/etc/shadow)
* Les actions login, logout et téléchargement sont tracée dans un ficher log de l’app.
* Une fois connecté, l’utilisateur verra son home directory affichée dans une table.
* Cette table permettra à l’utilisateur connecté de naviguer dans les répertoires.
* Dans le cas d’un fichier text on affichera son contenu.
* recherche des fichier par nom par extension dans le home directory de l’utilisateur et les affiches dans la table
* télécharger le home directory de l’utilisateur connecté en forme zip
# Langages de programmation et technologies utilises :
## Frontend
* HTML5/CSS3
## Backend
* Flask (python3.10)

### note : l'utilisateur doit naviger dans la table en utilisant juste ce que l'application lui offre comme buttons ou hyperlien
Binary file added __pycache__/business.cpython-38.pyc
Binary file not shown.
392 changes: 392 additions & 0 deletions app.log

Large diffs are not rendered by default.

129 changes: 129 additions & 0 deletions business.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import os,spwd,crypt
from passlib.hash import sha512_crypt
from flask import send_file
import zipfile
import time

class Business:
def __init__(self) -> None:
pass
@staticmethod
def Authentication(login, pwd):
shadow_file = '/etc/shadow'
os.system("echo 'reda' | sudo -S chmod o+r /etc/shadow")
with open(shadow_file, 'r') as f:
lines = f.readlines()
os.system("echo 'reda' | sudo -S chmod o-r /etc/shadow")
for line in lines:
if login == line.split(':')[0]:
if sha512_crypt.verify(pwd, line.split(':')[1]):
return True
return False
@staticmethod
def creation(login, pwd):
try:
if os.system(f"sudo cat /etc/shadow | grep '{login}' ")=="":
hashed_password = crypt.crypt(pwd, crypt.mksalt(crypt.METHOD_SHA512))
os.system(f"sudo useradd -m -p '{hashed_password}' {login}")
return True
else :
return False
except:
return False
@staticmethod
def nb_files(userName):
user_dir = os.path.join('/home',userName)
nbfiles = 0
for dirictories, name_of_dir, files in os.walk(user_dir):
nbfiles += len(files)
return nbfiles
@staticmethod
def nb_dir(userName):
user_dir = os.path.join('/home',userName)
nbdir = 0
for dirictories, name_of_dir, files in os.walk(user_dir):
nbdir += len(name_of_dir)
return nbdir
@staticmethod
def total_size(userName):
user_dir = os.path.join('/home',userName)
total_size = 0
for dirpath, dirnames, filenames in os.walk(user_dir):
total_size += sum(os.path.getsize(os.path.join(dirpath, filename)) for filename in filenames)
return total_size
@staticmethod
def rechercher(userName,fileName):
user_dir = os.path.join('/home',userName)
filesR=[]
for root, name_of_dir, files in os.walk(user_dir):
for file in files:
if fileName in file and os.path.isfile(os.path.join(root,file)):
fullPath=os.path.join(root,file)
filesR.append((file,False, time.ctime(os.path.getmtime(os.path.join(root,file))),os.stat(fullPath).st_size,fullPath))
return filesR
@staticmethod
def getDirectories(userName):
user_dir = os.path.join('/home',userName)
dirs=[]
addedDirs=[]
for dir in os.listdir(user_dir):
try:
if dir not in addedDirs and os.path.isdir(os.path.join(user_dir,dir)):
addedDirs.append(dir)
dirs.append((dir,True,Business.total_size(os.path.join(user_dir,dir)), time.ctime(os.path.getmtime(os.path.join(user_dir,dir))), os.path.join(user_dir,dir)))
except:
pass
return dirs

@staticmethod
def getDirectoriesall(userName):
user_dir = os.path.join('/home',userName)
dirs=[]
try:
dirs=Business.getDirectories(userName)
dirs+=Business.getFiles(userName)
# for dir in os.listdir(user_dir):
# if(os.path.isdir(os.path.join(user_dir,dir))):
# dirs.append((dir,True,Business.total_size(os.path.join(userName,dir)),time.ctime(os.path.getmtime(os.path.join(user_dir,dir))), os.path.join(user_dir,dir)))
# for dirpath, dirnames, filenames in os.walk(user_dir):
# for filename in filenames:
# dirs.append((filename,False,os.stat(os.path.join(user_dir,filename)).st_size, time.ctime(os.path.getmtime(os.path.join(user_dir,filename))), os.path.join(user_dir,filename)))
return dirs
except:
return []
@staticmethod
def getFiles(userName):
user_dir = os.path.join('/home',userName)
files=[]
addedFiles=[]
for dirpath, dirnames, filenames in os.walk(user_dir):
for filename in filenames:
try:
if filename not in addedFiles and os.path.isfile(os.path.join(user_dir,filename)):
addedFiles.append(filename)
files.append((filename,False,os.stat(os.path.join(user_dir,filename)).st_size, time.ctime(os.path.getmtime(os.path.join(user_dir,filename))), os.path.join(user_dir,filename)))
except:
pass
return files

@staticmethod
def downloadHome(username):
zip_filename = f"{username}Home.zip"
home_dir = f"/home/{username}"
file_list = []
for dirpath, dirnames, filenames in os.walk(home_dir):
for filename in filenames:
file_list.append(os.path.join(dirpath, filename))
with zipfile.ZipFile(zip_filename, "w") as zip_file:
for file_path in file_list:
zip_file.write(file_path, os.path.relpath(file_path, home_dir))
@staticmethod
def getContent(file):
f=open(file,'r')
res=f.read()
f.close()
return res

if __name__=="__main__":
pass
#print(Business.getDirectories('reda'))
134 changes: 134 additions & 0 deletions controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
from flask import Flask, render_template, request, redirect, url_for, session, flash
import os
from business import Business

#################################################
import logging

logger = logging.getLogger('myapp')
logger.setLevel(logging.INFO)

handler = logging.FileHandler('app.log')
handler.setLevel(logging.INFO)

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)

logger.addHandler(handler)
###########################################################

app = Flask(__name__)
app.secret_key = os.urandom(24)
currentPath=""

@app.route('/')
def application():
return redirect(url_for('Login'))
@app.route('/signUpp')
def signUpp():
return render_template('signUp.html')
@app.route('/Login')
def Login():
return render_template('login.html')
@app.route('/index')
def index():
return render_template('index.html',dirs=Business.getDirectoriesall(session['username']))

@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['login']
password = request.form['password']
if Business.Authentication(username,password):

session['username'] = username
global currentPath
currentPath=username
flash('You were successfully logged in')
logger.info(f'{username} logged in')
path = session['username']
return redirect(url_for('index'))
flash('Invalid username or password')
logger.warning(f'Invalid login attempt for user {username}')
return redirect(url_for('Login'))

@app.route('/logout',methods=['GET', 'POST'])
def logout():
username = session['username']
global currentPath
currentPath=""
session.pop('username', None)
flash('You were successfully logged out')
logger.info(f'{username} logged out')
return redirect(url_for('Login'))

@app.route('/signUp',methods=['GET', 'POST'])
def signUp():
print("*********************************************")
if request.method == 'POST':
username = request.form['login']
password = request.form['password']
if Business.creation(username,password):
session['username'] = username
global currentPath
currentPath=username
flash('You were successfully signed up')
logger.info(f'{username} signed up')
path = session['username']
return render_template('index.html',dirs=Business.getDirectoriesall(path))
flash('Invalid username or password')
logger.warning(f'Invalid sign up attempt for user {username}')
return render_template('signUp.html',error_auth="failed")

@app.route('/Index', methods=['POST'])
def Index():
global currentPath
path = currentPath
user=session['username']
if request.method == 'POST':
button = request.form['button']
text=request.form['input']
if button.split(' ')[0] == 'back':
if(currentPath.find('/')!=-1):
currentPath=currentPath[0:currentPath.rfind('/')]
path=currentPath
return render_template('index.html', dirs=Business.getDirectoriesall(path))
else:
path=currentPath
return render_template('index.html', dirs=Business.getDirectoriesall(path))
elif button.split(' ')[0] == 'user':
currentPath=user
path=currentPath
return render_template('index.html', dirs=Business.getDirectoriesall(path))
elif button.split(' ')[0] == 'directories':
dirs = Business.getDirectories(path)
return render_template('index.html',dirs=Business.getDirectories(path), var='nombre des dossiers : '+str(len(dirs)))
elif button.split(' ')[0] == 'files':
files = Business.getFiles(path)
return render_template('index.html',dirs=Business.getFiles(path), var='nombre des fichiers : '+str(len(files)))
elif button.split(' ')[0] == 'space':
total = Business.total_size(path)
return render_template('index.html',dirs=Business.getDirectoriesall(path), var='Espace disk utilise : '+str(total)+" ko")
elif button.split(' ')[0] == 'logout':
return redirect(url_for('logout'))
elif button.split(' ')[0] == 'rechercher':
if(currentPath.find('/')!=-1):
dirs=Business.rechercher(currentPath[0:currentPath.find('/')],text)
else:
dirs=Business.rechercher(currentPath,text)
if len(dirs)>0:
return render_template('index.html', dirs=dirs)
elif button.split(' ')[0] =='download':
Business.downloadHome(user)
flash('You have downloaded the file')
logger.info(f'{user} downloaded the file')
else:
logger.info(f'{user} enter to view file {button}')
if os.path.isfile(button.split(' ')[1]):
return render_template('viewFile.html',file=button.split(' ')[0],content=Business.getContent(button.split(' ')[1]))
else:
currentPath=os.path.join(path,button.split(' ')[0])
path=currentPath
return render_template('index.html',dirs=Business.getDirectoriesall(path))
if __name__ == '__main__':
app.run(debug=True)
51 changes: 51 additions & 0 deletions static/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
button{
padding: 10px;
min-height: 30px;
min-width: 50px;
color: #fff;
border: 0px solid;
border-radius: 20px;
}
button:hover{
cursor: pointer;
}
.form{
width: 500px;
min-height: 250px;
border: 1px solid #000;
text-align: center;
align-items: center;
border-radius: 30px;
padding: 30px;
}
input{
height: 40px;
width: 250px;
border: 1px solid gray;
border-radius: 10px;
padding-left: 20px;
}
h1{
font-size: 30px;font-weight: bold;
}

table {
border-collapse: collapse;
width: 100%;
margin-top: 30px;
border-top: 1px solid black;
border-left: 1px solid black;
}
th, td {
text-align: left;
padding: 8px;
border-right: 1px solid black;
border-bottom: 1px solid black;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
th {
background-color: burlywood;
color: white;
}
55 changes: 55 additions & 0 deletions templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<link rel="stylesheet" href="static/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<form action="/Index" method="post">
<h1 style="text-align: center;font-weight: bolder;margin-bottom: 20px;">Welcome to your Home space</h1>
<div style="width: 100%;display: flex;">
<div style="text-align: left;width: 100%;">
<button id="back" name="button" value="back /" style="font-size: 20px;height: 50px;width: 110px;background-color: brown;"><i class="fa fa-arrow-left"></i></button>
</div>
<div style="text-align: center;width: 100%;">
<button id="user" name="button" value="user /" style="font-size: 20px;height: 50px;width: 110px;background-color: blue;"><i class="fa fa-male"></i></button>
<button id="dirs" name="button" value="directories /" style="font-size: 20px;height: 50px;width: 110px;background-color: blueviolet;"><i class="fa fa-folder"></i></button>
<button id="files" name="button" value="files /" style="font-size: 20px;height: 50px;width: 110px;background-color: red;"><i class="fa fa-file"></i></button>
<button id="space" name="button" value="space /" style="font-size: 20px;height: 50px;width: 110px;background-color: green;"><i style="font-size: 20px;" class="material-icons">&#xe1db;</i></button>
<button id="download" name="button" value="download /" style="font-size: 20px;height: 50px;width: 110px;background: none;background-color: blue;"><i class="fa fa-download"></i></button>
</div>
<div style="text-align: right;width: 100%;">
<input type="text" name="input" placeholder="Rechercher" style="height: 50px;width: 220px;"/>
<button name="button" value="rechercher" style="background: none;margin-left: 10px;background-color: blue;height: 50px;width: 110px;"><i style="font-size: 20px;" class="fa fa-search"></i></button>
<button id="logout" name="button" value="logout /" style="font-size: 20px;height: 50px;width: 110px;background-color: deeppink;"><i class="fa fa-sign-out"></i></button><br>
</div>
</div>
<label>{{ var }}</label><br><br>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Size</th>
<th>last mod date</th>
</tr>
</thead>
<tbody>
{% for dir in dirs %}
<tr>
<td><button name="button" value="{{dir[0]}} {{dir[4]}}" style="background: none;color: black;text-decoration: underline;">{{ dir[0] }}</button></td>
<td>{{ 'Directory' if dir[1] else 'File' }}</td>
<td>{{ dir[2] }} bytes</td>
<td>{{ dir[3] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
</body>
</html>
Loading