From 09a88f782ef8c4f183600c52a973d5334976b2a4 Mon Sep 17 00:00:00 2001 From: WP White Security Date: Thu, 9 Jan 2020 17:02:02 +0100 Subject: [PATCH 01/16] updated screenshots list --- readme.txt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/readme.txt b/readme.txt index 856622b7..cb05fb78 100644 --- a/readme.txt +++ b/readme.txt @@ -189,17 +189,16 @@ Please refer to our [Support & Documentation pages](https://www.wpsecurityauditl == Screenshots == -1. The Audit Log Viewer from where the WordPress administrator can see all the security events generated by WP Security Audit Log WordPress plugin. +1. The WordPress activity logs from where the site administrator can see all the user and site changes. 2. See who is logged in to your WordPress and manage users sessions with [Users Sessions Management](https://www.wpsecurityauditlog.com/premium-features/wordpress-users-sessions-management-tools/?utm_source=wordpress.org&utm_medium=referral&utm_campaign=WSAL&utm_content=plugin+repos+description) -3. The WP Security Audit Log plugin settings from where WordPress administrator can configure generic plugin settings such as [reverse proxy support](https://www.wpsecurityauditlog.com/support-documentation/support-reverse-proxies-web-application-firewalls/?utm_source=wordpress.org&utm_medium=referral&utm_campaign=WSAL&utm_content=plugin+repos+description), who can manage the plugin etc. +3. The plugin settings from where site administrator can configure generic plugin settings such as [reverse proxy support](https://www.wpsecurityauditlog.com/support-documentation/support-reverse-proxies-web-application-firewalls/?utm_source=wordpress.org&utm_medium=referral&utm_campaign=WSAL&utm_content=plugin+repos+description), who can manage the plugin etc. 4. The WordPress audit trail settings from where you can configure automatic pruning of alerts, which timestamp should be used, how many 404 requests should be logged and more. 5. Configuring WordPress email and SMS alerts with the [Email & SMS Notifications module](https://www.wpsecurityauditlog.com/premium-features/email-notifications-wordpress-activity-log/?utm_source=wordpress.org&utm_medium=referral&utm_campaign=WSAL&utm_content=plugin+repos+description) 6. Search in the WordPress security audit log with the use filters to fine tune the search results. -7. The Enable/Disable Alerts settings node from where Administrators can disable or enable WordPress security alerts. +7. The Enable/Disable events section from where Administrators can disable or enable activity log events. 8. The Audit Log Viewer of a Super Admin in a WordPress multisite network installation with the Site selection drop down menu. -9. If there are more than 15 sites in a multisite, an auto complete site search shows up instead of the drop down menu (see [screenshots](https://wordpress.org/plugins/wp-security-audit-log/screenshots/) for reference) -10. WP Security Audit Log is integrated with the built-in revision system of WordPress, thus allowing you to see what content changes users make on your WordPress posts, pages and custom post types. For more information read [Keep Record of All WordPress Content Changes](https://www.wpsecurityauditlog.com/support-documentation/how-keep-record-of-content-changes/?utm_source=wordpress.org&utm_medium=referral&utm_campaign=WSAL&utm_content=plugin+repos+description) -11. Mirror the WordPress activity log to an external solution such as Syslog or Papertrail to centralize logging, ensure logs are always available and cannot be tampered with in the unfortunate case of a hack attack. +9. WP Security Audit Log is integrated with the built-in revision system of WordPress, thus allowing you to see what content changes users make on your WordPress posts, pages and custom post types. For more information read [Keep Record of All WordPress Content Changes](https://www.wpsecurityauditlog.com/support-documentation/how-keep-record-of-content-changes/?utm_source=wordpress.org&utm_medium=referral&utm_campaign=WSAL&utm_content=plugin+repos+description) +10. Mirror the WordPress activity log to an external solution such as Syslog or Papertrail to centralize logging, ensure logs are always available and cannot be tampered with in the unfortunate case of a hack attack. == Changelog == From 1afaa877f2b23d85b388ff87444077825b1b472b Mon Sep 17 00:00:00 2001 From: William Patton Date: Thu, 30 Jan 2020 12:21:28 +0000 Subject: [PATCH 02/16] :sparkles: Adds new plugin install and activate feature for 3rd party events --- .../Utilities/PluginInstallAndActivate.php | 152 ++++++++++++++ classes/Utilities/PluginInstallerAction.php | 187 ++++++++++++++++++ classes/Views/ToggleAlerts.php | 7 + img/addons/bbpress.png | Bin 0 -> 4768 bytes img/addons/wpforms.png | Bin 0 -> 8193 bytes img/addons/yoast.png | Bin 0 -> 11587 bytes js/common.js | 54 +++++ wp-security-audit-log.php | 9 + 8 files changed, 409 insertions(+) create mode 100644 classes/Utilities/PluginInstallAndActivate.php create mode 100644 classes/Utilities/PluginInstallerAction.php create mode 100644 img/addons/bbpress.png create mode 100644 img/addons/wpforms.png create mode 100644 img/addons/yoast.png diff --git a/classes/Utilities/PluginInstallAndActivate.php b/classes/Utilities/PluginInstallAndActivate.php new file mode 100644 index 00000000..27e27bcc --- /dev/null +++ b/classes/Utilities/PluginInstallAndActivate.php @@ -0,0 +1,152 @@ +get_installable_plugins(); + ?> + +

+ + + + + + + +
+
+ +

+
+
+ 'BBPress Add-on', + // 'image_filename' => 'bbpress.png', + // 'plugin_slug' => 'wp-bootstrap-blocks/wp-bootstrap-blocks.php', + // 'plugin_url' => 'https://downloads.wordpress.org/plugin/wp-bootstrap-blocks.latest-stable.zip', // TODO: make this match live url. + // 'event_tab_id' => '#tab-bbpress-forums', + // ), + // array( + // 'title' => 'WPForms Add-on', + // 'image_filename' => 'wpforms.png', + // 'plugin_slug' => 'google-sitemap-generator/sitemap.php', + // 'plugin_url' => 'https://downloads.wordpress.org/plugin/google-sitemap-generator.latest-stable.zip', // TODO: make this match live URL. + // 'event_tab_id' => '#tab-wpforms', + // ), + array( + 'title' => 'Yoast SEO', + 'image_filename' => 'yoast.png', + 'plugin_slug' => 'wordpress-seo/wp-seo.php', + 'plugin_url' => 'https://downloads.wordpress.org/plugin/wordpress-seo.latest-stable.zip', // TODO: make this match live URL. + 'event_tab_id' => '#tab-yoast-seo', + ), + ); + // runs through a filter so it can be added to programatically. + // NOTE: this means when using we need to test it's still an array. + return apply_filters( 'wsal_filter_installable_plugins', $plugins ); + } + } +} diff --git a/classes/Utilities/PluginInstallerAction.php b/classes/Utilities/PluginInstallerAction.php new file mode 100644 index 00000000..f16f25c8 --- /dev/null +++ b/classes/Utilities/PluginInstallerAction.php @@ -0,0 +1,187 @@ + esc_html__( 'Tried to install a zip or slug that was not in the allowed list', 'wp-security-audit-log' ), + ) + ); + } + + // Check if the plugin is installed. + if ( $this->is_plugin_installed( $plugin_slug ) ) { + // If plugin is installed but not active, activate it. + if ( ! is_plugin_active( $plugin_zip ) ) { + $this->run_activate( $plugin_slug ); + $this->activate( $plugin_zip ); + $result = 'activated'; + } else { + $result = 'already_installed'; + } + } else { + // No plugin found or plugin not present to be activated, so lets install it. + $this->install_plugin( $plugin_zip ); + $this->run_activate( $plugin_slug ); + $this->activate( $plugin_zip ); + $result = 'success'; + } + + wp_send_json( $result ); + } + + /** + * Install a plugin given a slug. + * + * @method install + * @since 4.0.1 + * @param string $plugin_zip URL to the direct zip file. + */ + public function install_plugin( $plugin_zip = '' ) { + // bail early if we don't have a slug to work with. + if ( empty( $plugin_zip ) ) { + return; + } + // get the core plugin upgrader if not already in the runtime. + if ( ! class_exists( 'Plugin_Upgrader' ) ) { + include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; + } + // clear the cache so we're using fresh data. + wp_cache_flush(); + $upgrader = new Plugin_Upgrader(); + $install_result = $upgrader->install( $plugin_zip ); + if ( ! $install_result || is_wp_error( $install_result ) ) { + if ( is_wp_error( $install_result ) ) { + return $install_result->get_error_message(); + } + die(); + } + } + + /** + * Activates a plugin that is available on the site. + * + * @method activate + * @since 4.0.1 + * @param string $plugin_zip URL to the direct zip file. + * @return void + */ + public function activate( $plugin_zip = '' ) { + // bail early if we don't have a slug to work with. + if ( empty( $plugin_zip ) ) { + return; + } + + // get core plugin functions if they are not already in runtime. + if ( ! function_exists( 'activate_plugin' ) ) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + + if ( ! is_plugin_active( $plugin_zip ) ) { + activate_plugin( $plugin_zip ); + } + } + + /** + * Activates a plugin that is available on the site. + * + * @method run_activate + * @since 4.0.1 + * @param string $plugin_slug slug for plugin. + */ + public function run_activate( $plugin_slug = '' ) { + // bail early if we don't have a slug to work with. + if ( empty( $plugin_slug ) ) { + return; + } + + $current = get_option( 'active_plugins' ); + $plugin = plugin_basename( trim( $plugin_slug ) ); + + if ( ! in_array( $plugin_slug, $current, true ) ) { + $current[] = $plugin_slug; + activate_plugin( $plugin_slug ); + } + return null; + } + + /** + * Check if a plugin is installed. + * + * @method is_plugin_installed + * @since 4.0.1 + * @param string $plugin_slug slug for plugin. + */ + public function is_plugin_installed( $plugin_slug = '' ) { + // bail early if we don't have a slug to work with. + if ( empty( $plugin_slug ) ) { + return; + } + + // get core plugin functions if not already in the runtime. + if ( ! function_exists( 'get_plugins' ) ) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + $all_plugins = get_plugins(); + + // true if plugin is already installed or false if not. + if ( ! empty( $all_plugins[ $plugin_slug ] ) ) { + return true; + } else { + return false; + } + + } + } +} diff --git a/classes/Views/ToggleAlerts.php b/classes/Views/ToggleAlerts.php index 123b265a..6fdb97ca 100644 --- a/classes/Views/ToggleAlerts.php +++ b/classes/Views/ToggleAlerts.php @@ -225,6 +225,9 @@ public function Render() { + + +
@@ -667,6 +670,10 @@ class="alert" + render(); + ?>

diff --git a/img/addons/bbpress.png b/img/addons/bbpress.png new file mode 100644 index 0000000000000000000000000000000000000000..5fa93102c939caa8ee61a5e8c5622783dedc877a GIT binary patch literal 4768 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 P4xp@{AzvYD9{j%mKFO~< literal 0 HcmV?d00001 diff --git a/img/addons/yoast.png b/img/addons/yoast.png new file mode 100644 index 0000000000000000000000000000000000000000..0cc0e88b37da6dc6cd953b82e423122d68ea612f GIT binary patch literal 11587 zcmXwf1yq#Z^Y^p6EFlfjjijV>2rS(QBGTP0B3(-(Atfy#Aky7kBHi63-ML7;`2GLh zvuF3&Gk5OH+_^Jz=Q;QDSye?A^BL(g001!M<)q#M04V0^e_viZ{k*+fxR z3V8hY$!hr-|3pFiAgAs8G-Kx97bL-y=Ke%P`6RC_jj{=%z`}k7?l%(z0BS&9O8lMs z{9(GAw}$lmZ@&>i{@@@3saLR|7zw0LPD=y>AsX6Jv8i&JFnrY2B3q7qg9UJSz^80~ z9w`W_2^3vTt->gpnGPp*S#huBdhq-qcGi`dzi-ffaAss~X(UzHa=3cs^~m6B$x){5 zWtUfuxHu(rPU3-8oZFsWRUF2b3a!oZQT8S5=20>^P&%N16}tfhQq&h~({k88MpiW5CABx_M##E- z<5ynND8d+^`_pG9)!JGq&r`jeF)I+-J7VG=OuNra3`!KW{v*JS42kY7!6pRq6NNvK z3DQUZzl~rX8U4L^pCAAEf$k~_jgNCBw+GSw#@LX^CreQ~XAFV&mpqK_<(I=FS*gP* zVyfQC1)5LHwmf@%pVQ|9XXEz5`2wuYd#MN?ilI`@XRk7{Mty?+GzRgKzM+wMHFnRX zUdUwC{j1(Hbd3LR{U&Q9wH1Zqe3)jt|J!0*WZZL9 z>CcWCqUH6fM3pid9#SPJustyy7?0oTQvjj?v{SjI5XS$+`bQR4QB8%A+*Pt0{9hv-pXx?_Z$ zH*_I8Wpb&N2R`R||Lv|=)-j}jQT+QbuFC`f<8<^(9?s!Uun8i{igV zO<2@cC}9Pb2d9Qi#m%9bOGJS>0#r>=-|2Mo=0&+iJ@~4%ms+z$G}H4iz0O5%ie!Sw ztjR^G6u8yAAwAN$o#mbiC2_!yHnvNHGXX)j%@L1=c#?+#o4 ze%xB^Jl3%EGYwd(wY`3b=*!hYJ?aT!0yn-ICCy3%LcyrcKv?)vGZ$g{j`xrjblfb@AC8yDx>-JGg%UqSUA`GhL2BfEq#loFIpFRP`fDtE%u3ZTr z?gj$)9-6LJs_=V1E0-XZ2f~_2?jZQJF~&Y5-~8&C&{){SUM6K(5QrynB0eJPqn%^| z->}i8-g&tO?7dsB%fYUB4D=OKE4+OJZdc-jeb9ob*zNfO3&6b0s)_hriSb&K+OLRO zd@zDDm`bt{b#Xg`S53c=^6@%# z7AYpi<_~dzn+WeGTYpU?Gy97dfJh;=b*Qpx=&mIC4@_!7wFz1y=P0NZIa~{yFdje1 z?Q^Uy2%Mbf>+hcqoRO;6m;dg22qwhg zWumZ3fY{?Dn$Dd*@{4=m(!?DFA3lpEuGm^3_o3_Ar9IKR>#- zIyo!5UosBlFuJL!df2-l25RmQ0!PT2KT$u&s3=&{^k*a-6sY;W# z>@=$ta3sNk9hcjh z3(g2B0O5_MYB#Gl-D`c^uuzgcya|T~h)0{dC`Q@t93PgGNo~<0DbPL33-)BfHUg!j zS67Am6U4=1;w75G{|*=S`uuX=5DWC3-9F0P?#{(R8M}ko1tC>iXxTb%FxDp81V87P zM>g^R2(@F3&kjN!1YSBEQ^PsXVk!kbbep$khn@k1H~{rT%yEwilZ)xnt&I{2fM&y> ze6(^KOOZ+Xt9uvqV5d*trZ^@k*HM#q_j7x-#7Xp@v3PcSt+ww?;C!ZxwiYvkC@=G^ z&@{$s_~h9|dq5fLMa`yJS(BH~$cNxLN=#l`%ut(vUuj2oYn8pa62_-5fgy;WXxGei zcTJ0~MY!oXQ6hZT{KH{BnOrpRW4i8jqU@U^unZOU_9YVWFC#mD7#g=Pa*mEfW1_fB zYAvKWRMsa8BNj`}r7P%rVIvisSK(~HhW!hz(M>am-eD+pFot2GW5;E>TCV5CQ=F9* zJB#%(I}ZHCPV4FIQAs8iP=e8LW5xS-4GP%7DZnzikZeq&Z(XYqpdinl;@_(cY7-KR z>HZKnr00Z@?GS$>zL(8|sYXM6U9wNf5j3UVM{G^%&`|c#78n2|pEza1b5uK#(=EllIb`4D_aAF{0A+5yFdcil^9jCX%0nZJX$Q?=iwRH#2Z9TwQ_ORCS^ zRATCjeZdk*0bdc*ikMyXjTMCA`lCaCfW++{M&ucR1uSYKR{YZ6R5@&46A9C+#Ie^b zW8ssoX1VAzE|%&8_#N*Jfqip&tGX^GBI1G`NmEwm?PD&}JPfc@KxbjT*=SB;&PRu( zEH@noc0E-Lqn;k5+v0SuYh}O`88BbSPdVWPtifD)A0DpfDhg~n9-V!|KA&V5<RDob#gBm~4w9)?ZptRu``WFoPia>a425~598{;w+S``D>^&$pnZdv{AXcx>moq1s z)XH@P+($?}wD;*(enLU$-Fa#}k4_I6I@@-_NzCDFFljhjFzq^+7BE)(Ck z29T|e&kf0yTxgZ0C>r=4NmlpYjGc^}&jOqXx^e{_d{P7>d zM;($Kco?5Li3z4rP+1lQZ;iS23sWqkWw{kUh)CzP;$EG9SR>FDqMRT3qK?$sG@Yx;`L+jU?_FXaT$4EWN ztj^q|=X-M>2Nod?%yzeDaYqfb7B->q9eX8S+iTmUE_4lS1ur(tsW zeVAPV1yZ(}L$Oh(9MJJhw9fr1W_@JjLiQ=4=Ycb#5zNs~Zdk6og`&npxeRYP8)iL} zVHiqwo|nFHlEbSMz&ksi8vmWC!CCn$`j+@W92_gOQ)^HG?{3LdNBcQcsV6KJsY|qRu>@Z7~cKj*%o1WDev(hP|mSP4CGxYwMip^!;?0YZWw-9!E z%~EGr-!Hg7Z;upgu6y@gqfjz#9$*&A3sa91ud9wj39W~!}Y`Nh{Kk_UzmJQ0wrbE z`>Ax=B>8RgShwnni|GaR*ePc_fhnG-@*pe6WUB!swvNSdY8&SE4rC+FNA{3-@u3b* z(As5KKSnd=ss(m)A$ohXZUE&-c>2W)2n*&!FG*TkInvYn>^Nz4(MS5UwGogN^UuH! zfk;xYAr(A}kG7}Y4wKb5A>1-&``BNfS3fSsUkc{A_ql1migyKv#S|#kuBK7~qGywC zn@>enQ*c2~s#^q!DHV08eFr& zInAv1i|!*3-H;yj>$i_F=Oh3tw#8_QmrjtNpSdThB9Psp(ay<|xZ}10jeRWQb!w8UXw$0#AN9!tN zjG#z`VEaHocbc%*w#4GX+}Y{|!(l27scRx_(FRi2FF*yR1=anQdMT-7ex<^G3%T|; zE=JWFCnCDrSR8lNlnqDJB5}`^jhTzqrLv@YytSR+)H2a%__O^G2L{vVp` zCG$Z`BkcxMcNs>=jIR(&kvp5mPr7>M@DC`jzM?|CZrIqUU(!?wp+qXkmyDuveS<8e zAxx{o4PfAunqgYAd0njtb555=|h%={}Eu@tu4jz94vUb+|KJ72Luo}vD2 zNb{FFm^42G4yj@IBsijX_NU-)bJo{KREaK%lz*5bq^KaLlAsjs+yf?vZLS9K1j&-t z#K-JZbfc_*5Dwzn1J7wG;XW0Ag{hw-Zw~Fj=&M1STqW1+BFI+O7bSg(!Da313i$%` zd+2WJCuinkbuCGh+%(8fsq?c}xlxL0i`T9A^XvO8d>gFL)Wb-! z{VMcg*ZD5vkHYB!M@#*i8*wPHo>LQXSbfF=jr48(N{Ym&*gQp&(+94d)73v=$-6`= z{X6K!zPA!}3zV+>;EF9)yqE^bh_mDdsqtj|&5t2i0)Zt$GJQcYf>q01Y)tQLEb%ur zK*s)0qGNE}P@;&|8Eb2UPmz(aC-oOGahZJ|eBqR*_>PLGplG+q`5I4gZyR; z_wZVZmA6jdz$o)GWM|PIWVUY|E^Y?v75w2}n{cZ0mN65xO5wx;YZ@T`PoVGYB8nqc z!MVSctdLQB+Pjlj8ov%~Kg4!)msm#!z6$7&yD(a88t2a$aboVCOOOzA)n~gDMMwAI|e>uL61MX2H(}@ZgvK+ytxn#uF2Ut z$)e#RJL9$}Ok}k%h-#usPE~xMd~mXim@w#_qOqB2OWEy#>9dGURjHe_L~#tv3Onte zLulMdxv_3LuHDSy4U%?;@jQvj9-qnSL-Q2TPaW=$HR>h|!jFDMQa&Sfo(sq=!NjQR zn2L*j#dluH|CT4-&VTY7JL>?tKBEk7_q~79JKsjjpPP-46`fSkm9391(9?K86X8yx zN35rx&ftU;u-v=<8$ABdj8(>M8vRwA!rRou;f{*^^T(;ivfL3aB!L`JORDH_l4gWOtwEr4UahV?u%Wm|Kw=COTczmh578WtS=?|7thRWJAf0RcurtXRWxm zxjE4URa_4_qsb)Z`nQ-1hbElZ&btz0M5;G5f@Fz{|U`EQ;D|i{2 zJG!0s9_o78PXe~3!`gCJIjjwaVUGtPtvl!K{+GZ2z^d!r5oBN&W{gDojCxtNa+W!n zr3a$5sD+Yf*CY<3#yQmndH6~hJ1M9f$O48_2!j#H16QSr1)AhnAyXJ^DN(l~$FZVm zW<@{wk)+D^CFabP+DqfH`k$I{tpiox<-iWZxGd`ebCNVNO+Np%(d25M-MW0t>6_l> zVN(uHrE?iD9_Rwp>~RBKVU~n3#oVh{2Er$6p|Qg;PP#NTD`W)DbLkBPh8mNjMo__$ z4}#@|v5-luUMf9L&tIO;*Ck>WUr7OC83&JUvCc?ZyMN>~kW%9s*7fmx!!uPPKlSA ziJAiqC8NJyZ%QdosB|w%_^Mc6j(-l0dR@=x8{@Fa#eNnJ$MNi=e2GcZDtJRKsh4x2 z{sreWs$ij#??-qfEx%1mO6 zEu?~#jzM0|HWBH$>-W`6x)5W1ZgbsfhCcgW$An{K3VUCOqLr31Quxfhwlq4W_&b{O z9VYzu;&1$BhUwX;UAUDz#mCtTh`JyC*N0;)zii-!h6<6-cvQCP zXawEq%PspuKdhyjlgK{a>Q`mU)|zjj(?w{cBi0So{rYbdJiXq>X!@;Q#SM-x3{<{l z6L^s#s3@O)f2B8BKYA?TpTBzxYwkp^d+uP|!ykw2^_H4i+qLN%8zIJnma8T078+$~ z`uO=l;x%F;$Hmx<-B=z`_5asQ>X+3JRXLe$*wP^1uPTx%#MrrZQ z>gK+V)ena8{XREu-Vi~e$j`VTH3rhY*bDvlXD5q~hguc#K*aMY<3Rp_uqvzcy<(i0 z$WwD!sA<%QHq|2H*ZGR`8|y1yiwB90NIOIo?u*-^;v7riFZDqkbY&xv2#_yaX!(SIxNo=Rk78Y7k ztlmU2suzsCMC-9_Y2iXTwa{0s1|QMbJVu$*+ve$A=e6rXLVWDF7%Tpgvo*34H`}>! zKmYMi^=)Vt@*A+$XLLo5Y_Eg^-3Y#CTX>ljFgP#C#=sYa$I+~;Bqa1CBT(PSjmnx1 zi&soCnTx)hOVqi!1@2Gk5n)+s=yskz)kz$zg2Mv5p6y`s8r3rUO+vH5iVC`HFkG#G&tp(^chXJ2misnC%!Gn{xjN?Y&J z@Tk0&wcGjo@15Vf6!?y(K{1@Cob*riAJu0gqx|jET>X?#ITQ)5_yHMROSBx`Ixtpv zBI0r+G^73u<=Zl0q+>>;9Qjmo%h`l5#_{jO4O@^?Nwzm-KH=0zW^E3-Xui$+5s5)} zE)%U5tPJ+2qv*m+%A~TSGA}Gembq5Qx9+KOO?ho`SY;cD|HM-zY-U9;Io`erUAvxt zfu~z!waq{2!774Kxo%M*+5%6`l> zC*ldm?%7@C*sywq-B8X}q|-%CF3l-v9g+J%QZ&9Q$$gMi&pUXThF&lB>t^T6$cg(t zQ{2xYa$(2Mw<~Mpm-O5~VFD~Pj`@~VM z$mc^gf3Z z4wTTPdd|EVAVNxo&)%_hVJM(fX+pc{r4sktw4|bOBisnuw(vMB`{xwAin~UYfmV~O zS!!~~gj&a9B!)u|cuZ;%0y9KTeZ_*UtWO(|IwH8S)5(W@63qpzDuzG{apu9ijrHsQI!8(%%h9Lt4-dI)ncq(`)ufA2D;RuumF*c z>Dr-X3Tk@pByJ*N)AN4o;3SWA{j2kkVkCEgVXm+!vWJ%I1pdXF1;0$;O%0rtuqtxe zqI92YTa+amO$y`|th{~tmcKx|F7P}s@-5zMR}en+8n~DG0}HZCNR}4PH56ypUk%|n z{sb$)=>CTVIHbB-vgPNw*sc&h{ zSz_=9#4oP5Vyh-|To)|=+F*(PWkRMw#(c?~lcTK9f^_cthE3~s53*(8K#+{T0Y&GA zFN}32{G4mp#&Sz65qX)6tyuEn!$Bn0=k#hg0`#My=Yp48kv| zXf8)zs}i`M$^8+`G_(hZkcw~PosQK}48>@Eh(GhjSoe*qa{ozz7I7Fum9LI2=cD{{ zV~wTcB)kDg_1a1BddV{H2t0fJP*QbepO3KI_k}2R^+HDJS0^F$Ueg_QWX)Cfe@l5o zkF4F6?u}H$BA~fVEnV%Lw?{KC--s~j;FrK#^avb9eNGNBtnK3vrciO5CM4-<694ow zT6Zt~>U+WSd&?d(5YM!v^yS6EHNoQk&~ZzS`J>!K^%<~7&NMHcgbnmDEF!$s{v{&%R9F_E=IG`nlUg6qQ0!GQlS`fx5S09(&EE9z{o1 zDWl`i)Mq^Gn}|myrk$_*)Pxam;Xoj(*KEx1s-l^TmyqH;__c)iID}Hfu@`@~YKz9N z44BB|ZaZ9h!5izdfMqJn*uQeHXqHGuHyu1It-n=QHU%zIt@vHh>3K$1u<2)Yi=Q*23LNc=%uEN)q`m3EY z7-CM)UX&7(q1Gxml1{aV=R3y)PE_8-{Y%1Ec^Hj|Ls63I1O z-SJw1`w~5dpofMC^LYnw1ReafdBQt?cQ$TwO%2z@(b*Wh$_ByQH=47>1%t%cu%4kv zaQimKupORBiJWldA1xo>Z()el^71@kt@Qvg5J^fxW|ZU3F}{;_{K*HWV4V8Ium`Lx zMmROL=9DNR&%RCdY$YJ7`)3AT zkhFC5OCl87cTgZR0l3F`=IiJ18X5!$K$-D%|ahQ|2_gJpduvTZJfs5?=_}woDI{wUyr)Bi=~`IZm$gD zTavrm7L;Ali>>saYpL+OkmiyL>6HLtw5xtRhcUx30OF`No^9%}V0kI7F(@D#Fp8x_ zgEaO{Tp5NMyh=*@E?@^0sSqa6xmtp(YT~bOHN|twJc8ZDm20d>Z&Oa${@0Kd^rD-v zkCTHl>;=H(N48X->dzHuw_sY-I%{55Bjj6AM;c`u7R;W+lyqqyfKhPy3Y(rcznchX zMdbV#Zwkhxqs8Q6#|auXs^&yxBeoI`+A?yWhb4*&JlJYKd)MAR(mgwnm5wugq{^6N zwwm^+Lw38kJ+IW;(ch48m`Vpm6rmXEO0#d<7#=D5I{IHAEEh3i!X>p4e{U_HJs>?H zq(C1mZ*3cs6K^nISJMQ-1~NqvSHy~1CaPqsVM^&KWklfk6EOwQPyxD=LsZ*$I2%~D6P5c_heeyDEC_Wqx> z88BWt`O>sWw?Z^imzMTfq$4HyajMdZA3WTIF@V4#A z0@1x^A)HJThW+i1Y&b+Q7}QE1D`h2Sd#CmPF$ynph(3JR2TYO9(a;FxqN40MY(Z*r z%_5@2SNJf$hef<*3xO|?r@a+CA%mzzK z9rTSuc#fKJWI|s&XN)K4m+X1}mvn(+n~rr?3#TCMtYz#~%`uL>pCkB!vr2P~K-m&qwL?`@Xx!8(c(V5xZb<7&$P*5S6BIo(x6+Yx1fbP7r*KcEba!unE(GUhZE+r%i_Qkh?suE+WMJ8OpQ2F^FMtv{Mtc%7 zeXZAR^{V{NPt#Jn8Cr(<=g477GyWe0;m$CGuk=)6#={kxFAcT6`bJJzHwqxc#N=Nb zcLU|$wBFFS()JEf<^_WbZawFFKvu+B~te51;(zy~;uf1gmEJu9p@JxD;Frh&41^Czbc?8dz( zYMv9Z<cZ!XVw&+z>zYPwN+~` zQcgeh1$0g|HvSvdrM`@fcA*%tevB!#`6qx-&Id87q2{B$3~o94{*;RIV5dw+J#m`A zey;vP7v3lDL=ob+-3%hP=GhJN%eoN!qmY6}gQd$fP^j9hw-3@a8a@9{_E9@vAyX}E znNNuQpX{(E^5^YC3xv;`wFAKVMNj&3*l_B4dF3zWYqM6B_0#{4;)aOrOMWjT_UNM@ z_5Ud$B>b|~wkwJep-)Cyp>HaY8;=$lu@rqW9+Lr>rfezxF+w-#>S2h)WHJA&%Z|e+ zx3j|=EPeg|MskUR6gXeP@)>$4EtZFaxGbuwt&?vq-KtuPMyH-6^0W>-LNez|Xq1Zj Sji2DofV{MdRH=kf!2biyP58wC literal 0 HcmV?d00001 diff --git a/js/common.js b/js/common.js index efcaaae2..91b21276 100644 --- a/js/common.js +++ b/js/common.js @@ -52,4 +52,58 @@ jQuery( document ).ready( function() { }); jQuery( 'head' ).append( '' ); + + // Add on installer + jQuery(".install-addon").not('.disabled').click( function(e) { + // Disable other buttons whilst the process is happening. + jQuery(".install-addon").not(this).prop('disabled', true); + + jQuery(this).html( wsalCommonData.installing ); + var currentButton = jQuery(this); + var PluginSlug = jQuery(this).attr('data-plugin-slug'); + var nonceValue = jQuery(this).attr('data-nonce'); + var PluginDownloadUrl = jQuery(this).attr('data-plugin-download-url'); + var RedirectToTab = jQuery(this).attr('data-plugin-event-tab-id'); + jQuery(currentButton).next('.spinner').show('200'); + e.preventDefault(); + jQuery.ajax({ + type: 'POST', + dataType : "json", + url: wsalCommonData.ajaxURL, + data : { + action: "run_addon_install", + plugin_slug: PluginSlug, + plugin_url: PluginDownloadUrl, + _wpnonce: nonceValue + }, + complete: function( data ) { + if( data.responseText == '"already_installed"' ) { + jQuery(currentButton).html( wsalCommonData.already_installed ).addClass('disabled'); + jQuery(currentButton).next('.spinner').hide('200'); + window.location.href="admin.php?page=wsal-togglealerts" + RedirectToTab; + jQuery('[href="' + RedirectToTab + '"]').trigger('click'); + jQuery(currentButton).addClass('disabled'); + } else if ( data.responseText == '"activated"' ) { + jQuery(currentButton).html( wsalCommonData.activated ).addClass('disabled'); + jQuery(currentButton).next('.spinner').hide('200'); + window.location.href="admin.php?page=wsal-togglealerts" + RedirectToTab; + jQuery('[href="' + RedirectToTab + '"]').trigger('click'); + jQuery(currentButton).addClass('disabled'); + } else if ( JSON.stringify(data.responseText).toLowerCase().indexOf('failed') >= 0 ) { + jQuery(currentButton).html( wsalCommonData.failed ).addClass('disabled'); + jQuery(currentButton).next('.spinner').hide('200'); + } else if ( data.responseText == '"success"' || JSON.stringify(data.responseText).toLowerCase().indexOf('success') >= 0 ) { + jQuery(currentButton).html( wsalCommonData.installed ).addClass('disabled'); + jQuery(currentButton).next('.spinner').hide('200'); + window.location.href="admin.php?page=wsal-togglealerts" + RedirectToTab; + // Reload as tabs are not present on page. + location.reload(); + } + jQuery(".install-addon").not(this).prop('disabled', false); + }, + }); + }); + + // Totally disabling the button. + jQuery(".install-addon.disabled").prop('disabled', true); }); diff --git a/wp-security-audit-log.php b/wp-security-audit-log.php index edf09662..06fccf62 100644 --- a/wp-security-audit-log.php +++ b/wp-security-audit-log.php @@ -351,6 +351,10 @@ public function includes() { require_once 'classes/Views/Search.php'; require_once 'classes/Views/Settings.php'; require_once 'classes/Views/ToggleAlerts.php'; + + // Utilities. + require_once 'classes/Utilities/PluginInstallAndActivate.php'; + require_once 'classes/Utilities/PluginInstallerAction.php'; } // Connectors. @@ -420,6 +424,11 @@ public function init_hooks() { add_action( 'wsal_freemius_loaded', array( $this, 'adjust_freemius_strings' ) ); $this->init_freemius(); + + if ( is_admin() ) { + $plugin_installer_ajax = new WSAL_PluginInstallerAction(); + $plugin_installer_ajax->register(); + } } /** From f06b337e813163e8e9e7e827ad33f03deb1666b5 Mon Sep 17 00:00:00 2001 From: William Patton Date: Thu, 30 Jan 2020 12:29:51 +0000 Subject: [PATCH 03/16] :bug: Ensure users with 'no-fs' plugin do not get a fatal error --- wp-security-audit-log.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wp-security-audit-log.php b/wp-security-audit-log.php index 06fccf62..e865e36f 100644 --- a/wp-security-audit-log.php +++ b/wp-security-audit-log.php @@ -889,7 +889,7 @@ public function freemius_show_admin_notice( $show, $msg ) { */ public function adjust_freemius_strings() { // only update these messages if using premium plugin. - if ( ! wsal_freemius()->is_premium() ) { + if ( ( ! wsal_freemius()->is_premium() ) || ( ! method_exists( wsal_freemius(), 'override_il8n' ) ) ) { return; } wsal_freemius()->override_i18n( From 7d30f28be6836c2a64a7bcaee07f8713ec3b458b Mon Sep 17 00:00:00 2001 From: William Patton Date: Thu, 30 Jan 2020 12:34:31 +0000 Subject: [PATCH 04/16] :sparkles: Add new filters for updating event type and object texts --- classes/AlertManager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classes/AlertManager.php b/classes/AlertManager.php index 09687bb5..608754b2 100644 --- a/classes/AlertManager.php +++ b/classes/AlertManager.php @@ -1187,7 +1187,7 @@ public function get_display_object_text( $object ) { break; } - return $display; + return apply_filters( 'wsal_event_object_text', $display, $object ); } /** @@ -1324,7 +1324,7 @@ public function get_display_event_type_text( $event_type ) { break; } - return $display; + return apply_filters( 'wsal_event_type_text', $display, $event_type ); } /** From 173bd4444d3c3455d59e942a9d4b29f066ef854c Mon Sep 17 00:00:00 2001 From: William Patton Date: Thu, 30 Jan 2020 12:36:56 +0000 Subject: [PATCH 05/16] :pencil: Update severity description texts --- defaults.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/defaults.php b/defaults.php index 3e04fc3e..84624476 100644 --- a/defaults.php +++ b/defaults.php @@ -154,11 +154,11 @@ function wsaldefaults_wsal_init() { ) ); - $wsal->constants->AddConstant( 'WSAL_CRITICAL', 1, __( 'Critical, high-impact messages.', 'wp-security-audit-log' ) ); - $wsal->constants->AddConstant( 'WSAL_HIGH', 6, __( 'High severity messages.', 'wp-security-audit-log' ) ); - $wsal->constants->AddConstant( 'WSAL_MEDIUM', 10, __( 'Medium severity messages.', 'wp-security-audit-log' ) ); - $wsal->constants->AddConstant( 'WSAL_LOW', 15, __( 'Low severity messages.', 'wp-security-audit-log' ) ); - $wsal->constants->AddConstant( 'WSAL_INFORMATIONAL', 20, __( 'Run-time notice.', 'wp-security-audit-log' ) ); + $wsal->constants->AddConstant( 'WSAL_CRITICAL', 1, __( 'Critical severity events.', 'wp-security-audit-log' ) ); + $wsal->constants->AddConstant( 'WSAL_HIGH', 6, __( 'High severity events.', 'wp-security-audit-log' ) ); + $wsal->constants->AddConstant( 'WSAL_MEDIUM', 10, __( 'Medium severity events.', 'wp-security-audit-log' ) ); + $wsal->constants->AddConstant( 'WSAL_LOW', 15, __( 'Low severity events.', 'wp-security-audit-log' ) ); + $wsal->constants->AddConstant( 'WSAL_INFORMATIONAL', 20, __( 'Informational events.', 'wp-security-audit-log' ) ); // Create list of default alerts. $wsal->alerts->RegisterGroup( From e55fbb0aaa5a34687d7ebac1755064064926e287 Mon Sep 17 00:00:00 2001 From: William Patton Date: Thu, 30 Jan 2020 12:40:32 +0000 Subject: [PATCH 06/16] :pencil: Altered description text and event type of some events --- classes/Sensors/Content.php | 1 + defaults.php | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/classes/Sensors/Content.php b/classes/Sensors/Content.php index d4799fd5..522c9cee 100644 --- a/classes/Sensors/Content.php +++ b/classes/Sensors/Content.php @@ -541,6 +541,7 @@ public function event_update_term_data( $data, $term_id, $taxonomy, $args ) { 'old_name' => $old_name, 'new_name' => $new_name, 'TagLink' => $term_link, + 'Slug' => $new_slug, ) ); } diff --git a/defaults.php b/defaults.php index 84624476..4fbee852 100644 --- a/defaults.php +++ b/defaults.php @@ -212,7 +212,7 @@ function wsaldefaults_wsal_init() { array( 2120, WSAL_INFORMATIONAL, __( 'User removed post tag', 'wp-security-audit-log' ), __( 'Removed tag(s) from the post %PostTitle% %LineBreak% ID: %PostID% %LineBreak% Type: %PostType% %LineBreak% Status: %PostStatus% %LineBreak% Removed tag(s): %tag% %PostUrlIfPlublished% %LineBreak% %EditorLinkPost%', 'wp-security-audit-log' ), 'post', 'modified' ), array( 2121, WSAL_INFORMATIONAL, __( 'User created new tag', 'wp-security-audit-log' ), __( 'Created the tag %TagName% %LineBreak% Slug: %Slug% %LineBreak% %TagLink%', 'wp-security-audit-log' ), 'tag', 'created' ), array( 2122, WSAL_LOW, __( 'User deleted tag', 'wp-security-audit-log' ), __( 'Deleted the tag %TagName% %LineBreak% Slug: %Slug%', 'wp-security-audit-log' ), 'tag', 'deleted' ), - array( 2123, WSAL_INFORMATIONAL, __( 'User renamed tag', 'wp-security-audit-log' ), __( 'Renamed the tag %old_name% %LineBreak% New name: %new_name% %LineBreak% Slug: %Slug% %LineBreak% %TagLink%', 'wp-security-audit-log' ), 'tag', 'modified' ), + array( 2123, WSAL_INFORMATIONAL, __( 'User renamed tag', 'wp-security-audit-log' ), __( 'Old name: %old_name% %LineBreak% New name: %new_name% %LineBreak% Slug: %Slug% %LineBreak% %TagLink%', 'wp-security-audit-log' ), 'tag', 'renamed' ), array( 2124, WSAL_INFORMATIONAL, __( 'User changed tag slug', 'wp-security-audit-log' ), __( 'Changed the slug of the tag %tag% %LineBreak% Previous slug: %old_slug% %LineBreak% New slug: %new_slug% %LineBreak% %TagLink%', 'wp-security-audit-log' ), 'tag', 'modified' ), array( 2125, WSAL_INFORMATIONAL, __( 'User changed tag description', 'wp-security-audit-log' ), __( 'Changed the description of the tag %tag% %LineBreak% Slug: %Slug% %LineBreak% Previous description: %old_desc% %LineBreak% New description: %new_desc% %LineBreak% %TagLink%', 'wp-security-audit-log' ), 'tag', 'modified' ), ), @@ -230,7 +230,7 @@ function wsaldefaults_wsal_init() { array( 2053, WSAL_LOW, __( 'User created a custom field for a post', 'wp-security-audit-log' ), __( 'Created a new custom field called %MetaKey% in the post %PostTitle% %LineBreak% Post ID: %PostID% %LineBreak% Post Type: %PostType% %LineBreak% Post Status: %PostStatus% %LineBreak% Custom field value: %MetaValue% %PostUrlIfPlublished% %LineBreak% %EditorLinkPost% %LineBreak% %MetaLink%', 'wp-security-audit-log' ), 'post', 'modified' ), array( 2054, WSAL_LOW, __( 'User updated a custom field value for a post', 'wp-security-audit-log' ), __( 'Modified the value of the custom field %MetaKey% in the post %PostTitle% %LineBreak% Post ID: %PostID% %LineBreak% Post Type: %PostType% %LineBreak% Post Status: %PostStatus% %LineBreak% Previous custom field value: %MetaValueOld% %LineBreak% New custom field value: %MetaValueNew% %PostUrlIfPlublished% %LineBreak% %EditorLinkPost% %LineBreak% %MetaLink%.', 'wp-security-audit-log' ), 'custom-field', 'modified' ), array( 2055, WSAL_MEDIUM, __( 'User deleted a custom field from a post', 'wp-security-audit-log' ), __( 'Deleted the custom field %MetaKey% from the post %PostTitle% %LineBreak% Post ID: %PostID% %LineBreak% Post Type: %PostType% %LineBreak% Post Status: %PostStatus% %PostUrlIfPlublished% %LineBreak% %EditorLinkPost%', 'wp-security-audit-log' ), 'custom-field', 'deleted' ), - array( 2062, WSAL_LOW, __( 'User updated a custom field name for a post', 'wp-security-audit-log' ), __( 'Renamed the custom field %MetaKeyOld% in the post %PostTitle% %LineBreak% New name: %MetaKeyNew% %LineBreak% Post ID: %PostID% %LineBreak% Post Type: %PostType% %LineBreak% Post Status: %PostStatus% %PostUrlIfPlublished% %LineBreak% %EditorLinkPost% %LineBreak% %MetaLink%', 'wp-security-audit-log' ), 'custom-field', 'modified' ), + array( 2062, WSAL_LOW, __( 'User updated a custom field name for a post', 'wp-security-audit-log' ), __( 'Old custom field name: %MetaKeyOld% %LineBreak% New custom field name: %MetaKeyNew% %LineBreak% Post: %PostTitle% %LineBreak% Post ID: %PostID% %LineBreak% Post Type:%PostType% %LineBreak% Post Status: %PostStatus% %PostUrlIfPlublished% %LineBreak% %EditorLinkPost%', 'wp-security-audit-log' ), 'custom-field', 'renamed' ), ), /** @@ -275,7 +275,7 @@ function wsaldefaults_wsal_init() { array( 2081, WSAL_MEDIUM, __( 'User deleted menu', 'wp-security-audit-log' ), __( 'Deleted the menu %MenuName%', 'wp-security-audit-log' ), 'menu', 'deleted' ), array( 2082, WSAL_LOW, __( 'User changed menu setting', 'wp-security-audit-log' ), __( 'The setting in the %MenuName% %LineBreak% Setting: %MenuSetting%', 'wp-security-audit-log' ), 'menu', 'enabled' ), array( 2083, WSAL_LOW, __( 'User modified content in a menu', 'wp-security-audit-log' ), __( 'Modified an item in the menu %MenuName% %LineBreak% Item type: %ContentType% %LineBreak% Item name: %ContentName%', 'wp-security-audit-log' ), 'menu', 'modified' ), - array( 2084, WSAL_LOW, __( 'User changed name of a menu', 'wp-security-audit-log' ), __( 'Renamed the menu %OldMenuName% %LineBreak% New name: %NewMenuName%', 'wp-security-audit-log' ), 'menu', 'modified' ), + array( 2084, WSAL_LOW, __( 'User changed name of a menu', 'wp-security-audit-log' ), __( 'Old name: %OldMenuName% %LineBreak% New name: %NewMenuName%', 'wp-security-audit-log' ), 'menu', 'renamed' ), array( 2085, WSAL_LOW, __( 'User changed order of the objects in a menu', 'wp-security-audit-log' ), __( 'Changed the order of the items in the menu %MenuName%', 'wp-security-audit-log' ), 'menu', 'modified' ), array( 2089, WSAL_LOW, __( 'User moved objects as a sub-item', 'wp-security-audit-log' ), __( 'Menu name: %MenuName% %LineBreak% Moved item %ItemName% as a sub-item of %ParentName%', 'wp-security-audit-log' ), 'menu', 'modified' ), ), @@ -550,7 +550,7 @@ function wsaldefaults_wsal_init() { array( 9015, WSAL_MEDIUM, __( 'User changed status of a product', 'wp-security-audit-log' ), __( 'Changed the status of the product %ProductTitle% %LineBreak% ID: %PostID% %LineBreak% Previous status: %OldStatus% %LineBreak% New status: %NewStatus% %LineBreak% %EditorLinkProduct%', 'wp-security-audit-log' ), 'woocommerce-product', 'modified' ), array( 9072, WSAL_INFORMATIONAL, __( 'User opened a product in the editor', 'wp-security-audit-log' ), __( 'Opened the product %ProductTitle% in the editor %LineBreak% ID: %PostID% %LineBreak% Status: %ProductStatus% %LineBreak% %EditorLinkProduct%', 'wp-security-audit-log' ), 'woocommerce-product', 'opened' ), array( 9073, WSAL_INFORMATIONAL, __( 'User viewed a product', 'wp-security-audit-log' ), __( 'Viewed the product %ProductTitle% page %LineBreak% ID: %PostID% %LineBreak% Status: %ProductStatus% %LineBreak% %EditorLinkProduct%', 'wp-security-audit-log' ), 'woocommerce-product', 'viewed' ), - array( 9077, WSAL_MEDIUM, __( 'User renamed a product', 'wp-security-audit-log' ), __( 'Renamed the product %ProductTitle% %LineBreak% ID: %PostID% %LineBreak% Status: %ProductStatus% %LineBreak% Previous name: %OldTitle% %LineBreak% New name: %NewTitle% %LineBreak% %EditorLinkProduct%', 'wp-security-audit-log' ), 'woocommerce-product', 'modified' ), + array( 9077, WSAL_MEDIUM, __( 'User renamed a product', 'wp-security-audit-log' ), __( 'Old name: %OldTitle% %LineBreak% New name: %NewTitle% %LineBreak% ID: %PostID% %LineBreak% Status: %ProductStatus% %LineBreak% %EditorLinkProduct%', 'wp-security-audit-log' ), 'woocommerce-product', 'renamed' ), array( 9016, WSAL_MEDIUM, __( 'User changed type of a price', 'wp-security-audit-log' ), __( 'Changed the %PriceType% of the product %ProductTitle% %LineBreak% ID: %PostID% %LineBreak% Status: %ProductStatus% %LineBreak% Previous price: %OldPrice% %LineBreak% New price: %NewPrice% %LineBreak% %EditorLinkProduct%', 'wp-security-audit-log' ), 'woocommerce-product', 'modified' ), array( 9017, WSAL_MEDIUM, __( 'User changed the SKU of a product', 'wp-security-audit-log' ), __( 'Changed the SKU of the product %ProductTitle% %LineBreak% ID: %PostID% %LineBreak% Status: %ProductStatus% %LineBreak% Previous SKU: %OldSku% %LineBreak% New SKU: %NewSku% %LineBreak% %EditorLinkProduct%', 'wp-security-audit-log' ), 'woocommerce-product', 'modified' ), array( 9018, WSAL_LOW, __( 'User changed the stock status of a product', 'wp-security-audit-log' ), __( 'Changed the stock status of the product %ProductTitle% %LineBreak% ID: %PostID% %LineBreak% Status: %ProductStatus% %LineBreak% Previous stock status: %OldStatus% %LineBreak% New stock status: %NewStatus% %LineBreak% %EditorLinkProduct%', 'wp-security-audit-log' ), 'woocommerce-product', 'modified' ), @@ -626,7 +626,7 @@ function wsaldefaults_wsal_init() { array( 9068, WSAL_LOW, __( 'User changed the usage limits settings of a coupon', 'wp-security-audit-log' ), __( 'Changed the Usage Limits of the coupon %CouponName% %LineBreak% Previous usage limits: %OldMetaValue% %LineBreak% New usage limits: %NewMetaValue% %LineBreak% %EditorLinkCoupon%', 'wp-security-audit-log' ), 'woocommerce-store', 'modified' ), array( 9069, WSAL_INFORMATIONAL, __( 'User changed the description of a coupon', 'wp-security-audit-log' ), __( 'Changed the description of the coupon %CouponName% %LineBreak% Previous description: %OldDescription% %LineBreak% New description: %NewDescription% %LineBreak% %EditorLinkCoupon%', 'wp-security-audit-log' ), 'woocommerce-store', 'modified' ), array( 9070, E_WARNING, __( 'User changed the status of a coupon', 'wp-security-audit-log' ), __( 'Changed the Status of the WooCommerce coupon %CouponName% from %OldStatus% to %NewStatus%.', 'wp-security-audit-log' ), 'woocommerce-store' ), - array( 9071, WSAL_INFORMATIONAL, __( 'User renamed a WooCommerce coupon', 'wp-security-audit-log' ), __( 'Renamed the coupon %OldName% %LineBreak% New name: %NewName% %LineBreak% %LineBreak% %EditorLinkCoupon%', 'wp-security-audit-log' ), 'woocommerce-store', 'modified' ), + array( 9071, WSAL_INFORMATIONAL, __( 'User renamed a WooCommerce coupon', 'wp-security-audit-log' ), __( 'Old coupon name: %OldName% %LineBreak% New coupon name: %NewName% %LineBreak% %EditorLinkCoupon%', 'wp-security-audit-log' ), 'woocommerce-store', 'renamed' ), ), __( 'Orders', 'wp-security-audit-log' ) => array( From 66e684c18f4abf96d629677cd0494551954428be Mon Sep 17 00:00:00 2001 From: William Patton Date: Thu, 30 Jan 2020 12:43:32 +0000 Subject: [PATCH 07/16] :pencil2: Add 'renamed' and 'duplicated' to event types --- classes/AlertManager.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/classes/AlertManager.php b/classes/AlertManager.php index 608754b2..a178eee6 100644 --- a/classes/AlertManager.php +++ b/classes/AlertManager.php @@ -1223,6 +1223,8 @@ public function get_event_type_data() { 'stopped' => __( 'Stopped', 'wp-security-audit-log' ), 'removed' => __( 'Removed', 'wp-security-audit-log' ), 'unblocked' => __( 'Unblocked', 'wp-security-audit-log' ), + 'renamed' => __( 'Renamed', 'wp-security-audit-log' ), + 'duplicated' => __( 'Duplicated', 'wp-security-audit-log' ), ); // sort the types alphabetically. asort( $types ); @@ -1320,6 +1322,12 @@ public function get_display_event_type_text( $event_type ) { case 'unblocked': $display = __( 'Unblocked', 'wp-security-audit-log' ); break; + case 'renamed': + $display = __( 'Renamed', 'wp-security-audit-log' ); + break; + case 'duplicated': + $display = __( 'Duplicated', 'wp-security-audit-log' ); + break; default: break; } From b4929dd89c154f6bbdac13c0e98b23a21d1adbe1 Mon Sep 17 00:00:00 2001 From: William Patton Date: Thu, 30 Jan 2020 12:46:45 +0000 Subject: [PATCH 08/16] :pencil: Update addon installer strings --- wp-security-audit-log.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/wp-security-audit-log.php b/wp-security-audit-log.php index e865e36f..b4ab396d 100644 --- a/wp-security-audit-log.php +++ b/wp-security-audit-log.php @@ -1117,8 +1117,13 @@ public function render_footer() { // Set data array for common script. $script_data = array( - 'ajaxURL' => admin_url( 'admin-ajax.php' ), - 'liveEvents' => $live_events_enabled, + 'ajaxURL' => admin_url( 'admin-ajax.php' ), + 'liveEvents' => $live_events_enabled, + 'installing' => __( 'Installing, please wait', 'wp-security-audit-log' ), + 'already_installed' => __( 'Already installed', 'wp-security-audit-log' ), + 'installed' => __( 'Addon installed', 'wp-security-audit-log' ), + 'activated' => __( 'Addon activated', 'wp-security-audit-log' ), + 'failed' => __( 'Install failed', 'wp-security-audit-log' ), ); if ( $live_events_enabled ) { $occurrence = new WSAL_Models_Occurrence(); From 7c78687fdf04c6b7af0c3564a26b1bc025e0de0f Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Sat, 1 Feb 2020 11:10:44 +0000 Subject: [PATCH 09/16] :sparkles: Add WPForms addon to list of installbale plugins --- classes/Utilities/PluginInstallAndActivate.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/classes/Utilities/PluginInstallAndActivate.php b/classes/Utilities/PluginInstallAndActivate.php index 27e27bcc..1f179b5d 100644 --- a/classes/Utilities/PluginInstallAndActivate.php +++ b/classes/Utilities/PluginInstallAndActivate.php @@ -129,13 +129,13 @@ public static function get_installable_plugins() { // 'plugin_url' => 'https://downloads.wordpress.org/plugin/wp-bootstrap-blocks.latest-stable.zip', // TODO: make this match live url. // 'event_tab_id' => '#tab-bbpress-forums', // ), - // array( - // 'title' => 'WPForms Add-on', - // 'image_filename' => 'wpforms.png', - // 'plugin_slug' => 'google-sitemap-generator/sitemap.php', - // 'plugin_url' => 'https://downloads.wordpress.org/plugin/google-sitemap-generator.latest-stable.zip', // TODO: make this match live URL. - // 'event_tab_id' => '#tab-wpforms', - // ), + array( + 'title' => 'WPForms Add-on', + 'image_filename' => 'wpforms.png', + 'plugin_slug' => 'wp-security-audit-log-add-on-for-wpforms/wsal-wpforms.php', + 'plugin_url' => 'https://downloads.wordpress.org/plugin/wp-security-audit-log-add-on-for-wpforms.latest-stable.zip', + 'event_tab_id' => '#tab-wpforms', + ), array( 'title' => 'Yoast SEO', 'image_filename' => 'yoast.png', From cfe5aed2de4a2a76047444345bd75b1980e9f83d Mon Sep 17 00:00:00 2001 From: William Patton Date: Tue, 4 Feb 2020 16:37:16 +0000 Subject: [PATCH 10/16] :sparkles: add new filters to modifying the quicktags used in formatter --- classes/Settings.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/classes/Settings.php b/classes/Settings.php index cd118571..947d3d77 100644 --- a/classes/Settings.php +++ b/classes/Settings.php @@ -1748,7 +1748,12 @@ public function meta_formatter( $name, $value, $occ_id, $highlight ) { case strncmp( $value, 'http://', 7 ) === 0: case strncmp( $value, 'https://', 8 ) === 0: - return '' . esc_html( $value ) . ''; + $updated_line = apply_filters( 'wsal_link_filter', $value, $name ); + if ( $updated_line !== $value ) { + return $updated_line; + } else { + return '' . esc_html( $value ) . ''; + } case in_array( $name, array( '%PostStatus%', '%ProductStatus%' ), true ): if ( ! empty( $value ) && 'publish' === $value ) { @@ -1802,7 +1807,9 @@ public function meta_formatter( $name, $value, $occ_id, $highlight ) { return $highlight_start_tag . dirname( $value ) . $highlight_end_tag; default: - return $highlight_start_tag . esc_html( $value ) . $highlight_end_tag; + // if we didn't get a match already try get one via a filter. + $filtered_formatted_value = apply_filters( 'wsal_meta_formatter_custom_formatter', $value, $name ); + return ( $value !== $filtered_formatted_value ) ? $filtered_formatted_value : $highlight_start_tag . esc_html( $value ) . $highlight_end_tag; } } From a314a8f4f98a7a355b314fec628147199001a8f0 Mon Sep 17 00:00:00 2001 From: William Patton Date: Tue, 4 Feb 2020 16:38:52 +0000 Subject: [PATCH 11/16] :bug: update plugin to account for alert groups with varying depths --- classes/AlertManager.php | 47 ++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/classes/AlertManager.php b/classes/AlertManager.php index a178eee6..77cb52b4 100644 --- a/classes/AlertManager.php +++ b/classes/AlertManager.php @@ -433,27 +433,56 @@ public function Register( $info ) { * Register a whole group of items. * * @param array $groups - An array with group name as the index and an array of group items as the value. - * Item values is an array of [type, code, description, message] respectively. + * Item values is an array of [type, code, description, message, object, event type] respectively. */ public function RegisterGroup( $groups ) { foreach ( $groups as $name => $group ) { foreach ( $group as $subname => $subgroup ) { - foreach ( $subgroup as $item ) { - if ( ! isset( $item[4] ) ) { - $item[4] = ''; // Set default event object. - } + // Check to see if this ground has any subgroups + if( $this->GetArrayDepth( $group ) > 1 ) { + foreach ( $subgroup as $item ) { + if ( ! isset( $item[4] ) ) { + $item[4] = ''; // Set default event object. + } + + if ( ! isset( $item[5] ) ) { + $item[5] = ''; // Set default event type. + } - if ( ! isset( $item[5] ) ) { - $item[5] = ''; // Set default event type. + list( $type, $code, $desc, $mesg, $object, $event_type ) = $item; + $this->Register( array( $type, $code, $name, $subname, $desc, $mesg, $object, $event_type ) ); } + // If no subgroups are found, process them accordingly. + } else { + foreach ( $group as $item ) { + if ( ! isset( $item[4] ) ) { + $item[4] = ''; // Set default event object. + } + + if ( ! isset( $item[5] ) ) { + $item[5] = ''; // Set default event type. + } - list( $type, $code, $desc, $mesg, $object, $event_type ) = $item; - $this->Register( array( $type, $code, $name, $subname, $desc, $mesg, $object, $event_type ) ); + list( $type, $code, $desc, $mesg, $object, $event_type ) = $item; + $this->Register( array( $type, $code, $name, $subname, $desc, $mesg, $object, $event_type ) ); + } } } } } + public function GetArrayDepth( $array ) { + $depth = 0; + $iteIte = new RecursiveIteratorIterator( new RecursiveArrayIterator( $array ) ); + + foreach ($iteIte as $ite) { + $d = $iteIte->getDepth(); + $depth = $d > $depth ? $d : $depth; + } + + return $depth; + } + /** * Duplicate Event Notice * From 1357a43f2773b2af9e93a5768ebd163e70550bd7 Mon Sep 17 00:00:00 2001 From: William Patton Date: Tue, 4 Feb 2020 16:40:44 +0000 Subject: [PATCH 12/16] :speech_balloon: Update some strings used by the install and activator --- wp-security-audit-log.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wp-security-audit-log.php b/wp-security-audit-log.php index b4ab396d..6d3f2021 100644 --- a/wp-security-audit-log.php +++ b/wp-security-audit-log.php @@ -1121,8 +1121,8 @@ public function render_footer() { 'liveEvents' => $live_events_enabled, 'installing' => __( 'Installing, please wait', 'wp-security-audit-log' ), 'already_installed' => __( 'Already installed', 'wp-security-audit-log' ), - 'installed' => __( 'Addon installed', 'wp-security-audit-log' ), - 'activated' => __( 'Addon activated', 'wp-security-audit-log' ), + 'installed' => __( 'Add-on installed', 'wp-security-audit-log' ), + 'activated' => __( 'Add-on activated', 'wp-security-audit-log' ), 'failed' => __( 'Install failed', 'wp-security-audit-log' ), ); if ( $live_events_enabled ) { From bcd5132524ec9754fb109341974e1e7a1bf75697 Mon Sep 17 00:00:00 2001 From: William Patton Date: Tue, 4 Feb 2020 16:41:35 +0000 Subject: [PATCH 13/16] :pencil: Update install and activator data and sanitization --- .../Utilities/PluginInstallAndActivate.php | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/classes/Utilities/PluginInstallAndActivate.php b/classes/Utilities/PluginInstallAndActivate.php index 1f179b5d..cde9d1de 100644 --- a/classes/Utilities/PluginInstallAndActivate.php +++ b/classes/Utilities/PluginInstallAndActivate.php @@ -76,38 +76,42 @@ public function render() { $our_plugins = $this->get_installable_plugins(); ?> -

+

- - - + + +
+ + +
+

+


-
@@ -130,18 +134,12 @@ public static function get_installable_plugins() { // 'event_tab_id' => '#tab-bbpress-forums', // ), array( - 'title' => 'WPForms Add-on', - 'image_filename' => 'wpforms.png', - 'plugin_slug' => 'wp-security-audit-log-add-on-for-wpforms/wsal-wpforms.php', - 'plugin_url' => 'https://downloads.wordpress.org/plugin/wp-security-audit-log-add-on-for-wpforms.latest-stable.zip', - 'event_tab_id' => '#tab-wpforms', - ), - array( - 'title' => 'Yoast SEO', - 'image_filename' => 'yoast.png', - 'plugin_slug' => 'wordpress-seo/wp-seo.php', - 'plugin_url' => 'https://downloads.wordpress.org/plugin/wordpress-seo.latest-stable.zip', // TODO: make this match live URL. - 'event_tab_id' => '#tab-yoast-seo', + 'title' => 'WPForms', + 'image_filename' => 'wpforms.png', + 'plugin_slug' => 'wp-security-audit-log-add-on-for-wpforms/wsal-wpforms.php', + 'plugin_url' => 'https://downloads.wordpress.org/plugin/wp-security-audit-log-add-on-for-wpforms.latest-stable.zip', + 'event_tab_id' => '#tab-wpforms', + 'plugin_description' => 'Keep a record of when someone adds, modified or delete forms, entries and more in the WPForms plugin.', ), ); // runs through a filter so it can be added to programatically. From cc9756c7a86a8df34f24c9c4ce2b31ef22b50db5 Mon Sep 17 00:00:00 2001 From: William Patton Date: Tue, 4 Feb 2020 16:42:31 +0000 Subject: [PATCH 14/16] :art: Update some styles for tabs and don't show save button on install page --- classes/Views/ToggleAlerts.php | 16 ++++++++++++++++ js/common.js | 14 ++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/classes/Views/ToggleAlerts.php b/classes/Views/ToggleAlerts.php index 6fdb97ca..53c77e64 100644 --- a/classes/Views/ToggleAlerts.php +++ b/classes/Views/ToggleAlerts.php @@ -787,6 +787,22 @@ public function Header() { table#tab-frontend-events tr:nth-child(12) td:first-child { padding-left: 10px; } + [href="#tab-0" i], [data-parent="tab-wpforms"] { + display: none; + } + .addon-wrapper img { + max-width: 200px; + } + .addon-wrapper { + max-width: 25%; + display: inline-block; + border: 1px solid #eee; + padding: 20px; + text-align: center; + } + .addon-wrapper:hover { + border: 1px solid #ccc; + } Date: Mon, 10 Feb 2020 20:13:27 +0100 Subject: [PATCH 15/16] updated changelog + up version --- readme.txt | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/readme.txt b/readme.txt index cb05fb78..bdc411d9 100644 --- a/readme.txt +++ b/readme.txt @@ -6,7 +6,7 @@ License URI: https://www.gnu.org/licenses/gpl.html Tags: wordpress security plugin, wordpress security audit log, audit log, activity logs, event log wordpress, wordpress user tracking, wordpress activity log, wordpress audit, security event log, audit trail, wordpress security monitor, wordpress admin, wordpress admin monitoring, user activity, admin, multisite, dashboard, notification, wordpress monitoring, email notification, wordpress email alerts, SMS messages, tracking, user tracking, user activity report, wordpress audit trail Requires at least: 3.6 Tested up to: 5.3.2 -Stable tag: 4.0.0 +Stable tag: 4.0.1 Requires PHP: 5.5 An easy to use & comprehensive WordPress activity log plugin to log all changes on WordPress sites & multisite networks. @@ -153,9 +153,10 @@ We need help translating the plugin and the WordPress Security Alerts. Please vi * Spanish translation by the [WP Body team](https://wpbody.com/) * French translations by Denis Moscato -#### Activity Log Extensions +#### Activity Log add-ons for third party plugins -* [Activity Log for MainWP](https://www.wpsecurityauditlog.com/activity-log-mainwp-extension/?utm_source=wordpress.org&utm_medium=referral&utm_campaign=WSAL&utm_content=plugin+repos+description): This extension allows you to keep a log of MainWP network changes and to view the activity logs of all child sites from one central location - the MainWP dashboard. +* [Activity Log for MainWP](https://www.wpsecurityauditlog.com/activity-log-mainwp-extension/): This MainWP extension allows you to keep a log of MainWP network changes and to view the activity logs of all child sites from one central location - the MainWP dashboard. +* [Activity Log add-on for WPForms](https://www.wpsecurityauditlog.com/integrations/activity-log-wpforms/): Install this add-on with the WP Security Audit Log to keep a log of changes in WPForms plugin, forms, form files, entries (leads) and more. #### Related Links and Documentation @@ -202,30 +203,31 @@ Please refer to our [Support & Documentation pages](https://www.wpsecurityauditl == Changelog == -= 4.0.0 (2020-01-09) = += 4.0.1 (2020-02-13) = -Release notes: [Update 4.0.0 - New UI & activity log metadata](https://www.wpsecurityauditlog.com/releases/update-4/) +Release notes: [Update 4.0.1 - activity logs for WPForms](https://www.wpsecurityauditlog.com/releases/update-4-0-1/) * **New features** - * New activity log viewer with two different view modes: grid and list view. - * Two new types of [WodPress activity log metadata](https://www.wpsecurityauditlog.com/support-documentation/metadata-wordpress-activity-log-events/): event type and object. OPTIONAL: [Upgrade old activity log data to v4](https://www.wpsecurityauditlog.com/support-documentation/activity-log-data-upgrade-plugin/). - * New [WordPress activity log severity levels](https://www.wpsecurityauditlog.com/support-documentation/severity-levels-wordpress-activity-log/) (and icons). - * New UI / UX for the [WordPress activity log search & filters](https://www.wpsecurityauditlog.com/premium-features/search-filters-wordpress-activity-log/). - * Added search filters for the two new metadata types in the activity logs: event type and object. + * [Activity logs for WPForms](http://www.wpsecurityauditlog.com/integrations/activity-log-wpforms/' + * One-click installation and activation feature for new third party plugins add-ons. + * New Third Party Plugins tab in Enable/Disable Events section to allow users to install add-ons for third party plugins. + * Added the new event types "Renamed" and "Duplicated" (more on [activity log event types](https://www.wpsecurityauditlog.com/support-documentation/objects-event-types-wordpress-activity-log/)). + * Added several new [hooks in the plugin](https://www.wpsecurityauditlog.com/support-documentation/list-hooks/), mainly to allow custom editor link, to add custom column to the logs viewer, to add new event types and objects. * **Improvements** - * Updated the severity levels of all activity log events. - * Included the two new metadata types in the email notification templates (event type and object metadata). - * Added a notification to refresh search when the filters change. - * Added several new reference links in the plugin's help text. - + * Updated event IDs 2123, 2062, 2084, 9077 and 9071 so they now use the "Renamed" event type. + * Updated the [activity log severity levels](https://www.wpsecurityauditlog.com/support-documentation/severity-levels-wordpress-activity-log/' definitions in defaults.php) + * Updated / improved some of the help text messages. + * Plugin does not automatically retrieve the IP addresses and latest change of logged in users if there are 100+ sessions (performance improvement). + * Localized text in JS files. + * Started removing obsolete code. + * Added new filter to allow custom %EditorLinkWPForm% from custom events add-ons. + * **Bug fixes** - * Addressed a warning message in the logs generated by the connector when using PHP 7.4. - * Fixed an issue which was triggered when using the User Switching filter hook. - * Few spelling mistakes in the plugin's UI and settings pages. + * Only the path of the added, modified or deleted file was reported in daily summary email. = Earlier versions = From 1963d773694d714186597420386d67123514ba23 Mon Sep 17 00:00:00 2001 From: WP White Security Date: Mon, 10 Feb 2020 20:13:53 +0100 Subject: [PATCH 16/16] upped version to 4.0.1 --- wp-security-audit-log.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wp-security-audit-log.php b/wp-security-audit-log.php index 6d3f2021..12424f51 100644 --- a/wp-security-audit-log.php +++ b/wp-security-audit-log.php @@ -4,7 +4,7 @@ * Plugin URI: http://www.wpsecurityauditlog.com/ * Description: Identify WordPress security issues before they become a problem. Keep track of everything happening on your WordPress including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Security Audit Log generates a security alert for everything that happens on your WordPress blogs and websites. Use the Audit Log Viewer included in the plugin to see all the security alerts. * Author: WP White Security - * Version: 4.0.0 + * Version: 4.0.1 * Text Domain: wp-security-audit-log * Author URI: http://www.wpwhitesecurity.com/ * License: GPL2 @@ -46,7 +46,7 @@ class WpSecurityAuditLog { * * @var string */ - public $version = '4.0.0'; + public $version = '4.0.1'; // Plugin constants. const PLG_CLS_PRFX = 'WSAL_';