Skip to content

Commit

Permalink
add exprot funtion and add config currently do nothing
Browse files Browse the repository at this point in the history
  • Loading branch information
deepattic committed Dec 1, 2024
1 parent 72086f2 commit 1e3f855
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 17 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ wheels/

# Virtual environments
.venv
data/*.csv
54 changes: 49 additions & 5 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import csv
import os
import time
from datetime import datetime
from typing import Annotated

import questionary
import typer
from rich import print
from rich.console import Console
from rich.prompt import Confirm, Prompt
from rich.progress import Progress, SpinnerColumn, TextColumn
from rich.prompt import Prompt
from rich.table import Table

from libwardenpy.db import get_connection
Expand Down Expand Up @@ -76,6 +80,44 @@ def create(
print("Username exists")


@app.command()
def export(
username: str,
password: Annotated[
str,
typer.Option(
"--password", "-p", prompt=True, confirmation_prompt=True, hide_input=True
),
],
):
global authenticated, auth_data, data
data.username = username
data.master_password = password
auth_data.username = username
key = authenticate_user(get_connection(), data)
if key is not None:
auth_data.key = key
authenticated = True
passwords = list_passwords(get_connection(), auth_data)
if passwords is not None:
with Progress(
SpinnerColumn(),
TextColumn("[progress.description]{task.description}"),
transient=True,
) as progress:
progress.add_task(description="Writing data to csv...", total=None)
time.sleep(1.5)
with open(
f"data/export-{datetime.today().date()}.csv", "w", newline=""
) as csvfile:
writer = csv.writer(
csvfile, delimiter=",", quotechar="|", quoting=csv.QUOTE_MINIMAL
)
for entry in passwords:
writer.writerow(entry)
print("Done!")


def main() -> None:
global authenticated
if authenticated:
Expand All @@ -86,13 +128,14 @@ def main() -> None:
\ V V / (_| | | | (_| | __/ | | | __/ | |
\_/\_/ \__,_|_| \__,_|\___|_| |_|_| |_|
-- created by supun
type .help or ? for help and x or .exit to exit.
1.) Add a Entry [A]
2.) Search Entry [S]
3.) List Entries [L]
4.) Delete Entry [D]
PRESS X TO QUITE
"""
print(banner)
main_logic()
Expand Down Expand Up @@ -136,7 +179,7 @@ def main_logic():
table.add_column("Site/Url", style="blue")
table.add_column("Password", style="red")
for item in passwords:
table.add_row(item[0], item[1].decode("utf-8"))
table.add_row(item[0], item[1])
console = Console()
console.print(table)

Expand Down Expand Up @@ -167,8 +210,9 @@ def main_logic():
qmark="> ",
pointer=">",
).ask()
delete_the_entry: bool = Confirm.ask(
f"Are You sure You want to delete [bold red]{id}[/bold red]?"
delete_the_entry = Prompt.ask(
f"Are You sure You want to delete [bold red]{id}[/bold red] {'[y/N]'} ?",
default=False,
)
if delete_the_entry:
delete_passwod(get_connection(), auth_data, id)
Expand Down
7 changes: 7 additions & 0 deletions libwardenpy/configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from dataclasses import dataclass


@dataclass
class AppConfig:
EXPORT_DIRECTORY: str = "data/"
PASSWORD_LENGTH: int = 20
16 changes: 9 additions & 7 deletions libwardenpy/funtionality.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import secrets
import sqlite3
from dataclasses import dataclass
from typing import List
from typing import Optional

import argon2
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
Expand All @@ -21,9 +21,9 @@ def __init__(self, username: str, master_password: str) -> None:
@dataclass
class AuthenticatedData:
username: str
key: bytes | None
key: Optional[bytes]

def __init__(self, username: str, key: bytes | None) -> None:
def __init__(self, username: str, key: Optional[bytes]) -> None:
self.username = username
self.key = key

Expand Down Expand Up @@ -66,7 +66,7 @@ def register_user(connection, data: UnAuthData) -> bool:
### verify the password hash matches given password and if matches create a new
### key for to encrypt the child items ( passwords, sites under given user) else
### if given user not found exit the program and if passwod doesnot match give a err
def authenticate_user(connection, data: UnAuthData) -> bytes | None:
def authenticate_user(connection, data: UnAuthData) -> Optional[bytes]:
with connection as conn:
cursor = conn.execute(
"SELECT password_hash, salt FROM users WHERE username = ?",
Expand Down Expand Up @@ -128,7 +128,7 @@ def add_password(connection, data: AuthenticatedData, entry: Entry) -> None:

### get the password for the site from sqlite database and decrept them
### and show them
def get_password(connection, data: AuthenticatedData, site: str) -> List | None:
def get_password(connection, data: AuthenticatedData, site: str) -> Optional[list]:
if not data.key:
return

Expand All @@ -154,7 +154,7 @@ def get_password(connection, data: AuthenticatedData, site: str) -> List | None:

### get the passwords of all the sites from sqlite database and decrept them
### and show them
def list_passwords(connection, data: AuthenticatedData) -> List | None:
def list_passwords(connection, data: AuthenticatedData) -> Optional[list]:
if not data.key:
return

Expand All @@ -171,7 +171,9 @@ def list_passwords(connection, data: AuthenticatedData) -> List | None:
return [
(
site,
ChaCha20Poly1305(data.key).decrypt(nonce, encrypted_password, None),
ChaCha20Poly1305(data.key)
.decrypt(nonce, encrypted_password, None)
.decode("utf-8"),
)
for site, encrypted_password, nonce in result
]
Expand Down
8 changes: 6 additions & 2 deletions libwardenpy/passgen.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import secrets
import string

from libwardenpy.configuration import AppConfig

config = AppConfig()


### this create a password with default length 14 and has digis uppercase and lowecase letters
def generate_password(lenght: int = 14) -> str:
def generate_password(lenght: int = config.PASSWORD_LENGTH) -> str:
alphabet = string.ascii_letters + string.digits
while True:
password = "".join(secrets.choice(alphabet) for _i in range(lenght))
password = "".join(secrets.choice(alphabet) for _ in range(lenght))
if (
any(c.islower() for c in password)
and any(c.isupper() for c in password)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_functionality.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ def test_list_passwords():
passwords = list_passwords(conn, auth_data)
assert passwords is not None
assert len(passwords) == 2
assert any(p[0] == "site1.com" and p[1].decode() == "pass1" for p in passwords)
assert any(p[0] == "site2.com" and p[1].decode() == "pass2" for p in passwords)
assert any(p[0] == "site1.com" and p[1] == "pass1" for p in passwords)
assert any(p[0] == "site2.com" and p[1] == "pass2" for p in passwords)


def test_delete_password():
Expand Down
3 changes: 2 additions & 1 deletion tests/test_password_generation.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import random

from libwardenpy.passgen import generate_password


def test_default_password_generation() -> None:
default_password = generate_password()
assert len(default_password) == 14
assert len(default_password) == 20


def test_password_generation_with_length() -> None:
Expand Down

0 comments on commit 1e3f855

Please sign in to comment.