-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUserManager.py
More file actions
224 lines (189 loc) · 8.39 KB
/
UserManager.py
File metadata and controls
224 lines (189 loc) · 8.39 KB
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
import json
import bcrypt
import time
from cryptography.fernet import Fernet
from datetime import datetime, timedelta
class UserCredentialsManager:
def __init__(self, credentials_file='credentials.json', key_file='encryption.key', timestamp_file='key_timestamp.json'):
self.credentials_file = credentials_file
self.key_file = key_file
self.timestamp_file = timestamp_file
# Load or generate encryption key
self.key = self.load_or_generate_key()
self.fernet = Fernet(self.key)
# Load or initialize credentials storage
self.credentials = self.load_credentials()
# Check if key rotation is needed
self.check_key_rotation()
def load_or_generate_key(self):
"""Load encryption key from file or generate a new one."""
try:
with open(self.key_file, 'rb') as f:
return f.read()
except FileNotFoundError:
key = Fernet.generate_key()
with open(self.key_file, 'wb') as f:
f.write(key)
return key
def load_key_timestamp(self):
"""Load timestamp of the last key rotation from file."""
try:
with open(self.timestamp_file, 'r') as f:
return json.load(f).get('last_rotation', None)
except (FileNotFoundError, json.JSONDecodeError):
return None
def save_key_timestamp(self):
"""Save the current timestamp as the last rotation time."""
timestamp = {'last_rotation': time.time()}
with open(self.timestamp_file, 'w') as f:
json.dump(timestamp, f)
def load_credentials(self):
"""Load credentials from a JSON file."""
try:
with open(self.credentials_file, 'r') as f:
encrypted_data = json.load(f)
# Decrypt each entry
return {self.decrypt(key): self.decrypt(value) for key, value in encrypted_data.items()}
except (FileNotFoundError, json.JSONDecodeError):
return {}
def save_credentials(self):
"""Save encrypted credentials to the file."""
encrypted_data = {self.encrypt(key): self.encrypt(value) for key, value in self.credentials.items()}
with open(self.credentials_file, 'w') as f:
json.dump(encrypted_data, f)
def encrypt(self, data):
"""Encrypt data using Fernet encryption."""
return self.fernet.encrypt(data.encode()).decode()
def decrypt(self, encrypted_data):
"""Decrypt data using Fernet decryption."""
return self.fernet.decrypt(encrypted_data.encode()).decode()
def hash_password(self, password):
"""Hash a password using bcrypt with a salt."""
# bcrypt automatically salts the password for you
hashed_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
return hashed_password.decode()
def verify_password(self, hashed_password, password):
"""Verify a hashed password using bcrypt."""
return bcrypt.checkpw(password.encode(), hashed_password.encode())
def add_user(self, username, password):
"""Add a new user to the credentials manager."""
if username in self.credentials:
print(f"User {username} already exists.")
return
hashed_password = self.hash_password(password)
self.credentials[username] = hashed_password
self.save_credentials()
print(f"User {username} added successfully.")
def update_password(self, username, new_password):
"""Update a user's password."""
if username not in self.credentials:
print(f"User {username} does not exist.")
return
hashed_password = self.hash_password(new_password)
self.credentials[username] = hashed_password
self.save_credentials()
print(f"Password for {username} updated successfully.")
def update_username(self, old_username, new_username):
"""Update a user's username."""
if old_username not in self.credentials:
print(f"User {old_username} does not exist.")
return
if new_username in self.credentials:
print(f"User {new_username} already exists.")
return
self.credentials[new_username] = self.credentials.pop(old_username)
self.save_credentials()
print(f"Username {old_username} changed to {new_username}.")
def delete_user(self, username):
"""Delete a user from the credentials manager."""
if username in self.credentials:
del self.credentials[username]
self.save_credentials()
print(f"User {username} deleted successfully.")
else:
print(f"User {username} not found.")
def authenticate_user(self, username, password):
"""Authenticate a user based on username and password."""
if username in self.credentials:
hashed_password = self.credentials[username]
if self.verify_password(hashed_password, password):
print(f"Authentication successful for {username}.")
return True
else:
print(f"Authentication failed for {username}. Incorrect password.")
else:
print(f"User {username} not found.")
return False
def check_key_rotation(self):
"""Check if key rotation is needed based on the last rotation timestamp."""
last_rotation = self.load_key_timestamp()
if not last_rotation:
# No previous rotation, set a timestamp for the first time
self.save_key_timestamp()
return
# Define key rotation interval (e.g., 30 days)
rotation_interval = timedelta(days=30)
last_rotation_time = datetime.fromtimestamp(last_rotation)
current_time = datetime.now()
if current_time - last_rotation_time >= rotation_interval:
print("Key rotation is needed. Rotating key...")
self.rotate_key()
def rotate_key(self):
"""Perform key rotation: decrypt all data with the old key and re-encrypt with the new key."""
old_key = self.key
self.key = Fernet.generate_key()
self.fernet = Fernet(self.key)
# Decrypt all credentials and re-encrypt them with the new key
old_credentials = self.credentials.copy()
self.credentials = {}
for username, hashed_password in old_credentials.items():
decrypted_username = self.decrypt(username)
decrypted_password = self.decrypt(hashed_password)
encrypted_username = self.encrypt(decrypted_username)
encrypted_password = self.encrypt(decrypted_password)
self.credentials[encrypted_username] = encrypted_password
# Save the new credentials and timestamp
self.save_credentials()
self.save_key_timestamp()
print("Key rotation completed successfully.")
def show_menu():
"""Display the main menu."""
print("\nUser Credentials Manager")
print("1. Add User")
print("2. Authenticate User")
print("3. Update Password")
print("4. Update Username")
print("5. Delete User")
print("6. Exit")
def main():
"""Run the menu-driven user credentials manager."""
manager = UserCredentialsManager()
while True:
show_menu()
choice = input("Enter your choice (1-6): ")
if choice == '1':
username = input("Enter username: ")
password = input("Enter password: ")
manager.add_user(username, password)
elif choice == '2':
username = input("Enter username: ")
password = input("Enter password: ")
manager.authenticate_user(username, password)
elif choice == '3':
username = input("Enter username: ")
new_password = input("Enter new password: ")
manager.update_password(username, new_password)
elif choice == '4':
old_username = input("Enter old username: ")
new_username = input("Enter new username: ")
manager.update_username(old_username, new_username)
elif choice == '5':
username = input("Enter username to delete: ")
manager.delete_user(username)
elif choice == '6':
print("Exiting... Goodbye!")
break
else:
print("Invalid choice. Please try again.")
if __name__ == "__main__":
main()