The main plugin code, NP_Paranoia.php
<? /* NP_Paranoia ----------- Nucleus plugin to notify of new account creation, account deletion and successful and failed login attempts. Why? My blog has been hacked a couple of times - once it had the site headers tweaked to add spam links, although I can't find anything changed from the second hack other than the creation of another member account. I did notice a number of failed login attempts for my own account in the action log though. So, this should at least let me know by email when/if this happens again. To do list 1) Look into more graceful upgrade options from PluginDevWiki 2) Contemplate value of logging successful and failed logins to action log as this already happens - although NP_Paranoia logs IP address as well. 3) Other possible features: a) Alert on NP_Paranoia being uninstalled b) Alert on NP_Paranoia options changed c) Alert on member options changed 4) Must learn to code properly... History v0.1 - Initial version (Kevin Whitworth) Finally, a couple of thank you's: 1) Base plugin structure taken from NP_PingPong - thanks admun! 2) Email sending taken from NP_NewAccount - thanks Gen! */ class NP_Paranoia extends NucleusPlugin { function getName() { return 'Paranoia'; } function getAuthor() { return 'Kevin Whitworth'; } function getURL() { return 'http://www.jacurutu.org.uk/nucleuscms/'; } function getVersion() { return '0.1'; } function getMinNucleusVersion() { return '330'; } function getDescription() { return _PARANOIA_DESC; } // TODO must check what this does - better leave it for now... function supportsFeature($what) { switch($what) { case 'SqlTablePrefix': return 1; default: return 0; } } function init() { $language = ereg_replace( '[\\|/]', '', getLanguageName()); if (file_exists($this->getDirectory() . $language . '.php')) { include_once($this->getDirectory() . $language . '.php'); }else { include_once($this->getDirectory() . 'english.php'); } } function install() { $this->createOption('pna_emailadd',_PARANOIA_EMAILADDRESS,'text',''); // Email address to send alerts to $this->createOption('pna_newmem',_PARANOIA_ALERTNEWMEMBER,'yesno','yes'); // Notify new member $this->createOption('pna_delmem',_PARANOIA_ALERTDELETEMEMBER,'yesno','yes'); // Notify member deletion $this->createOption('pna_failed',_PARANOIA_ALERTFAILEDLOGIN,'yesno','yes'); // Notify on successful login $this->createOption('pna_success',_PARANOIA_ALERTSUCCESSFULLOGIN,'yesno','no'); // Notify on successful login $this->createOption('pna_log',_PARANOIA_LOG, 'yesno', 'no'); // Enables Action Log logging of each enabled alert } function getEventList() { return array('PostRegister', 'PreDeleteMember', 'LoginSuccess', 'LoginFailed'); } // New Member Account Created Event function event_PostRegister($data) { // $data is 'MEMBER' object // TODO check whether this is needed? global $DIR_PLUGINS, $DIR_NUCLEUS; // Check whether alert new member option set if($this->getOption('pna_newmem') == "yes") { //extract member name $newmember = $data['member']; $newmemberdisplayname = $newmember->getDisplayName(); // TODO consider turning the email section into a separate function // Get email address set in options $alert_email = $this->getOption('pna_emailadd'); //send alerts to this email // get admin email from '.sql_table('config').' for the 'from' header in both messages $the_admin_email = "SELECT value FROM ".sql_table('config')." WHERE name = 'AdminEmail'"; $admin_email = mysql_result(mysql_query($the_admin_email),0); // if no alert email specified, send alert to admin email if (!$alert_email) { $alert_email = $admin_email; } // Set from address to admin email $from = "From: $admin_email\n"; // Create subject from definitions $alert_subject = _PARANOIA_NEWMEMBERMESSAGESUBJECT; // create message body // TODO note this could probably be done better - possibly separate file (eg as per NP_NewAccount) or via string replacements from language file definitions $alert_message = _PARANOIA_NEWMEMBERMESSAGEBODY . " " . $newmemberdisplayname; // Send the alert email mail($alert_email, $alert_subject, $alert_message, $from); // Check whether to log in ActionLog if($this->getOption('pna_log') == "yes") { // Log an INFO item to action log stating name of member and submitting IP address ACTIONLOG::add(INFO, _PARANOIA_NEWMEMBERACTIONLOG . ': ' . $newmemberdisplayname . ', ' . _PARANOIA_IPADDRESS . ': ' . getenv('REMOTE_ADDR')); } } } // Member Account Deleted Event function event_PreDeleteMember($data) { // $data is 'MEMBER' object // TODO check whether this is needed? global $DIR_PLUGINS, $DIR_NUCLEUS; // Check whether alert new member option set if($this->getOption('pna_delmem') == "yes") { //extract member name $delmember = $data['member']; $delmemberdisplayname = $delmember->getDisplayName(); // TODO consider turning the email section into a separate function // Get email address set in options $alert_email = $this->getOption('pna_emailadd'); //send alerts to this email // get admin email from '.sql_table('config').' for the 'from' header in both messages $the_admin_email = "SELECT value FROM ".sql_table('config')." WHERE name = 'AdminEmail'"; $admin_email = mysql_result(mysql_query($the_admin_email),0); // if no alert email specified, send alert to admin email if (!$alert_email) { $alert_email = $admin_email; } // Set from address to admin email $from = "From: $admin_email\n"; // Create subject from definitions $alert_subject = _PARANOIA_DELETEMEMBERMESSAGESUBJECT; // create message body // TODO note this could probably be done better - possibly separate file (eg as per NP_NewAccount) or via string replacements from language file definitions $alert_message = _PARANOIA_DELETEDMEMBERMESSAGEBODY . " " . $delmemberdisplayname; // Send the alert email mail($alert_email, $alert_subject, $alert_message, $from); // Check whether to log in ActionLog if($this->getOption('pna_log') == "yes") { // Log an INFO item to action log stating name of member and submitting IP address ACTIONLOG::add(INFO, _PARANOIA_DELETEDMEMBERACTIONLOG . ': ' . $delmemberdisplayname . ', ' . _PARANOIA_IPADDRESS . ': ' . getenv('REMOTE_ADDR')); } } } // Login Success Event function event_LoginSuccess($data) { // $data is 'MEMBER' object // check whether this is needed? global $DIR_PLUGINS, $DIR_NUCLEUS; // Check whether alert new member option set if($this->getOption('pna_success') == "yes") { //extract member name $loginmember = $data['member']; $loginmemberdisplayname = $loginmember->getDisplayName(); // TODO consider turning the email section into a separate function // Get email address set in options $alert_email = $this->getOption('pna_emailadd'); //send alerts to this email // get admin email from '.sql_table('config').' for the 'from' header in both messages $the_admin_email = "SELECT value FROM ".sql_table('config')." WHERE name = 'AdminEmail'"; $admin_email = mysql_result(mysql_query($the_admin_email),0); // if no alert email specified, send alert to admin email if (!$alert_email) { $alert_email = $admin_email; } // Set from address to admin email $from = "From: $admin_email\n"; // Create subject from definitions $alert_subject = _PARANOIA_LOGINSUCCESSMESSAGESUBJECT; // create message body // note this could probably be done better - possibly separate file (eg as per NP_NewAccount) // or via string replacements from language file definitions $alert_message = _PARANOIA_LOGINSUCCESSMESSAGEBODY . " " . $loginmemberdisplayname; // Send the alert email mail($alert_email, $alert_subject, $alert_message, $from); // Check whether to log in ActionLog if($this->getOption('pna_log') == "yes") { // Log an INFO item to action log stating name of member and submitting IP address ACTIONLOG::add(INFO, _PARANOIA_LOGINSUCCESSACTIONLOG . ': ' . $loginmemberdisplayname . ', ' . _PARANOIA_IPADDRESS . ': ' . getenv('REMOTE_ADDR')); } } } // Login Failed Event function event_LoginFailed($data) { // $data is 'username' // check whether this is needed? global $DIR_PLUGINS, $DIR_NUCLEUS; // Check whether alert new member option set if($this->getOption('pna_failed') == "yes") { //extract username $username = $data['username']; // TODO consider turning the email section into a separate function // Get email address set in options $alert_email = $this->getOption('pna_emailadd'); //send alerts to this email // get admin email from '.sql_table('config').' for the 'from' header in both messages $the_admin_email = "SELECT value FROM ".sql_table('config')." WHERE name = 'AdminEmail'"; $admin_email = mysql_result(mysql_query($the_admin_email),0); // if no alert email specified, send alert to admin email if (!$alert_email) { $alert_email = $admin_email; } // Set from address to admin email $from = "From: $admin_email\n"; // Create subject from definitions $alert_subject = _PARANOIA_LOGINFAILEDMESSAGESUBJECT; // create message body // note this could probably be done better - possibly separate file (eg as per NP_NewAccount) // or via string replacements from language file definitions $alert_message = _PARANOIA_LOGINFAILEDMESSAGEBODY . " " . $username; // Send the alert email mail($alert_email, $alert_subject, $alert_message, $from); // Check whether to log in ActionLog if($this->getOption('pna_log') == "yes") { // Log a WARNING item to action log stating username and submitting IP address ACTIONLOG::add(WARNING, _PARANOIA_LOGINFAILEDACTIONLOG . ': ' . $username . ', ' . _PARANOIA_IPADDRESS . ': ' . getenv('REMOTE_ADDR')); } } } } ?>
You'll also need the language file (or files if anyone wants to translate it) which live in the 'paranoia' subdirectory, starting with english.php
<?php // Options text define('_PARANOIA_DESC', 'This plugin sends an email when a new member account is created, and alerts when successful or failed login attempts occur.'); define('_PARANOIA_EMAILADDRESS', 'Email address to send alerts to - leave blank to use admin email address'); define('_PARANOIA_ALERTNEWMEMBER', 'Email when a new member account is created'); define('_PARANOIA_ALERTDELETEMEMBER', 'Email when a member account is deleted'); define('_PARANOIA_ALERTSUCCESSFULLOGIN', 'Email when a member successfully logs in'); define('_PARANOIA_ALERTFAILEDLOGIN', 'Email when a member fails to logs in'); define('_PARANOIA_LOG', 'Log recorded events to action log'); // Email message text define('_PARANOIA_NEWMEMBERMESSAGESUBJECT', 'New member account created'); // Alert email subject for new member created define('_PARANOIA_DELETEMEMBERMESSAGESUBJECT', 'Nember account deleted'); // Alert email subject for member deleted define('_PARANOIA_LOGINFAILEDMESSAGESUBJECT', 'Login failure'); // Alert email subject for login failed define('_PARANOIA_LOGINSUCCESSMESSAGESUBJECT', 'Login success'); // Alert email subject for login success define('_PARANOIA_NEWMEMBERMESSAGEBODY', 'A new account was created for'); // Alert email body for new member created define('_PARANOIA_DELETEDMEMBERMESSAGEBODY', 'The member account was deleted for'); // Alert email body for member deleted define('_PARANOIA_LOGINFAILEDMESSAGEBODY', 'A login attempt failed for'); // Alert email body for login failed define('_PARANOIA_LOGINSUCCESSMESSAGEBODY', 'A login attempt was successful for'); // Alert email body for login success // Action log messages define('_PARANOIA_NEWMEMBERACTIONLOG', 'NP_Paranoia: new account created. Member'); // ActionLog message for new account define('_PARANOIA_DELETEDMEMBERACTIONLOG', 'NP_Paranoia: account deleted. Member'); // ActionLog message for account deleted define('_PARANOIA_LOGINFAILEDACTIONLOG', 'NP_Paranoia: login failed. Username'); // ActionLog message for login failed define('_PARANOIA_LOGINSUCCESSACTIONLOG', 'NP_Paranoia: login success. Member'); // ActionLog message for login success define('_PARANOIA_IPADDRESS', 'IP address'); // IP address - no idea if this is different in other languages, so it's here just in case! ?>