-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbackup_server.py
executable file
·268 lines (229 loc) · 10.1 KB
/
backup_server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#! /usr/bin/env python
# Super simple server to save and retrieve data from a user
from flask import Flask, render_template, request, send_from_directory, redirect, jsonify
from werkzeug import serving
import bcrypt
import re # regex
import json # JSON tools
from pathlib import Path # Path tools
from flask_cors import CORS
app = Flask(__name__, template_folder='templates', static_folder='docs')
CORS(app)
# giza a look - debug
from pprint import pprint
# debug - delete
# https://flask.palletsprojects.com/en/0.12.x/patterns/favicon/
@app.route('/favicon.ico')
def favicon():
print(f"favicon path: {Path(app.root_path).joinpath('static/favicon.ico')}")
return send_from_directory(Path(app.root_path).joinpath('static'), 'favicon.ico', mimetype='image/vnd.microsoft.icon')
@app.route('/')
def home():
return """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>payCheck</title>
<style>
body {
background-color: #008100;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
font-family: Arial, sans-serif;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
max-width: 100vw;
}
.qr-container {
width: 60%;
display: flex;
justify-content: center;
align-items: center;
}
.qr-container img {
width: 100%;
height: auto;
}
.app-name {
color: white;
font-size: 2.2rem;
text-align: center;
margin-top: 20px;
width: 80%;
}
a {
text-decoration: none;
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
</style>
</head>
<body>
<div class="container">
<a href="https://unacceptablebehaviour.github.io/paycheck/">
<div class="qr-container">
<img src="docs/static/assets/images/QR-code-w-icon-noShort.png" alt="payCheck QR Code">
</div>
<h1 class="app-name">payCheck</h1>
</a>
</div>
</body>
</html>
"""
# import uuid
# NAMESPACE = str(uuid.uuid4())
# print("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ")
# print(NAMESPACE)
# print("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ")
NAMESPACE = '388e5ead-9872-4181-aef2-225b7cae61dd'
# UUID:{
# 'user_name': 'John Doe',
# 'user_email': '[email protected]', # for PWD reset
# 'user_password': 'SHA3-512',
# }
userDB_PATH = Path('./scratch/_save/user_DB.json')
userDB = json.load(userDB_PATH.open('r'))
@app.route('/login', methods=['POST', 'GET'])
def login():
global userDB
if request.method == 'POST':
print("Login / NEW USER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - S")
data = request.get_json()
command = data.get('command')
user_uuid = data.get('userUUID')
user_name = data.get('username')
password = data.get('password')
user_email = data.get('email')
time_stamp = data.get('unixTimestamp')
contract_hours = data.get('contractHours')
tax_year = data.get('taxYear')
hrs_anual_leave_allocation = data.get('hrs_anual_leave_allocation')
print(f"U: {user_name}\nUUID: {user_uuid}\nCMD: {command}")
print(' - ^ - ')
pprint(data)
print(' - o - ')
if user_uuid in userDB:
pprint(userDB[user_uuid])
else:
print(f"NOT FOUND {user_uuid}")
print(' - _ - ')
# verify user inputs are valid - see /save route
print("Login / NEW USER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - E")
if not user_uuid or user_uuid == "null" or user_uuid == "undefined":
return jsonify({'message': 'Invalid UUID provided'}), 400
if command == 'NEW_USER':
print(f"[POST] CREATING ACCOUNT")
# Hash the password with bcrypt (automatically includes salt)
password_bytes = password.encode('utf-8')
hashed_password = bcrypt.hashpw(password_bytes, bcrypt.gensalt(rounds=12))
# Store the hashed password (it's a bytes object, so convert to string)
userDB[user_uuid] = {
'user_name': user_name,
'user_email': user_email,
'user_password': hashed_password.decode('utf-8'), # Store as string
'time_stamp': time_stamp,
'contract_hours': contract_hours,
'tax_year': tax_year,
'hrs_anual_leave_allocation': hrs_anual_leave_allocation
}
# Save the updated userDB to file
try:
with open(userDB_PATH, 'w') as json_file:
json.dump(userDB, json_file, indent=2)
print(' - new user - ')
pprint(userDB[user_uuid])
print(' - x - ')
return jsonify({'message': 'Account successfully created'}), 200
except Exception as e:
print(f'Error writing user database: {e}')
return jsonify({'message': 'Internal Server Error - PROBLEM SAVING USER'}), 500
elif command == 'LOGIN': # move this code to save route - no real concept of logging in
if user_uuid in userDB:
stored_user = userDB[user_uuid]
stored_hash = stored_user['user_password'].encode('utf-8')
# Check if the provided password matches the stored hash
if bcrypt.checkpw(password.encode('utf-8'), stored_hash):
return jsonify({'message': 'Login successful', 'status': 'success'}), 200
else:
return jsonify({'message': 'Invalid credentials'}), 401
else:
return jsonify({'message': 'User not found'}), 404
else: # unknown command
return jsonify({'message': 'Internal Server Error - UKNOWN COMMAND'}), 500
@app.route('/save', methods=['POST', 'GET'])
def save():
data_dir = Path('./scratch/_save')
if request.method == 'POST':
print("PC data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - S")
data = request.get_json()
command = data.get('command')
user_uuid = data.get('userUUID')
local_storage_key = data.get('localStorageKey')
# uuid regex r'[\d\w]{8}-[\d\w]{4}-[\d\w]{4}-[\d\w]{4}-[\d\w]{12}'
# storKey regex r'[\d\w]{4}_[\d\w]{4}_WKS_\d\d-\d\d'
if not re.match(r'[\d\w]{8}-[\d\w]{4}-[\d\w]{4}-[\d\w]{4}-[\d\w]{12}', user_uuid):
print(f"ERROR - INVALID USER UUID {user_uuid}")
return jsonify({'message': 'Internal Server Error - INVALID USER UUID'}), 500
if not re.match(r'[\d\w]{4}_[\d\w]{4}_WKS_\d\d-\d\d', local_storage_key):
print(f"ERROR - INVALID STORAGE KEY {local_storage_key}")
return jsonify({'message': 'Internal Server Error - INVALID LOCAL STORAGE KEY'}), 500
file_path = data_dir.joinpath(f"{user_uuid}_{local_storage_key}.json")
pprint(data)
print(f"FILE: {file_path}")
print("PC data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - E")
if command == 'SAVE':
print(f"[POST] SAVE request SAVING to: {file_path}")
try:
with open(file_path, 'w') as json_file:
json.dump(data, json_file, indent=2)
return jsonify({'message': 'Successfully saved to server'}), 200
except Exception as e:
print(f'Error writing file: {e}')
return jsonify({'message': 'Internal Server Error - PROBLEM SAVING FILE'}), 500
elif command == 'RETRIEVE':
#file_path = data_dir.joinpath(f"{data['userUUID']}_{data['localStorageKey']}_data.json")
print(f"[POST] RETRIEVING request from: {file_path}")
try:
with open(file_path, 'r') as json_file:
data = json.load(json_file)
return jsonify(data), 200
except Exception as e:
print(f'Error reading file: {e}')
return jsonify({'message': 'Internal Server Error - PROBLEM LOADING FILE'}), 500
else: # unknown command
return jsonify({'message': 'Internal Server Error - UKNOWN COMMAND'}), 500
# elif request.method == 'GET':
# file_path = data_dir.joinpath('default_GET_file.json')
# print(f"[GET] SHOULD NEVER HAPPEN from: {file_path}")
# print(f"PWD: {Path.cwd()}")
# try:
# with open(file_path, 'r') as json_file:
# data = json.load(json_file)
# return jsonify(data), 200
# except Exception as e:
# print(f'Error reading file: {e}')
# return jsonify({'message': 'Internal Server Error - PROBLEM LOADING FILE'}), 500
if __name__ == '__main__':
# https://pythonprogramminglanguage.com/flask-hello-world/
# reserved port numbers
# https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
app.run(host='0.0.0.0', port=50030)
# setting up SSL for image capture:
# https://blog.miguelgrinberg.com/post/running-your-flask-application-over-https
# pip install pyOpenSSL
#app.run(host='192.168.1.13', port=50030, ssl_context='adhoc')
# Note for deployment:
# http://flask.pocoo.org/docs/1.0/deploying/#deployment