def commit_info(bot, trigger, match=None): match = match or trigger URL = 'https://api.github.com/repos/%s/commits/%s' % (match.group(1), match.group(2)) try: raw = fetch_api_endpoint(bot, URL) except HTTPError: bot.say('[Github] API returned an error.') return NOLIMIT data = json.loads(raw) try: if len(data['commit']['message'].split('\n')) > 1: body = data['commit']['message'].split('\n')[0] + '...' else: body = data['commit']['message'].split('\n')[0] except (KeyError): bot.say( '[Github] API says this is an invalid commit. Please report this if you know it\'s a correct link!' ) return NOLIMIT if body.strip() == '': body = 'No commit message provided.' response = [ bold('[Github]'), ' [', match.group(1), '] ', data['author']['login'], ': ', body, bold(' | '), str(data['stats']['total']), ' changes in ', str(len(data['files'])), ' files' ] bot.say(''.join(response))
def issue_info(bot, trigger, match=None): match = match or trigger URL = 'https://api.github.com/repos/%s/issues/%s' % (match.group(1), match.group(2)) try: raw = fetch_api_endpoint(bot, URL) except HTTPError: bot.say('[Github] API returned an error.') return NOLIMIT data = json.loads(raw) try: if len(data['body'].split('\n')) > 1: body = data['body'].split('\n')[0] + '...' else: body = data['body'].split('\n')[0] except (KeyError): bot.say( '[Github] API says this is an invalid issue. Please report this if you know it\'s a correct link!' ) return NOLIMIT if body.strip() == '': body = 'No description provided.' response = [ bold('[Github]'), ' [', match.group(1), ' #', str(data['number']), '] ', data['user']['login'], ': ', data['title'], bold(' | '), body ] bot.say(''.join(response))
def issue_info(bot, trigger, match=None): match = match or trigger URL = 'https://api.github.com/repos/%s/issues/%s' % (match.group(1), match.group(2)) try: raw = web.get(URL) except HTTPError: bot.say('The GitHub API returned an error.') return NOLIMIT data = json.loads(raw) try: if len(data['body'].split('\n')) > 1: body = data['body'].split('\n')[0] + '...' else: body = data['body'].split('\n')[0] except (KeyError): bot.say('The API says this is an invalid issue. Please report this if you know it\'s a correct link!') return NOLIMIT response = [ bold('[Github]'), ' [', match.group(1), ' #', str(data['number']), '] ', data['user']['login'], ': ', data['title'], bold(' | '), body ] bot.say(''.join(response))
def default_mask(trigger): welcome = formatting.color('Benvenuto su:', formatting.colors.PURPLE) chan = formatting.color(trigger.sender, formatting.colors.TEAL) topic_ = formatting.bold('Topic:') topic_ = formatting.color('| ' + topic_, formatting.colors.PURPLE) arg = formatting.color('{}', formatting.colors.GREEN) return '{} {} {} {}'.format(welcome, chan, topic_, arg)
def default_mask(trigger): welcome = formatting.color('Welcome to:', formatting.colors.PURPLE) chan = formatting.color(trigger.sender, formatting.colors.TEAL) topic_ = formatting.bold('Topic:') topic_ = formatting.color('| ' + topic_, formatting.colors.PURPLE) arg = formatting.color('{}', formatting.colors.GREEN) return '{} {} {} {}'.format(welcome, chan, topic_, arg)
def fmt_response(bot, trigger, URL, from_regex=False): data = get_data(bot, trigger, URL) if not data: return response = [bold("[Github]"), " ", str(data["full_name"])] if data["description"] != None: response.append(" - " + str(data["description"])) if not data["language"].strip() == "": response.extend([" | ", data["language"].strip()]) response.extend( [ " | Last Push: ", str(data["pushed_at"]), " | Stargazers: ", str(data["stargazers_count"]), " | Watchers: ", str(data["watchers_count"]), " | Forks: ", str(data["forks_count"]), " | Network: ", str(data["network_count"]), " | Open Issues: ", str(data["open_issues"]), ] ) if not from_regex: response.extend([" | ", data["html_url"]]) bot.say("".join(response))
def fmt_response(bot, trigger, URL, from_regex=False): data = get_data(bot, trigger, URL) if not data: return response = [bold('[Github]'), ' ', str(data['full_name'])] if data['description'] != None: response.append(' - ' + str(data['description'])) if not data['language'].strip() == '': response.extend([' | ', data['language'].strip()]) response.extend([ ' | Last Push: ', str(data['pushed_at']), ' | Stargazers: ', str(data['stargazers_count']), ' | Watchers: ', str(data['watchers_count']), ' | Forks: ', str(data['forks_count']), ' | Network: ', str(data['network_count']), ' | Open Issues: ', str(data['open_issues']) ]) if not from_regex: response.extend([' | ', data['html_url']]) bot.say(''.join(response))
def issue_info(bot, trigger, match=None): match = match or trigger URL = 'https://api.github.com/repos/%s/issues/%s' % (match.group(1), match.group(2)) if (match.group(3)): URL = 'https://api.github.com/repos/%s/issues/comments/%s' % (match.group(1), match.group(3)) try: raw = fetch_api_endpoint(bot, URL) except HTTPError: bot.say('[Github] API returned an error.') return NOLIMIT data = json.loads(raw) try: if len(data['body'].split('\n')) > 1 and len(data['body'].split('\n')[0]) > 180: body = data['body'].split('\n')[0] + '...' elif len(data['body'].split('\n')) > 2 and len(data['body'].split('\n')[0]) <= 180: body = ' '.join(data['body'].split('\n')[:2]) + '...' else: body = data['body'].split('\n')[0] except (KeyError): bot.say('[Github] API says this is an invalid issue. Please report this if you know it\'s a correct link!') return NOLIMIT if body.strip() == '': body = 'No description provided.' response = [ bold('[Github]'), ' [', match.group(1), ' #', match.group(2), '] ', data['user']['login'], ': ' ] if ('title' in data): response.append(data['title']) response.append(bold(' | ')) response.append(body) bot.say(''.join(response))
def error(bot, msg): print("{}: {}".format(str(datetime.datetime.now()), msg)) if "initialized" in bot.memory: if "last_error_msg" not in bot.memory["ff"] or bot.memory["ff"]["last_error_msg"] != msg: bot.memory["ff"]["last_error_msg"] = msg bot.msg( bot.config.freifunk.change_announce_target, formatting.color("{}: {}".format(formatting.bold("[ERROR]"), msg), formatting.colors.RED), )
def rpost_info(bot, trigger, match=None): r = praw.Reddit(user_agent=USER_AGENT) match = match or trigger s = r.get_submission(url=match.group(1)) message = ('[REDDIT] {title} {link}{nsfw} | {points} points ({percent}) | ' '{comments} comments | Posted by {author} | ' 'Created at {created}') if s.is_self: link = '(self.{})'.format(s.subreddit.display_name) else: link = '({}) to r/{}'.format(s.url, s.subreddit.display_name) if s.over_18: nsfw = bold(color(' [NSFW]', colors.RED)) sfw = bot.db.get_channel_value(trigger.sender, 'sfw') if sfw: link = '(link hidden)' bot.write([ 'KICK', trigger.sender, trigger.nick, 'Linking to NSFW content in a SFW channel.' ]) else: nsfw = '' if s.author: author = s.author.name else: author = '[deleted]' tz = time.get_timezone(bot.db, bot.config, None, trigger.nick, trigger.sender) time_created = dt.datetime.utcfromtimestamp(s.created_utc) created = time.format_time(bot.db, bot.config, tz, trigger.nick, trigger.sender, time_created) if s.score > 0: point_color = colors.GREEN else: point_color = colors.RED percent = color(unicode(s.upvote_ratio * 100) + '%', point_color) h = HTMLParser.HTMLParser() message = message.format(title=h.unescape(s.title), link=link, nsfw=nsfw, points=s.score, percent=percent, comments=s.num_comments, author=author, created=created) bot.say(message)
def rpost_info(bot, trigger, match=None): r = praw.Reddit(user_agent=USER_AGENT) match = match or trigger s = r.get_submission(url=match.group(1)) message = ( "[REDDIT] {title} {link}{nsfw} | {points} points ({percent}) | " "{comments} comments | Posted by {author} | " "Created at {created}" ) if s.is_self: link = "(self.{})".format(s.subreddit.display_name) else: link = "({}) to r/{}".format(s.url, s.subreddit.display_name) if s.over_18: nsfw = bold(color(" [NSFW]", colors.RED)) sfw = bot.db.get_channel_value(trigger.sender, "sfw") if sfw: link = "(link hidden)" bot.write(["KICK", trigger.sender, trigger.nick, "Linking to NSFW content in a SFW channel."]) else: nsfw = "" if s.author: author = s.author.name else: author = "[deleted]" tz = time.get_timezone(bot.db, bot.config, None, trigger.nick, trigger.sender) time_created = dt.datetime.utcfromtimestamp(s.created_utc) created = time.format_time(bot.db, bot.config, tz, trigger.nick, trigger.sender, time_created) if s.score > 0: point_color = colors.GREEN else: point_color = colors.RED percent = color(unicode(s.upvote_ratio * 100) + "%", point_color) h = HTMLParser.HTMLParser() message = message.format( title=h.unescape(s.title), link=link, nsfw=nsfw, points=s.score, percent=percent, comments=s.num_comments, author=author, created=created, ) bot.say(message)
def rpost_info(bot, trigger, match=None): r = praw.Reddit(user_agent=USER_AGENT) match = match or trigger s = r.get_submission(url=match.group(1)) if (comment_regex.match(match.group(0))): return rcomment_info(bot, trigger, s) message = ('[REDDIT] {title} {link}{nsfw} | {points} points ({percent}) | ' '{comments} comments | Posted by {author} | ' 'Created at {created}') if s.is_self: link = '(self.{})'.format(s.subreddit.display_name) else: link = '({}) to /r/{}'.format(s.url, s.subreddit.display_name) if s.over_18: nsfw = bold(color(' [NSFW]', colors.RED)) sfw = bot.db.get_channel_value(trigger.sender, 'sfw') if sfw: link = '(link hidden)' bot.write(['KICK', trigger.sender, trigger.nick, 'Linking to NSFW content in a SFW channel.']) else: nsfw = '' if s.author: author = s.author.name else: author = '[deleted]' tz = time.get_timezone(bot.db, bot.config, None, trigger.nick, trigger.sender) time_created = dt.datetime.utcfromtimestamp(s.created_utc) created = time.format_time(bot.db, bot.config, tz, trigger.nick, trigger.sender, time_created) if s.score > 0: point_color = colors.GREEN else: point_color = colors.RED percent = color(unicode(s.upvote_ratio * 100) + '%', point_color) h = HTMLParser.HTMLParser() message = message.format( title=h.unescape(s.title), link=link, nsfw=nsfw, points=s.score, percent=percent, comments=s.num_comments, author=author, created=created) bot.say(message)
def commit_info(bot, trigger, match=None): match = match or trigger URL = 'https://api.github.com/repos/%s/commits/%s' % (match.group(1), match.group(2)) try: raw = fetch_api_endpoint(bot, URL) except HTTPError: bot.say('[Github] API returned an error.') return NOLIMIT data = json.loads(raw) try: if len(data['commit']['message'].split('\n')) > 1: body = data['commit']['message'].split('\n')[0] + '...' else: body = data['commit']['message'].split('\n')[0] except (KeyError): bot.say('[Github] API says this is an invalid commit. Please report this if you know it\'s a correct link!') return NOLIMIT if body.strip() == '': body = 'No commit message provided.' response = [ bold('[Github]'), ' [', match.group(1), '] ', data['author']['login'], ': ', body, bold(' | '), str(data['stats']['total']), ' changes in ', str(len(data['files'])), ' files' ] bot.say(''.join(response))
def commit_info(bot, trigger, match=None): match = match or trigger URL = "https://api.github.com/repos/%s/commits/%s" % (match.group(1), match.group(2)) try: raw = fetch_api_endpoint(bot, URL) except HTTPError: bot.say("[Github] API returned an error.") return NOLIMIT data = json.loads(raw) try: if len(data["commit"]["message"].split("\n")) > 1: body = data["commit"]["message"].split("\n")[0] + "..." else: body = data["commit"]["message"].split("\n")[0] except (KeyError): bot.say("[Github] API says this is an invalid commit. Please report this if you know it's a correct link!") return NOLIMIT if body.strip() == "": body = "No commit message provided." response = [ bold("[Github]"), " [", match.group(1), "] ", data["author"]["login"], ": ", body, bold(" | "), str(data["stats"]["total"]), " changes in ", str(len(data["files"])), " files", ] bot.say("".join(response))
def issue_info(bot, trigger, match=None): match = match or trigger URL = "https://api.github.com/repos/%s/issues/%s" % (match.group(1), match.group(2)) try: raw = fetch_api_endpoint(bot, URL) except HTTPError: bot.say("[Github] API returned an error.") return NOLIMIT data = json.loads(raw) try: if len(data["body"].split("\n")) > 1: body = data["body"].split("\n")[0] + "..." else: body = data["body"].split("\n")[0] except (KeyError): bot.say("[Github] API says this is an invalid issue. Please report this if you know it's a correct link!") return NOLIMIT if body.strip() == "": body = "No description provided." response = [ bold("[Github]"), " [", match.group(1), " #", str(data["number"]), "] ", data["user"]["login"], ": ", data["title"], bold(" | "), body, ] bot.say("".join(response))
def rcomment_info(bot, trigger, s): message = ('[REDDIT] Comment on {link}{nsfw} | {created} | {points} points | ' '{author}: {message}') if (s.comments[0] == None): return c = s.comments[0] if s.is_self: link = '(self.{})'.format(s.subreddit.display_name) else: link = '({}) to /r/{}'.format(s.url, s.subreddit.display_name) if s.over_18: nsfw = bold(color(' [NSFW]', colors.RED)) sfw = bot.db.get_channel_value(trigger.sender, 'sfw') if sfw: link = '(link hidden)' bot.write(['KICK', trigger.sender, trigger.nick, 'Linking to NSFW content in a SFW channel.']) else: nsfw = '' if c.author: author = c.author.name else: author = '[deleted]' tz = time.get_timezone(bot.db, bot.config, None, trigger.nick, trigger.sender) time_created = dt.datetime.utcfromtimestamp(c.created_utc) created = time.format_time(bot.db, bot.config, tz, trigger.nick, trigger.sender, time_created) h = HTMLParser.HTMLParser() message = message.format( title=h.unescape(s.title), link=s.short_link, nsfw=nsfw, points=c.score, author=author, created=created, message=c) bot.say(message)
def rpost_info(bot, trigger, match=None): r = praw.Reddit(user_agent=USER_AGENT) match = match or trigger s = r.get_submission(url=match.group(1)) message = ('[REDDIT] {title} {link}{nsfw} | {points} points ({percent}) | ' '{comments} comments | Posted by {author}') if s.is_self: link = '(self.{})'.format(s.subreddit.display_name) else: link = '({}) to r/{}'.format(s.url, s.subreddit.display_name) if s.over_18: nsfw = bold(color(' [NSFW]', colors.RED)) #TODO implement per-channel settings db, and make this able to kick else: nsfw = '' if s.author: author = s.author.name else: author = '[deleted]' #TODO add creation time with s.created if s.score > 0: point_color = colors.GREEN else: point_color = colors.RED percent = color(unicode(s.upvote_ratio * 100) + '%', point_color) message = message.format(title=s.title, link=link, nsfw=nsfw, points=s.score, percent=percent, comments=s.num_comments, author=author) bot.say(message)
def fmt_response(bot, trigger, URL, from_regex=False): data = get_data(bot, trigger, URL) if not data: return response = [ bold('[Github]'), ' ', str(data['full_name']) ] if data['description'] != None: response.append(' - ' + str(data['description'])) if not data['language'].strip() == '': response.extend([' | ', data['language'].strip()]) response.extend([ ' | Last Push: ', str(data['pushed_at']), ' | Stargazers: ', str(data['stargazers_count']), ' | Watchers: ', str(data['watchers_count']), ' | Forks: ', str(data['forks_count']), ' | Network: ', str(data['network_count']), ' | Open Issues: ', str(data['open_issues']) ]) if not from_regex: response.extend([' | ', data['html_url']]) bot.say(''.join(response))
def rpost_info(bot, trigger, match=None): r = praw.Reddit(user_agent=USER_AGENT) match = match or trigger s = r.get_submission(url=match.group(1)) message = ( "[REDDIT] {title} {link}{nsfw} | {points} points ({percent}) | " "{comments} comments | Posted by {author}" ) if s.is_self: link = "(self.{})".format(s.subreddit.display_name) else: link = "({}) to r/{}".format(s.url, s.subreddit.display_name) if s.over_18: nsfw = bold(color(" [NSFW]", colors.RED)) # TODO implement per-channel settings db, and make this able to kick else: nsfw = "" if s.author: author = s.author.name else: author = "[deleted]" # TODO add creation time with s.created if s.score > 0: point_color = colors.GREEN else: point_color = colors.RED percent = color(unicode(s.upvote_ratio * 100) + "%", point_color) message = message.format( title=s.title, link=link, nsfw=nsfw, points=s.score, percent=percent, comments=s.num_comments, author=author ) bot.say(message)
def rpost_info(bot, trigger, match=None): r = praw.Reddit(user_agent=USER_AGENT) match = match or trigger s = r.get_submission(url=match.group(1)) message = ('[REDDIT] {title} {link}{nsfw} | {points} points ({percent}) | ' '{comments} comments | Posted by {author} {ago}') if s.is_self: link = '(self.{})'.format(s.subreddit.display_name) else: link = '({}) to r/{}'.format(s.url, s.subreddit.display_name) if s.over_18: nsfw = bold(color(' [NSFW]', colors.RED)) #TODO implement per-channel settings db, and make this able to kick else: nsfw = '' if s.author: author = s.author.name else: author = '[deleted]' if s.score > 0: point_color = colors.GREEN else: point_color = colors.RED percent = color(unicode(s.upvote_ratio * 100) + '%', point_color) posted_ago = human(datetime.datetime.utcnow() - datetime.datetime.utcfromtimestamp(int(s.created_utc))) message = message.format( title=s.title, link=link, nsfw=nsfw, points=s.score, percent=percent, comments=s.num_comments, author=author, ago=posted_ago) bot.say(message)
def rpost_info(bot, trigger, match=None): r = praw.Reddit(user_agent='Willie IRC bot - see dft.ba/-williesource for more') match = match or trigger s = r.get_submission(url=match.group(1)) message = ('[REDDIT] {title} {link}{nsfw} | {points} points ({percent}) | ' '{comments} comments | Posted by {author}') if s.is_self: link = '(self.{})'.format(s.subreddit.display_name) else: link = '({}) to r/{}'.format(s.url, s.subreddit.display_name) if s.over_18: nsfw = bold(color(' [NSFW]', colors.RED)) #TODO implement per-channel settings db, and make this able to kick else: nsfw = '' if s.author: author = s.author.name else: author = '[deleted]' #TODO add creation time with s.created if s.score > 0: point_color = colors.GREEN else: point_color = colors.RED percent = color(unicode(s.upvote_ratio * 100) + '%', point_color) message = message.format( title=s.title, link=link, nsfw=nsfw, points=s.score, percent=percent, comments=s.num_comments, author=author) bot.say(message)
def url_handler(bot, trigger): """ Check for malicious URLs """ check = True # Enable URL checking strict = False # Strict mode: kick on malicious URL positives = 0 # Number of engines saying it's malicious total = 0 # Number of total engines use_vt = True # Use VirusTotal if bot.config.has_section('safety'): check = bot.config.safety.enabled_by_default if check is None: # If not set, assume default check = True else: check = bool(check) # DB overrides config: setting = bot.db.get_channel_value(trigger.sender, 'safety') if setting is not None: if setting == 'off': return # Not checking elif setting in ['on', 'strict', 'local', 'local strict']: check = True if setting == 'strict' or setting == 'local strict': strict = True if setting == 'local' or setting == 'local strict': use_vt = False if not check: return # Not overriden by DB, configured default off netloc = urlparse(trigger).netloc if any(regex.search(netloc) for regex in known_good): return # Whitelisted apikey = bot.config.safety.vt_api_key try: if apikey is not None and use_vt: payload = { 'resource': unicode(trigger), 'apikey': apikey, 'scan': '1' } if trigger not in bot.memory['safety_cache']: result = web.post(vt_base_api_url + 'report', payload) if sys.version_info.major > 2: result = result.decode('utf-8') result = json.loads(result) age = time.time() data = { 'positives': result['positives'], 'total': result['total'], 'age': age } bot.memory['safety_cache'][trigger] = data if len(bot.memory['safety_cache']) > 1024: _clean_cache(bot) else: print('using cache') result = bot.memory['safety_cache'][trigger] positives = result['positives'] total = result['total'] except Exception as e: LOGGER.debug('Error from checking URL with VT.', exc_info=True) pass # Ignoring exceptions with VT so MalwareDomains will always work if unicode(netloc).lower() in malware_domains: # malwaredomains is more trustworthy than some VT engines # therefor it gets a weight of 10 engines when calculating confidence positives += 10 total += 10 if positives > 1: # Possibly malicious URL detected! confidence = '{}%'.format(round((positives / total) * 100)) msg = 'link posted by %s is possibliy malicious ' % bold(trigger.nick) msg += '(confidence %s - %s/%s)' % (confidence, positives, total) bot.say('[' + bold(color('WARNING', 'red')) + '] ' + msg) if strict: bot.write([ 'KICK', trigger.sender, trigger.nick, 'Posted a malicious link' ])
def findandreplace(bot, trigger): # Don't bother in PM if trigger.is_privmsg: return # Correcting other person vs self. rIdentifier = Identifier(trigger.group(1) or trigger.nick) search_dict = bot.memory['find_lines'] # only do something if there is conversation to work with if trigger.sender not in search_dict: return if Identifier(rIdentifier) not in search_dict[trigger.sender]: return rest = [trigger.group(2), trigger.group(3)] find = rest[0].replace('\\\\', '\\') replace = rest[1] me = False # /me command flags = (trigger.group(4) or '') # If g flag is given, replace all. Otherwise, replace once. if 'g' in flags: count = -1 else: count = 1 # repl is a lambda function which performs the substitution. i flag turns # off case sensitivity. re.U turns on unicode replacement. reflags = 0 if 'i' in flags: reflags = re.U | re.I # Look back through the user's lines in the channel until you find a line # where the replacement works try: find = re.compile(find, reflags) except re.error as e: bot.reply(u'That ain\'t valid regex! (%s)' % (e.message)) return for line in reversed(search_dict[trigger.sender][rIdentifier]): if line.startswith("\x01ACTION"): me = True # /me command line = line[8:] else: me = False new_phrase = find.sub(replace, line, count == 1) if new_phrase != line: # we are done break if not new_phrase or new_phrase == line: return # Didn't find anything # Save the new "edited" message. action = (me and '\x01ACTION ') or '' # If /me message, prepend \x01ACTION templist = search_dict[trigger.sender][rIdentifier] templist.append(action + new_phrase) search_dict[trigger.sender][rIdentifier] = templist bot.memory['find_lines'] = search_dict # output if not me: new_phrase = '%s to say: %s' % (bold('meant'), new_phrase) if trigger.group(1): phrase = '%s thinks %s %s' % (trigger.nick, rIdentifier, new_phrase) else: phrase = '%s %s' % (trigger.nick, new_phrase) bot.say(phrase)
def fetch(bot, initial=False): global session_maker_instance headers = {"User-Agent": "ff-irc-bot"} if "alfred_last_modified" in bot.memory["ff"]: headers["If-Modified-Since"] = bot.memory["ff"]["alfred_last_modified"] try: result = requests.get(bot.config.freifunk.alfred_uri, headers=headers) except Exception as e: print("Problems requesting alfred.json: {}".format(str(e))) return if result.status_code == 304: # no update since last fetch return if result.status_code != 200: # err, we have a problem! print("Unable to get alfred.json! Status code: {:d}".format(result.status_code)) return try: mapdata = json.loads(result.text) except ValueError as e: # err, we have a problem! print("Unable to parse JSON! Error: {}".format(str(e))) return # No problems? Everything fine? Update last modified timestamp! bot.memory["ff"]["alfred_last_modified"] = result.headers["Last-Modified"] session = session_maker_instance() with session.no_autoflush: # Set all Nodes offline. Only nodes present in alfred.json are online. for node in session.query(Node).filter(Node.source == "alfred.json"): node.online = False node.clientcount = 0 for key, data in mapdata.items(): data["mac"] = key data["online"] = True data["source"] = "alfred.json" session.merge(Node(data)) if not initial: for node in filter(lambda item: type(item) is Node, session.new): bot.msg(bot.config.freifunk.channel, "Neuer Knoten: {:s}".format(str(node))) node.firstseen = datetime.datetime.now() for node in filter(lambda item: type(item) is Node, session.dirty): attrs = inspect(node).attrs location_updated = False for attr in attrs: if ( attr.key not in (["lastseen", "firstseen"] + bot.config.freifunk.get_list("change_no_announce")) and attr.history.has_changes() ): if attr.key == "online": bot.msg( bot.config.freifunk.change_announce_target, "Knoten {:s} ist nun {:s}".format( formatting.bold(str(node.name)), formatting.color("online", formatting.colors.GREEN) if attr.value else formatting.color("offline", formatting.colors.RED), ), ) elif attr.key == "lat" or attr.key == "lon": if not location_updated: location_updated = True if attrs.lat.history.has_changes(): old_lat = attrs.lat.history.deleted[0] else: old_lat = attrs.lat.value if attrs.lon.history.has_changes(): old_lon = attrs.lon.history.deleted[0] else: old_lon = attrs.lon.value if old_lat and old_lon and attrs.lat.value and attrs.lon.value: bot.msg( bot.config.freifunk.change_announce_target, "Knoten {:s} änderte seine Position um {:.0f} Meter: {:s}".format( formatting.bold(str(node.name)), calc_distance(old_lat, old_lon, attrs.lat.value, attrs.lon.value), bot.config.freifunk.map_uri.format( lat=attrs.lat.value, lon=attrs.lon.value ), ), ) elif attrs.lat.value and attrs.lon.value: bot.msg( bot.config.freifunk.change_announce_target, "Knoten {:s} hat nun eine Position: {:s}".format( formatting.bold(str(node.name)), bot.config.freifunk.map_uri.format( lat=attrs.lat.value, lon=attrs.lon.value ), ), ) else: bot.msg( bot.config.freifunk.change_announce_target, "Knoten {:s} hat keine Position mehr".format(formatting.bold(str(node.name))), ) else: bot.msg( bot.config.freifunk.change_announce_target, "Knoten {:s} änderte {:s} von {:s} zu {:s}".format( formatting.bold(str(node.name)), str(attr.key), str(attr.history.deleted[0]), str(attr.value), ), ) try: session.commit() if not initial: check_highscores(bot) except: session.rollback() raise finally: session.close()
def get_prefix(): prefix = color('[', 'grey') + 'deviant' + bold('art') + color(']', 'grey') return prefix
def fetch(bot, initial=False): global session_maker_instance headers = {"User-Agent": "ff-irc-bot"} if "nodes_last_modified" in bot.memory["ff"]: headers["If-Modified-Since"] = bot.memory["ff"]["nodes_last_modified"] try: result = requests.get(bot.config.freifunk.nodes_uri, headers=headers, timeout=5) except requests.exceptions.ConnectTimeout: error(bot, "Problems requesting nodes.json: Timeout") return except requests.exceptions.ConnectionError: error(bot, "Problems requesting nodes.json: ConnectionError") return except Exception as e: error(bot, "Problems requesting nodes.json: {}".format(type(e))) return if result.status_code == 304: # no update since last fetch return if result.status_code != 200: # err, we have a problem! error(bot, "Unable to get nodes.json! Status code: {:d}".format(result.status_code)) return try: mapdata = json.loads(result.text) except ValueError as e: # err, we have a problem! error(bot, "Unable to parse JSON! {}".format(str(e))) return # No problems? Everything fine? Update last modified timestamp! bot.memory["ff"]["nodes_last_modified"] = result.headers["Last-Modified"] # .. and clear last error if "last_error_msg" in bot.memory["ff"] and bot.memory["ff"]["last_error_msg"]: bot.memory["ff"]["last_error_msg"] = None bot.msg( bot.config.freifunk.change_announce_target, formatting.color("Everything back to normal!", formatting.colors.GREEN), ) session = session_maker_instance() with session.no_autoflush: # Set all Nodes offline. Only nodes present in nodes.json and with online True are online. for node in session.query(Node).filter(Node.source == "nodes.json"): node.online = False node.clientcount = 0 for key, data in mapdata["nodes"].items(): data["node_id"] = key data["source"] = "nodes.json" node = Node(data) if not (node.site_code and node.site_code == "ffka"): continue session.merge(node) nodes_new = filter(lambda item: type(item) is Node, session.new) nodes_changed = filter(lambda item: type(item) is Node and not node.gateway, session.dirty) msgs = {} msgs[bot.config.freifunk.channel] = [] msgs[bot.config.freifunk.change_announce_target] = [] if not initial: for node in nodes_new: node.firstseen = datetime.datetime.now() if node.gateway: msgs[bot.config.freifunk.channel].append("Neues Gateway: {:s}".format(str(node))) else: msgs[bot.config.freifunk.channel].append("Neuer Knoten: {:s}".format(str(node))) for node in nodes_changed: attrs = inspect(node).attrs location_updated = False for attr in attrs: if ( attr.key not in (["lastseen"] + bot.config.freifunk.get_list("change_no_announce")) and attr.history.has_changes() ): if attr.key == "online": msgs[bot.config.freifunk.change_announce_target].append( "Knoten {:s} ist nun {:s}".format( formatting.bold(str(node.name)), formatting.color("online", formatting.colors.GREEN) if attr.value else formatting.color("offline", formatting.colors.RED), ) ) elif attr.key == "lat" or attr.key == "lon": if not location_updated: location_updated = True if attrs.lat.history.has_changes(): old_lat = attrs.lat.history.deleted[0] else: old_lat = attrs.lat.value if attrs.lon.history.has_changes(): old_lon = attrs.lon.history.deleted[0] else: old_lon = attrs.lon.value if old_lat and old_lon and attrs.lat.value and attrs.lon.value: msgs[bot.config.freifunk.change_announce_target].append( "Knoten {:s} änderte seine Position um {:.0f} Meter: {:s}".format( formatting.bold(str(node.name)), calc_distance(old_lat, old_lon, attrs.lat.value, attrs.lon.value), bot.config.freifunk.meshviewer_uri.format(id=node.node_id), ) ) elif attrs.lat.value and attrs.lon.value: msgs[bot.config.freifunk.change_announce_target].append( "Knoten {:s} hat nun eine Position: {:s}".format( formatting.bold(str(node.name)), bot.config.freifunk.meshviewer_uri.format(id=node.node_id), ) ) else: msgs[bot.config.freifunk.change_announce_target].append( "Knoten {:s} hat keine Position mehr".format(formatting.bold(str(node.name))) ) else: msgs[bot.config.freifunk.change_announce_target].append( "Knoten {:s} änderte {:s} von {:s} zu {:s}".format( formatting.bold(str(node.name)), str(attr.key), str(attr.history.deleted[0]), str(attr.value), ) ) try: session.commit() check_highscores(bot) except: session.rollback() raise finally: session.close() for target in msgs: for msg in msgs[target]: bot.msg(target, msg)
def findandreplace(bot, trigger): # Don't bother in PM if trigger.is_privmsg: return # Correcting other person vs self. rnick = Identifier(trigger.group(1) or trigger.nick) search_dict = bot.memory['find_lines'] # only do something if there is conversation to work with if trigger.sender not in search_dict: return if Identifier(rnick) not in search_dict[trigger.sender]: return #TODO rest[0] is find, rest[1] is replace. These should be made variables of #their own at some point. rest = [trigger.group(2), trigger.group(3)] rest[0] = rest[0].replace(r'\/', '/') rest[1] = rest[1].replace(r'\/', '/') me = False # /me command flags = (trigger.group(4) or '') # If g flag is given, replace all. Otherwise, replace once. if 'g' in flags: count = -1 else: count = 1 # repl is a lambda function which performs the substitution. i flag turns # off case sensitivity. re.U turns on unicode replacement. if 'i' in flags: regex = re.compile(re.escape(rest[0]), re.U | re.I) repl = lambda s: re.sub(regex, rest[1], s, count == 1) else: repl = lambda s: s.replace(rest[0], rest[1], count) # Look back through the user's lines in the channel until you find a line # where the replacement works for line in reversed(search_dict[trigger.sender][rnick]): if line.startswith("\x01ACTION"): me = True # /me command line = line[8:] else: me = False new_phrase = repl(line) if new_phrase != line: # we are done break if not new_phrase or new_phrase == line: return # Didn't find anything # Save the new "edited" message. action = (me and '\x01ACTION ') or '' # If /me message, prepend \x01ACTION templist = search_dict[trigger.sender][rnick] templist.append(action + new_phrase) search_dict[trigger.sender][rnick] = templist bot.memory['find_lines'] = search_dict # output if not me: new_phrase = '%s to say: %s' % (bold('meant'), new_phrase) if trigger.group(1): phrase = '%s thinks %s %s' % (trigger.nick, rnick, new_phrase) else: phrase = '%s %s' % (trigger.nick, new_phrase) bot.say(phrase)
def url_handler(bot, trigger): """ Check for malicious URLs """ check = True # Enable URL checking strict = False # Strict mode: kick on malicious URL positives = 0 # Number of engines saying it's malicious total = 0 # Number of total engines use_vt = True # Use VirusTotal if bot.config.has_section('safety'): check = bot.config.safety.enabled_by_default if check is None: # If not set, assume default check = True else: check = bool(check) # DB overrides config: setting = bot.db.get_channel_value(trigger.sender, 'safety') if setting is not None: if setting == 'off': return # Not checking elif setting in ['on', 'strict', 'local', 'local strict']: check = True if setting == 'strict' or setting == 'local strict': strict = True if setting == 'local' or setting == 'local strict': use_vt = False if not check: return # Not overriden by DB, configured default off netloc = urlparse(trigger).netloc if any(regex.search(netloc) for regex in known_good): return # Whitelisted apikey = bot.config.safety.vt_api_key try: if apikey is not None and use_vt: payload = {'resource': unicode(trigger), 'apikey': apikey, 'scan': '1'} if trigger not in bot.memory['safety_cache']: result = web.post(vt_base_api_url + 'report', payload) if sys.version_info.major > 2: result = result.decode('utf-8') result = json.loads(result) age = time.time() data = {'positives': result['positives'], 'total': result['total'], 'age': age} bot.memory['safety_cache'][trigger] = data if len(bot.memory['safety_cache']) > 1024: _clean_cache(bot) else: print('using cache') result = bot.memory['safety_cache'][trigger] positives = result['positives'] total = result['total'] except Exception as e: LOGGER.debug('Error from checking URL with VT.', exc_info=True) pass # Ignoring exceptions with VT so MalwareDomains will always work if unicode(netloc).lower() in malware_domains: # malwaredomains is more trustworthy than some VT engines # therefor it gets a weight of 10 engines when calculating confidence positives += 10 total += 10 if positives > 1: # Possibly malicious URL detected! confidence = '{}%'.format(round((positives / total) * 100)) msg = 'link posted by %s is possibliy malicious ' % bold(trigger.nick) msg += '(confidence %s - %s/%s)' % (confidence, positives, total) bot.say('[' + bold(color('WARNING', 'red')) + '] ' + msg) if strict: bot.write(['KICK', trigger.sender, trigger.nick, 'Posted a malicious link'])
def findandreplace(bot, trigger): # Don't bother in PM if trigger.is_privmsg: return # Correcting other person vs self. rnick = Nick(trigger.group(1) or trigger.nick) search_dict = bot.memory['find_lines'] # only do something if there is conversation to work with if trigger.sender not in search_dict: return if Nick(rnick) not in search_dict[trigger.sender]: return #TODO rest[0] is find, rest[1] is replace. These should be made variables of #their own at some point. rest = [trigger.group(3), trigger.group(4)] rest[0] = rest[0].replace(r'\/', '/') rest[1] = rest[1].replace(r'\/', '/') me = False # /me command flags = (trigger.group(5) or '') # If g flag is given, replace all. Otherwise, replace once. if 'g' in flags: count = -1 else: count = 1 # repl is a lambda function which performs the substitution. i flag turns # off case sensitivity. re.U turns on unicode replacement. if trigger.group(2).startswith('S'): precomp = rest[0] else: precomp = re.escape(rest[0]) if 'i' in flags: regex = re.compile(precomp, re.U | re.I) else: regex = re.compile(precomp, re.U) repl = lambda s: re.sub(regex, rest[1], s, count == 1) # Look back through the user's lines in the channel until you find a line # where the replacement works for line in reversed(search_dict[trigger.sender][rnick]): if line.startswith("\x01ACTION"): me = True # /me command line = line[8:] else: me = False new_phrase = repl(line) if new_phrase != line: # we are done break if not new_phrase or new_phrase == line: return # Didn't find anything # Save the new "edited" message. action = (me and '\x01ACTION ') or '' # If /me message, prepend \x01ACTION templist = search_dict[trigger.sender][rnick] templist.append(action + new_phrase) search_dict[trigger.sender][rnick] = templist bot.memory['find_lines'] = search_dict # output if not me: new_phrase = '%s to say: %s' % (bold('meant'), new_phrase) if trigger.group(1): phrase = '%s thinks %s %s' % (trigger.nick, rnick, new_phrase) else: phrase = '%s %s' % (trigger.nick, new_phrase) bot.say(phrase)
def get_prefix(): prefix = color('[', 'grey') + bold(color('Curse', 'yellow')) + color(']', 'grey') return prefix