1+ import sqlite3
2+ import hashlib
3+ import secrets
4+ import base64
5+ import string
6+ from cryptography .fernet import Fernet
7+ from cryptography .hazmat .primitives import hashes
8+ from cryptography .hazmat .primitives .kdf .pbkdf2 import PBKDF2HMAC
9+ import getpass
10+ import sys
11+ import pyperclip
12+
13+ class PasswordManager :
14+ def __init__ (self , database_name = "passwords.db" ):
15+ self .database_name = database_name
16+ self .key = None
17+ self .cipher_suite = None
18+ self .setup_database ()
19+
20+ def setup_database (self ):
21+ # Uzsāk SQLite datubāzi ar vajadzīgajām tabulām
22+ conn = sqlite3 .connect (self .database_name )
23+ cursor = conn .cursor ()
24+
25+ # Veido master paroles tabulu (priekš hash un salta)
26+ cursor .execute ('''
27+ CREATE TABLE IF NOT EXISTS master_password (
28+ id INTEGER PRIMARY KEY,
29+ password_hash TEXT NOT NULL,
30+ salt TEXT NOT NULL
31+ )''' )
32+
33+ # Veido paroles tabulu (glabā šifrētus datus)
34+ cursor .execute ('''
35+ CREATE TABLE IF NOT EXISTS passwords (
36+ id INTEGER PRIMARY KEY,
37+ service TEXT NOT NULL,
38+ username TEXT NOT NULL,
39+ encrypted_password TEXT NOT NULL
40+ )''' )
41+
42+ conn .commit ()
43+ conn .close ()
44+
45+ def generate_password (self , length = 16 , copy_to_clipboard = True ):
46+ # Izveidot drošu paroli un pēc izvēles kopējiet to.
47+ if length < 8 :
48+ raise ValueError ("Paroles garumam ir jābūt vismaz 8 rakstzīmēm" )
49+
50+ # Iekļauj visas rakstzīmes
51+ lowercase = string .ascii_lowercase
52+ uppercase = string .ascii_uppercase
53+ digits = string .digits
54+ special = "!@#$%^&*()_+-=[]{}|;:,.<>?"
55+
56+ # Nodrošina vismaz vienu rakstzīmi no visiem
57+ password = [
58+ secrets .choice (lowercase ),
59+ secrets .choice (uppercase ),
60+ secrets .choice (digits ),
61+ secrets .choice (special )
62+ ]
63+
64+ # Iepilda pārējo ar random rakstzīmēm
65+ all_chars = lowercase + uppercase + digits + special
66+ remaining_length = length - len (password )
67+ password .extend (secrets .choice (all_chars ) for _ in range (remaining_length ))
68+
69+ # Sajauc paroli
70+ password_list = list (password )
71+ secrets .SystemRandom ().shuffle (password_list )
72+
73+ final_password = '' .join (password_list )
74+
75+ # Nokopē paroli ja tas ir nepieciešams
76+ if copy_to_clipboard :
77+ pyperclip .copy (final_password )
78+
79+ return final_password
80+
81+ def generate_key (self , password : str , salt : bytes = None ) -> bytes :
82+ # Izveido šifrēšanas atslēgu no paroles izmantojot PBKDF2
83+ if salt is None :
84+ salt = secrets .token_bytes (16 )
85+
86+ kdf = PBKDF2HMAC (
87+ algorithm = hashes .SHA256 (),
88+ length = 32 ,
89+ salt = salt ,
90+ iterations = 100000 ,
91+ )
92+ key = base64 .urlsafe_b64encode (kdf .derive (password .encode ()))
93+ return key , salt
94+
95+ def hash_password (self , password : str , salt : bytes = None ) -> tuple :
96+ # Hasho paroli ar saltu izmantojot SHA-256
97+ if salt is None :
98+ salt = secrets .token_bytes (16 )
99+
100+ hasher = hashlib .sha256 ()
101+ hasher .update (salt + password .encode ())
102+ password_hash = hasher .hexdigest ()
103+
104+ return password_hash , salt
105+
106+ def initialize_master_password (self , master_password : str ):
107+ # Iestata master paroli pirmo reizi
108+ conn = sqlite3 .connect (self .database_name )
109+ cursor = conn .cursor ()
110+
111+ # Pārbauda vai master parole jau eksistē
112+ cursor .execute ("SELECT COUNT(*) FROM master_password" )
113+ if cursor .fetchone ()[0 ] > 0 :
114+ raise Exception ("Master parole jau inicializēta" )
115+
116+ # Hasho master paroli ar jaunu saltu
117+ password_hash , salt = self .hash_password (master_password )
118+
119+ # Glabā hashu un saltu
120+ cursor .execute (
121+ "INSERT INTO master_password (password_hash, salt) VALUES (?, ?)" ,
122+ (password_hash , base64 .b64encode (salt ).decode ())
123+ )
124+
125+ conn .commit ()
126+ conn .close ()
127+
128+ # Uzāk šifrēšanas atslēgu
129+ self .key , _ = self .generate_key (master_password , salt )
130+ self .cipher_suite = Fernet (self .key )
131+
132+ def unlock (self , master_password : str ) -> bool :
133+ # Pārbaude master paroli un uzsāk šifrēšanas atslēgu
134+ conn = sqlite3 .connect (self .database_name )
135+ cursor = conn .cursor ()
136+
137+ cursor .execute ("SELECT password_hash, salt FROM master_password" )
138+ stored_hash , stored_salt = cursor .fetchone ()
139+ stored_salt = base64 .b64decode (stored_salt )
140+
141+ # Pārbauda paroli
142+ password_hash , _ = self .hash_password (master_password , stored_salt )
143+ if password_hash != stored_hash :
144+ conn .close ()
145+ return False
146+
147+ # Uzsāk šifrēsanas atslēgu
148+ self .key , _ = self .generate_key (master_password , stored_salt )
149+ self .cipher_suite = Fernet (self .key )
150+
151+ conn .close ()
152+ return True
153+
154+ def add_password (self , service : str , username : str , password : str ):
155+ # Pievieno jaunu paroli
156+ if not self .cipher_suite :
157+ raise Exception ("Paroļu pārvaldnieks ir slēgts" )
158+
159+ encrypted_password = self .cipher_suite .encrypt (password .encode ())
160+
161+ conn = sqlite3 .connect (self .database_name )
162+ cursor = conn .cursor ()
163+
164+ cursor .execute (
165+ "INSERT INTO passwords (service, username, encrypted_password) VALUES (?, ?, ?)" ,
166+ (service , username , encrypted_password .decode ())
167+ )
168+
169+ conn .commit ()
170+ conn .close ()
171+
172+ def get_password (self , service : str , username : str ) -> str :
173+ # Ņem paroli priekš specifiskā pakalpojuma un lietotājvārda
174+ if not self .cipher_suite :
175+ raise Exception ("Paroļu pārvaldnieks ir slēgts" )
176+
177+ conn = sqlite3 .connect (self .database_name )
178+ cursor = conn .cursor ()
179+
180+ cursor .execute (
181+ "SELECT encrypted_password FROM passwords WHERE service = ? AND username = ?" ,
182+ (service , username )
183+ )
184+
185+ result = cursor .fetchone ()
186+ if not result :
187+ conn .close ()
188+ raise Exception ("Parole nav atrasta" )
189+
190+ encrypted_password = result [0 ]
191+ decrypted_password = self .cipher_suite .decrypt (encrypted_password .encode ()).decode ()
192+
193+ conn .close ()
194+ return decrypted_password
195+
196+ def list_services (self ) -> list :
197+ # Norāda visus glabātos pakalpojumus un lietotājvārdus
198+ conn = sqlite3 .connect (self .database_name )
199+ cursor = conn .cursor ()
200+
201+ cursor .execute ("SELECT service, username FROM passwords" )
202+ services = cursor .fetchall ()
203+
204+ conn .close ()
205+ return services
206+
207+ def main ():
208+ # Mēģina importēt pyperclip, ja datorā tas nav instalēts tad to izprintē
209+ try :
210+ import pyperclip
211+ except ImportError :
212+ print ("Pyperclip bibliotēka ir nepieciešama priekš kopēšanas funkcionalitātes" )
213+ print ("Lūdzu instalējat to izmantojot: pip install pyperclip" )
214+ return
215+
216+ pm = PasswordManager ()
217+
218+ # Pārbauda vai master parolei vajag būt uzsāktai
219+ conn = sqlite3 .connect (pm .database_name )
220+ cursor = conn .cursor ()
221+ cursor .execute ("SELECT COUNT(*) FROM master_password" )
222+ is_initialized = cursor .fetchone ()[0 ] > 0
223+ conn .close ()
224+
225+ if not is_initialized :
226+ print ("Inicializējiet savu paroļu pārvaldnieku:" )
227+ master_password = getpass .getpass ("Izveidojiet master paroli: " )
228+ confirm_password = getpass .getpass ("Apstipriniet galveno paroli: " )
229+
230+ if master_password != confirm_password :
231+ print ("Paroles nesakrīt" )
232+ return
233+
234+ pm .initialize_master_password (master_password )
235+ print ("Master parole veiksmīgi inicializēta!" )
236+
237+ # Galvenais loops
238+ while True :
239+ if not pm .cipher_suite :
240+ master_password = getpass .getpass ("Ievadiet master paroli: " )
241+ if not pm .unlock (master_password ):
242+ print ("Nederīga master parole!" )
243+ continue
244+
245+ print ("\n 1. Pievienot paroli" )
246+ print ("2. Dabūt paroli" )
247+ print ("3. Izveidot drošu paroli" )
248+ print ("4. Norādīt glabātos datus" )
249+ print ("5. Iziet" )
250+
251+ choice = input ("\n Izvēlies opciju: " )
252+
253+ try :
254+ if choice == "1" :
255+ service = input ("\n Pakalpojums: " )
256+ username = input ("Lietotājvārds: " )
257+ use_generated = input ("Izmantot drošu paroli? (y/n): " ).lower () == 'y'
258+
259+ if use_generated :
260+ length = int (input ("Password length (minimum 8): " ))
261+ password = pm .generate_password (length )
262+ print (f"Izveidotā parole: { password } " )
263+ print ("Parole tika nokopēta!" )
264+ else :
265+ password = getpass .getpass ("Parole: " )
266+
267+ pm .add_password (service , username , password )
268+ print ("Parole tika pievienota!" )
269+
270+ elif choice == "2" :
271+ service = input ("\n Pakalpojums: " )
272+ username = input ("Lietotajvards: " )
273+ password = pm .get_password (service , username )
274+ pyperclip .copy (password )
275+ print (f"Parole: { password } " )
276+ print ("Parole tika nokopēta!" )
277+
278+ elif choice == "3" :
279+ length = int (input ("Paroles garums (minimums 8): " ))
280+ password = pm .generate_password (length )
281+ print (f"Izveidotā parole: { password } " )
282+ print ("Parole tika nokopēta!" )
283+
284+ elif choice == "4" :
285+ services = pm .list_services ()
286+ print ("\n Glabātie dati:" )
287+ for service , username in services :
288+ print (f"Pakalpojums: { service } , Lietotājvārds: { username } " )
289+
290+ elif choice == "5" :
291+ print ("Uz redzēšanos!" )
292+ break
293+
294+ else :
295+ print ("Nederīga opcija!" )
296+
297+ # Ja kaut kas gāja greizi tad izprintēt kas notikās
298+ except Exception as e :
299+ print (f"Error: { e } " )
300+
301+ # Lai šo var izmantot citās programmās
302+ if __name__ == "__main__" :
303+ main ()
0 commit comments