def toggle_safety(bot: SopelWrapper, trigger: Trigger): """Set safety setting for channel.""" if not trigger.admin and bot.channels[trigger.sender].privileges[ trigger.nick] < plugin.OP: bot.reply('Only channel operators can change safety settings') return new_mode = None if trigger.group(2): new_mode = trigger.group(2).lower() if not new_mode or (new_mode != "default" and new_mode not in SAFETY_MODES): bot.reply( "Current mode: {}. Available modes: {}, or default ({})".format( bot.db.get_channel_value( trigger.sender, "safety", "default", ), ", ".join(SAFETY_MODES), bot.settings.safety.default_mode, )) return if new_mode == "default": bot.db.delete_channel_value(trigger.sender, "safety") else: bot.db.set_channel_value(trigger.sender, "safety", new_mode) bot.say('Safety is now set to "%s" for this channel' % new_mode)
def url_handler(bot: SopelWrapper, trigger: Trigger): """Checks for malicious URLs.""" mode = bot.db.get_channel_value( trigger.sender, "safety", bot.settings.safety.default_mode, ) if mode == "off": return local_only = "local" in mode or bot.settings.safety.vt_api_key is None strict = "strict" in mode for url in tools.web.search_urls(trigger): safe_url = safeify_url(url) positives = 0 # Number of engines saying it's malicious total = 0 # Number of total engines try: hostname = urlparse(url).hostname.lower() except ValueError: pass # Invalid address else: if any(regex.search(hostname) for regex in known_good): continue # explicitly trusted if hostname in bot.memory[SAFETY_CACHE_LOCAL_KEY]: LOGGER.debug("[local] domain in blocklist: %r", hostname) positives += 1 total += 1 result = virustotal_lookup(bot, url, local_only=local_only) if result: positives += result["positives"] total += result["total"] if positives >= 1: # Possibly malicious URL detected! LOGGER.info( "Possibly malicious link (%s/%s) posted in %s by %s: %r", positives, total, trigger.sender, trigger.nick, safe_url, ) bot.say( "{} {} of {} engine{} flagged a link {} posted as malicious". format( bold(color("WARNING:", colors.RED)), positives, total, "" if total == 1 else "s", bold(trigger.nick), )) if strict: bot.kick(trigger.nick, trigger.sender, "Posted a malicious link")
def title_auto(bot: SopelWrapper, trigger: Trigger): """ Automatically show titles for URLs. For shortened URLs/redirects, find where the URL redirects to and show the title for that (or call a function from another plugin to give more information). """ # Enabled or disabled by feature flag if not bot.settings.url.enable_auto_title: return # Avoid fetching links from another command if re.match(bot.config.core.prefix + r'\S+', trigger): return unchecked_urls = web.search_urls( trigger, exclusion_char=bot.config.url.exclusion_char, clean=True) urls = [] safety_cache = bot.memory.get("safety_cache", {}) safety_cache_local = bot.memory.get("safety_cache_local", {}) for url in unchecked_urls: # Avoid fetching known malicious links if url in safety_cache and safety_cache[url]["positives"] > 0: continue if urlparse(url).hostname.lower() in safety_cache_local: continue urls.append(url) for url, title, domain, tinyurl, dispatched in process_urls( bot, trigger, urls): if not dispatched: message = '%s | %s' % (title, domain) if tinyurl: message += ' ( %s )' % tinyurl # Guard against responding to other instances of this bot. if message != trigger: bot.say(message) bot.memory["last_seen_url"][trigger.sender] = url