Advertisement
MizunoBrasil

Gerenciador de Senhas v. 5.6

Nov 14th, 2024
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.31 KB | None | 0 0
  1. import tkinter as tk
  2. from tkinter import ttk, messagebox, filedialog
  3. import sqlite3
  4. import pyperclip
  5. import webbrowser
  6. from reportlab.lib.pagesizes import letter, landscape
  7. from reportlab.pdfgen import canvas
  8. import shutil
  9.  
  10. class Application(tk.Tk):
  11.     def __init__(self):
  12.         super().__init__()
  13.         self.title("Gerenciador de Senhas de Sites - Versão 5.6")
  14.         self.geometry("1000x600")
  15.         self.sort_order_site = "asc"
  16.         self.sort_order_login = "asc"
  17.         self.init_db()
  18.         self.create_widgets()
  19.         self.create_menu()
  20.         self.date_label = ttk.Label(self, text="Mizuno - 02/11/2024")
  21.         self.date_label.place(x=10, y=self.winfo_height() - 30)
  22.         self.center_window()
  23.  
  24.     def create_widgets(self):
  25.         self.search_var = tk.StringVar()
  26.         self.search_entry = ttk.Entry(self, textvariable=self.search_var, width=50)
  27.         self.search_entry.pack(pady=(0, 10))
  28.  
  29.         # Vincula o evento KeyRelease para busca em tempo real
  30.         self.search_entry.bind("<KeyRelease>", lambda event: self.search_records())
  31.  
  32.         self.search_button = ttk.Button(self, text="Pesquisar", command=self.search_records)
  33.         self.search_button.pack(pady=(0, 10))
  34.  
  35.         # Botão Atualizar com o mesmo comportamento do código 1
  36.         self.refresh_button = ttk.Button(self, text="Atualizar", command=self.refresh_tree)
  37.         self.refresh_button.pack(pady=(0, 10))
  38.  
  39.         self.tree = ttk.Treeview(self, columns=("Site", "URL", "Login", "Senha"), show="headings")
  40.         self.tree.heading("Site", text="Site", command=self.sort_sites)
  41.         self.tree.heading("URL", text="URL")
  42.         self.tree.heading("Login", text="Login", command=self.sort_login)
  43.         self.tree.heading("Senha", text="Senha")
  44.         self.tree.pack(pady=10, side="left", fill="both", expand=True)
  45.  
  46.         scrollbar = ttk.Scrollbar(self, orient="vertical", command=self.tree.yview)
  47.         scrollbar.pack(side="right", fill="y")
  48.         self.tree.configure(yscrollcommand=scrollbar.set)
  49.  
  50.         self.add_button = ttk.Button(self, text="Adicionar", command=self.add_entry)
  51.         self.add_button.pack()
  52.         self.edit_button = ttk.Button(self, text="Editar", command=self.edit_entry)
  53.         self.edit_button.pack()
  54.         self.delete_button = ttk.Button(self, text="Excluir", command=self.confirm_delete)
  55.         self.delete_button.pack()
  56.         self.pdf_button = ttk.Button(self, text="Exportar PDF", command=self.export_to_pdf)
  57.         self.pdf_button.pack()
  58.        
  59.         # Botões de Backup e Restauração
  60.         self.backup_button = ttk.Button(self, text="Fazer Backup", command=self.backup_data)
  61.         self.backup_button.pack()
  62.         self.restore_button = ttk.Button(self, text="Restaurar Backup", command=self.restore_data)
  63.         self.restore_button.pack()
  64.  
  65.         self.load_data()
  66.         self.tree.bind("<Button-3>", self.popup_menu)
  67.         self.tree.bind("<Double-1>", self.open_url)
  68.  
  69.     def create_menu(self):
  70.         self.menu_bar = tk.Menu(self)
  71.         self.file_menu = tk.Menu(self.menu_bar, tearoff=0)
  72.         self.file_menu.add_command(label="Sobre", command=self.show_about_dialog)
  73.         self.file_menu.add_separator()
  74.         self.file_menu.add_command(label="Sair", command=self.quit_app)
  75.         self.menu_bar.add_cascade(label="Arquivo", menu=self.file_menu)
  76.         self.config(menu=self.menu_bar)
  77.  
  78.     def open_url(self, event):
  79.         if self.tree.selection():
  80.             item = self.tree.selection()[0]
  81.             url = self.tree.item(item, "values")[1]
  82.             webbrowser.open(url)
  83.  
  84.     def center_window(self):
  85.         self.update_idletasks()
  86.         width = self.winfo_width()
  87.         height = self.winfo_height()
  88.         x = (self.winfo_screenwidth() - width) // 2
  89.         y = (self.winfo_screenheight() - height) // 2
  90.         self.geometry(f'{width}x{height}+{x}+{y}')
  91.  
  92.     def init_db(self):
  93.         self.conn = sqlite3.connect("dados.db")
  94.         self.cursor = self.conn.cursor()
  95.         self.cursor.execute("""
  96.            CREATE TABLE IF NOT EXISTS senhas (
  97.                id INTEGER PRIMARY KEY AUTOINCREMENT,
  98.                site TEXT,
  99.                url TEXT,
  100.                login TEXT,
  101.                senha TEXT
  102.            )
  103.        """)
  104.         self.conn.commit()
  105.  
  106.     def load_data(self):
  107.         self.cursor.execute("SELECT site, url, login, senha FROM senhas")
  108.         for row in self.cursor.fetchall():
  109.             self.tree.insert("", "end", values=row)
  110.  
  111.     def save_data(self):
  112.         self.cursor.execute("DELETE FROM senhas")
  113.         for item in self.tree.get_children():
  114.             values = self.tree.item(item, "values")
  115.             self.cursor.execute("INSERT INTO senhas (site, url, login, senha) VALUES (?, ?, ?, ?)", values)
  116.         self.conn.commit()
  117.  
  118.     def refresh_tree(self):
  119.         for item in self.tree.get_children():
  120.             self.tree.delete(item)
  121.         self.load_data()
  122.  
  123.     def add_entry(self):
  124.         AddEntryWindow(self)
  125.  
  126.     def edit_entry(self):
  127.         try:
  128.             item = self.tree.selection()[0]
  129.             values = self.tree.item(item, "values")
  130.             EditEntryWindow(self, values)
  131.         except IndexError:
  132.             messagebox.showerror("Erro", "Selecione um registro para editar.")
  133.  
  134.     def delete_entry(self):
  135.         selected_item = self.tree.selection()[0]
  136.         site = self.tree.item(selected_item, "values")[0]
  137.         self.cursor.execute("DELETE FROM senhas WHERE site=?", (site,))
  138.         self.conn.commit()
  139.         self.tree.delete(selected_item)
  140.  
  141.     def confirm_delete(self):
  142.         try:
  143.             if messagebox.askyesno("Confirmar", "Tem certeza que deseja excluir este registro?"):
  144.                 self.delete_entry()
  145.         except IndexError:
  146.             messagebox.showerror("Erro", "Selecione um registro para excluir.")
  147.  
  148.     def popup_menu(self, event):
  149.         popup_menu = tk.Menu(self, tearoff=0)
  150.         popup_menu.add_command(label="Copiar URL", command=lambda: self.copy_to_clipboard(1))
  151.         popup_menu.add_command(label="Copiar Login", command=lambda: self.copy_to_clipboard(2))
  152.         popup_menu.add_command(label="Copiar Senha", command=lambda: self.copy_to_clipboard(3))
  153.         popup_menu.post(event.x_root, event.y_root)
  154.  
  155.     def copy_to_clipboard(self, column_index):
  156.         item = self.tree.selection()[0]
  157.         value = self.tree.item(item, "values")[column_index]
  158.         pyperclip.copy(value)
  159.  
  160.     def sort_sites(self):
  161.         items = self.tree.get_children("")
  162.         if self.sort_order_site == "asc":
  163.             sorted_items = sorted(items, key=lambda x: self.tree.item(x, "values")[0])
  164.             self.sort_order_site = "desc"
  165.         else:
  166.             sorted_items = sorted(items, key=lambda x: self.tree.item(x, "values")[0], reverse=True)
  167.             self.sort_order_site = "asc"
  168.         for item in sorted_items:
  169.             self.tree.move(item, "", "end")
  170.  
  171.     def sort_login(self):
  172.         items = self.tree.get_children("")
  173.         if self.sort_order_login == "asc":
  174.             sorted_items = sorted(items, key=lambda x: self.tree.item(x, "values")[2])
  175.             self.sort_order_login = "desc"
  176.         else:
  177.             sorted_items = sorted(items, key=lambda x: self.tree.item(x, "values")[2], reverse=True)
  178.             self.sort_order_login = "asc"
  179.         for item in sorted_items:
  180.             self.tree.move(item, "", "end")
  181.  
  182.     def show_about_dialog(self):
  183.         messagebox.showinfo("Sobre", "Filtre os dados por Site ou por Login ou pesquise na caixa de texto.\n\nVersão 5.6 - Última atualização: 15/11/2024, Mizuno.")
  184.  
  185.     def quit_app(self):
  186.         self.conn.close()
  187.         self.destroy()
  188.  
  189.     def search_records(self):
  190.         search_term = self.search_var.get().strip().lower()
  191.  
  192.         # Limpa a TreeView antes de preencher com os resultados da pesquisa
  193.         for item in self.tree.get_children():
  194.             self.tree.delete(item)
  195.  
  196.         # Se não houver termo de pesquisa, exibe todos os registros
  197.         if not search_term:
  198.             self.load_data()
  199.             return
  200.  
  201.         # Realiza a consulta de acordo com o termo de pesquisa
  202.         self.cursor.execute("""
  203.            SELECT site, url, login, senha FROM senhas
  204.            WHERE lower(site) LIKE ? OR lower(url) LIKE ? OR lower(login) LIKE ?
  205.        """, ('%' + search_term + '%', '%' + search_term + '%', '%' + search_term + '%'))
  206.  
  207.         for row in self.cursor.fetchall():
  208.             self.tree.insert("", "end", values=row)
  209.  
  210.     def export_to_pdf(self):
  211.         file_name = "informacoes_exportadas.pdf"
  212.         c = canvas.Canvas(file_name, pagesize=landscape(letter))
  213.         c.setFont("Helvetica", 10)
  214.  
  215.         x_position = 40
  216.         y_position = 550
  217.  
  218.         headers = ["Site", "URL", "Login", "Senha"]
  219.         for header in headers:
  220.             c.drawString(x_position, y_position, header)
  221.             x_position += 200
  222.  
  223.         y_position -= 20
  224.         x_position = 40
  225.  
  226.         for item in self.tree.get_children():
  227.             if y_position < 40:
  228.                 c.showPage()
  229.                 c.setFont("Helvetica", 10)
  230.                 y_position = 550
  231.                 x_position = 40
  232.                 for header in headers:
  233.                     c.drawString(x_position, y_position, header)
  234.                     x_position += 200
  235.                 y_position -= 20
  236.                 x_position = 40
  237.  
  238.             values = self.tree.item(item, "values")
  239.             for value in values:
  240.                 c.drawString(x_position, y_position, str(value))
  241.                 x_position += 200
  242.             y_position -= 20
  243.             x_position = 40
  244.  
  245.         c.save()
  246.         messagebox.showinfo("Exportação de dados", f"Arquivo {file_name} foi gerado com sucesso.")
  247.  
  248.     def backup_data(self):
  249.         backup_file = filedialog.asksaveasfilename(defaultextension=".db", filetypes=[("Database files", "*.db")])
  250.         if backup_file:
  251.             try:
  252.                 shutil.copy("dados.db", backup_file)
  253.                 messagebox.showinfo("Backup", "Backup realizado com sucesso.")
  254.             except Exception as e:
  255.                 messagebox.showerror("Erro", f"Erro ao fazer backup: {e}")
  256.  
  257.     def restore_data(self):
  258.         restore_file = filedialog.askopenfilename(filetypes=[("Database files", "*.db")])
  259.         if restore_file:
  260.             try:
  261.                 shutil.copy(restore_file, "dados.db")
  262.                 self.conn.close()  # Fecha a conexão para recarregar os dados restaurados
  263.                 self.conn = sqlite3.connect("dados.db")
  264.                 self.cursor = self.conn.cursor()
  265.                 self.refresh_tree()
  266.                 messagebox.showinfo("Restauração", "Restauração realizada com sucesso.")
  267.             except Exception as e:
  268.                 messagebox.showerror("Erro", f"Erro ao restaurar backup: {e}")
  269.  
  270. class AddEntryWindow(tk.Toplevel):
  271.     def __init__(self, parent):
  272.         super().__init__(parent)
  273.         self.title("Adicionar Entrada")
  274.         self.geometry("400x300")
  275.         self.create_widgets()
  276.         self.center_window()
  277.  
  278.     def create_widgets(self):
  279.         self.site_label = ttk.Label(self, text="Site:")
  280.         self.site_label.pack(pady=5)
  281.         self.site_entry = ttk.Entry(self, width=50)
  282.         self.site_entry.pack(pady=5)
  283.  
  284.         self.url_label = ttk.Label(self, text="URL:")
  285.         self.url_label.pack(pady=5)
  286.         self.url_entry = ttk.Entry(self, width=50)
  287.         self.url_entry.pack(pady=5)
  288.  
  289.         self.login_label = ttk.Label(self, text="Login:")
  290.         self.login_label.pack(pady=5)
  291.         self.login_entry = ttk.Entry(self, width=50)
  292.         self.login_entry.pack(pady=5)
  293.  
  294.         self.senha_label = ttk.Label(self, text="Senha:")
  295.         self.senha_label.pack(pady=5)
  296.         self.senha_entry = ttk.Entry(self, width=50)
  297.         self.senha_entry.pack(pady=5)
  298.  
  299.         self.save_button = ttk.Button(self, text="Salvar", command=self.save_entry)
  300.         self.save_button.pack(pady=20)
  301.  
  302.     def center_window(self):
  303.         self.update_idletasks()
  304.         width = self.winfo_width()
  305.         height = self.winfo_height()
  306.         x = (self.winfo_screenwidth() - width) // 2
  307.         y = (self.winfo_screenheight() - height) // 2
  308.         self.geometry(f'{width}x{height}+{x}+{y}')
  309.  
  310.     def save_entry(self):
  311.         site = self.site_entry.get().strip()
  312.         url = self.url_entry.get().strip()
  313.         login = self.login_entry.get().strip()
  314.         senha = self.senha_entry.get().strip()
  315.         if site and url and login and senha:
  316.             self.master.cursor.execute("INSERT INTO senhas (site, url, login, senha) VALUES (?, ?, ?, ?)",
  317.                                        (site, url, login, senha))
  318.             self.master.conn.commit()
  319.             self.master.refresh_tree()
  320.             self.destroy()
  321.         else:
  322.             messagebox.showerror("Erro", "Todos os campos devem ser preenchidos.")
  323.  
  324. class EditEntryWindow(tk.Toplevel):
  325.     def __init__(self, parent, values):
  326.         super().__init__(parent)
  327.         self.title("Editar Entrada")
  328.         self.geometry("400x300")
  329.         self.values = values
  330.         self.create_widgets()
  331.         self.center_window()
  332.  
  333.     def create_widgets(self):
  334.         self.site_label = ttk.Label(self, text="Site:")
  335.         self.site_label.pack(pady=5)
  336.         self.site_entry = ttk.Entry(self, width=50)
  337.         self.site_entry.pack(pady=5)
  338.         self.site_entry.insert(0, self.values[0])
  339.  
  340.         self.url_label = ttk.Label(self, text="URL:")
  341.         self.url_label.pack(pady=5)
  342.         self.url_entry = ttk.Entry(self, width=50)
  343.         self.url_entry.pack(pady=5)
  344.         self.url_entry.insert(0, self.values[1])
  345.  
  346.         self.login_label = ttk.Label(self, text="Login:")
  347.         self.login_label.pack(pady=5)
  348.         self.login_entry = ttk.Entry(self, width=50)
  349.         self.login_entry.pack(pady=5)
  350.         self.login_entry.insert(0, self.values[2])
  351.  
  352.         self.senha_label = ttk.Label(self, text="Senha:")
  353.         self.senha_label.pack(pady=5)
  354.         self.senha_entry = ttk.Entry(self, width=50)
  355.         self.senha_entry.pack(pady=5)
  356.         self.senha_entry.insert(0, self.values[3])
  357.  
  358.         self.save_button = ttk.Button(self, text="Salvar", command=self.save_entry)
  359.         self.save_button.pack(pady=20)
  360.  
  361.     def center_window(self):
  362.         self.update_idletasks()
  363.         width = self.winfo_width()
  364.         height = self.winfo_height()
  365.         x = (self.winfo_screenwidth() - width) // 2
  366.         y = (self.winfo_screenheight() - height) // 2
  367.         self.geometry(f'{width}x{height}+{x}+{y}')
  368.  
  369.     def save_entry(self):
  370.         site = self.site_entry.get().strip()
  371.         url = self.url_entry.get().strip()
  372.         login = self.login_entry.get().strip()
  373.         senha = self.senha_entry.get().strip()
  374.         if site and url and login and senha:
  375.             selected_item = self.master.tree.selection()[0]
  376.             self.master.cursor.execute("""
  377.                UPDATE senhas
  378.                SET site = ?, url = ?, login = ?, senha = ?
  379.                WHERE site = ?
  380.            """, (site, url, login, senha, self.values[0]))
  381.             self.master.conn.commit()
  382.             self.master.refresh_tree()
  383.             self.destroy()
  384.         else:
  385.             messagebox.showerror("Erro", "Todos os campos devem ser preenchidos.")
  386.  
  387. def main():
  388.     app = Application()
  389.     app.mainloop()
  390.  
  391. if __name__ == "__main__":
  392.     main()
  393.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement