§
    	Êjã  ã                  óð   — d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlmZ ddlmZmZ  ej        e¦  «        ZdZdZdd„Zdd„Z G d„ de¦  «        Z G d„ d¦  «        ZdS )a  Client API keys, persisted to ``data/keys.json``.

Only a SHA-256 hash and a short display prefix are stored; the plaintext key is
returned once, when it is created. ``last_used_at`` is kept in memory and
written out by ``flush()`` so that authenticating a request never touches disk.
é    )ÚannotationsN)ÚPath)Ú	BaseModelÚFieldzm2a-é   ÚkeyÚstrÚreturnc                ór   — t          j        |                      ¦   «         ¦  «                             ¦   «         S ©N)ÚhashlibÚsha256ÚencodeÚ	hexdigest©r   s    ú.C:\Projects\Muse2API\src\muse2api\auth\keys.pyÚhash_keyr      s&   € ÝŒ>˜#Ÿ*š*™,œ,Ñ'Ô'×1Ò1Ñ3Ô3Ð3ó    c                 ó:   — t           t          j        d¦  «        z   S )Né   )Ú
KEY_PREFIXÚsecretsÚtoken_urlsafe© r   r   Úgenerate_keyr   "   s   € Ý�Ô-¨bÑ1Ô1Ñ1Ð1r   c                  ó°   — e Zd ZU  ed„ ¬¦  «        Zded<   ded<   ded<   ded<    eej        ¬¦  «        Zded	<   d
Zded<   dZ	ded<   dZ
ded<   dd„ZdS )ÚApiKeyc                 óH   — dt          j        ¦   «         j        d d…         z   S )NÚkey_é
   )ÚuuidÚuuid4Úhexr   r   r   ú<lambda>zApiKey.<lambda>'   s   € ¨FµT´Z±\´\Ô5EÀcÀrÀcÔ5JÑ,J€ r   )Údefault_factoryr	   ÚidÚnameÚprefixÚhashÚfloatÚ
created_atg        Úlast_used_atFÚboolÚrevokedÚ Únoter
   Údictc                ó2   — |                       ddh¬¦  «        S )z#Serialisable view without the hash.Újsonr)   )ÚmodeÚexclude©Ú
model_dump©Úselfs    r   ÚpubliczApiKey.public0   s   € à�Š F°V°HˆÑ=Ô=Ð=r   N)r
   r1   )Ú__name__Ú
__module__Ú__qualname__r   r&   Ú__annotations__Útimer+   r,   r.   r0   r:   r   r   r   r   r   &   s¶   € € € € € € ØˆeÐ$JÐ$JÐKÑKÔK€BÐKÐKÐKÑKØ€I€I�IØ€K€K�KØ€I€I�IØ˜¨d¬iÐ8Ñ8Ô8€JÐ8Ð8Ð8Ñ8Ø€LÐÐÐÑØ€GÐÐÐÑØ€D€N€N€N�Nð>ð >ð >ð >ð >ð >r   r   c                  óh   — e Zd Zdd„Zdd„Zd d„Zd!d„Zd"d„Zd#d„Zd$d%d„Z	d&d„Z
dd„Zdd„Zd'd„ZdS )(ÚKeyStoreÚpathr   r
   ÚNonec                ó`   — || _         i | _        t          j        ¦   «         | _        d| _        d S )NF)rB   Ú_keysÚasyncioÚLockÚ_lockÚ_dirty)r9   rB   s     r   Ú__init__zKeyStore.__init__6   s(   € ØˆŒ	Ø(*ˆŒ
Ý”\‘^”^ˆŒ
ØˆŒˆˆr   c              ƒ  ó  K  — | j                              ¦   «         sd S t          j        | j         j        d¬¦  «        ƒ d {V —†}|                     ¦   «         r/d„ d„ t          j        |¦  «        D ¦   «         D ¦   «         | _        d S d S )Núutf-8©Úencodingc                ó   — i | ]
}|j         |“ŒS r   )r&   ©Ú.0Úks     r   ú
<dictcomp>z!KeyStore.load.<locals>.<dictcomp>A   s   € Ð_Ð_Ð_ a˜!œ$ Ð_Ð_Ð_r   c              3  óJ   K  — | ]}t                                |¦  «        V — Œd S r   )r   Úmodel_validate)rQ   Úis     r   ú	<genexpr>z KeyStore.load.<locals>.<genexpr>A   s0   è è € Ð+^Ð+^È­F×,AÒ,AÀ!Ñ,DÔ,DÐ+^Ð+^Ð+^Ð+^Ð+^Ð+^r   )	rB   Úis_filerF   Ú	to_threadÚ	read_textÚstripr3   ÚloadsrE   )r9   Úraws     r   ÚloadzKeyStore.load<   s›   è è € ØŒy× Ò Ñ"Ô"ð 	ØˆFÝÔ% d¤iÔ&9ÀGÐLÑLÔLÐLÐLÐLÐLÐLÐLˆØ�9Š9‰;Œ;ð 	`Ø_Ð_Ð+^Ð+^ÍdÌjÐY\ÉoÌoÐ+^Ñ+^Ô+^Ð_Ñ_Ô_ˆDŒJˆJˆJð	`ð 	`r   úlist[ApiKey]c                óT   — t          | j                             ¦   «         d„ ¬¦  «        S )Nc                ó   — | j         S r   )r+   )rR   s    r   r$   zKeyStore.all.<locals>.<lambda>D   s   € ¸¼€ r   r   )ÚsortedrE   Úvaluesr8   s    r   ÚallzKeyStore.allC   s'   € Ý�d”j×'Ò'Ñ)Ô)Ð/EÐ/EÐFÑFÔFÐFr   Úkey_idr	   úApiKey | Nonec                ó6   — | j                              |¦  «        S r   )rE   Úget©r9   re   s     r   rh   zKeyStore.getF   s   € ØŒz�~Š~˜fÑ%Ô%Ð%r   Úprovidedc                ó®   — |sdS t          |¦  «        }d}| j                             ¦   «         D ]%}t          j        ||j        ¦  «        r	|j        s|}Œ&|S )zOReturn the active key matching ``provided``, comparing hashes in constant time.N)r   rE   rc   ÚhmacÚcompare_digestr)   r.   )r9   rj   ÚdigestÚfoundr   s        r   ÚverifyzKeyStore.verifyI   si   € àð 	Ø�4Ý˜(Ñ#Ô#ˆØˆà”:×$Ò$Ñ&Ô&ð 	ð 	ˆCÝÔ" 6¨3¬8Ñ4Ô4ð ¸S¼[ð Ø�øØˆr   r   r   c                óh   — t          j         ¦   «         }||j        z
  dk    r||_        d| _        d S d S )Né   T)r?   r,   rI   )r9   r   Únows      r   ÚtouchzKeyStore.touchU   s;   € ÝŒi‰kŒkˆà�Ô!Ñ! QÒ&Ð&Ø"ˆCÔØˆDŒKˆKˆKð 'Ð&r   r/   r'   r0   útuple[ApiKey, str]c              ƒ  óÖ   K  — t          ¦   «         }t          |||d t          …         t          |¦  «        ¬¦  «        }|| j        |j        <   |                      ¦   «         ƒ d {V —† ||fS )N)r'   r0   r(   r)   )r   r   Ú_DISPLAY_LENr   rE   r&   Úsave)r9   r'   r0   Ú	plaintextr   s        r   ÚcreatezKeyStore.create\   su   è è € Ý ‘N”Nˆ	Ý˜$ T°)¸M½\¸MÔ2JÝ" 9Ñ-Ô-ð/ñ /ô /ˆà ˆŒ
�3”6ÑØ�iŠi‰kŒkÐÐÐÐÐÐÐØ�Iˆ~Ðr   r-   c              ƒ  óx   K  — | j                              |d ¦  «        €dS |                      ¦   «         ƒ d {V —† dS )NFT)rE   Úpoprx   ri   s     r   ÚremovezKeyStore.removed   sF   è è € ØŒ:�>Š>˜& $Ñ'Ô'Ð/Ø�5Ø�iŠi‰kŒkÐÐÐÐÐÐÐØˆtr   c              ƒ  ó"  K  — d| _         t          j        d„ |                      ¦   «         D ¦   «         dd¬¦  «        }| j        4 ƒd {V —† t          j        | j        |¦  «        ƒ d {V —† d d d ¦  «        ƒd {V —† d S # 1 ƒd {V —†swxY w Y   d S )NFc                ó:   — g | ]}|                      d ¬¦  «        ‘ŒS )r3   )r4   r6   rP   s     r   ú
<listcomp>z!KeyStore.save.<locals>.<listcomp>l   s&   € ÐLÐLÐL¸A˜aŸlšl°˜lÑ7Ô7ÐLÐLÐLr   é   )Úensure_asciiÚindent)rI   r3   Údumpsrd   rH   rF   rY   Ú_atomic_write)r9   Úpayloads     r   rx   zKeyStore.savej   sU  è è € ØˆŒÝ”*ÐLÐLÀÇÂÁÄÐLÑLÔLØ*/¸ð;ñ ;ô ;ˆà”:ð 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	AÝÔ# DÔ$6¸Ñ@Ô@Ð@Ð@Ð@Ð@Ð@Ð@Ð@ð	Að 	Að 	Añ 	Aô 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Að 	Aøøøð 	Að 	Að 	Að 	Að 	Að 	As   Á
!A>Á>
BÂBc              ƒ  óÂ   K  — | j         rU	 |                      ¦   «         ƒ d{V —† dS # t          $ r+ d| _         t                               d| j        ¦  «         Y dS w xY wdS )z1Persist pending ``last_used_at`` updates, if any.NTzfailed to write %s)rI   rx   ÚOSErrorÚlogÚ	exceptionrB   r8   s    r   ÚflushzKeyStore.flushq   s‡   è è € àŒ;ð 	?ð?Ø—i’i‘k”kÐ!Ð!Ð!Ð!Ð!Ð!Ð!Ð!Ð!øÝð ?ð ?ð ?Ø"�”Ý—’Ð2°D´IÑ>Ô>Ð>Ð>Ð>Ð>ð?øøøð	?ð 	?s   ‹' §1AÁAr†   c                óü  — | j         j                             dd¬¦  «         t          j        | j         j        dd¬¦  «        \  }}	 t          j        |dd¬¦  «        5 }|                     |¦  «         d d d ¦  «         n# 1 swxY w Y   t          j        |d	¦  «         t          j	        || j         ¦  «         d S # t          $ r5 t
          j                              |¦  «        rt          j        |¦  «         ‚ w xY w)
NT)ÚparentsÚexist_okz.keys.z.tmp)Údirr(   ÚsuffixÚwrL   rM   i€  )rB   ÚparentÚmkdirÚtempfileÚmkstempÚosÚfdopenÚwriteÚchmodÚreplaceÚBaseExceptionÚexistsÚunlink)r9   r†   ÚfdÚtmpÚfs        r   r…   zKeyStore._atomic_writez   s.  € ØŒ	Ô×Ò t°dÐÑ;Ô;Ð;ÝÔ" t¤yÔ'7ÀÐQWÐXÑXÔX‰ˆˆCð	Ý”˜2˜s¨WÐ5Ñ5Ô5ð !¸Ø—’˜Ñ Ô Ð ð!ð !ð !ñ !ô !ð !ð !ð !ð !ð !ð !øøøð !ð !ð !ð !åŒH�S˜%Ñ Ô Ð ÝŒJ�s˜DœIÑ&Ô&Ð&Ð&Ð&øÝð 	ð 	ð 	ÝŒw�~Š~˜cÑ"Ô"ð Ý”	˜#‘”�Øð	øøøs0   ÁB< ÁB Á4B< Â BÂB< ÂBÂ2B< Â<?C;N)rB   r   r
   rC   )r
   rC   )r
   r_   )re   r	   r
   rf   )rj   r	   r
   rf   )r   r   r
   rC   )r/   )r'   r	   r0   r	   r
   ru   )re   r	   r
   r-   )r†   r	   r
   rC   )r;   r<   r=   rJ   r^   rd   rh   rp   rt   rz   r}   rx   r‹   r…   r   r   r   rA   rA   5   s  € € € € € ðð ð ð ð`ð `ð `ð `ðGð Gð Gð Gð&ð &ð &ð &ð
ð 
ð 
ð 
ðð ð ð ðð ð ð ð ðð ð ð ðAð Að Að Að?ð ?ð ?ð ?ðð ð ð ð ð r   rA   )r   r	   r
   r	   )r
   r	   )Ú__doc__Ú
__future__r   rF   r   rl   r3   Úloggingr–   r   r”   r?   r!   Úpathlibr   Úpydanticr   r   Ú	getLoggerr;   r‰   r   rw   r   r   r   rA   r   r   r   ú<module>r§      sQ  ððð ð #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø €€€Ø €€€Ø €€€Ø 	€	€	€	Ø €€€Ø €€€Ø €€€Ø €€€Ø Ð Ð Ð Ð Ð à %Ð %Ð %Ð %Ð %Ð %Ð %Ð %à€gÔ˜Ñ!Ô!€à€
Ø€ð4ð 4ð 4ð 4ð2ð 2ð 2ð 2ð>ð >ð >ð >ð >ˆYñ >ô >ð >ðPð Pð Pð Pð Pñ Pô Pð Pð Pð Pr   