aboutsummaryrefslogtreecommitdiff
path: root/mod/vegan/start.php
diff options
context:
space:
mode:
Diffstat (limited to 'mod/vegan/start.php')
-rw-r--r--mod/vegan/start.php449
1 files changed, 449 insertions, 0 deletions
diff --git a/mod/vegan/start.php b/mod/vegan/start.php
new file mode 100644
index 000000000..cee529e8f
--- /dev/null
+++ b/mod/vegan/start.php
@@ -0,0 +1,449 @@
+<?php
+/**
+ * Vegan, an anti-spam plugin for Elgg 1.8
+ *
+ * @author hellekin
+ * @package lorea
+ * @subpackage vegan
+ * @copyright 2012,2013 Lorea Faeries <federation@lorea.org>
+ * @license GNU Affero General Public License version 3 or later
+ * @website https://lorea.org/plugins/vegan
+ *
+ * Friendly note to spammers: never cross my path.
+ */
+
+elgg_register_event_handler('init', 'system', 'vegan_init');
+
+/**
+ * vegan_init -- Initialize plugin functionality
+ *
+ * @return void
+ */
+function vegan_init() {
+
+ // Register Tests
+ // elgg_register_plugin_hook_handler('test', 'system', 'vegan_tests');
+
+ // Provide Admin Interface
+ elgg_register_event_handler('pagesetup', 'system', 'vegan_admin_sandbox_page_setup');
+ elgg_extend_view('admin/user_opt/extend', 'vegan/admin_sandboxed_users');
+ elgg_extend_view('css/admin', 'vegan/css_admin');
+
+ // Extend CSS
+ elgg_extend_view('elgg', 'css', 'vegan/css');
+
+ // @todo Replace ReportedContent functionality
+
+ // Hook to registration to block obvious spammers
+ elgg_register_plugin_hook_handler('register', 'user', 'vegan_blacklist_email');
+
+ // Hook to entity creation to restrict access to saved objects
+ elgg_register_event_handler('create', 'group', 'vegan_block_create_group');
+ elgg_register_event_handler('create', 'object', 'vegan_block_create_object');
+
+ // Hook to actions to block spammers from saving objects
+ $actions = array(
+ 'blog/save',
+ 'bookmark/save',
+ 'thewire/add',
+ );
+ foreach ($actions AS $action) {
+ elgg_register_plugin_hook_handler('action', $action, 'vegan_block_action');
+ }
+
+ // Hook to creating,river to prevent river spam
+ elgg_register_plugin_hook_handler('creating', 'river', 'vegan_block_river');
+
+ // @todo clear vegan_sandboxed flag when user joins group/make friends
+ // make it smart enough to make spammers' job hard to circumvent
+
+}
+
+/**
+ * vegan_block_action -- Prevent spammers from saving anything
+ *
+ * @hook Plugin action, *save
+ *
+ * @param String $hook the action to block
+ * @param String $type the entity type (usually object)
+ * @param Mixed $foo ignored parameter
+ * @param Mixed $bar ignored parameter
+ * @return Boolean TRUE if the current user is a recognized spammer, FALSE otherwise.
+ */
+function vegan_block_action($hook, $type, $foo, $bar) {
+
+ $user_guid = elgg_get_logged_in_user_guid();
+
+ return vegan_is_spammer($user_guid);
+
+}
+
+/**
+ * vegan_block_create_group -- Force access to ACCESS_PRIVATE for sandboxed users
+ *
+ * @hook Event create, group
+ *
+ * @param String $event the event (create)
+ * @param String $type the entity type (group)
+ * @param Array $params contains 'entity' key
+ *
+ * @return Boolean TRUE to allow action, FALSE to prevent it
+ */
+function vegan_block_create_group($event, $type, $params) {
+
+ $group = $params['entity'];
+ $guid = $group->owner_guid;
+
+ if ($guid && vegan_is_sandboxed($guid)) {
+ system_message(elgg_echo('vegan:sandboxed:group'));
+ $group->set('access_id', ACCESS_PRIVATE);
+ // Return FALSE to delete group if sandboxed user is a spammer
+ return !vegan_is_spammer($guid);
+ }
+
+ return TRUE; // Accept group creation
+
+}
+
+/**
+ * vegan_block_create_object -- Force access to ACCESS_PRIVATE for sandboxed users.
+ *
+ * @hook Event create, object
+ *
+ * @param String $event the event (create)
+ * @param String $type the entity type (object)
+ * @param Array $params contains 'entity' key
+ *
+ * @return Boolean TRUE to allow action, FALSE to prevent it
+ */
+function vegan_block_create_object($event, $type, $params) {
+
+ $object = $params['entity'];
+ $guid = $object->owner_guid;
+
+ if ($guid && vegan_is_sandboxed($guid)) {
+ system_message(elgg_echo('vegan:sandboxed:object'));
+ $object->set('access_id', ACCESS_PRIVATE);
+ // Return FALSE to delete object if sandboxed user is a spammer
+ return !vegan_is_spammer($guid);
+ }
+
+ return TRUE; // Accept object creation
+
+}
+
+/**
+ * vegan_block_river -- Prevent river spam from sandboxed users
+ *
+ * @hook Plugin creating,river
+ *
+ * @param String $hook the plugin hook (creating)
+ * @param String $type the entity type (river)
+ * @param Mixed $foo ignored parameter
+ * @param Array $values arguments for view
+ *
+ * @return Mixed TRUE to prevent item from being sent to the river, void otherwise.
+ */
+function vegan_block_river($hook, $type, $foo, $values) {
+
+ error_log("===== vegan_block_river $hook,$type ($foo) $values");
+
+ if (vegan_is_sandboxed($values['subject_guid'])) {
+ return TRUE;
+ }
+
+}
+
+/**
+ * vegan_is_sandboxed -- Determine whether to sandbox the user or not
+ *
+ * @param Integer $user_guid the GUID of the user entity to test
+ *
+ * @return Boolean TRUE if sandboxed, FALSE otherwise.
+ */
+function vegan_is_sandboxed($user_guid) {
+
+ $sandboxed = FALSE;
+
+ // Get user and current time
+ $user = get_entity($user_guid);
+ $now = time();
+
+ if (!elgg_instanceof($user, 'user')) {
+ error_log("===== vegan_sandboxed content owner '$user_guid' is not a user!");
+ return FALSE;
+ }
+
+ // Account was activated by email
+ if ($user->validation_method == 'email') {
+
+ $md = elgg_get_metadata(array(
+ 'guid' => $user_guid,
+ 'metadata_name' => 'validated',
+ 'limit' => 1,
+ ));
+ error_log("===== vegan_sandboxed md $md->time_updated");
+
+ // and less than 2 minutes ago: die motherfucker
+ if ($user->last_login == 0 && $md && ($now - $md->time_updated) < 120) {
+ error_log("===== Gotcha! Killing spammer on first post");
+ $user->delete();
+ $sandboxed = TRUE; // return TRUE to block the river
+ }
+ // and less than an hour ago
+ /*
+ else if ($md && ($now - $md->updated_at) < 3600) {
+ error_log("===== vegan_sandboxed recent account");
+ $sandboxed = TRUE;
+ }
+ */
+
+ }
+
+ // If it's sandboxed, force ACCESS_PRIVATE
+ if ($user->vegan_sandboxed) {
+ // Keep track of retries, for future use
+ error_log("===== User is sandboxed ({$owner->vegan_sandboxed_tries})");
+ $user->vegan_sandboxed_tries = (int)$user->vegan_sandboxed_tries + 1;
+ $sandboxed = TRUE;
+ }
+
+ // Skip admins
+ if (!$user->isAdmin()) {
+
+ // You have zero friends
+ if (!$user->getFriends()) {
+ error_log("===== Sandboxed user (no friends)");
+ $sandboxed = TRUE;
+ }
+
+ // You're not cooperating
+ if (!$user->getGroups()) {
+ error_log("===== Sandboxed user (no groups)");
+ $sandboxed = TRUE;
+ }
+
+ }
+
+ if ($sandboxed) {
+ $user->set('vegan_sandboxed', TRUE);
+ // @todo limit access collections to private
+ }
+
+ return $sandboxed;
+
+}
+
+/**
+ * vegan_blacklist_email -- Prevent user registration from a notorious
+ * spam source
+ *
+ * Blacklists suck, but enough is enough.
+ *
+ * @hook Plugin register, user
+ *
+ * @param String $hook the plugin hook (register)
+ * @param String $type the entity type (user)
+ * @param Mixed $value the return value
+ * @param Array $params contains 'user' key
+ *
+ * @return FALSE to prevent user registration
+ */
+function vegan_blacklist_email($hook, $type, $value, $params) {
+
+ // Hardcode forbidden patterns: humans don't use them
+ static $noway = array(
+ '/\+.*@hotmail\.com$/',
+ );
+
+ // Grab the email
+ $email = $params['user']->email;
+ error_log("===== vegan_blacklist_email $hook,$type $email");
+
+ if (!empty($email)) {
+
+ // Exclude forbidden patterns
+ foreach($noway AS $pattern) {
+ if (preg_match($pattern, $email)) {
+ error_log("===== Vegan prevented registration of $email");
+ return FALSE;
+ }
+ }
+
+ // Exclude additional site-specific blacklisted domains
+ $bad_domains = string_to_tag_array(elgg_get_plugin_setting('bad_domains', 'vegan'));
+ $domain = explode('@', $email, 2);
+
+ error_log("===== Vegan testing $email against " . implode(', ', $bad_domains));
+
+ if (is_array($bad_domains) && in_array($domain[1], $bad_domains)) {
+ error_log("===== Vegan prevented registration of $email (bad domain: $domain[1])");
+ return FALSE;
+ }
+
+ }
+
+}
+
+/**
+ * vegan_admin_sandboxed_users -- View and manage suspicious users
+ *
+ */
+
+/**
+ * vegan_admin_sandboxed_page_setup -- Provide admin interface
+ *
+ */
+function vegan_admin_sandboxed_page_setup() {
+ if (elgg_get_context() == 'admin' && elgg_is_admin_logged_in()) {
+ elgg_register_admin_menu_item('administer', 'vegan', 'lorea');
+ }
+}
+
+/*
+function vegan_strike($hook, $type, $value, $params) {
+ $report = $params['report'];
+ $reporter = $report->getOwnerEntity();
+ $current_user_guid = elgg_get_loggedin_user_guid();
+ if ($reporter->guid == $current_user_guid && $reporter->spam_hunter) {
+ // Kill the beast
+ // TODO get reported object owner, or reported user
+ $spammer_guid = -1;
+ $spammer = elgg_get_user_entity($spammer_guid);
+ // Ban
+ if ($spammer->ban()) {
+ system_message(elgg_echo('vegan:killed_spammer'));
+ $report->state = 'archived';
+ $report->save();
+ } else {
+ register_error(elgg_echo('vegan:spammer_escaped'));
+ }
+ }
+
+}
+
+
+function vegan_grant_hunter_role($user_guid) {
+ $user = elgg_get_user($user_guid);
+ if (elgg_instanceof($user, 'user') && !$user->banned) {
+ $user->spam_hunter = true;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+function vegan_can_hunt($user = NULL) {
+ if (!$user) {
+ $user = elgg_get_loggedin_user();
+ }
+ if (!elgg_instanceof($user, 'user') || $user->banned) {
+ return FALSE;
+ }
+
+ return ($user->spam_hunter);
+}
+
+
+*/
+
+/**
+ * Vegan Reporting functions
+ *
+ * Use the `vegan_flag` function, it will sort things out.
+ * `vegan_*_spammer` function are for internal use.
+ */
+/*
+function vegan_flag($stuff) {
+ // Build function name
+ $flag_func = "vegan_";
+
+ // Check who is reporting
+ $reporter = elgg_get_loggedin_user();
+
+ if (!$user) {
+ // Anonymous reporting
+ $vegan_func.= "watch";
+ } else if ($user->spam_hunter || $user->admin) {
+ // Direct kill
+ $vegan_func = "ban";
+ } else {
+ // Report by authenticated user
+ $vegan_func = "block";
+ }
+ $vegan_func.= "_spammer";
+
+ // Check what is reported
+ if ($stuff instanceof ElggUser) {
+ // A user
+ } else if (is_numeric($stuff)) {
+ // A GUID
+ $stuff = get_entity($stuff);
+ } else if (preg_match($stuff, "/^https?:\/\/[^\/]+/(?:pg\/)profile\/([^\/\?\b]+)/", $stuff, $m)) {
+ $stuff = get_user_by_username($m[2]);
+ }
+
+ if ($stuff instanceof ElggUser) {
+ $spammer_guid = $stuff->getGUID();
+ } else if ($stuff instanceof ElggEntity) {
+ $spammer_guid = $stuff->getOwnerGUID();
+ } else {
+ elgg_register_error(elgg_echo('vegan:error:invalid_reference'));
+ return FALSE;
+ }
+
+ return $vegan_func($spammer_guid);
+}
+
+
+// Report a spammer anonymously
+// will raise the vegan_watch count for that entity
+function vegan_snitch_spammer($user) {
+ $user->vegan_watch = (int)$user->vegan_watch + 1;
+ // notify...
+ system_message(elgg_echo('vegan:action:success'));
+ return TRUE;
+}
+
+// Block a spammer
+// Reporter won't see it anymore
+function vegan_block_spammer($user) {
+ $reporter_guid = get_loggedin_user_guid();
+ // Watch it
+ $user->vegan_watch = (int)$user->vegan_watch + 1;
+ // Block it
+ elgg_create_entity_relationship($reporter_guid, $user->guid, "blocked");
+ // Notify...
+ system_message(elgg_echo('vegan:action:success'));
+ return TRUE;
+}
+
+// Ban a spammer
+function vegan_ban_spammer($user) {
+ $reporter_guid = elgg_get_loggedin_user_guid();
+ // Ban it
+ $user->ban("spammer");
+ // Notify
+ system_message(elgg_echo('vegan:action:success'));
+ return TRUE;
+}
+
+*/
+
+/**
+ * vegan_spammer -- Determine whether a user is a spammer
+ *
+ * @param Integer $user_guid GUID of the user entity to test
+ *
+ * @return Boolean TRUE is user is a recognized spammer, FALSE otherwise.
+ */
+function vegan_is_spammer($user_guid) {
+
+ $user = get_entity($user_guid);
+
+ if (elgg_instanceof($user, 'user') && !$user->isBanned()) {
+ return (bool)$user->spammer;
+ }
+
+ return FALSE;
+
+}