Merge pull request #1 from tippero/master

Bring up to date
This commit is contained in:
jw 2017-10-28 19:04:16 -07:00 committed by GitHub
commit c69bef1a41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 260 additions and 37 deletions

View file

@ -15,7 +15,7 @@ coinspecs = {
"symbol": "XMR", "symbol": "XMR",
"atomic_units": 1e12, "atomic_units": 1e12,
"denominations": [[1000000, 1, "piconero"], [1000000000, 1e6, "micronero"], [1000000000000, 1e9, "millinero"]], "denominations": [[1000000, 1, "piconero"], [1000000000, 1e6, "micronero"], [1000000000000, 1e9, "millinero"]],
"address_length": [95, 95], # min/max size of addresses "address_length": [[95, 95], [106, 106]], # min/max size of addresses
"address_prefix": ['4', '9'], # allowed prefixes of addresses "address_prefix": ['4', '9'], # allowed prefixes of addresses
"min_withdrawal_fee": 10000000000, "min_withdrawal_fee": 10000000000,
"web_wallet_url": "https://mymonero.com/", # None is there's none "web_wallet_url": "https://mymonero.com/", # None is there's none

View file

@ -28,6 +28,7 @@ payment_confirmations = 6
tipbot_balance_cache_time = 35 # seconds tipbot_balance_cache_time = 35 # seconds
site_game_salt = '' site_game_salt = ''
openalias_address = None openalias_address = None
rpc_timeout = 180
admins = ["freenode:moneromooo", "freenode:moneromoo"] admins = ["freenode:moneromooo", "freenode:moneromoo"]
@ -116,3 +117,4 @@ kitsune_max_loss = 35
# how much are we prepared to lose as a ratio of our current pot # how much are we prepared to lose as a ratio of our current pot
kitsune_max_loss_ratio = 0.1 kitsune_max_loss_ratio = 0.1
spammer_allowed = ['_Slack', 'i2p-relay']

View file

@ -29,7 +29,8 @@ def Announce(link,cmd):
return return
nextid=redis_get('cryptokingdom:announcements:nextid') nextid=redis_get('cryptokingdom:announcements:nextid')
if nextid==None: if nextid==None:
nextid=0 nextid=1
nextid=long(nextid)
text = " ".join(cmd[1:]) text = " ".join(cmd[1:])
redis_hset('cryptokingdom:announcements',nextid,'From %s: %s'%(link.user.nick,text)) redis_hset('cryptokingdom:announcements',nextid,'From %s: %s'%(link.user.nick,text))
nextid+=1 nextid+=1
@ -54,8 +55,8 @@ def Cancel(link,cmd):
redis_hdel('cryptokingdom:announcements',which) redis_hdel('cryptokingdom:announcements',which)
def Help(link): def Help(link):
link.send(link,'Announce anything that you want others to know') link.send_private('Announce anything that you want others to know')
link.send(link,'Offers, auctions, other information') link.send_private('Offers, auctions, other information')

View file

@ -314,6 +314,8 @@ class IRCNetwork(Network):
self.update_last_active_time(chan,GetNick(who)) self.update_last_active_time(chan,GetNick(who))
# resplit to avoid splitting text that contains ':' # resplit to avoid splitting text that contains ':'
text = data.split(' :',1)[1] text = data.split(' :',1)[1]
if self.on_event:
self.on_event('message',link=Link(self,User(self,GetNick(who),who),Group(self,chan)),message=text)
exidx = text.find('!') exidx = text.find('!')
if exidx != -1 and len(text)>exidx+1 and text[exidx+1] in string.ascii_letters and self.is_acceptable_command_prefix(text[:exidx]): if exidx != -1 and len(text)>exidx+1 and text[exidx+1] in string.ascii_letters and self.is_acceptable_command_prefix(text[:exidx]):
cmd = text.split('!')[1] cmd = text.split('!')[1]
@ -338,7 +340,7 @@ class IRCNetwork(Network):
self.userstable[chan][nick] = None self.userstable[chan][nick] = None
log_log("New list of users in %s: %s" % (chan, str(self.userstable[chan].keys()))) log_log("New list of users in %s: %s" % (chan, str(self.userstable[chan].keys())))
if self.on_event: if self.on_event:
self.on_event('user-joined',link=Link(self,User(self,nick),Group(self,chan))) self.on_event('user-joined',link=Link(self,User(self,nick,who),Group(self,chan)))
elif action == 'PART': elif action == 'PART':
nick = GetNick(who) nick = GetNick(who)
@ -443,6 +445,8 @@ class IRCNetwork(Network):
(r,w,x)=select.select([self.irc.fileno()],[],[],1) (r,w,x)=select.select([self.irc.fileno()],[],[],1)
if self.irc.fileno() in r: if self.irc.fileno() in r:
newdata=self._irc_recv(4096,socket.MSG_DONTWAIT) newdata=self._irc_recv(4096,socket.MSG_DONTWAIT)
if len(newdata) == 0:
raise RuntimeError('0 bytes received, EOF')
else: else:
newdata = None newdata = None
if self.irc.fileno() in x: if self.irc.fileno() in x:

View file

@ -161,14 +161,18 @@ def UpdateCoin(data):
def Deposit(link,cmd): def Deposit(link,cmd):
Help(link) Help(link)
def RandomPaymentID(link,cmd):
link.send_private(" New payment ID: %s" % GetRandomPaymentID(link))
def Help(link): def Help(link):
GetAccount(link.identity()) GetAccount(link.identity())
link.send_private("You can send %s to your account:" % coinspecs.name); link.send_private("You can send %s to your account using this address AND payment ID:" % coinspecs.name);
address=GetTipbotAddress() or 'ERROR' address=GetTipbotAddress() or 'ERROR'
link.send_private(" Address: %s" % address) link.send_private(" Address: %s" % address)
if config.openalias_address != None: if config.openalias_address != None:
link.send_private(" (or %s when using OpenAlias)" % config.openalias_address) link.send_private(" (or %s when using OpenAlias)" % config.openalias_address)
link.send_private(" Payment ID: %s" % GetPaymentID(link)) link.send_private(" Use your primary payment ID: %s" % GetPaymentID(link))
link.send_private(" OR generate random payment ids at will with: !randompid")
link.send_private("Incoming transactions are credited after %d confirmations" % config.payment_confirmations) link.send_private("Incoming transactions are credited after %d confirmations" % config.payment_confirmations)
RegisterModule({ RegisterModule({
@ -182,4 +186,11 @@ RegisterCommand({
'function': Deposit, 'function': Deposit,
'help': "Show instructions about depositing %s" % coinspecs.name 'help': "Show instructions about depositing %s" % coinspecs.name
}) })
RegisterCommand({
'module': __name__,
'name': 'randompid',
'function': RandomPaymentID,
'registered': True,
'help': "Generate a new random payment ID"
})

View file

@ -15,6 +15,7 @@ import time
import threading import threading
import re import re
import praw import praw
import logging
import tipbot.config as config import tipbot.config as config
from tipbot.log import log_error, log_warn, log_info, log_log from tipbot.log import log_error, log_warn, log_info, log_log
from tipbot.user import User from tipbot.user import User
@ -44,7 +45,7 @@ class RedditNetwork(Network):
try: try:
cfg=config.network_config[self.name] cfg=config.network_config[self.name]
self.login=cfg['login'] self.login=cfg['login']
password=GetPassword(self.name) password=GetPassword(self.name+'/password')
self.subreddits=cfg['subreddits'] self.subreddits=cfg['subreddits']
user_agent=cfg['user_agent'] user_agent=cfg['user_agent']
self.update_period=cfg['update_period'] self.update_period=cfg['update_period']
@ -52,9 +53,19 @@ class RedditNetwork(Network):
self.keyword=cfg['keyword'] self.keyword=cfg['keyword']
self.use_unread_api=cfg['use_unread_api'] self.use_unread_api=cfg['use_unread_api']
self.cache_timeout=cfg['cache_timeout'] self.cache_timeout=cfg['cache_timeout']
client_id=GetPassword(self.name+'/client_id')
client_secret=GetPassword(self.name+'/client_secret')
username=GetPassword(self.name+'/username')
self.reddit=praw.Reddit(user_agent=user_agent,cache_timeout=self.cache_timeout) if False:
self.reddit.login(self.login,password) handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
logger = logging.getLogger('prawcore')
logger.setLevel(logging.DEBUG)
logger.addHandler(handler)
self.reddit=praw.Reddit(client_id=client_id,client_secret=client_secret,password=password,user_agent=user_agent,username=username)
log_info("Logged in reddit as " + str(self.reddit.user.me()))
self.items_cache=dict() self.items_cache=dict()
self.stop = False self.stop = False
@ -107,18 +118,23 @@ class RedditNetwork(Network):
return return
if not hasattr(item.author,'name'): if not hasattr(item.author,'name'):
log_warn('author of %s has no name field, ignored' % str(item.id)) log_warn('author of %s has no name field, ignored' % str(item.id))
if True:
try: try:
item.mark_as_read() item.mark_read()
except Exception,e: except Exception,e:
log_warning('Failed to mark %s as read: %s' % (item.id,str(e))) log_warn('Failed to mark %s as read: %s' % (item.id,str(e)))
return return
author=self.canonicalize(item.author.name) author=self.canonicalize(item.author.name)
if author==self.canonicalize(self.login): if author and author==self.canonicalize(self.login):
return return
if item.id in self.last_seen_ids: if item.id in self.last_seen_ids:
#log_log('Already seen %s %.1f hours ago by %s: %s (%s), skipping' % (item.id,age/3600,str(author),repr(title),repr(item.body))) log_log('Already seen %s %.1f hours ago by %s: %s (%s), skipping' % (item.id,age/3600,str(author),repr(title),repr(item.body)))
try:
item.mark_read()
except Exception,e:
log_warn('Failed to mark %s as read: %s' % (item.id,str(e)))
return return
age=time.time()-item.created_utc age=time.time()-item.created_utc
@ -155,7 +171,7 @@ class RedditNetwork(Network):
line=line.replace(self.keyword,'').strip() line=line.replace(self.keyword,'').strip()
if self.on_command: if self.on_command:
try: try:
parent_item=self.reddit.get_info(thing_id=item.parent_id) parent_item=next(self.reddit.info([item.parent_id]))
if not hasattr(parent_item,'author'): if not hasattr(parent_item,'author'):
raise RuntimeError('Parent item has no author') raise RuntimeError('Parent item has no author')
author=parent_item.author.name author=parent_item.author.name
@ -167,10 +183,11 @@ class RedditNetwork(Network):
self.on_command(link,synthetic_cmd) self.on_command(link,synthetic_cmd)
except Exception,e: except Exception,e:
log_error('Failed to tip %s\'s parent: %s' % (item.id,str(e))) log_error('Failed to tip %s\'s parent: %s' % (item.id,str(e)))
if True:
try: try:
item.mark_as_read() item.mark_read()
except Exception,e: except Exception,e:
log_warning('Failed to mark %s as read: %s' % (item.id,str(e))) log_warn('Failed to mark %s as read: %s' % (item.id,str(e)))
def _schedule_reply(self,item,recipient,text): def _schedule_reply(self,item,recipient,text):
log_log('scheduling reply to %s:%s: %s' % (item.id if item else '""',recipient or '""',text)) log_log('scheduling reply to %s:%s: %s' % (item.id if item else '""',recipient or '""',text))
@ -214,7 +231,10 @@ class RedditNetwork(Network):
if fullname in self.items_cache: if fullname in self.items_cache:
item=self.items_cache[fullname] item=self.items_cache[fullname]
if not item: if not item:
item=self.reddit.get_info(thing_id=fullname) item = self.reddit.mesage(fullname)
if not item:
gen=self.reddit.info([fullname])
item=next(gen, None)
if not item: if not item:
log_error('Failed to find item %s to post %s' % (fullname,text)) log_error('Failed to find item %s to post %s' % (fullname,text))
redis_lpop('reddit:replies') redis_lpop('reddit:replies')
@ -226,9 +246,6 @@ class RedditNetwork(Network):
redis_lpop('reddit:replies') redis_lpop('reddit:replies')
except praw.errors.RateLimitExceeded,e:
log_info('Rate limited trying to send %s, will retry: %s' % (data,str(e)))
return False
except Exception,e: except Exception,e:
log_error('Error sending %s, will retry: %s' % (data,str(e))) log_error('Error sending %s, will retry: %s' % (data,str(e)))
return False return False
@ -256,15 +273,15 @@ class RedditNetwork(Network):
self._parse(message,not message.was_comment) self._parse(message,not message.was_comment)
else: else:
messages=self.reddit.get_inbox() for message in self.reddit.inbox.unread(limit=self.load_limit):
for message in messages: #if not message.was_comment:
if not message.was_comment:
self._parse(message,True) self._parse(message,True)
sr=self.reddit.get_subreddit("+".join(self.subreddits)) #print "Submissions from %s" % ("+".join(self.subreddits))
comments=sr.get_comments(limit=self.load_limit) #sr=self.reddit.subreddit("+".join(self.subreddits))
for comment in comments: #for s in sr.new(limit=self.load_limit):
self._parse(comment,False) # for comment in s.comments:
# self._parse(comment,False)
while self._post_next_reply(): while self._post_next_reply():
pass pass

170
tipbot/modules/spammer.py Normal file
View file

@ -0,0 +1,170 @@
#!/bin/python
#
# Cryptonote tipbot - matylda commands
# Copyright 2014, 2015 moneromooo
#
# The Cryptonote tipbot is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
import sys
import redis
import string
import re
import tipbot.config as config
from tipbot.log import log_error, log_warn, log_info, log_log
import tipbot.coinspecs as coinspecs
from tipbot.utils import *
from tipbot.user import User
from tipbot.link import Link
from tipbot.redisdb import *
from tipbot.command_manager import *
def BanUser(link):
log_info('Banning %s (%s)' % (link.user.nick, link.user.ident))
if not link.group:
return
chan=link.group.name
log_info("chan: " + chan)
net=link.network
try:
cmd="MODE " + chan + " +b " + link.user.ident
net._irc_sendmsg(cmd)
cmd="KICK " + chan + " " + link.user.nick
net._irc_sendmsg(cmd)
except:
pass
def MuteUser(link):
log_info('Muting %s (%s)' % (link.user.nick, link.user.ident))
if not link.group:
return
chan=link.group.name
log_info("chan: " + chan)
net=link.network
try:
cmd="MODE " + chan + " +q " + link.user.ident
net._irc_sendmsg(cmd)
except:
pass
def OnUserJoined(event,*args,**kwargs):
link=kwargs['link']
nick=link.user.nick.lower()
if nick=="lbft" or nick=="lbft_":
BanUser(link)
triggers=[l.lower() for l in [
"triple your btc", "pm me to begin", "hatt uu",
"accelerate the blockchain", "u stappid", "me a message to begin",
"the ops have confirmed", "expanding technology", "exploding technology",
"allah is doing", "pm me to get going", "defragment the blockchain to grow"
]]
def OnMessage(event,*args,**kwargs):
line=kwargs['message']
if not line:
return
link=kwargs['link']
if IsAdmin(link):
return
if link.nick in config.allowed:
return
line=re.sub(r'\x03[0-9]?[0-9]?','',line)
line=re.sub(r'\x0f','',line)
line=line.lower().strip()
log_info("Testing: " + line)
for expr in triggers:
if re.match(".*"+expr+".*",line):
MuteUser(link)
return
def AddTrigger(link,cmd):
triggers.append(" ".join(cmd[1:]))
def ShowTriggers(link,cmd):
link.send(", ".join(triggers))
def Ban(link,cmd):
link.send("disabled") # need to ban by ident
return
try:
who=cmd[1]
except Exception,e:
link.send("usage: ban <nick>")
return
group=link.group
if not group:
link.send("Not in a channel")
return
l=Link(link.network,User(link.network,who),group)
BanUser(l)
def Mute(link,cmd):
link.send("disabled") # need to mute by ident
return
try:
who=cmd[1]
except Exception,e:
link.send("usage: mute <nick>")
return
group=link.group
if not group:
link.send("Not in a channel")
return
l=Link(link.network,User(link.network,who),group)
MuteUser(l)
def Help(link):
link.send_private('Ban assholes')
RegisterModule({
'name': __name__,
'help': Help,
})
RegisterEventHandler({
'module': __name__,
'event': 'user-joined',
'function': OnUserJoined,
})
RegisterEventHandler({
'module': __name__,
'event': 'message',
'function': OnMessage,
})
RegisterCommand({
'module': __name__,
'name': 'add_trigger',
'function': AddTrigger,
'admin': True,
'help': "add keyword trigger to spammer trap"
})
RegisterCommand({
'module': __name__,
'name': 'show_triggers',
'function': ShowTriggers,
'admin': True,
'help': "list keyword triggers"
})
RegisterCommand({
'module': __name__,
'name': 'ban',
'function': Ban,
'admin': True,
'help': "ban a user"
})
RegisterCommand({
'module': __name__,
'name': 'mute',
'function': Mute,
'admin': True,
'help': "mute a user"
})

View file

@ -10,9 +10,10 @@
# #
class User: class User:
def __init__(self,network,nick): def __init__(self,network,nick,ident=None):
self.network=network self.network=network
self.nick=nick self.nick=nick
self.ident=ident
def check_registered(self): def check_registered(self):
pass pass

View file

@ -17,6 +17,8 @@ import time
import threading import threading
import math import math
import string import string
import random
from Crypto.Random.random import getrandbits
from decimal import * from decimal import *
import tipbot.config as config import tipbot.config as config
import tipbot.coinspecs as coinspecs import tipbot.coinspecs as coinspecs
@ -55,8 +57,10 @@ def GetParam(parms,idx):
return parms[idx] return parms[idx]
return None return None
def GetPaymentID(link): def GetPaymentID(link,random=False):
salt="2u3g55bkwrui32fi3g4bGR$j5g4ugnujb-"+coinspecs.name+"-"; salt="2u3g55bkwrui32fi3g4bGR$j5g4ugnujb-"+coinspecs.name+"-";
if random:
salt = salt + "-" + str(time.time()) + "-" + str(getrandbits(128))
p = hashlib.sha256(salt+link.identity()).hexdigest(); p = hashlib.sha256(salt+link.identity()).hexdigest();
try: try:
redis_hset("paymentid",p,link.identity()) redis_hset("paymentid",p,link.identity())
@ -64,6 +68,9 @@ def GetPaymentID(link):
log_error('GetPaymentID: failed to set payment ID for %s to redis: %s' % (link.identity(),str(e))) log_error('GetPaymentID: failed to set payment ID for %s to redis: %s' % (link.identity(),str(e)))
return p return p
def GetRandomPaymentID(link):
return GetPaymentID(link, True)
def GetIdentityFromPaymentID(p): def GetIdentityFromPaymentID(p):
if not redis_hexists("paymentid",p): if not redis_hexists("paymentid",p):
log_log('PaymentID %s not found' % p) log_log('PaymentID %s not found' % p)
@ -76,8 +83,18 @@ def GetIdentityFromPaymentID(p):
identity = "freenode:"+identity identity = "freenode:"+identity
return identity return identity
def IsAddressLengthValid(address):
if type(coinspecs.address_length[0]) == list:
for allist in coinspecs.address_length:
if len(address) >= allist[0] and len(address) <= allist[1]:
return True
else:
if len(address) >= coinspecs.address_length[0] and len(address) <= coinspecs.address_length[1]:
return True
return False
def IsValidAddress(address): def IsValidAddress(address):
if len(address) < coinspecs.address_length[0] or len(address) > coinspecs.address_length[1]: if not IsAddressLengthValid(address):
return False return False
for prefix in coinspecs.address_prefix: for prefix in coinspecs.address_prefix:
if address.startswith(prefix): if address.startswith(prefix):
@ -198,7 +215,7 @@ def StringToUnits(s):
def SendJSONRPCCommand(host,port,method,params): def SendJSONRPCCommand(host,port,method,params):
try: try:
http = httplib.HTTPConnection(host,port,timeout=20) http = httplib.HTTPConnection(host,port,timeout=config.rpc_timeout)
except Exception,e: except Exception,e:
log_error('SendJSONRPCCommand: Error connecting to %s:%u: %s' % (host, port, str(e))) log_error('SendJSONRPCCommand: Error connecting to %s:%u: %s' % (host, port, str(e)))
raise raise
@ -235,7 +252,7 @@ def SendJSONRPCCommand(host,port,method,params):
def SendHTMLCommand(host,port,method): def SendHTMLCommand(host,port,method):
try: try:
http = httplib.HTTPConnection(host,port,timeout=20) http = httplib.HTTPConnection(host,port,timeout=config.rpc_timeout)
except Exception,e: except Exception,e:
log_error('SendHTMLCommand: Error connecting to %s:%u: %s' % (host, port, str(e))) log_error('SendHTMLCommand: Error connecting to %s:%u: %s' % (host, port, str(e)))
raise raise