+
    ij7                         R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RItRtRt	R t
R tR tR tR tRtR tR	 tR
 tRR ltR tR tR t ! R R]P.                  4      tR# )u  sshj.discover — ssh config parsing + lazy rc/history discovery
(leaf).

B2 step 3: moved verbatim from sshj_cli.py (single-file era) — no
behavior change. The Discovery thread takes its Checker by
constructor argument, so this module imports nothing from the
package.
Nip  c            
       a . oV3R lp R
 F4  p\         P                  P                  V4      pV'       g   K,  V ! V4       K6  	  V ! \         P                  P	                  R4      4       V ! R4       \        \        P                  ! R4      4       F  pV ! V4       K  	  ^ pV^8  Edt   V^,          p\        S4      pS EFB  p \        V4      ;_uu_ 4       pVP                  4       pRRR4       XP                  4        F  p	T	P                  4       p
T
'       d   T
P                  R4      '       d   K4  RT
9   d   T
P                  R4      MT
P                  R4      w  rpTP                  4       P                  4       R	8w  g   TP                  4       '       g   K  TP!                  4        FN  p\        \        P                  ! \         P                  P	                  T4      4      4       F  pT ! T4       K  	  KP  	  K  	  EKE  	  \        S4      V8X  g   EKx   S# S#   + '       g   i     EL?; i  \         d     EK  i ; i)z9Every ssh config file in play (deduped, order preserved).c                    < \         P                  P                  V 4      p V S9  d;   \         P                  P                  V 4      '       d   SP	                  V 4       R # R # R # N)ospath
expanduserisfileappend)pfiless   &src/sshj/discover.pyaddconfig_files.<locals>.add!   sB    GGq!E>bggnnQ//LLO 0>    z~/.ssh/configz/etc/ssh/ssh_configz/etc/ssh/ssh_config.d/*.confN#= include)SSHJ_CONFIG
SSH_CONFIG)r   environgetr   r   sortedgloblenopenreadOSError
splitlinesstrip
startswith	partitionlowersplit)r   envvgdepthknownffhtextrawlinek_patr
   r   s                  @r   config_filesr1      s   E
 -JJNN31F - ?+,DII<=>A ? E
!)
E
A!WW779D  (yy{ts3325+4>>#.#~~c2 a779??$	1779C#DIIbgg.@.@.E$FGA H % ) " u:L5L# WW s0   H2H(H2H/)H2/H22IIc                   . Rr! \        V 4      ;_uu_ 4       pVP                  4       P                  4       pRRR4       X F  pTP	                  4       pT'       d   TP                  R4      '       d   K4  RT9   d   TP                  R4      w  rxp	MTP                  R4      w  rxp	TP	                  4       P                  4       T	P	                  4       rT	'       g   K  TR8X  d0   T'       d   TP                  T4       RT	P                  4       R/ /pK  Tf   K  YR,          T&   K  	  T'       d   TP                  T4       T#   + '       g   i     EL; i  \         d    . u # i ; i)zTParse one ssh_config file -> list of {patterns, opts, from} entries (OSError -> []).Nr   r   r   hostpatternsopts)
r   r   r   r   r   r    r!   r"   r	   r#   )
r   entriescurr)   linesr,   r-   keyr/   vals
   &         r   parse_config_filer;   I   s   tS$ZZ1FFH'')E  yy{ts++$;..-KCC..-KCC99;$$&		S&=s#syy{FB7C_"K! " sN/ ZZ 	s-   E EE E	E E E&%E&c                 z    . p \        4        F*  p\        V4       F  pWR&   V P                  V4       K  	  K,  	  V # )z4All entries across every configured ssh_config file.from)r1   r;   r	   )r6   r)   es      r   parse_configsr?   g   s<    G^"1%AfINN1 &  Nr   c                <   . p \        V R4      ;_uu_ 4       pVP                  ^ \        P                  4       VP	                  4       p\        VR4      p WE,
          pVP                  V4       VP                  V4      P                  RR4      pVP                  4       pV^ 8X  g   \        V4      V8  d   W!) R uuRRR4       # \        V^,          RV4      pW8X  d   W!) R uuRRR4       # TpK    + '       g   i     M; i  \         d    . u # i ; iY!) R # )u  Last up-to-`n` lines of `path`, with bounded memory (H1).

Reads a 64 KiB window from the end of the file and widens it (4x,
capped at 8 MiB) until it holds more than `n` complete lines or the
whole file is covered — so a multi-GB shell history is never read
into memory. A window that starts mid-line drops that partial first
line (which is why the check is `> n`, not `>= n`). Returns [] on
any OSError, or fewer than `n` lines if the file is short (or the
cap was hit by pathologically long lines).
rbi   utf-8replaceNi   )r   seekr   SEEK_ENDtellminr   decoder   r   r   )	r   nr8   r)   sizewindowstartr+   
new_windows	   &&       r   
tail_linesrN   q   s     E$FF1bkk"668Du%Fuvvf~,,Wi@)A:Ua :  !!_dC
' :  $   	:sA   D B#C3;
D C3$
D /C33D	>D D DDc                v   \        4       pV  F2  pRVR,          9   g   K  VP                  VR,          R,          4       K4  	   \        \        P                  P                  R4      4      ;_uu_ 4       pV EF  pVP                  R4      '       d   K  VP                  4       pV'       d   V^ ,          P                  R4      '       d   KU  V^ ,          P                  R4       F  pVP                  4       pVP                  R4      '       d)   VP                  R4      P                  R	4      ^ ,          pMVP                  R	4      ^ ,          pV'       d%   R
V9   g   \        P                  ! RV4      '       d   K  VP                  V4       K  	  EK  	  RRR4        \        P                  ! . RORR^R7      P                  p\        P                  ! RT4       F#  pTP                  TP!                  ^4      4       K%  	  T#   + '       g   i     Lw; i  \         d     Li ; i  \"         d     T# i ; i)zOConcrete hostnames to expand wildcards against: config HostNames + known_hosts.hostnamer5   z~/.ssh/known_hostsr   |,[z[]:@z[\da-f]+NTcapture_outputr+   timeoutz"Name"\s*:\s*"([^"]+)")	tailscalestatusz--json)setr   r   r   r   r   r    r#   r   re	fullmatchr   
subprocessrunstdoutfinditergroup	Exception)	r6   cr>   r)   lnpartsxoutms	   &        r   candidate_poolrj      s   A6"EE!F)J'( "''$$%9:;;q==%%
a 3 3C 8 8q,A	A||C((GGDM//4Q7GGCLO!||K;; EE!H -  <(nn-dA77=v 	 6<AEE!''!* = H9 <;$    Hs\   0H 47H,H
BH#H:HH A$H) H	H H H&%H&)H87H8c                j  a	 \        V 4      p. pV  EFP  o	S	R,           EF>  pRV9   g   RV9   d   \        ;QJ d#    V	3R l\         4       F  '       g   K   RM	  RM! V	3R l\         4       4      '       g   K\  \        P                  ! R\        P
                  ! V4      P                  RR	4      P                  R
R4      ,           R,           4      p\        V4       FJ  pVP                  V4      '       g   K  VP                  RVRS	R,          RS	P                  RR4      /4       KL  	  EK  VP                  RVRS	R,          RS	P                  RR4      /4       EKA  	  EKS  	  \        4       . rvV F<  pVR,          V9  g   K  VP                  VR,          4       VP                  V4       K>  	  V# )zjExpand wildcard Host patterns against the candidate pool (routing-opts only); dedupe by alias, first wins.r4   ?*c              3   :   <"   T F  qSR ,          9   x  K  	  R# 5i)r5   N ).0or>   s   & r   	<genexpr>expand_hosts.<locals>.<genexpr>   s     @<a&	><s   TF^z\?.z\*z.*$aliasr5   r=    )rj   anyROUTING_OPTSr\   compileescaperC   r   matchr	   r   r[   r   )
r6   poolrh   r0   rxcandseenuniqhr>   s
   &        @r   expand_hostsr      sY   '"D
CZ==CczSCZ s@<@sss@<@@@ZZ"))C.00<DDUDQQTWWY"4LDxx~~

GT61V9$*AEE&",=$? @ )
 

GS&!F)"AEE&"$57 8 !   $W:T!HHQwZ KKN  Kr   c                    / p \         P                  ! RRRV .RR^R7      pVP                  P                  4        FE  pVP	                  R4      w  rVpVP                  4       W%P                  4       P                  4       &   KG  	  RVP                  RVP                  RR4      4      R	VP                  R	VP                  R	R4      4      R
VP                  R
VP                  R
R4      4      RVP                  RR4      /#   \         d     Li ; i)zUssh -G a host -> {user, hostname, port, timeout}; falls back to the entry's own opts.ssh-G--TrV   r   userrx   rP   port22rX   connecttimeout0	r^   r_   r`   r   r!   r   r"   rc   r   )rw   r5   inforre   r.   r/   r%   s   &&      r   resolver      s    DNNE4u5*.T1F((%%'Bll3'GA!&'ggiD"# ( 	&"!56DHHZ*b)AB&$!78488,c2	   s   BC? ?DDc                   V P                  4       p \        P                  ! V4      pT'       d,   \        P
                  P                  T^ ,          4      R8w  d   R# ^RrCT\        T4      8  d   Y#,          pTR8X  d   MTR8X  d2   T^,           \        T4      8  d   Y#^,           ,          pT^,          pKX  TP                  R4      '       d9   T\        9   d#   T^,           \        T4      8  d   T^,          pK  T^,          pK   T\        T4      8  d   R# Y#,          pTP                  R4      w  rxp	TR8X  d   RpMTpT	P                  R4      ^8X  dN   T	P                  R^4      ^,          P                  4       '       d!   T	P                  R4      w  rp
T;'       g    T
pT	'       g   R# T^,           pT\        T4      8  dO   Y+,          pTP                  R4      '       d/   Y\        9   d   T^,           \        T4      8  d   ^M^,          pK]   T\        T4      8  d	   Y+,          MRpYyYL3#   \         d     R# i ; i)zParse an ssh command line -> (user, host, port) or None. Ignores the
remainder after the target (remote command); callers check for our own
probe's 'true' separately via the returned target index.Nr   rx   -p-rU   rT   )r   shlexr#   
ValueErrorr   r   basenamer   r    SSH_FLAG_ARGS
rpartitioncountisdigitr!   )r-   stoksir   ttargetr   r/   r3   p2jrests   &            r   ssh_target_from_liner      s    	

A{{1~ 277##DG,5t
c$i-G:9QT*A;DFA<<M!a!ec$i&7QQCI~WF%%c*MDTrzzz#!

3 21 5 = = ? ?nnS)zzr	AA
c$i-G<<M)a!ec$i.?aGA#d)m47Dt!!U  s   H4 4IIc                   / p \         P                  ! RRRV.RR^R7      pVP                  P                  4        FE  pVP	                  R4      w  rp
V
P                  4       WXP                  4       P                  4       &   KG  	  T ;'       g    VP                  RR4      pVP                  R	V4      pT;'       g    RpV'       d   VR
8X  d$   VP                  RR
4      pV'       g
   VR9  d   TpY'       d   VR9  d   RV 2MR,           pV'       d   V RV 2pRTRTR	TRT;'       g    R
RVP                  RR4      RVRVRVRVRV 2,           /	#   \         d     Li ; i)z5Build a host dict for a lazily discovered raw target.r   r   r   TrV   r   r   rx   rP   r   r   rT   rU   rw   rX   r   r   r   srcsrc_pathdisp   ·)rx   r   r   )r   r3   r   r   r   r   r   re   r.   r/   r%   uhnr
   cfgpr   s   &&&&&           r   	make_hostr   !  s^   DNNE4t4*.T1F((%%'Bll3'GA!&'ggiD"# (
 	$$$A	*d	#B

AT	xx%J.AaAZ$7Qqc7R@F3axT61j"AIIy$((3CS*IfeS*hDRu:%' '  s   BE E"!E"c                    . p \         P                  P                  R4      pV'       d/   V P                  \         P                  P                  V4      4       R F1  pV P                  \         P                  P                  V4      4       K3  	  \        4       . rCV  FT  pW#9  g   K  \         P                  P                  V4      '       g   K2  VP                  V4       VP                  V4       KV  	  V# )z?Existing shell rc files (SOURCE env first) for history seeding.SOURCE)z	~/.bashrcz~/.bash_profilez
~/.profilez~/.bash_aliasesz~/.zshrcz~/.zprofile	r   r   r   r	   r   r   r[   r   r   )rh   r   r
   r   r   s        r   rc_filesr   <  s    
C
**..
"C


277%%c*+)

277%%a()) $=RWW^^A..HHQKKKN  Kr   c                    . p \         P                  P                  R4      pV'       d   V P                  V4       V \         P                  P                  R4      \         P                  P                  R4      .,          p \        4       . r2V  FT  pWB9  g   K  \         P                  P                  V4      '       g   K2  VP                  V4       VP                  V4       KV  	  V# )z2Existing shell history files (HISTFILE env first).HISTFILEz~/.bash_historyz~/.zsh_historyr   )rh   histr   r   r
   s        r   history_filesr   M  s    
C::>>*%D

4BGG01GG/02 2C$=RWW^^A..HHQKKKN  Kr   c              #    "   \        4       p\        4        F  p \        VRRR7      ;_uu_ 4       pVP                  4       pRRR4       XP                  4        F  pRT9  d   K  Rp \        T4      pTf4   \        P                  ! RT4       F  p\        T4      pT'       g   K   M	  T'       g   K[  T^,          R8w  g   Kk  Tw  rrY3pY9   d   K{  Y9   g   T RT	 2T 9   d   K  TP                  T4       YT
R	T3x  K  	  K  	  \        4        F  p\        V\        4      pV F  pVP                  R
4      '       d   VP                  R^4      R,          pRV9  d   K<  \        V4      pV'       d   V^,          R8X  d   K_  Vw  rrW3pW9   d   Ko  W9   g   V RV	 2V 9   d   K  VP                  V4       WV
RV3x  K  	  K  	  R#   + '       g   i     EL; i  \         d     EK  i ; i  \         d     ELi ; i5i)zzYield (user, host, port, src, src_path) found in rc files + history,
deduped, skipping anything already in the static set.rB   rC   )encodingerrorsNr   z['\"]([^'\"]*ssh[^'\"]*)['\"]truerU   rcrT   ;r   )r[   r   r   r   r   r   r   rc   r\   findallr   r   rN   HISTORY_SCAN_TAILr    r#   )r(   r   r   r)   r+   re   r   qr   r3   r   r/   r9   r8   s   &             r   discover_candidatesr   ]  s     5D
	dWY??1vvx @ //#BBD+B/ |$DbIA/2Dt J tQ6)&*#Dl;=tfAdV$4$=$d22+ $ 8 4!23B}}S!!XXc1%b)B'+D47f,"&D,C{}4&$ 0E 9HHSMdFD00   5 @?? 		  s   HG#GG#
H)G64.H'	H5HD
HG G#H G##G3.H2G33H6HHHHc                   H   a a ] tR tRt oRtV 3R ltR tR tR tRt	Vt
V ;t# )	Discoveryi  zcLazily discovers ssh targets from rc files + history; appends them to
the visible set as they land.c                   < \         SV `  R R7       Wn        W n        \        P
                  ! 4       V n        . V n        RV n        R# )T)daemonFN)	super__init__r(   checker	threadingLocklockfounddone)selfr(   r   	__class__s   &&&r   r   Discovery.__init__  s9    %
NN$	
	r   c                    V P                   ;_uu_ 4        \        V P                  4      uuR R R 4       #   + '       g   i     R # ; ir   )r   listr   r   s   &r   snapshotDiscovery.snapshot  s#    YYY

# YYYs	   5A	c                    R V n         R# )TN)r   r   s   &r   stopDiscovery.stop  s	    	r   c                   \        V P                  4       F  pV P                  '       d    R # \        V!  pV'       d   VR,          '       g   K:  V P                  ;_uu_ 4        V P
                  P                  V4       V P                  P                  VR,          4       R R R 4       V P                  P                  V4       \        P                  ! R4       K  	  R #   + '       g   i     LG; i)NrP   rw   gQ?)r   r(   r   r   r   r   r	   r   r   add_hosttimesleep)r   r   r   s   &  r   r_   Discovery.run  s    '

3Dyyy4 AAjMM

!!!$

qz*  LL!!!$JJt 4 s   $>C!!C1)r   r   r   r(   r   )__name__
__module____qualname____firstlineno____doc__r   r   r   r_   __static_attributes____classdictcell____classcell__)r   __classdict__s   @@r   r   r     s#     %$ r   r   )z-lr   z-iz-oz-Fz-Ez-ez-cz-Jz-Lz-Rz-Dz-Wz-Mz-Sz-Iz-s)rP   r   r   	proxyjumpproxycommandidentityfile)rx   )r   r   r   r\   r   r^   r   r   r   r   r1   r;   r?   rN   rj   rz   r   r   r   r   r   r   r   Threadr   ro   r   r   <module>r      s     	 	    
A
  )X<B#P 8&1"h'6" 11h	   r   