+
    @ihQ                        R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIH	t	H
t
HtHt ^ RIHt ^ RIHt ^ RIHt ^ RIHt ^ RIHtHt ^ RIt^ RIt^ RIt^ R	IHt R
 R ltR R ltR R ltRR R llt ! R R4      t R t!]"R8X  d    ]!! 4        R# R#   ]# d    ]$! R4       ]PJ                  ! ^4        R# ]& d)   t']$! R]' 24       ]PJ                  ! ^4        Rt'A'R# Rt'A'i]( d)   t']$! R]' 24       ]PJ                  ! ^4        Rt'A'R# Rt'A'i]) d)   t']$! R]' 24       ]PJ                  ! ^4        Rt'A'R# Rt'A'i]* d)   t']$! R]' 24       ]PJ                  ! ^4        Rt'A'R# Rt'A'ii ; i)a
  
Secure Password Vault for Python Applications
Uses industry-standard encryption (AES-256-GCM) with PBKDF2 key derivation.

Supports encrypted master password storage:
  - VAULT_KEY  : Fernet key stored in project .env file
  - ID_ENC     : Master password encrypted with VAULT_KEY, stored in OS env var
  - VPATH      : Path to vault.enc, stored in OS env var
  - VAULT_DIR  : Path to this file, stored in OS env var

Setup (run once per machine):
  python vault.py setup              # generates VAULT_KEY, sets OS env vars
  python vault.py create             # initializes vault.enc

Credential management:
  python vault.py store <SERVICE> <USERNAME>
  python vault.py get   <SERVICE> [USERNAME]
  python vault.py list
  python vault.py delete <SERVICE> <USERNAME>
  python vault.py change-master

Master password utilities:
  python vault.py generate-key       # generate a new VAULT_KEY
  python vault.py encrypt-master     # encrypt master password with VAULT_KEY
  python vault.py decrypt-master     # verify/test decryption
N)Path)DictOptionalAnyTuple)
PBKDF2HMAC)hashes)AESGCM)Fernet)InvalidSignature
InvalidTag)datetimec                $    V ^8  d   QhR\         /#    returnstr)formats   "C:\code\desktop_vault\vault.py__annotate__r   3   s     * *C *    c                 H    \         P                  ! 4       P                  4       # )z=Generate a new Fernet key for encrypting the master password.)r
   generate_keydecode r   r   generate_vault_keyr   3   s     ''))r   c                <    V ^8  d   QhR\         R\         R\         /# r   master_password	vault_keyr   r   )r   s   "r   r   r   8   s!     8 8S 8S 8S 8r   c                    \        VP                  4       4      pVP                  V P                  4       4      P                  4       # )zy
Encrypt the master password using the VAULT_KEY.
Returns the encrypted token as a string (stored as ID_ENC OS env var).
)r
   encodeencryptr   )r   r    fs   && r   encrypt_master_passwordr%   8   s8    
 	y!"A99_++-.5577r   c                <    V ^8  d   QhR\         R\         R\         /# )r   id_encr    r   r   )r   s   "r   r   r   A   s!     / /C /C /C /r   c                    \        VP                  4       4      pVP                  V P                  4       4      P                  4       # )zz
Decrypt ID_ENC using VAULT_KEY to recover the master password.
Raises InvalidToken if either value is wrong or tampered.
)r
   r"   decryptr   )r'   r    r$   s   && r   decrypt_master_passwordr*   A   s5    
 	y!"A99V]]_%,,..r   c                0    V ^8  d   QhR\         R\         /# )r   r    r   r   )r   s   "r   r   r   J   s     < <s <c <r   c                F   \         P                  ! R4      pT ;'       g    \         P                  ! R4      pV'       d   V'       d    \        W4      # \         P                  ! R4      pV'       d   V# \
        P
                  ! R4      #   \         d    \	        R4      hi ; i)a)  
Resolve the master password using the two-part encrypted scheme:
  1. VAULT_KEY from argument or VAULT_KEY env var (set in project .env)
  2. ID_ENC from OS env var (set by setup script)
Falls back to ID (plaintext) for backward compatibility.
Falls back to interactive prompt if nothing is set.
ID_ENC	VAULT_KEYziFailed to decrypt master password. Check that VAULT_KEY in .env matches the key used when ID_ENC was set.IDEnter vault master password: )osgetenvr*   	Exception
ValueErrorgetpass)r    r'   keyplain_ids   &   r   resolve_master_passwordr8   J   s     YYx F

-
-ryy-C#	*677 yyH ??:;;  	Y 	s   
B	 	B c                   2  a  ] tR t^kt o RtR V 3R lR lltV 3R lR ltV 3R lR ltV 3R	 lR
 ltV 3R lR lt	V 3R lR lt
R V 3R lR lltR!V 3R lR lltR tR"V 3R lR lltR V 3R lR lltV 3R lR ltV 3R lR ltR V 3R lR lltR tRtV tR# )#SecureVaultap  
Secure password vault using AES-256-GCM encryption with PBKDF2 key derivation.

Security Features:
- AES-256-GCM encryption (authenticated encryption)
- PBKDF2-SHA256 key derivation (600,000 iterations)
- Cryptographically secure random salts and nonces
- Master password verification without storing password
- Encrypted master password support (ID_ENC + VAULT_KEY)
Nc                    < V ^8  d   QhRS[ /# )r   
vault_pathr   )r   __classdict__s   "r   r   SecureVault.__annotate__w   s        3  r   c                \   T;'       g    \         P                  ! R 4      pV'       d   \        V4      M
\        R4      V n        V P                  P                  P                  RRR7       \         P                  R8w  d&   V P                  P                  P                  R4       RV n        R# )VPATHzC:/code/vault/vault.encT)parentsexist_oknti  N)	r1   r2   r   r<   parentmkdirnamechmod_master_key)selfr<   resolveds   && r   __init__SecureVault.__init__w   su    337!3,4$x.$?X:Y$$TD$A77d?OO""((/r   c                ,   < V ^8  d   QhRS[ RS[RS[/# r   passwordsaltr   r   bytes)r   r=   s   "r   r   r>      s"     4 4C 4u 4 4r   c                    \        \        P                  ! 4       ^ VRR7      pVP                  VP	                  R4      4      # )    '	 )	algorithmlengthrP   
iterationsutf-8)r   r   SHA256deriver"   )rI   rO   rP   kdfs   &&& r   _derive_keySecureVault._derive_key   s8    mmo	
 zz(//'233r   c                ,   < V ^8  d   QhRS[ RS[RS[ /# rN   rQ   )r   r=   s   "r   r   r>      s'     [ [c [ [3 [r   c                n    \         P                  ! R VP                  R4      VR4      P                  4       # )sha256rY   rU   )hashlibpbkdf2_hmacr"   hex)rI   rO   rP   s   &&&r   _create_password_hash!SecureVault._create_password_hash   s+    ""8X__W-EtVTXXZZr   c                B   < V ^8  d   QhRS[ S[S[3,          RS[RS[/# )r   datar   r   )r   r   r   rR   )r   r=   s   "r   r   r>      s*     = =$sCx. =3 =5 =r   c                   \         P                  ! ^ 4      p\         P                  ! ^4      pV P                  W#4      pV P                  W#4      pRRR\        P
                  ! 4       P                  4       RVRV/p\        V4      pVP                  V\        P                  ! V4      P                  R4      R4      p	R\        P                  ! V4      P                  R4      R	\        P                  ! V4      P                  R4      R
\        P                  ! V	4      P                  R4      /p
\        P                  ! V
4      P                  R4      # )rT   versionz1.0createdpassword_hashentriesrY   NrP   nonce
ciphertext)secretstoken_bytesr]   re   r   now	isoformatr	   r#   jsondumpsr"   base64	b64encoder   )rI   rh   r   rP   rn   r6   rl   
vault_dataaesgcmro   encrypted_packages   &&&        r   _encrypt_dataSecureVault._encrypt_data   s   ""2&##B'522?Iux||~//1]t	

 ^^E4::j+A+H+H+QSWX
F$$T*11':V%%e,33G<&**:6==gF

 zz+,33G<<r   c                B   < V ^8  d   QhRS[ RS[RS[S[S[3,          /# )r   encrypted_datar   r   )rR   r   r   r   )r   r=   s   "r   r   r>      s2     b bE bC bDQTVYQYN br   c                    \         P                  ! VP                  R 4      4      p\        P                  ! VR,          4      p\        P                  ! VR,          4      p\        P                  ! VR,          4      pV P                  W$4      p\        V4      pVP                  WVR4      p	\         P                  ! V	P                  R 4      4      p
V P                  W$4      pV
R,          V8w  d   \        R4      hV
R,          #   \         d    \        R4      h\         P                  \        3 d   p\        R	4      ThRp?i\         d    \        R
4      hi ; i)rY   rP   rn   ro   Nrl   zInvalid master passwordrm   z Incorrect vault master password.z$Vault file is corrupt or unreadable.zAVault data signature invalid -- file may have been tampered with.)rt   loadsr   rv   	b64decoder]   r	   r)   re   r4   r   JSONDecodeErrorKeyErrorr   )rI   r~   r   packagerP   rn   ro   r6   ry   decrypted_datarx   expected_hashes   &&&          r   _decrypt_dataSecureVault._decrypt_data   s*   	bjj!6!6w!?@G##GFO4D$$WW%56E))',*?@J""?9CC[F#^^EtDNN$9$9'$BCJ 66MM/*m; !:;;i(( 	A?@@$$h/ 	LCD!K 	b`aa	bs$   DD .E3E4E  EEc                <   < V ^8  d   QhRS[ S[S[3,          RS[/# )r   rm   r   )r   r   r   tuple)r   r=   s   "r   r   r>      s#     	! 	!4S> 	!e 	!r   c                   R p\        VP                  4       4       FU  w  r4\        V\        4      '       g   K  RV9   g   K&  \        VR,          \        4      '       g   KE  VR,          pWT/W&   RpKW  	  V'       d   \        R4       W3# )FusernameTz4INFO: Vault migrated to multi-user format. Saving...)listitems
isinstancedictr   print)rI   rm   migratedservicevaluer   s   &&    r   _migrate_flat_vaultSecureVault._migrate_flat_vault   sv    "7==?3NG%&&:+>:eT^N_adCeCe ,$,#4 	 4
 HI  r   c                &   < V ^8  d   QhRS[ RS[/# )r   r   r   r   bool)r   r=   s   "r   r   r>      s      C 4 r   c                    V P                   P                  4       '       d<   \        R V P                    R24      pVP                  4       R8w  d   \	        R4       R# V'       g   \        4       p\        V4      ^8  d   \        R4      hV P                  / V4      pV P                   P                  V4       \        P                  R8w  d   V P                   P                  R4       \	        RV P                    24       R	# )
zVault already exists at z. Overwrite? (y/N): yzVault creation cancelled.F4Master password must be at least 12 characters long.rC   i  zVault created successfully at T)r<   existsinputlowerr   r8   lenr4   r{   write_bytesr1   rF   rG   )rI   r   responser~   s   &&  r   create_vaultSecureVault.create_vault   s    ??!!##77HH\]^H~~3&1257O"$STT++B@##N377d?OO!!%(.t.?@Ar   c                ,   < V ^8  d   QhRS[ RS[ RS[/# r   r   )r   r=   s   "r   r   r>      s#      C 3 RV r   c                   V P                   P                  4       '       g   \        R V P                    24       R# V'       g   \        V4      p V P                   P	                  4       pV P                  W14      V n        V P                  V P                  4      w  V n        pWn        V'       d   V P                  4        \        R4       R#   \         d   p\        RT 24        Rp?R# Rp?ii ; i)zVault not found at FzVault unlocked successfully.TzFailed to unlock vault: N)r<   r   r   r8   
read_bytesr   _vault_datar   _master_password_save_vaultr4   )rI   r   r    r~   r   r   s   &&&   r   unlock_vaultSecureVault.unlock_vault   s    %%''''89:5i@O	!__779N#11.RD)-)A)A$BRBR)S&Dh$3!  "01 	,QC01	s   A<C C1C,,C1c                    \        V R 4      '       d   V P                  '       g   \        R4      hV P                  V P                  V P                  4      pV P
                  P                  V4       R# )r   zVault is not unlockedN)hasattrr   RuntimeErrorr{   r   r<   r   )rI   r~   s   & r   r   SecureVault._save_vault   sV    t]++43H3H3H677++D,<,<d>S>ST##N3r   c          
      8   < V ^8  d   QhRS[ RS[ RS[ RS[ RS[/# )r   r   r   rO   notesr   r   )r   r=   s   "r   r   r>      s2      c S C PS ]a r   c                   \        V R 4      '       g   \        R4       R# \        P                  ! 4       P	                  4       pV P
                  P                  V/ 4      P                  V/ 4      pRVRVRVRVP                  RV4      RV/pWP
                  9  d   / V P
                  V&   WpP
                  V,          V&   V P                  4        \        RV R	V R
24       R# )r   +Vault is not unlocked. Please unlock first.Fr   rO   r   rk   modifiedPassword for '' / 'z' stored successfully.T)r   r   r   rr   rs   r   getr   )rI   r   r   rO   r   rr   existing_entryentrys   &&&&&   r   store_passwordSecureVault.store_password   s    t]++?@lln&&())--gr:>>xLU~)))S9
 ***(*DW%.3!(+wiuXJ6LMNr   c          	      R   < V ^8  d   QhRS[ RS[ RS[S[S[ S[3,          ,          /# r   r   r   r   )r   r   r   r   )r   r=   s   "r   r   r>      s2     	 	C 	3 	(4PSUXPX>BZ 	r   c                    \        V R 4      '       g   \        R4       R# V P                  P                  V4      pVf   R# Ve   VP                  V4      # V# )r   r   N)r   r   r   r   )rI   r   r   service_entriess   &&& r   get_passwordSecureVault.get_password   sW    t]++?@**..w7""&&x00r   c                    < V ^8  d   QhRS[ /# r   )r   )r   r=   s   "r   r   r>     s      t r   c                   \        V R 4      '       g   \        R4       . # V P                  V P                  4      w  V n        pV'       d   V P	                  4        . pV P                  P                  4        F`  w  r4\        V\        4      '       g   K  VP                  4        F/  w  rV\        V\        4      '       g   K  VP                  W534       K1  	  Kb  	  \        V4      # )r   r   )
r   r   r   r   r   r   r   r   appendsorted)rI   r   pairsr   usersr   r   s   &      r   list_servicesSecureVault.list_services  s    t]++?@I%)%=%=d>N>N%O"("..446NGeT**#(;;=eT**LL'!45 $1 7 e}r   c                ,   < V ^8  d   QhRS[ RS[ RS[/# r   r   )r   r=   s   "r   r   r>     s"      s c d r   c                   \        V R 4      '       g   \        R4       R# WP                  9  d   \        RV R24       R# W P                  V,          9  d   \        RV RV R24       R# V P                  V,          V V P                  V,          '       g   V P                  V V P                  4        \        RV R	V R
24       R# )r   r   Fz	Service 'z' not found in vault.z
Username 'z' not found under service 'z'.r   r   z' deleted successfully.T)r   r   r   r   )rI   r   r   s   &&&r   delete_passwordSecureVault.delete_password  s    t]++?@***IgY&;<=++G44Jxj(CG9BOPW%h/((  )wiuXJ6MNOr   c                &   < V ^8  d   QhRS[ RS[/# )r   new_passwordr   r   )r   r=   s   "r   r   r>   )  s      3 $ r   c                R   \        V R 4      '       g   \        R4       R# V'       g_    \        P                  ! R4      p\        P                  ! R4      pW8w  d   \        R4       K@  \        V4      ^8  d   \        R4       K]   Wn        V P                  4        \        R4       R# )	r   r   FTz!Enter NEW vault master password: z#Confirm new vault master password: z(Passwords don't match. Please try again.r   z%Master password changed successfully.)r   r   r5   r   r   r   )rI   r   confirm_passwords   && r   change_master_password"SecureVault.change_master_password)  s    t]++?@&/RS#*??3X#Y 3DE|$r)PQ ,56r   c                    \        V R 4      '       d   V P                  P                  4        V =\        V R4      '       d$   R\        V P                  4      ,          V n        V =\        R4       R# )r   r   xzVault locked.N)r   r   clearr   r   r   )rI   s   &r   
lock_vaultSecureVault.lock_vault=  s[    4''""$ 4+,,$'#d.C.C*D$DD!%or   )rH   r   r   r<   N)NN) )__name__
__module____qualname____firstlineno____doc__rK   r]   re   r{   r   r   r   r   r   r   r   r   r   r   r   __static_attributes____classdictcell__)r=   s   @r   r:   r:   k   s     	   4 4[ [= =(b b*	! 	! " &4 (	 	   " ( r   r:   c                     \         P                  ! R R7      p V P                  RRR7       V P                  RRR7       V P                  RRR	7      pVP	                  R
RR7       VP	                  RRR7       VP	                  RRR7       VP	                  RRR7       VP	                  RRR7       VP	                  RRR7      pVP                  RRR7       VP                  RRR7       VP                  RRRR7       VP	                  RRR7      pVP                  RR R7       VP                  RR!R"R#R$7       VP	                  R%R&R7       VP	                  R'R(R7      pVP                  RR R7       VP                  RRR7       VP	                  R)R*R7       V P                  4       pVP                  '       g   V P                  4        R"# \        VR+R"4      ;'       g    \        P                  ! R,4      pVP                  R
8X  d1   \        4       p\        R-V 24       \        R.4       \        R/4       R"# VP                  R8X  d`   T;'       g    \        R04      P                  4       p\        P                  ! R14      p\!        W4      p	\        R2V	 24       \        R34       R"# VP                  R8X  dt   T;'       g    \        R04      P                  4       p\        P                  ! R44      ;'       g    \        R54      P                  4       p
 \#        W4      p\        R64       R"# VP                  R8X  Ed   \        R84       \        4       p\        R9V 24       \        R:4       \        R;V R<24       \        P                  ! R=4      p\'        V4      ^8  d"   \        R>4       \(        P*                  ! ^4       \!        W4      p	VP,                  ;'       g    R?p\/        \1        \2        4      P5                  4       P6                  4      p\        R@4       \        RAV	 24       \        RBV 24       \        RCV 24       \        RD4       R"# \9        VP,                  4      pVP                  R8X  d   VP;                  4        R"# VP                  R8X  d   VP=                  VRE7      '       d   \        P                  ! RFVP>                   RGVP@                   RH24      pVPB                  ;'       g    \        RI4      P                  4       pVPE                  VP>                  VP@                  VV4       VPG                  4        R"# R"# VP                  R8X  Ed	   VP=                  VRE7      '       Ed   VPI                  VP>                  VP@                  4      pVfP   VP@                  '       d   RJVP>                   RGVP@                   RJ2MRJVP>                   RJ2p\        RKV 24       EMbVP@                  '       d   Tp\        RLVP>                   24       \        RMVR,           24       \        RNVRO,           24       VRP,          '       d   \        RQVRP,           24       \        RRVRS,           24       \        RTVRU,           24       M\K        VPM                  4       4       F  w  pp\        RLVP>                   24       \        RMVR,           24       \        RNVRO,           24       VRP,          '       d   \        RQVRP,           24       \        RRVRS,           24       \        RTVRU,           24       \        4        K  	  VPG                  4        R"# R"# VP                  R%8X  dz   VP=                  VRE7      '       d`   VPO                  4       pV'       d+   \        RV4       V F  w  pp\        RWV RXV RY24       K  	  M\        RZ4       VPG                  4        R"# R"# VP                  R'8X  d   VP=                  VRE7      '       dt   \        R[VP>                   RGVP@                   R\24      pVPQ                  4       R]8X  d'   VPS                  VP>                  VP@                  4       VPG                  4        R"# R"# VP                  R)8X  d=   VP=                  VRE7      '       d#   VPU                  4        VPG                  4        R"# R"# R"#   \$         d   p\        R7T 24        R"p?R"# R"p?ii ; i)^zSecure Password Vault)descriptionz--vault-pathz,Path to vault file (overrides VPATH env var))helpz--vault-keyzGFernet key for master password decryption (overrides VAULT_KEY env var)commandzAvailable commands)destr   zgenerate-keyzGenerate a new VAULT_KEYzencrypt-masterz0Encrypt master password with VAULT_KEY -> ID_ENCzdecrypt-masterz(Decrypt ID_ENC to verify master passwordsetupzDFull first-time setup: generate key, encrypt password, show env varscreatezCreate a new vaultstorezStore a passwordr   zService name (e.g. MULBUILDDB1)r   Usernamez--notesr   zOptional notes)defaultr   r   zRetrieve a passwordzService name?NzUsername (optional))nargsr   r   r   zList all servicesdeletezDelete a passwordzchange-masterzChange master passwordr    r.   z
VAULT_KEY=z)
Add VAULT_KEY to your project .env file.zKeep it out of source control.
zEnter VAULT_KEY: r0   z
ID_ENC=zH
Set ID_ENC as a persistent OS environment variable (see setup script).
r-   zEnter ID_ENC: z0Decryption successful. Master password verified.zDecryption failed: z 
=== Vault First-Time Setup ===
zGenerated VAULT_KEY:
  z%
Add this to every project .env file:z  VAULT_KEY=
z,Enter vault master password (min 12 chars): z/ERROR: Password must be at least 12 characters.zC:\code\vault\vault.enczS
Set these OS user environment variables (setup_vault.ps1 does this automatically):z  ID_ENC    = z  VPATH     = z  VAULT_DIR = z#
Then run:  python vault.py create
)r    zEnter password for 'r   z': z'Notes (optional, press Enter to skip): 'zNo password found for z
Service:  z
Username: z
Password: rO   r   z
Notes:    z
Created:  rk   z
Modified: r   zStored services:z  - z ()zNo passwords stored in vault.zDelete password for 'z
'? (y/N): r   )+argparseArgumentParseradd_argumentadd_subparsers
add_parser
parse_argsr   
print_helpgetattrr1   r2   r   r   r   stripr5   r%   r*   r3   r   sysexitr<   r   r   __file__resolverD   r:   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )parser
subparsersstore_pget_pdel_pargsr    r6   pwencr'   r   vpath	vault_dirvaultrO   r   resulttargetr   unamer   r   r   confirms                            r   mainr  K  s   $$1HIF
-[\
-vw&&I<P&QJ.1KL*1cd*1[\'1wx(1EF##G2D#EG*KL*5R6FG!!%.C!DE	y7	zdAVW&':;!!(1D!EE	y7	z
3/0HID<<<k40JJBIIk4JI ||~% "SE"#:;01||''==5!45;;=oo=>%b.	# Z[||''AAu%89??A))H%HH/?)@)F)F)H	-(5BDE 	||w23 "(./67SE$%__KLr7R<CDHHQK%b.OOCC'CX..0778	dese$%ug&'yk*+56 (E||x		 	22)=dll^5QUQ^Q^P__b'cdHzz]]U+T%U%[%[%]E  t}}hN	 3 
		22''dmmDF~DHMMM1T\\N%a@YZ[_[g[gZhhiWj.vh78
4<<.12
5#4"567
5#4"567>>JuW~&678
5#3"456
5#4"567$*6<<>$:LE5Jt||n56JuZ'8&9:;JuZ'8&9:;W~~
5>*:;<JuY'7&89:JuZ'8&9:;G %; 1 34 
		22'')E()).%GXD	H:Q78 */ 56 3 
	!	223DLL>t}}oU_`aG}}#%%%dllDMMB	 3 
	(	22((* 3 
)m  	-'s+,,	-s   c   d+c??d__main__z	
Aborted.zERROR: Permission denied -- zERROR: File not found -- zERROR: zERROR: Unexpected error -- r   )+r   r1   rt   rv   r5   rb   pathlibr   typingr   r   r   r   )cryptography.hazmat.primitives.kdf.pbkdf2r   cryptography.hazmat.primitivesr   +cryptography.hazmat.primitives.ciphers.aeadr	   cryptography.fernetr
   cryptography.exceptionsr   r   rp   r   r   r   r   r%   r*   r8   r:   r  r   KeyboardInterruptr   r   PermissionErrorr   FileNotFoundErrorr   r3   r   r   r   <module>r     s;  6 
      - - @ 1 > & @   
 *
8/<BY Y@Vr z   l ,QC01 )!-. sm +A3/0sZ   
B !E.9E.>E.?C""E.+E.,DE.E.D<<E.E.E))E.