Cw dZddlZddlZddlZddlZddlZddlmZddlm Z m Z ddl m Z ddl mZddlmZmZmZddlmZmZmZmZddlZdd lmZdd lmZdd lmZdd lm Z m!Z!dd l"m#Z#ddl$m%Z%ddl&m'Z'ddl(m)Z)dZ*dZ+dZ,ej-e.Z/GddZ0e0Z1Gdde2Z3Gdde2Z4e5Z6de5de6fdZ7e de5de6dzfdZ8e dde5fdZ9de5defd Z:de6fd!Z;d"ede6dzfd#Zd)e5d*e?de5fd+Z@e,fd,e?e5efd-eAde?e5e?e5eAfffd.ZBdS)/u  This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program.  If not, see . Copyright © 2019 Cloud Linux Software Inc. This software is also available under ImunifyAV commercial license, see N) defaultdict) lru_cachewraps)islice)Path)AnyCallable Coroutine) parse_qsl urlencodeurlparse urlunparse)IndependentAgentIDAPI)PanelException) HostingPanel)log_error_and_ignore safe_fileops)ImunifyPatchSubscriptionAPI)VulnerabilityAPI)VulnerabilityHitStatus)VulnerabilityHitz.imunify_patch_id c 2eZdZdZdZdZdZdZdZdZ e de j fd Z ed edefd Zd eded zfd Zd edededd fdZdd ed zdd fdZefdedeeegeeeed zffgeegeeeed zffffdZd S)PurchaseUrlCacheaDisk-based cache decorator for async functions. This class can be used as a decorator to cache results of async functions on disk with automatic expiration. The underlying diskcache.Cache is lazily initialized on first access to avoid import-time errors when the cache directory doesn't exist. Usage: @purchase_url_cache(ttl=3600) async def get_purchase_url(username: str) -> str | None: ... z#/var/imunify360/.cache/purchase_url purchase_url<icPd|_ttj|_dSN)_cacherasyncioLock_locksselfs T/opt/imunify360/venv/lib/python3.11/site-packages/imav/contracts/imunify_patch_id.py__init__zPurchaseUrlCache.__init__Ms.2 6A',6O6O returnct|j+tj|j|j|j|_|jS)z:Lazily initialize and return the diskcache.Cache instance.N)timeout size_limit)r! diskcacheCache CACHE_DIRTIMEOUT SIZE_LIMITr%s r'cachezPurchaseUrlCache.cacheQs= ; #/ ?DK {r)usernamec$tjd|S)zGenerate a cache key for the given username. Args: username: The username to generate a key for. Returns: A string with the prefixed username. :)r KEY_PREFIXr4s r' _make_keyzPurchaseUrlCache._make_key\s#-:::::r)Nc ||}|j|}|t|SdS#t$r&}t d|Yd}~dSd}~wwxYw)z*Get a cached value for the given username.Nz*Failed to read from purchase URL cache: %s)r9r3getstr Exceptionloggerwarning)r&r4 cache_keyvaluees r'_getzPurchaseUrlCache._geths x00IJNN9--E 5zz!4    NNG K K K44444 s?A A4A//A4rAttlc ||}|j|||dS#t$r&}td|Yd}~dSd}~wwxYw)zStore a value in the cache.)expirez)Failed to write to purchase URL cache: %sN)r9r3setr=r>r?)r&r4rArDr@rBs r'_setzPurchaseUrlCache._setts Kx00I JNN9eCN 8 8 8 8 8 K K K NNF J J J J J J J J J Ks26 A&A!!A&c ||jdS||}|j|dS#t$r&}t d|Yd}~dSd}~wwxYw)zClear the purchase URL cache. Args: username: If provided, clear only the cache entry for this user. If None, clear all cache entries. Nz&Failed to clear purchase URL cache: %s)r3clearr9deleter=r>r?)r&r4r@rBs r'rJzPurchaseUrlCache.clear|s H   """"" NN844  !!),,,,, H H H NNCQ G G G G G G G G G HsA/A BA;;Bc dttgttttdzffdttgttttdzffffd }|S)zCreate a decorator that caches async function results. Args: ttl: Time-to-live for cache entries in seconds. Defaults to DEFAULT_TTL (3600 seconds). Returns: A decorator function. funcNr*cftdtdtdzffd }|S)Nr4r*cK|}|td|||Sj|4d{V|}|0td|||cdddd{VS|d{V}|3td|||||cdddd{VS#1d{VswxYwYdS)Nz,Cache hit for username: %s, cached value: %sz9Cache hit (after lock) for username: %s, cached value: %sz'Cache miss for username: %s, result: %s)rCr>infor$rH)r4 cached_valueresultrMr&rDs r'wrapperz=PurchaseUrlCache.__call__..decorator..wrappers $yy22 +KKF $ (' ;x0""""""""#'99X#6#6L#/ )$(  ,""""""""""""""$(4>>111111F) E$"  (FC888!-""""""""""""""""""""""""""""""s 5C.AC.. C8;C8)rr<)rMrSr&rDs` r' decoratorz,PurchaseUrlCache.__call__..decoratorsX4[[" "" "d " "" "" "" "" "" "" "[" "HNr))r r<r r)r&rDrTs`` r'__call__zPurchaseUrlCache.__call__sx"( C5)CcDj,@"AAB(  seYsCt';<< =( ( ( ( ( ( ( Tr)r )__name__ __module__ __qualname____doc__r0 DEFAULT_TTLr7r1r2r(propertyr.r/r3 staticmethodr<r9rCintrHrJr r rrUr)r'rr9s  6IKJG!JPPPyX ;C ;C ; ; ;\ ; S S4Z    KSKK3K4KKKKHHcDjHDHHHH$;; ;  3%3S4Z#788 9:# #sC$J"6778 : ;;;;;;r)rceZdZdS)ImunifyPatchIdErrorNrVrWrXr^r)r'r`r`Dr)r`ceZdZdS)DiskQuotaErrorNrar^r)r'rdrdrbr)rdr4r*cKt|d{V}t|x}r|St}t||d{V|S)aEnsure the Imunify Patch ID file exists for the given user. This function checks if the Imunify Patch ID file exists in the user's home directory. If it does not exist, it generates a new ID, writes it to the file, and returns the ID. If the file already exists, it reads and returns the existing ID. Args: username (str): The username for which to ensure the ID file. Returns: ImunifyPatchUserId: The Imunify Patch user ID. N) _get_id_file _read_id_file _generate_id_write_id_file)r4id_file_ids r'ensure_id_filerlsq!********GG$$$s ..C # & &&&&&&&& Jr)c8Kt|4d{V t|d{V cdddd{VS#t$r&}td||Yd}~nd}~wwxYw dddd{VdS#1d{VswxYwYdS)Nz#Unable to ensure %s user id file %s)get_lockrlrdr>r?)r4rBs r'get_imunify_patch_idros!! '11111111 1    NN5           s4B A A2 A-(B -A22B  BB)maxsizec(tjS)zb Get a lock for the given username. Username argument used as cache key in lru_cache. )r"r#r8s r'rnrns <>>r)cXK tj|}t|jtz }t t dr4 t jt||S#t$rYnwxYw| s|j s9t d|j td|j  t jt|d{Vn#t t"f$rG}dt|vrt$|t dt|t|d}~wwxYwnB#t&$r5}t d|td||d}~wwxYw|S)zEGet a file with Imunify Patch user id and create it if does not existensure_regular_filezNo such user homedir: NzDisk quota exceededz$Unable to put %s in user home dir %szNo such user: z No such user )pwdgetpwnamrpw_dirIMUNIFY_PATCH_ID_FILEhasattrrrsr<FileNotFoundErrorexistsparentr>errorr`touchPermissionErrorOSErrorrdKeyError)r4user_pwdrjrBs r'rfrfs5<)) x''*?? >>%    ~~ 5>((**  FgnFFGGG)=W^== 5"(W6666666666#W- 5 5 5(CFF22(a/LL>- .14 5 5 EEE 0h00111!"<("<"<==1DE< NsBE( !A-- A:9A:$'D E$AEE$( F'20F""F'c2tjjS)zGenerate Imunify Patch id)uuiduuid4hexr^r)r'rhrh*s :<< r)rjc`|d5}t|D]?}|r;|ds&|x}r|ccdddS@ dddn #1swxYwYt d|ddS)zV Read Imunify Patch ID from `id_file`. If ID is not found, return `None`. r#Nz Cannot parse z, file is corrupted or empty)openreversed readlines startswithstripr>r?)rjflineimunify_patch_ids r'rgrg/s c  ,aQ[[]]++ , ,D ,DOOC00 ,'+zz||3#,+++ ,,,,,,,, ,,,,,,,,,,,,,,,,  NNH7HHHIII 4sAB7BB  B rkcKd|d} tjt||d{VdS#ttf$r.}t dt|t|d}~wwxYw)z$Write Imunify Patch id to `id_file`.zI# DO NOT EDIT # This file contains Imunify Patch id unique to this user  Nz'Unable to write %s in user home dir: %s) r write_textr<rr~r>r|rwr`)rjrktextrBs r'riri?s      )%c'llD99999999999 _ %))) 57La   "q( )s(4A3)A..A3r)rDc H Ktjd{V}|jsdStj}t |d{V}t }|}|d{V |gt} | d{V }n4#t$r'}td|i}Yd}~nd}~wwxYwfd|D t!jt j|kt jt*jkz} fd| D} t/t1jt!jd| Dd{V} ||pd|pd||ddt8|t| t;j| d d } t?|j| S) aGet the Imunify Patch purchase URL for a given user. This function builds a purchase URL with user-specific parameters. Results are cached on disk for PurchaseUrlCache.TTL seconds (1 hour). Imunify Patch purchase URL template: https://www.cloudlinux.com/purchase-imunify-patch?iaid= &imunify_patch_user_id=&server_ip=12.23.34.45 &username=johndoe&websites=example.com,anotherexample.com Defined in Jira ticket: https://cloudlinux.atlassian.net/browse/DEF-32303 Args: username: The username to generate the purchase URL for. Returns: The purchase URL string, or None if not eligible. NzError fetching domain paths: %sc$i|] \}}|v || Sr^r^).0domainpaths user_domainss r' z2get_imunify_patch_purchase_url..zs4 FE \ ! !  ! ! !r)cg|]=}D]&\}}|D]}|j||'>Sr^)items orig_filer)rhitr doc_rootspathuser_domain_pathss r' z2get_imunify_patch_purchase_url..s} !2!8!8!:!: FI   = # #D ) ) r)c6g|]}|Sr^)as_dict)rrs r'rz2get_imunify_patch_purchase_url..s ///3///r),T) sort_keys) iaidimunify_patch_user_idsubscription_target_id server_ipr4websitestotal_websitesvulnerable_domainsvulnerabilities) rget_purchase_eligibilityrrget_iaidror get_server_ipget_domains_per_userr;lenget_domain_pathsrrr>r|rselectwhereuserstatusr VULNERABLEgroup_by_severityr get_detailsget_vulnerabilities_idsjoinPURCHASE_URL_MAX_WEBSITESjsondumpsbuild_purchase_url)r4purchase_eligibilityrr panel_managerrr domain_pathsrBhitsrrurl_argsrrs @@r'get_imunify_patch_purchase_urlrPs**BDDDDDDDD ,t ) + +D"6x"@"@@@@@@@ NNM++--I'<<>>>>>>>>CC"L&&N+<<>>>>>>>>EEGG  6::: )  " $ $ * *  ( *  "&<&G G I  D (*  4//$///          O!6!<""7"=2HH\*D+D*DEFF(!"455:oFFF  H 2? J JJs/,C D &DD base_urlparamsc0t|}tt|jd}|d|D|t|d}t|S)NT)keep_blank_valuesci|] \}}||| Sr r^)rkvs r'rz&build_purchase_url..sIIIA1=1===r))doseq)query) r dictr rupdater_replacer r)rr parsed_url existing_qs new_parseds r'rrs(##Jy!1TJJJKKKIIIIIJJJ$$9[+M+M+M$NNJ j ! !!r)rlimitctd}t||D]:}|d}|dd}|dvr|||xxdz cc<;t |S)Nc*ttSr )rr]r^r)r'z#group_by_severity..sS!1!1r)appseverityUNKNOWN)HIGHMEDIUMLOWr)rrvaluesr;r)rrrRitemapp_namers r'rrs11 2 2F--//77,,;88J 22 ; ; ; 8 X & & &! + & & & <<r))CrYr"rloggingrtr collectionsr functoolsrr itertoolsrpathlibrtypingrr r urllib.parser r r rr.defence360agent.internals.iaidr"defence360agent.subsys.panels.baser+defence360agent.subsys.panels.hosting_panelrdefence360agent.utilsrr.imav.malwarelib.api.imunify_patch_subscriptionr!imav.malwarelib.api.vulnerabilityrimav.malwarelib.configrimav.malwarelib.modelrrwrMAX_SEVERITY_COUNT getLoggerrVr>rpurchase_url_cacher=r`rdr<ImunifyPatchUserIdrlrornrfrhrgrirrrr]rr^r)r'rsJ*  ######&&&&&&&&++++++++++CCCCCCCCCCCC@@@@@@======DDDDDD?>>>>>999999222222+  8 $ $NNNNNNNNb&%''     )        Y   3+=,  1Cd1J     4s######L( 4 $6$=     )$)-?)D))))"OK3OK3:OKOKOKOKd""d"s""""$  #s(^    #tCH~       r)