Add submodules

This commit is contained in:
Nyo 2016-10-02 22:48:14 +02:00
parent 40264ceffe
commit 88c80a4080
55 changed files with 405 additions and 1829 deletions

5
.gitignore vendored
View File

@ -2,4 +2,7 @@
config.ini
filters.txt
.data
.idea
.idea
common_funzia
common_refractor
common_memato

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "common"]
path = common
url = git@git.zxq.co:ripple/ripple-python-common.git

1
common Submodule

@ -0,0 +1 @@
Subproject commit 1d3a6a0020a73f4baedc68a879821f10431e4bfc

View File

@ -1,16 +0,0 @@
"""Contains user actions"""
IDLE = 0
AFK = 1
PLAYING = 2
EDITING = 3
MODDING = 4
MULTIPLAYER = 5
WATCHING = 6
UNKNOWN = 7
TESTING = 8
SUBMITTING = 9
PAUSED = 10
LOBBY = 11
MULTIPLAYING= 12
OSU_DIRECT = 13
NONE = 14

View File

@ -1,9 +0,0 @@
"""Console colors"""
PINK = '\033[95m'
BLUE = '\033[94m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'

View File

@ -1,17 +1,19 @@
from objects import fokabot
import random
from objects import glob
from constants import serverPackets
from constants import exceptions
from helpers import userHelper
from helpers import systemHelper
import requests
import json
from constants import mods
from helpers import generalFunctions
from helpers import logHelper as log
from constants import gameModes
from constants import privileges
import random
import requests
from common import generalUtils
from common.constants import mods
from common.log import logUtils as log
from common.ripple import userUtils
from constants import exceptions
from common.constants import gameModes
from common.constants import privileges
from constants import serverPackets
from helpers import systemHelper
from objects import fokabot
from objects import glob
"""
Commands callbacks
@ -147,8 +149,8 @@ def silence(fro, chan, message):
reason = ' '.join(message[3:])
# Get target user ID
targetUserID = userHelper.getID(target)
userID = userHelper.getID(fro)
targetUserID = userUtils.getID(target)
userID = userUtils.getID(fro)
# Make sure the user exists
if not targetUserID:
@ -177,7 +179,7 @@ def silence(fro, chan, message):
targetToken.silence(silenceTime, reason, userID)
else:
# User offline, silence user only in db
userHelper.silence(targetUserID, silenceTime, reason, userID)
userUtils.silence(targetUserID, silenceTime, reason, userID)
# Log message
msg = "{} has been silenced for the following reason: {}".format(target, reason)
@ -190,8 +192,8 @@ def removeSilence(fro, chan, message):
target = message[0].replace("_", " ")
# Make sure the user exists
targetUserID = userHelper.getID(target)
userID = userHelper.getID(fro)
targetUserID = userUtils.getID(target)
userID = userUtils.getID(fro)
if not targetUserID:
return "{}: user not found".format(target)
@ -202,7 +204,7 @@ def removeSilence(fro, chan, message):
targetToken.silence(0, "", userID)
else:
# user offline, remove islene ofnlt from db
userHelper.silence(targetUserID, 0, "", userID)
userUtils.silence(targetUserID, 0, "", userID)
return "{}'s silence reset".format(target)
@ -213,13 +215,13 @@ def ban(fro, chan, message):
target = message[0].replace("_", " ")
# Make sure the user exists
targetUserID = userHelper.getID(target)
userID = userHelper.getID(fro)
targetUserID = userUtils.getID(target)
userID = userUtils.getID(fro)
if not targetUserID:
return "{}: user not found".format(target)
# Set allowed to 0
userHelper.ban(targetUserID)
userUtils.ban(targetUserID)
# Send ban packet to the user if he's online
targetToken = glob.tokens.getTokenFromUsername(target)
@ -236,13 +238,13 @@ def unban(fro, chan, message):
target = message[0].replace("_", " ")
# Make sure the user exists
targetUserID = userHelper.getID(target)
userID = userHelper.getID(fro)
targetUserID = userUtils.getID(target)
userID = userUtils.getID(fro)
if not targetUserID:
return "{}: user not found".format(target)
# Set allowed to 1
userHelper.unban(targetUserID)
userUtils.unban(targetUserID)
log.rap(userID, "has unbanned {}".format(target), True)
return "Welcome back {}!".format(target)
@ -254,13 +256,13 @@ def restrict(fro, chan, message):
target = message[0].replace("_", " ")
# Make sure the user exists
targetUserID = userHelper.getID(target)
userID = userHelper.getID(fro)
targetUserID = userUtils.getID(target)
userID = userUtils.getID(fro)
if not targetUserID:
return "{}: user not found".format(target)
# Put this user in restricted mode
userHelper.restrict(targetUserID)
userUtils.restrict(targetUserID)
# Send restricted mode packet to this user if he's online
targetToken = glob.tokens.getTokenFromUsername(target)
@ -277,13 +279,13 @@ def unrestrict(fro, chan, message):
target = message[0].replace("_", " ")
# Make sure the user exists
targetUserID = userHelper.getID(target)
userID = userHelper.getID(fro)
targetUserID = userUtils.getID(target)
userID = userUtils.getID(fro)
if not targetUserID:
return "{}: user not found".format(target)
# Set allowed to 1
userHelper.unrestrict(targetUserID)
userUtils.unrestrict(targetUserID)
log.rap(userID, "has removed restricted mode from {}".format(target), True)
return "Welcome back {}!".format(target)
@ -386,7 +388,7 @@ def getPPMessage(userID, just_data = False):
currentAcc = token.tillerino[2]
# Send request to LETS api
resp = requests.get("http://127.0.0.1:5002/api/v1/pp?b={}&m={}&a={}".format(currentMap, currentMods, currentAcc), timeout=10).text
resp = requests.get("http://127.0.0.1:5002/api/v1/pp?b={}&m={}".format(currentMap, currentMods, currentAcc), timeout=10).text
data = json.loads(resp)
# Make sure status is in response data
@ -405,23 +407,23 @@ def getPPMessage(userID, just_data = False):
# Return response in chat
# Song name and mods
msg = "{song}{plus}{mods} ".format(song=data["song_name"], plus="+" if currentMods > 0 else "", mods=generalFunctions.readableMods(currentMods))
msg = "{song}{plus}{mods} ".format(song=data["song_name"], plus="+" if currentMods > 0 else "", mods=generalUtils.readableMods(currentMods))
# PP values
if currentAcc == -1:
msg += "95%: {pp95}pp | 98%: {pp98}pp | 99% {pp99}pp | 100%: {pp100}pp".format(pp100=data["pp"][0], pp99=data["pp"][1], pp98=data["pp"][2], pp95=data["pp"][3])
else:
msg += "{acc:.2f}%: {pp}pp".format(acc=token.tillerino[2], pp=data["pp"][0])
originalAR = data["ar"]
# calc new AR if HR/EZ is on
if (currentMods & mods.Easy) > 0:
if (currentMods & mods.EASY) > 0:
data["ar"] = max(0, data["ar"] / 2)
if (currentMods & mods.HardRock) > 0:
if (currentMods & mods.HARDROCK) > 0:
data["ar"] = min(10, data["ar"] * 1.4)
arstr = " ({})".format(originalAR) if originalAR != data["ar"] else ""
# Beatmap info
msg += " | {bpm} BPM | AR {ar}{arstr} | {stars:.2f} stars".format(bpm=data["bpm"], stars=data["stars"], ar=data["ar"], arstr=arstr)
@ -433,10 +435,10 @@ def getPPMessage(userID, just_data = False):
except exceptions.apiException:
# API error
return "Unknown error in LETS API call. Please tell this to a dev."
except:
#except:
# Unknown exception
# TODO: print exception
return False
# return False
def tillerinoNp(fro, chan, message):
try:
@ -455,15 +457,15 @@ def tillerinoNp(fro, chan, message):
modsEnum = 0
mapping = {
"-Easy": mods.Easy,
"-NoFail": mods.NoFail,
"+Hidden": mods.Hidden,
"+HardRock": mods.HardRock,
"+Nightcore": mods.Nightcore,
"+DoubleTime": mods.DoubleTime,
"-HalfTime": mods.HalfTime,
"+Flashlight": mods.Flashlight,
"-SpunOut": mods.SpunOut
"-Easy": mods.EASY,
"-NoFail": mods.NOFAIL,
"+Hidden": mods.HIDDEN,
"+HardRock": mods.HARDROCK,
"+Nightcore": mods.NIGHTCORE,
"+DoubleTime": mods.DOUBLETIME,
"-HalfTime": mods.HALFTIME,
"+Flashlight": mods.FLASHLIGHT,
"-SpunOut": mods.SPUNOUT
}
if playWatch:
@ -513,23 +515,23 @@ def tillerinoMods(fro, chan, message):
modsEnum = 0
break
elif i == "NF":
modsEnum += mods.NoFail
modsEnum += mods.NOFAIL
elif i == "EZ":
modsEnum += mods.Easy
modsEnum += mods.EASY
elif i == "HD":
modsEnum += mods.Hidden
modsEnum += mods.HIDDEN
elif i == "HR":
modsEnum += mods.HardRock
modsEnum += mods.HARDROCK
elif i == "DT":
modsEnum += mods.DoubleTime
modsEnum += mods.DOUBLETIME
elif i == "HT":
modsEnum += mods.HalfTime
modsEnum += mods.HALFTIME
elif i == "NC":
modsEnum += mods.Nightcore
modsEnum += mods.NIGHTCORE
elif i == "FL":
modsEnum += mods.Flashlight
modsEnum += mods.FLASHLIGHT
elif i == "SO":
modsEnum += mods.SpunOut
modsEnum += mods.SPUNOUT
# Set mods
token.tillerino[1] = modsEnum
@ -582,22 +584,22 @@ def tillerinoLast(fro, chan, message):
return False
diffString = "difficulty_{}".format(gameModes.getGameModeForDB(data["play_mode"]))
rank = generalFunctions.getRank(data["play_mode"], data["mods"], data["accuracy"],
data["300_count"], data["100_count"], data["50_count"], data["misses_count"])
rank = generalUtils.getRank(data["play_mode"], data["mods"], data["accuracy"],
data["300_count"], data["100_count"], data["50_count"], data["misses_count"])
ifPlayer = "{0} | ".format(fro) if chan != "FokaBot" else ""
ifFc = " (FC)" if data["max_combo"] == data["fc"] else " {0}x/{1}x".format(data["max_combo"], data["fc"])
beatmapLink = "[http://osu.ppy.sh/b/{1} {0}]".format(data["sn"], data["bid"])
hasPP = data["play_mode"] == gameModes.std or data["play_mode"] == gameModes.mania
hasPP = data["play_mode"] == gameModes.STD or data["play_mode"] == gameModes.MANIA
msg = ifPlayer
msg += beatmapLink
if data["play_mode"] != gameModes.std:
if data["play_mode"] != gameModes.STD:
msg += " <{0}>".format(gameModes.getGameModeForPrinting(data["play_mode"]))
if data["mods"]:
msg += ' +' + generalFunctions.readableMods(data["mods"])
msg += ' +' + generalUtils.readableMods(data["mods"])
if not hasPP:
msg += " | {0:,}".format(data["score"])
@ -657,9 +659,9 @@ def pp(fro, chan, message):
return False
if gameMode is None:
gameMode = token.gameMode
if gameMode == gameModes.taiko or gameMode == gameModes.ctb:
if gameMode == gameModes.TAIKO or gameMode == gameModes.CTB:
return "PP for your current game mode is not supported yet."
pp = userHelper.getPP(token.userID, gameMode)
pp = userUtils.getPP(token.userID, gameMode)
return "You have {:,} pp".format(pp)

View File

@ -1,36 +0,0 @@
std = 0
taiko = 1
ctb = 2
mania = 3
def getGameModeForDB(gameMode):
"""
Convert a gamemode number to string for database table/column
gameMode -- gameMode int or variable (ex: gameMode.std)
return -- game mode readable string for db
"""
if gameMode == std:
return "std"
elif gameMode == taiko:
return "taiko"
elif gameMode == ctb:
return "ctb"
else:
return "mania"
def getGameModeForPrinting(gameMode):
"""
Convert a gamemode number to string for showing to a user (e.g. !last)
gameMode -- gameMode int or variable (ex: gameMode.std)
return -- game mode readable string for a human
"""
if gameMode == std:
return "osu!"
elif gameMode == taiko:
return "Taiko"
elif gameMode == ctb:
return "CatchTheBeat"
else:
return "osu!mania"

View File

@ -1,30 +0,0 @@
Nomod = 0
NoFail = 1
Easy = 2
NoVideo = 4
Hidden = 8
HardRock = 16
SuddenDeath = 32
DoubleTime = 64
Relax = 128
HalfTime = 256
Nightcore = 512
Flashlight = 1024
Autoplay = 2048
SpunOut = 4096
Relax2 = 8192
Perfect = 16384
Key4 = 32768
Key5 = 65536
Key6 = 131072
Key7 = 262144
Key8 = 524288
keyMod = 1015808
FadeIn = 1048576
Random = 2097152
LastMod = 4194304
Key9 = 16777216
Key10 = 33554432
Key1 = 67108864
Key3 = 134217728
Key2 = 268435456

View File

@ -1,21 +0,0 @@
USER_PUBLIC = 1
USER_NORMAL = 2 << 0
USER_DONOR = 2 << 1
ADMIN_ACCESS_RAP = 2 << 2
ADMIN_MANAGE_USERS = 2 << 3
ADMIN_BAN_USERS = 2 << 4
ADMIN_SILENCE_USERS = 2 << 5
ADMIN_WIPE_USERS = 2 << 6
ADMIN_MANAGE_BEATMAPS = 2 << 7
ADMIN_MANAGE_SERVERS = 2 << 8
ADMIN_MANAGE_SETTINGS = 2 << 9
ADMIN_MANAGE_BETAKEYS = 2 << 10
ADMIN_MANAGE_REPORTS = 2 << 11
ADMIN_MANAGE_DOCS = 2 << 12
ADMIN_MANAGE_BADGES = 2 << 13
ADMIN_VIEW_RAP_LOGS = 2 << 14
ADMIN_MANAGE_PRIVILEGES = 2 << 15
ADMIN_SEND_ALERTS = 2 << 16
ADMIN_CHAT_MOD = 2 << 17
ADMIN_KICK_USERS = 2 << 18
USER_PENDING_VERIFICATION = 2 << 19

View File

@ -1,11 +1,11 @@
""" Contains functions used to write specific server packets to byte streams """
from helpers import packetHelper
from common.constants import privileges
from common.ripple import userUtils
from constants import dataTypes
from helpers import userHelper
from objects import glob
from constants import userRanks
from constants import packetIDs
from constants import privileges
from constants import userRanks
from helpers import packetHelper
from objects import glob
""" Login errors packets """
def loginFailed():
@ -56,7 +56,7 @@ def userSupporterGMT(supporter, GMT):
return packetHelper.buildPacket(packetIDs.server_supporterGMT, [[result, dataTypes.UINT32]])
def friendList(userID):
friends = userHelper.getFriendList(userID)
friends = userUtils.getFriendList(userID)
return packetHelper.buildPacket(packetIDs.server_friendsList, [[friends, dataTypes.INT_LIST]])
def onlineUsers():
@ -95,9 +95,9 @@ def userPanel(userID, force = False):
# Only admins and normal users are currently supported
if username == "FokaBot":
userRank = userRanks.MOD
elif userHelper.isInPrivilegeGroup(userID, "community manager"):
elif userUtils.isInPrivilegeGroup(userID, "community manager"):
userRank = userRanks.MOD
elif userHelper.isInPrivilegeGroup(userID, "developer"):
elif userUtils.isInPrivilegeGroup(userID, "developer"):
userRank = userRanks.ADMIN
elif (userToken.privileges & privileges.USER_DONOR) > 0:
userRank = userRanks.SUPPORTER
@ -150,7 +150,7 @@ def sendMessage(fro, to, message):
[fro, dataTypes.STRING],
[message, dataTypes.STRING],
[to, dataTypes.STRING],
[userHelper.getID(fro), dataTypes.SINT32]
[userUtils.getID(fro), dataTypes.SINT32]
])
def channelJoinSuccess(userID, chan):

View File

@ -1,7 +1,8 @@
from objects import glob
from constants import serverPackets
from common.log import logUtils as log
from constants import exceptions
from helpers import logHelper as log
from constants import serverPackets
from objects import glob
def handle(userToken, _):
# get usertoken data

View File

@ -1,9 +1,10 @@
from objects import glob
from common.constants import actions
from common.log import logUtils as log
from common.ripple import userUtils
from constants import clientPackets
from constants import serverPackets
from helpers import userHelper
from helpers import logHelper as log
from constants import actions
from objects import glob
def handle(userToken, packetData):
# Get usertoken data
@ -11,13 +12,13 @@ def handle(userToken, packetData):
username = userToken.username
# Make sure we are not banned
if userHelper.isBanned(userID):
if userUtils.isBanned(userID):
userToken.enqueue(serverPackets.loginBanned())
return
# Send restricted message if needed
if not userToken.restricted:
if userHelper.isRestricted(userID):
if userUtils.isRestricted(userID):
userToken.setRestricted()
# Change action packet
@ -34,7 +35,7 @@ if userToken.matchID != -1 and userToken.actionID != actions.MULTIPLAYING and us
'''
# Update cached stats if our pp changedm if we've just submitted a score or we've changed gameMode
if (userToken.actionID == actions.PLAYING or userToken.actionID == actions.MULTIPLAYING) or (userToken.pp != userHelper.getPP(userID, userToken.gameMode)) or (userToken.gameMode != packetData["gameMode"]):
if (userToken.actionID == actions.PLAYING or userToken.actionID == actions.MULTIPLAYING) or (userToken.pp != userUtils.getPP(userID, userToken.gameMode)) or (userToken.gameMode != packetData["gameMode"]):
# Always update game mode, or we'll cache stats from the wrong game mode if we've changed it
userToken.gameMode = packetData["gameMode"]
userToken.updateCachedStats()

View File

@ -1,7 +1,8 @@
from objects import glob
from common.constants import mods
from constants import clientPackets
from constants import matchModModes
from constants import mods
from objects import glob
def handle(userToken, packetData):
# Get token data
@ -22,13 +23,13 @@ def handle(userToken, packetData):
# Host can set global DT/HT
if userID == match.hostUserID:
# If host has selected DT/HT and Freemod is enabled, set DT/HT as match mod
if (packetData["mods"] & mods.DoubleTime) > 0:
match.changeMatchMods(mods.DoubleTime)
if (packetData["mods"] & mods.DOUBLETIME) > 0:
match.changeMatchMods(mods.DOUBLETIME)
# Nightcore
if (packetData["mods"] & mods.Nightcore) > 0:
match.changeMatchMods(match.mods+mods.Nightcore)
elif (packetData["mods"] & mods.HalfTime) > 0:
match.changeMatchMods(mods.HalfTime)
if (packetData["mods"] & mods.NIGHTCORE) > 0:
match.changeMatchMods(match.mods + mods.NIGHTCORE)
elif (packetData["mods"] & mods.HALFTIME) > 0:
match.changeMatchMods(mods.HALFTIME)
else:
# No DT/HT, set global mods to 0 (we are in freemod mode)
match.changeMatchMods(0)

View File

@ -1,12 +1,14 @@
from objects import glob
import random
from common import generalUtils
from common.log import logUtils as log
from constants import clientPackets
from constants import matchModModes
import random
from constants import matchTeamTypes
from constants import matchTeams
from constants import slotStatuses
from helpers import logHelper as log
from helpers import generalFunctions
from objects import glob
def handle(userToken, packetData):
# Read new settings
@ -59,7 +61,7 @@ def handle(userToken, packetData):
# Update match settings
match.inProgress = packetData["inProgress"]
if packetData["matchPassword"] != "":
match.matchPassword = generalFunctions.stringMd5(packetData["matchPassword"])
match.matchPassword = generalUtils.stringMd5(packetData["matchPassword"])
else:
match.matchPassword = ""
match.beatmapName = packetData["beatmapName"]

View File

@ -1,9 +1,10 @@
from constants import serverPackets
from common.log import logUtils as log
from constants import clientPackets
from objects import glob
from events import joinMatchEvent
from constants import exceptions
from helpers import logHelper as log
from constants import serverPackets
from events import joinMatchEvent
from objects import glob
def handle(userToken, packetData):
try:

View File

@ -1,11 +1,12 @@
from helpers import userHelper
from common.log import logUtils as log
from common.ripple import userUtils
from constants import clientPackets
from helpers import logHelper as log
def handle(userToken, packetData):
# Friend add packet
packetData = clientPackets.addRemoveFriend(packetData)
userHelper.addFriend(userToken.userID, packetData["friendID"])
userUtils.addFriend(userToken.userID, packetData["friendID"])
# Console output
log.info("{} have added {} to their friends".format(userToken.username, str(packetData["friendID"])))

View File

@ -1,11 +1,12 @@
from helpers import userHelper
from common.log import logUtils as log
from common.ripple import userUtils
from constants import clientPackets
from helpers import logHelper as log
def handle(userToken, packetData):
# Friend remove packet
packetData = clientPackets.addRemoveFriend(packetData)
userHelper.removeFriend(userToken.userID, packetData["friendID"])
userUtils.removeFriend(userToken.userID, packetData["friendID"])
# Console output
log.info("{} have removed {} from their friends".format(userToken.username, str(packetData["friendID"])))

View File

@ -1,6 +1,7 @@
from common.log import logUtils as log
from constants import serverPackets
from objects import glob
from helpers import logHelper as log
def handle(userToken, _):
# Get userToken data

View File

@ -1,10 +1,11 @@
from common import generalUtils
from common.log import logUtils as log
from constants import clientPackets
from constants import serverPackets
from objects import glob
from constants import exceptions
from helpers import logHelper as log
from constants import serverPackets
from helpers import chatHelper as chat
from helpers import generalFunctions
from objects import glob
def handle(userToken, packetData):
# read packet data
@ -34,7 +35,7 @@ def joinMatch(userToken, matchID, password, isPasswordHashed = False):
# Hash password if needed
if isPasswordHashed == False and password != "":
password = generalFunctions.stringMd5(password)
password = generalUtils.stringMd5(password)
# Check password
# TODO: Admins can enter every match

View File

@ -1,15 +1,17 @@
from helpers import userHelper
from constants import serverPackets
from constants import exceptions
from objects import glob
from helpers import locationHelper
from helpers import countryHelper
import sys
import traceback
from helpers import logHelper as log
from helpers import chatHelper as chat
from constants import privileges
import time
import traceback
from common.constants import privileges
from common.log import logUtils as log
from common.ripple import userUtils
from constants import exceptions
from constants import serverPackets
from helpers import chatHelper as chat
from helpers import countryHelper
from helpers import locationHelper
from objects import glob
def handle(tornadoRequest):
# Data to return
@ -51,24 +53,24 @@ def handle(tornadoRequest):
# Try to get the ID from username
username = str(loginData[0])
userID = userHelper.getID(username)
userID = userUtils.getID(username)
if not userID:
# Invalid username
raise exceptions.loginFailedException()
if not userHelper.checkLogin(userID, loginData[1]):
if not userUtils.checkLogin(userID, loginData[1]):
# Invalid password
raise exceptions.loginFailedException()
# Make sure we are not banned or locked
priv = userHelper.getPrivileges(userID)
if userHelper.isBanned(userID) == True and priv & privileges.USER_PENDING_VERIFICATION == 0:
priv = userUtils.getPrivileges(userID)
if userUtils.isBanned(userID) == True and priv & privileges.USER_PENDING_VERIFICATION == 0:
raise exceptions.loginBannedException()
if userHelper.isLocked(userID) == True and priv & privileges.USER_PENDING_VERIFICATION == 0:
if userUtils.isLocked(userID) == True and priv & privileges.USER_PENDING_VERIFICATION == 0:
raise exceptions.loginLockedException()
# 2FA check
if userHelper.check2FA(userID, requestIP):
if userUtils.check2FA(userID, requestIP):
log.warning("Need 2FA check for user {}".format(loginData[0]))
raise exceptions.need2FAException()
@ -76,8 +78,8 @@ def handle(tornadoRequest):
# Verify this user (if pending activation)
firstLogin = False
if priv & privileges.USER_PENDING_VERIFICATION > 0 or userHelper.hasVerifiedHardware(userID) == False:
if userHelper.verifyUser(userID, clientData):
if priv & privileges.USER_PENDING_VERIFICATION > 0 or userUtils.hasVerifiedHardware(userID) == False:
if userUtils.verifyUser(userID, clientData):
# Valid account
log.info("Account {} verified successfully!".format(userID))
glob.verifiedCache[str(userID)] = 1
@ -90,7 +92,7 @@ def handle(tornadoRequest):
# Save HWID in db for multiaccount detection
hwAllowed = userHelper.logHardware(userID, clientData, firstLogin)
hwAllowed = userUtils.logHardware(userID, clientData, firstLogin)
# This is false only if HWID is empty
# if HWID is banned, we get restricted so there's no
@ -99,7 +101,7 @@ def handle(tornadoRequest):
raise exceptions.haxException()
# Log user IP
userHelper.logIP(userID, requestIP)
userUtils.logIP(userID, requestIP)
# Delete old tokens for that user and generate a new one
glob.tokens.deleteOldTokens(userID)
@ -111,7 +113,7 @@ def handle(tornadoRequest):
# Send message if donor expires soon
if responseToken.privileges & privileges.USER_DONOR > 0:
expireDate = userHelper.getDonorExpire(responseToken.userID)
expireDate = userUtils.getDonorExpire(responseToken.userID)
if expireDate-int(time.time()) <= 86400*3:
expireDays = round((expireDate-int(time.time()))/86400)
expireIn = "{} days".format(expireDays) if expireDays > 1 else "less than 24 hours"
@ -119,7 +121,7 @@ def handle(tornadoRequest):
# Set silence end UNIX time in token
responseToken.silenceEndTime = userHelper.getSilenceEnd(userID)
responseToken.silenceEndTime = userUtils.getSilenceEnd(userID)
# Get only silence remaining seconds
silenceSeconds = responseToken.getSilenceSecondsLeft()
@ -193,15 +195,15 @@ def handle(tornadoRequest):
log.warning("Location skipped")
location = [0,0]
countryLetters = "XX"
country = countryHelper.getCountryID(userHelper.getCountry(userID))
country = countryHelper.getCountryID(userUtils.getCountry(userID))
# Set location and country
responseToken.setLocation(location)
responseToken.setCountry(country)
# Set country in db if user has no country (first bancho login)
if userHelper.getCountry(userID) == "XX":
userHelper.setCountry(userID, countryLetters)
if userUtils.getCountry(userID) == "XX":
userUtils.setCountry(userID, countryLetters)
# Send to everyone our userpanel if we are not restricted
if not responseToken.restricted:

View File

@ -1,8 +1,10 @@
from objects import glob
from constants import serverPackets
import time
from helpers import logHelper as log
from common.log import logUtils as log
from constants import serverPackets
from helpers import chatHelper as chat
from objects import glob
def handle(userToken, _=None):
# get usertoken data

View File

@ -1,6 +1,7 @@
from objects import glob
from helpers import logHelper as log
from common.log import logUtils as log
from helpers import chatHelper as chat
from objects import glob
def handle(userToken, _):
# Get usertoken data

View File

@ -1,5 +1,5 @@
from constants import serverPackets
from helpers import logHelper as log
def handle(userToken, packetData):
# Update cache and send new stats

View File

@ -1,6 +1,7 @@
from common.log import logUtils as log
from constants import clientPackets
from constants import serverPackets
from helpers import logHelper as log
def handle(userToken, packetData):
# get token data

View File

@ -1,10 +1,11 @@
from common.log import logUtils as log
from common.ripple import userUtils
from constants import clientPackets
from constants import serverPackets
from constants import exceptions
from objects import glob
from helpers import userHelper
from helpers import logHelper as log
from constants import serverPackets
from helpers import chatHelper as chat
from objects import glob
def handle(userToken, packetData):
try:
@ -50,7 +51,7 @@ def handle(userToken, packetData):
c.enqueue(serverPackets.fellowSpectatorJoined(userID))
# Console output
log.info("{} are spectating {}".format(username, userHelper.getUsername(packetData["userID"])))
log.info("{} are spectating {}".format(username, userUtils.getUsername(packetData["userID"])))
except exceptions.tokenNotFoundException:
# Stop spectating if token not found
log.warning("Spectator start: token not found")

View File

@ -1,6 +1,7 @@
from common.log import logUtils as log
from constants import clientPackets
from constants import serverPackets
from helpers import logHelper as log
def handle(userToken, packetData):
# Read userIDs list

View File

@ -1,6 +1,7 @@
from common.log import logUtils as log
from constants import clientPackets
from constants import serverPackets
from helpers import logHelper as log
def handle(userToken, packetData):
# Read userIDs list

View File

@ -1,17 +1,19 @@
from helpers import requestHelper
from constants import exceptions
import json
from objects import glob
from helpers import chatHelper
from helpers import logHelper as log
class handler(requestHelper.asyncRequestHandler):
from common.log import logUtils as log
from common.web import requestsManager
from constants import exceptions
from helpers import chatHelper
from objects import glob
class handler(requestsManager.asyncRequestHandler):
def asyncGet(self):
statusCode = 400
data = {"message": "unknown error"}
try:
# Check arguments
if not requestHelper.checkArguments(self.request.arguments, ["k", "to", "msg"]):
if not requestsManager.checkArguments(self.request.arguments, ["k", "to", "msg"]):
raise exceptions.invalidArgumentsException()
# Check ci key

View File

@ -1,9 +1,11 @@
from helpers import requestHelper
from constants import exceptions
import json
from common.web import requestsManager
from constants import exceptions
from objects import glob
class handler(requestHelper.asyncRequestHandler):
class handler(requestsManager.asyncRequestHandler):
def asyncGet(self):
statusCode = 400
data = {"message": "unknown error"}

View File

@ -1,8 +1,10 @@
from helpers import requestHelper
import json
from common.web import requestsManager
from objects import glob
class handler(requestHelper.asyncRequestHandler):
class handler(requestsManager.asyncRequestHandler):
def asyncGet(self):
statusCode = 400
data = {"message": "unknown error"}

View File

@ -1,8 +1,10 @@
from helpers import requestHelper
import json
from common.web import requestsManager
from objects import glob
class handler(requestHelper.asyncRequestHandler):
class handler(requestsManager.asyncRequestHandler):
def asyncGet(self):
statusCode = 400
data = {"message": "unknown error"}

View File

@ -1,16 +1,17 @@
from helpers import requestHelper
from helpers import logHelper as log
import json
from objects import glob
from constants import exceptions
class handler(requestHelper.asyncRequestHandler):
from common.web import requestsManager
from constants import exceptions
from objects import glob
class handler(requestsManager.asyncRequestHandler):
def asyncGet(self):
statusCode = 400
data = {"message": "unknown error"}
try:
# Check arguments
if not requestHelper.checkArguments(self.request.arguments, ["u"]):
if not requestsManager.checkArguments(self.request.arguments, ["u"]):
raise exceptions.invalidArgumentsException()
# Get userID and its verified cache thing

View File

@ -1,17 +1,19 @@
from helpers import requestHelper
from constants import exceptions
import json
from objects import glob
from helpers import systemHelper
from helpers import logHelper as log
class handler(requestHelper.asyncRequestHandler):
from common.log import logUtils as log
from common.web import requestsManager
from constants import exceptions
from helpers import systemHelper
from objects import glob
class handler(requestsManager.asyncRequestHandler):
def asyncGet(self):
statusCode = 400
data = {"message": "unknown error"}
try:
# Check arguments
if not requestHelper.checkArguments(self.request.arguments, ["k"]):
if not requestsManager.checkArguments(self.request.arguments, ["k"]):
raise exceptions.invalidArgumentsException()
# Check ci key

View File

@ -1,60 +1,61 @@
import datetime
import gzip
from helpers import requestHelper
from objects import glob
from constants import exceptions
from constants import packetIDs
from helpers import packetHelper
from constants import serverPackets
from events import sendPublicMessageEvent
from events import sendPrivateMessageEvent
from events import channelJoinEvent
from events import channelPartEvent
from events import changeActionEvent
from events import cantSpectateEvent
from events import startSpectatingEvent
from events import stopSpectatingEvent
from events import spectateFramesEvent
from events import friendAddEvent
from events import friendRemoveEvent
from events import logoutEvent
from events import loginEvent
from events import setAwayMessageEvent
from events import joinLobbyEvent
from events import createMatchEvent
from events import partLobbyEvent
from events import changeSlotEvent
from events import joinMatchEvent
from events import partMatchEvent
from events import changeMatchSettingsEvent
from events import changeMatchPasswordEvent
from events import changeMatchModsEvent
from events import matchReadyEvent
from events import matchLockEvent
from events import matchStartEvent
from events import matchPlayerLoadEvent
from events import matchSkipEvent
from events import matchFramesEvent
from events import matchCompleteEvent
from events import matchNoBeatmapEvent
from events import matchHasBeatmapEvent
from events import matchTransferHostEvent
from events import matchFailedEvent
from events import matchInviteEvent
from events import matchChangeTeamEvent
from events import userStatsRequestEvent
from events import requestStatusUpdateEvent
from events import userPanelRequestEvent
# Exception tracking
import tornado.web
import tornado.gen
import sys
import traceback
from raven.contrib.tornado import SentryMixin
from helpers import logHelper as log
class handler(SentryMixin, requestHelper.asyncRequestHandler):
import tornado.gen
import tornado.web
from raven.contrib.tornado import SentryMixin
from common.log import logUtils as log
from common.web import requestsManager
from constants import exceptions
from constants import packetIDs
from constants import serverPackets
from events import cantSpectateEvent
from events import changeActionEvent
from events import changeMatchModsEvent
from events import changeMatchPasswordEvent
from events import changeMatchSettingsEvent
from events import changeSlotEvent
from events import channelJoinEvent
from events import channelPartEvent
from events import createMatchEvent
from events import friendAddEvent
from events import friendRemoveEvent
from events import joinLobbyEvent
from events import joinMatchEvent
from events import loginEvent
from events import logoutEvent
from events import matchChangeTeamEvent
from events import matchCompleteEvent
from events import matchFailedEvent
from events import matchFramesEvent
from events import matchHasBeatmapEvent
from events import matchInviteEvent
from events import matchLockEvent
from events import matchNoBeatmapEvent
from events import matchPlayerLoadEvent
from events import matchReadyEvent
from events import matchSkipEvent
from events import matchStartEvent
from events import matchTransferHostEvent
from events import partLobbyEvent
from events import partMatchEvent
from events import requestStatusUpdateEvent
from events import sendPrivateMessageEvent
from events import sendPublicMessageEvent
from events import setAwayMessageEvent
from events import spectateFramesEvent
from events import startSpectatingEvent
from events import stopSpectatingEvent
from events import userPanelRequestEvent
from events import userStatsRequestEvent
from helpers import packetHelper
from objects import glob
class handler(SentryMixin, requestsManager.asyncRequestHandler):
@tornado.web.asynchronous
@tornado.gen.engine
def asyncPost(self):

View File

@ -1,12 +1,12 @@
from objects import glob
from helpers import logHelper as log
from common.log import logUtils as log
from common.ripple import userUtils
from constants import exceptions
from constants import serverPackets
from objects import fokabot
from helpers import discordBotHelper
from helpers import userHelper
from events import logoutEvent
from constants import messageTemplates
from constants import serverPackets
from events import logoutEvent
from objects import fokabot
from objects import glob
def joinChannel(userID = 0, channel = "", token = None, toIRC = True):
"""
@ -272,7 +272,7 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True):
# File and discord logs (public chat only)
if to.startswith("#"):
log.chat("{fro} @ {to}: {message}".format(fro=username, to=to, message=str(message.encode("utf-8"))))
discordBotHelper.sendChatlog("**{fro} @ {to}:** {message}".format(fro=username, to=to, message=str(message.encode("utf-8"))[2:-1]))
glob.schiavo.sendChatlog("**{fro} @ {to}:** {message}".format(fro=username, to=to, message=str(message.encode("utf-8"))[2:-1]))
return 0
except exceptions.userSilencedException:
token.enqueue(serverPackets.silenceEndTime(token.getSilenceSecondsLeft()))
@ -314,7 +314,7 @@ def fixUsernameForIRC(username):
return username.replace(" ", "_")
def IRCConnect(username):
userID = userHelper.getID(username)
userID = userUtils.getID(username)
if not userID:
log.warning("{} doesn't exist".format(username))
return
@ -332,7 +332,7 @@ def IRCDisconnect(username):
log.info("{} disconnected from IRC".format(username))
def IRCJoinChannel(username, channel):
userID = userHelper.getID(username)
userID = userUtils.getID(username)
if not userID:
log.warning("{} doesn't exist".format(username))
return
@ -342,7 +342,7 @@ def IRCJoinChannel(username, channel):
return joinChannel(userID, channel)
def IRCPartChannel(username, channel):
userID = userHelper.getID(username)
userID = userUtils.getID(username)
if not userID:
log.warning("{} doesn't exist".format(username))
return

View File

@ -1,4 +1,4 @@
from constants import bcolors
from common.constants import bcolors
from objects import glob
def printServerStartHeader(asciiArt):
@ -28,7 +28,7 @@ def printServerStartHeader(asciiArt):
printColored("> Welcome to pep.py osu!bancho server v{}".format(glob.VERSION), bcolors.GREEN)
printColored("> Made by the Ripple team", bcolors.GREEN)
printColored("> {}https://git.zxq.co/ripple/pep.py".format(bcolors.UNDERLINE), bcolors.GREEN)
printColored("> Press CTRL+C to exit\n",bcolors.GREEN)
printColored("> Press CTRL+C to exit\n", bcolors.GREEN)
def printNoNl(string):
"""

View File

@ -1,222 +0,0 @@
import queue
import MySQLdb
from helpers import logHelper as log
class worker():
"""
A single MySQL worker
"""
def __init__(self, connection, temporary=False):
"""
Initialize a MySQL worker
:param connection: database connection object
:param temporary: if True, this worker will be flagged as temporary
"""
self.connection = connection
self.temporary = temporary
log.debug("Created MySQL worker. Temporary: {}".format(self.temporary))
def ping(self):
"""
Ping MySQL server using this worker.
:return: True if connected, False if error occured.
"""
try:
self.connection.cursor(MySQLdb.cursors.DictCursor).execute("SELECT 1+1")
return True
except:
return False
def __del__(self):
"""
Close connection to the server
:return:
"""
self.connection.close()
log.debug("Destroyed MySQL worker.")
class connectionsPool():
"""
A MySQL workers pool
"""
def __init__(self, host, username, password, database, initialSize=16):
"""
Initialize a MySQL connections pool
:param host: MySQL host
:param username: MySQL username
:param password: MySQL password
:param database: MySQL database name
:param initialSize: initial pool size
"""
self.config = (host, username, password, database)
self.maxSize = initialSize
self.pool = queue.Queue(0)
self.consecutiveEmptyPool = 0
self.fillPool()
def newWorker(self, temporary=False):
"""
Create a new worker.
:param temporary: if True, flag the worker as temporary
:return: instance of worker class
"""
db = MySQLdb.connect(*self.config)
db.autocommit(True)
conn = worker(db, temporary)
return conn
def expandPool(self, newWorkers=5):
"""
Add some new workers to the pool
:param newWorkers: number of new workers
:return:
"""
self.maxSize += newWorkers
self.fillPool()
def fillPool(self):
"""
Fill the queue with workers until its maxSize
:return:
"""
size = self.pool.qsize()
if self.maxSize > 0 and size >= self.maxSize:
return
newConnections = self.maxSize-size
for _ in range(0, newConnections):
self.pool.put_nowait(self.newWorker())
def getWorker(self):
"""
Get a MySQL connection worker from the pool.
If the pool is empty, a new temporary worker is created.
:return: instance of worker class
"""
if self.pool.empty():
# The pool is empty. Spawn a new temporary worker
log.warning("Using temporary worker")
worker = self.newWorker(True)
# Increment saturation
self.consecutiveEmptyPool += 1
# If the pool is usually empty, expand it
if self.consecutiveEmptyPool >= 5:
log.warning("MySQL connections pool is saturated. Filling connections pool.")
self.expandPool()
else:
# The pool is not empty. Get worker from the pool
# and reset saturation counter
worker = self.pool.get()
self.consecutiveEmptyPool = 0
# Return the connection
return worker
def putWorker(self, worker):
"""
Put the worker back in the pool.
If the worker is temporary, close the connection
and destroy the object
:param worker: worker object
:return:
"""
if worker.temporary:
del worker
else:
self.pool.put_nowait(worker)
class db:
"""
A MySQL helper with multiple workers
"""
def __init__(self, host, username, password, database, initialSize):
"""
Initialize a new MySQL database helper with multiple workers.
This class is thread safe.
:param host: MySQL host
:param username: MySQL username
:param password: MySQL password
:param database: MySQL database name
:param initialSize: initial pool size
"""
self.pool = connectionsPool(host, username, password, database, initialSize)
def execute(self, query, params = ()):
"""
Executes a query
:param query: query to execute. You can bind parameters with %s
:param params: parameters list. First element replaces first %s and so on
"""
cursor = None
worker = self.pool.getWorker()
try:
# Create cursor, execute query and commit
cursor = worker.connection.cursor(MySQLdb.cursors.DictCursor)
cursor.execute(query, params)
log.debug(query)
return cursor.lastrowid
except MySQLdb.OperationalError:
del worker
worker = None
return self.execute(query, params)
finally:
# Close the cursor and release worker's lock
if cursor is not None:
cursor.close()
if worker is not None:
self.pool.putWorker(worker)
def fetch(self, query, params = (), all = False):
"""
Fetch a single value from db that matches given query
:param query: query to execute. You can bind parameters with %s
:param params: parameters list. First element replaces first %s and so on
:param all: fetch one or all values. Used internally. Use fetchAll if you want to fetch all values
"""
cursor = None
worker = self.pool.getWorker()
try:
# Create cursor, execute the query and fetch one/all result(s)
cursor = worker.connection.cursor(MySQLdb.cursors.DictCursor)
cursor.execute(query, params)
log.debug(query)
if all == True:
return cursor.fetchall()
else:
return cursor.fetchone()
except MySQLdb.OperationalError:
del worker
worker = None
return self.fetch(query, params, all)
finally:
# Close the cursor and release worker's lock
if cursor is not None:
cursor.close()
if worker is not None:
self.pool.putWorker(worker)
def fetchAll(self, query, params = ()):
"""
Fetch all values from db that matche given query.
Calls self.fetch with all = True.
:param query: query to execute. You can bind parameters with %s
:param params: parameters list. First element replaces first %s and so on
"""
return self.fetch(query, params, True)

View File

@ -1,136 +0,0 @@
from constants import mods
from time import gmtime, strftime
import hashlib
def stringMd5(string):
"""
Return string's md5
string -- string to hash
return -- string's md5 hash
"""
d = hashlib.md5()
d.update(string.encode("utf-8"))
return d.hexdigest()
def stringToBool(s):
"""
Convert a string (True/true/1) to bool
s -- string/int value
return -- True/False
"""
return s == "True" or s == "true" or s == "1" or s == 1
def hexString(s):
"""
Output s' bytes in HEX
s -- string
return -- string with hex value
"""
return ":".join("{:02x}".format(ord(str(c))) for c in s)
def readableMods(__mods):
"""
Return a string with readable std mods.
Used to convert a mods number for oppai
__mods -- mods bitwise number
return -- readable mods string, eg HDDT
"""
r = ""
if __mods == 0:
return r
if __mods & mods.NoFail > 0:
r += "NF"
if __mods & mods.Easy > 0:
r += "EZ"
if __mods & mods.Hidden > 0:
r += "HD"
if __mods & mods.HardRock > 0:
r += "HR"
if __mods & mods.DoubleTime > 0:
r += "DT"
if __mods & mods.HalfTime > 0:
r += "HT"
if __mods & mods.Flashlight > 0:
r += "FL"
if __mods & mods.SpunOut > 0:
r += "SO"
return r
def getRank(gameMode, __mods, acc, c300, c100, c50, cmiss):
"""
Return a string with rank/grade for a given score.
Used mainly for "tillerino"
gameMode -- mode (0 = osu!, 1 = Taiko, 2 = CtB, 3 = osu!mania)
__mods -- mods bitwise number
acc -- accuracy
c300 -- 300 hit count
c100 -- 100 hit count
c50 -- 50 hit count
cmiss -- miss count
return -- rank/grade string
"""
total = c300 + c100 + c50 + cmiss
hdfl = (__mods & (mods.Hidden | mods.Flashlight | mods.FadeIn)) > 0
ss = "sshd" if hdfl else "ss"
s = "shd" if hdfl else "s"
if gameMode == 0 or gameMode == 1:
# osu!std / taiko
ratio300 = c300 / total
ratio50 = c50 / total
if ratio300 == 1:
return ss
if ratio300 > 0.9 and ratio50 <= 0.01 and cmiss == 0:
return s
if (ratio300 > 0.8 and cmiss == 0) or (ratio300 > 0.9):
return "a"
if (ratio300 > 0.7 and cmiss == 0) or (ratio300 > 0.8):
return "b"
if ratio300 > 0.6:
return "c"
return "d"
elif gameMode == 2:
# CtB
if acc == 100:
return ss
if acc > 98:
return s
if acc > 94:
return "a"
if acc > 90:
return "b"
if acc > 85:
return "c"
return "d"
elif gameMode == 3:
# osu!mania
if acc == 100:
return ss
if acc > 95:
return s
if acc > 90:
return "a"
if acc > 80:
return "b"
if acc > 70:
return "c"
return "d"
return "a"
def strContains(s, w):
return (' ' + w + ' ') in (' ' + s + ' ')
def getTimestamp():
"""
Return current time in YYYY-MM-DD HH:MM:SS format.
Used in logs.
"""
return strftime("%Y-%m-%d %H:%M:%S", gmtime())

View File

@ -1,8 +1,9 @@
import urllib.request
import json
import urllib.request
from common.log import logUtils as log
from objects import glob
from helpers import logHelper as log
def getCountry(ip):
"""

View File

@ -1,135 +0,0 @@
from constants import bcolors
from helpers import discordBotHelper
from helpers import generalFunctions
from objects import glob
from helpers import userHelper
import time
import os
ENDL = "\n" if os.name == "posix" else "\r\n"
def logMessage(message, alertType = "INFO", messageColor = bcolors.ENDC, discord = None, alertDev = False, of = None, stdout = True):
"""
Logs a message to stdout/discord/file
message -- message to log
alertType -- can be any string. Standard types: INFO, WARNING and ERRORS. Defalt: INFO
messageColor -- message color (see constants.bcolors). Default = bcolots.ENDC (no color)
discord -- discord channel (bunker/cm/staff/general). Optional. Default = None
alertDev -- if True, devs will receive an hl on discord. Default: False
of -- if not None but a string, log the message to that file (inside .data folder). Eg: "warnings.txt" Default: None (don't log to file)
stdout -- if True, print the message to stdout. Default: True
"""
# Get type color from alertType
if alertType == "INFO":
typeColor = bcolors.GREEN
elif alertType == "WARNING":
typeColor = bcolors.YELLOW
elif alertType == "ERROR":
typeColor = bcolors.RED
elif alertType == "CHAT":
typeColor = bcolors.BLUE
elif alertType == "DEBUG":
typeColor = bcolors.PINK
else:
typeColor = bcolors.ENDC
# Message without colors
finalMessage = "[{time}] {type} - {message}".format(time=generalFunctions.getTimestamp(), type=alertType, message=message)
# Message with colors
finalMessageConsole = "{typeColor}[{time}] {type}{endc} - {messageColor}{message}{endc}".format(
time=generalFunctions.getTimestamp(),
type=alertType,
message=message,
typeColor=typeColor,
messageColor=messageColor,
endc=bcolors.ENDC)
# Log to console
if stdout:
print(finalMessageConsole)
# Log to discord if needed
if discord is not None:
if discord == "bunker":
discordBotHelper.sendConfidential(message, alertDev)
elif discord == "cm":
discordBotHelper.sendCM(message)
elif discord == "staff":
discordBotHelper.sendStaff(message)
elif discord == "general":
discordBotHelper.sendGeneral(message)
# Log to file if needed
if of is not None:
glob.fileBuffers.write(".data/"+of, finalMessage+ENDL)
def warning(message, discord = None, alertDev = False):
"""
Log a warning to stdout (always) and discord (optional)
message -- warning message
discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None
alertDev -- if True, send al hl to devs on discord. Optional. Default = False.
"""
logMessage(message, "WARNING", bcolors.YELLOW, discord, alertDev)
def error(message, discord = None, alertDev = True):
"""
Log an error to stdout (always) and discord (optional)
message -- error message
discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None
alertDev -- if True, send al hl to devs on discord. Optional. Default = False.
"""
logMessage(message, "ERROR", bcolors.RED, discord, alertDev)
def info(message, discord = None, alertDev = False):
"""
Log an info message to stdout
message -- info message
discord -- if not None, send message to that discord channel through schiavo. Optional. Default = None
alertDev -- if True, send al hl to devs on discord. Optional. Default = False.
"""
logMessage(message, "INFO", bcolors.ENDC, discord, alertDev)
def debug(message):
"""
Log a debug message to stdout if server is running in debug mode
message -- debug message
"""
if glob.debug:
logMessage(message, "DEBUG", bcolors.PINK)
def chat(message):
"""
Log public messages to stdout and chatlog_public.txt
message -- chat message
"""
logMessage(message, "CHAT", bcolors.BLUE, of="chatlog_public.txt")
def pm(message):
"""
Log private messages to stdout and chatlog_private.txt
message -- chat message
"""
logMessage(message, "CHAT", bcolors.BLUE, of="chatlog_private.txt")
def rap(userID, message, discord=False, through="FokaBot"):
"""
Log a private message to Admin logs
userID -- userID of who made the action
message -- message without subject (eg: "is a meme" becomes "user is a meme")
discord -- if True, send message to discord
through -- "through" thing string. Optional. Default: "FokaBot"
"""
glob.db.execute("INSERT INTO rap_logs (id, userid, text, datetime, through) VALUES (NULL, %s, %s, %s, %s)", [userID, message, int(time.time()), through])
if discord:
username = userHelper.getUsername(userID)
logMessage("{} {}".format(username, message), discord=True)

View File

@ -1,35 +0,0 @@
from helpers import cryptHelper
import base64
import bcrypt
def checkOldPassword(password, salt, rightPassword):
"""
Check if password+salt corresponds to rightPassword
password -- input password
salt -- password's salt
rightPassword -- right password
return -- bool
"""
return rightPassword == cryptHelper.crypt(password, "$2y$" + str(base64.b64decode(salt)))
def checkNewPassword(password, dbPassword):
"""
Check if a password (version 2) is right.
password -- input password
dbPassword -- the password in the database
return -- bool
"""
password = password.encode("utf8")
dbPassword = dbPassword.encode("utf8")
return bcrypt.hashpw(password, dbPassword) == dbPassword
def genBcrypt(password):
"""
Bcrypts a password.
password -- the password to hash.
return -- bytestring
"""
return bcrypt.hashpw(password.encode("utf8"), bcrypt.gensalt(10, b'2a'))

View File

@ -1,101 +0,0 @@
import tornado
import tornado.web
import tornado.gen
from tornado.ioloop import IOLoop
from objects import glob
import threading
from helpers import logHelper as log
class asyncRequestHandler(tornado.web.RequestHandler):
"""
Tornado asynchronous request handler
create a class that extends this one (requestHelper.asyncRequestHandler)
use asyncGet() and asyncPost() instad of get() and post().
Done. I'm not kidding.
"""
@tornado.web.asynchronous
@tornado.gen.engine
def get(self, *args, **kwargs):
try:
yield tornado.gen.Task(runBackground, (self.asyncGet, tuple(args), dict(kwargs)))
except Exception as e:
yield tornado.gen.Task(self.captureException, exc_info=True)
finally:
if not self._finished:
self.finish()
@tornado.web.asynchronous
@tornado.gen.engine
def post(self, *args, **kwargs):
try:
yield tornado.gen.Task(runBackground, (self.asyncPost, tuple(args), dict(kwargs)))
except Exception as e:
yield tornado.gen.Task(self.captureException, exc_info=True)
finally:
if not self._finished:
self.finish()
def asyncGet(self, *args, **kwargs):
self.send_error(405)
self.finish()
def asyncPost(self, *args, **kwargs):
self.send_error(405)
self.finish()
def getRequestIP(self):
realIP = self.request.headers.get("X-Forwarded-For") if glob.cloudflare == True else self.request.headers.get("X-Real-IP")
if realIP is not None:
return realIP
return self.request.remote_ip
def runBackground(data, callback):
"""
Run a function in the background.
Used to handle multiple requests at the same time
"""
func, args, kwargs = data
def _callback(result):
#glob.busyThreads -= 1
IOLoop.instance().add_callback(lambda: callback(result))
glob.pool.apply_async(func, args, kwargs, _callback)
#threading.Thread(target=checkPoolSaturation).start()
#glob.busyThreads += 1
def checkPoolSaturation():
"""
Check the number of busy threads in connections pool.
If the pool is 100% busy, log a message to sentry
"""
size = int(glob.conf.config["server"]["threads"])
if glob.busyThreads >= size:
msg = "Connections threads pool is saturated!"
log.warning(msg)
glob.application.sentry_client.captureMessage(msg, level="warning", extra={
"workersBusy": glob.busyThreads,
"workersTotal": size
})
def checkArguments(arguments, requiredArguments):
"""
Check that every requiredArguments elements are in arguments
arguments -- full argument list, from tornado
requiredArguments -- required arguments list es: ["u", "ha"]
handler -- handler string name to print in exception. Optional
return -- True if all arguments are passed, none if not
"""
for i in requiredArguments:
if i not in arguments:
return False
return True
def printArguments(t):
"""
Print passed arguments, for debug purposes
t -- tornado object (self)
"""
print("ARGS::")
for i in t.request.arguments:
print ("{}={}".format(i, t.get_argument(i)))

View File

@ -1,15 +1,18 @@
from objects import glob
from constants import serverPackets
from helpers import consoleHelper
import psutil
import math
import os
import signal
import sys
import threading
import signal
from helpers import logHelper as log
from constants import bcolors
import time
import math
import psutil
from common.constants import bcolors
from common.log import logUtils as log
from constants import serverPackets
from helpers import consoleHelper
from objects import glob
def dispose():
"""

View File

@ -1,640 +0,0 @@
from helpers import passwordHelper
from constants import gameModes
from constants import privileges
from helpers import generalFunctions
from objects import glob
from helpers import logHelper as log
import time
from constants import privileges
def getID(username):
"""
Get username's user ID from userID cache (if cache hit)
or from db (and cache it for other requests) if cache miss
username -- user
return -- user id or 0
"""
# Add to cache if needed
if username not in glob.userIDCache:
userID = glob.db.fetch("SELECT id FROM users WHERE username = %s LIMIT 1", [username])
if userID == None:
return 0
glob.userIDCache[username] = userID["id"]
# Get userID from cache
return glob.userIDCache[username]
def checkLogin(userID, password):
"""
Check userID's login with specified password
db -- database connection
userID -- user id
password -- plain md5 password
return -- True or False
"""
# Get password data
passwordData = glob.db.fetch("SELECT password_md5, salt, password_version FROM users WHERE id = %s LIMIT 1", [userID])
# Make sure the query returned something
if passwordData is None:
return False
# Return valid/invalid based on the password version.
if passwordData["password_version"] == 2:
return passwordHelper.checkNewPassword(password, passwordData["password_md5"])
if passwordData["password_version"] == 1:
ok = passwordHelper.checkOldPassword(password, passwordData["salt"], passwordData["password_md5"])
if not ok: return False
newpass = passwordHelper.genBcrypt(password)
glob.db.execute("UPDATE users SET password_md5=%s, salt='', password_version='2' WHERE id = %s LIMIT 1", [newpass, userID])
def exists(userID):
"""
Check if userID exists
userID -- user ID to check
return -- bool
"""
result = glob.db.fetch("SELECT id FROM users WHERE id = %s LIMIT 1", [userID])
if result is None:
return False
else:
return True
def getSilenceEnd(userID):
"""
Get userID's **ABSOLUTE** silence end UNIX time
Remember to subtract time.time() to get the actual silence time
userID -- userID
return -- UNIX time
"""
return glob.db.fetch("SELECT silence_end FROM users WHERE id = %s LIMIT 1", [userID])["silence_end"]
def silence(userID, seconds, silenceReason, author = 999):
"""
Silence someone
userID -- userID
seconds -- silence length in seconds
silenceReason -- Silence reason shown on website
author -- userID of who silenced the user. Default: 999
"""
# db qurey
silenceEndTime = int(time.time())+seconds
glob.db.execute("UPDATE users SET silence_end = %s, silence_reason = %s WHERE id = %s LIMIT 1", [silenceEndTime, silenceReason, userID])
# Loh
targetUsername = getUsername(userID)
# TODO: exists check im drunk rn i need to sleep (stampa piede ubriaco confirmed)
if seconds > 0:
log.rap(author, "has silenced {} for {} seconds for the following reason: \"{}\"".format(targetUsername, seconds, silenceReason), True)
else:
log.rap(author, "has removed {}'s silence".format(targetUsername), True)
def getRankedScore(userID, gameMode):
"""
Get userID's ranked score relative to gameMode
userID -- userID
gameMode -- int value, see gameModes
return -- ranked score
"""
modeForDB = gameModes.getGameModeForDB(gameMode)
return glob.db.fetch("SELECT ranked_score_"+modeForDB+" FROM users_stats WHERE id = %s LIMIT 1", [userID])["ranked_score_"+modeForDB]
def getTotalScore(userID, gameMode):
"""
Get userID's total score relative to gameMode
userID -- userID
gameMode -- int value, see gameModes
return -- total score
"""
modeForDB = gameModes.getGameModeForDB(gameMode)
return glob.db.fetch("SELECT total_score_"+modeForDB+" FROM users_stats WHERE id = %s LIMIT 1", [userID])["total_score_"+modeForDB]
def getAccuracy(userID, gameMode):
"""
Get userID's average accuracy relative to gameMode
userID -- userID
gameMode -- int value, see gameModes
return -- accuracy
"""
modeForDB = gameModes.getGameModeForDB(gameMode)
return glob.db.fetch("SELECT avg_accuracy_"+modeForDB+" FROM users_stats WHERE id = %s LIMIT 1", [userID])["avg_accuracy_"+modeForDB]
def getGameRank(userID, gameMode):
"""
Get userID's **in-game rank** (eg: #1337) relative to gameMode
userID -- userID
gameMode -- int value, see gameModes
return -- game rank
"""
modeForDB = gameModes.getGameModeForDB(gameMode)
result = glob.db.fetch("SELECT position FROM leaderboard_"+modeForDB+" WHERE user = %s LIMIT 1", [userID])
if result is None:
return 0
else:
return result["position"]
def getPlaycount(userID, gameMode):
"""
Get userID's playcount relative to gameMode
userID -- userID
gameMode -- int value, see gameModes
return -- playcount
"""
modeForDB = gameModes.getGameModeForDB(gameMode)
return glob.db.fetch("SELECT playcount_"+modeForDB+" FROM users_stats WHERE id = %s LIMIT 1", [userID])["playcount_"+modeForDB]
def getUsername(userID):
"""
Get userID's username
userID -- userID
return -- username
"""
return glob.db.fetch("SELECT username FROM users WHERE id = %s LIMIT 1", [userID])["username"]
def getFriendList(userID):
"""
Get userID's friendlist
userID -- userID
return -- list with friends userIDs. [0] if no friends.
"""
# Get friends from db
friends = glob.db.fetchAll("SELECT user2 FROM users_relationships WHERE user1 = %s", [userID])
if friends is None or len(friends) == 0:
# We have no friends, return 0 list
return [0]
else:
# Get only friends
friends = [i["user2"] for i in friends]
# Return friend IDs
return friends
def addFriend(userID, friendID):
"""
Add friendID to userID's friend list
userID -- user
friendID -- new friend
"""
# Make sure we aren't adding us to our friends
if userID == friendID:
return
# check user isn't already a friend of ours
if glob.db.fetch("SELECT id FROM users_relationships WHERE user1 = %s AND user2 = %s LIMIT 1", [userID, friendID]) is not None:
return
# Set new value
glob.db.execute("INSERT INTO users_relationships (user1, user2) VALUES (%s, %s)", [userID, friendID])
def removeFriend(userID, friendID):
"""
Remove friendID from userID's friend list
userID -- user
friendID -- old friend
"""
# Delete user relationship. We don't need to check if the relationship was there, because who gives a shit,
# if they were not friends and they don't want to be anymore, be it. ¯\_(ツ)_/¯
glob.db.execute("DELETE FROM users_relationships WHERE user1 = %s AND user2 = %s", [userID, friendID])
def getCountry(userID):
"""
Get userID's country **(two letters)**.
Use countryHelper.getCountryID with what that function returns
to get osu! country ID relative to that user
userID -- user
return -- country code (two letters)
"""
return glob.db.fetch("SELECT country FROM users_stats WHERE id = %s LIMIT 1", [userID])["country"]
def getPP(userID, gameMode):
"""
Get userID's PP relative to gameMode
userID -- user
return -- PP
"""
modeForDB = gameModes.getGameModeForDB(gameMode)
return glob.db.fetch("SELECT pp_{} FROM users_stats WHERE id = %s LIMIT 1".format(modeForDB), [userID])["pp_{}".format(modeForDB)]
def setCountry(userID, country):
"""
Set userID's country (two letters)
userID -- userID
country -- country letters
"""
glob.db.execute("UPDATE users_stats SET country = %s WHERE id = %s LIMIT 1", [country, userID])
def logIP(userID, ip):
"""
User IP log
USED FOR MULTIACCOUNT DETECTION
"""
glob.db.execute("""INSERT INTO ip_user (userid, ip, occurencies) VALUES (%s, %s, 1)
ON DUPLICATE KEY UPDATE occurencies = occurencies + 1""", [userID, ip])
def saveBanchoSession(userID, ip):
"""
Save userid and ip of this token in bancho_sessions table.
Used to cache logins on LETS requests
userID --
ip -- user's ip address
"""
glob.db.execute("INSERT INTO bancho_sessions (id, userid, ip) VALUES (NULL, %s, %s)", [userID, ip])
def deleteBanchoSessions(userID, ip):
"""
Delete this bancho session from DB
userID --
ip -- user's IP address
"""
try:
glob.db.execute("DELETE FROM bancho_sessions WHERE userid = %s AND ip = %s", [userID, ip])
except:
log.warning("Token for user: {} ip: {} doesn't exist".format(userID, ip))
def is2FAEnabled(userID):
"""
Check if 2FA is enabled on an account
userID --
return -- True if 2FA is enabled, False if 2FA is disabled
"""
result = glob.db.fetch("SELECT id FROM 2fa_telegram WHERE userid = %s LIMIT 1", [userID])
return True if result is not None else False
def check2FA(userID, ip):
"""
Check if an ip is trusted
userID --
ip -- user's IP address
return -- True if the IP is untrusted, False if it's trusted
"""
if not is2FAEnabled(userID):
return False
result = glob.db.fetch("SELECT id FROM ip_user WHERE userid = %s AND ip = %s", [userID, ip])
return True if result is None else False
def getUserStats(userID, gameMode):
"""
Get all user stats relative to gameMode with only two queries
userID --
gameMode -- gameMode number
return -- dictionary with results
"""
modeForDB = gameModes.getGameModeForDB(gameMode)
# Get stats
stats = glob.db.fetch("""SELECT
ranked_score_{gm} AS rankedScore,
avg_accuracy_{gm} AS accuracy,
playcount_{gm} AS playcount,
total_score_{gm} AS totalScore,
pp_{gm} AS pp
FROM users_stats WHERE id = %s LIMIT 1""".format(gm=modeForDB), [userID])
# Get game rank
result = glob.db.fetch("SELECT position FROM leaderboard_{} WHERE user = %s LIMIT 1".format(modeForDB), [userID])
if result is None:
stats["gameRank"] = 0
else:
stats["gameRank"] = result["position"]
# Return stats + game rank
return stats
def isAllowed(userID):
"""
Check if userID is not banned or restricted
userID -- id of the user
return -- True if not banned or restricted, otherwise false.
"""
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s LIMIT 1", [userID])
if result is not None:
return (result["privileges"] & privileges.USER_NORMAL) and (result["privileges"] & privileges.USER_PUBLIC)
else:
return False
def isRestricted(userID):
"""
Check if userID is restricted
userID -- id of the user
return -- True if not restricted, otherwise false.
"""
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s LIMIT 1", [userID])
if result is not None:
return (result["privileges"] & privileges.USER_NORMAL) and not (result["privileges"] & privileges.USER_PUBLIC)
else:
return False
def isBanned(userID):
"""
Check if userID is banned
userID -- id of the user
return -- True if not banned, otherwise false.
"""
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s LIMIT 1", [userID])
if result is not None:
return not (result["privileges"] & 3 > 0)
else:
return True
def isLocked(userID):
"""
Check if userID is locked
userID -- id of the user
return -- True if not locked, otherwise false.
"""
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s LIMIT 1", [userID])
if result != None:
return ((result["privileges"] & privileges.USER_PUBLIC > 0) and (result["privileges"] & privileges.USER_NORMAL == 0))
else:
return True
def ban(userID):
"""
Ban userID
userID -- id of user
"""
banDateTime = int(time.time())
glob.db.execute("UPDATE users SET privileges = privileges & %s, ban_datetime = %s WHERE id = %s LIMIT 1", [ ~(privileges.USER_NORMAL | privileges.USER_PUBLIC | privileges.USER_PENDING_VERIFICATION) , banDateTime, userID])
def unban(userID):
"""
Unban userID
userID -- id of user
"""
glob.db.execute("UPDATE users SET privileges = privileges | %s, ban_datetime = 0 WHERE id = %s LIMIT 1", [ (privileges.USER_NORMAL | privileges.USER_PUBLIC) , userID])
def restrict(userID):
"""
Put userID in restricted mode
userID -- id of user
"""
banDateTime = int(time.time())
glob.db.execute("UPDATE users SET privileges = privileges & %s, ban_datetime = %s WHERE id = %s LIMIT 1", [~privileges.USER_PUBLIC, banDateTime, userID])
def unrestrict(userID):
"""
Remove restricted mode from userID.
Same as unban().
userID -- id of user
"""
unban(userID)
def getPrivileges(userID):
"""
Return privileges for userID
userID -- id of user
return -- privileges number
"""
result = glob.db.fetch("SELECT privileges FROM users WHERE id = %s LIMIT 1", [userID])
if result is not None:
return result["privileges"]
else:
return 0
def setPrivileges(userID, priv):
"""
Set userID's privileges in db
userID -- id of user
priv -- privileges number
"""
glob.db.execute("UPDATE users SET privileges = %s WHERE id = %s LIMIT 1", [priv, userID])
def isInPrivilegeGroup(userID, groupName):
groupPrivileges = glob.db.fetch("SELECT privileges FROM privileges_groups WHERE name = %s LIMIT 1", [groupName])
if groupPrivileges is None:
return False
groupPrivileges = groupPrivileges["privileges"]
userToken = glob.tokens.getTokenFromUserID(userID)
if userToken is not None:
userPrivileges = userToken.privileges
else:
userPrivileges = getPrivileges(userID)
return (userPrivileges == groupPrivileges) or (userPrivileges == (groupPrivileges | privileges.USER_DONOR))
def appendNotes(userID, notes, addNl = True):
"""
Append "notes" to current userID's "notes for CM"
userID -- id of user
notes -- text to append
addNl -- if True, prepend \n to notes. Optional. Default: True.
"""
if addNl:
notes = "\n"+notes
glob.db.execute("UPDATE users SET notes=CONCAT(COALESCE(notes, ''),%s) WHERE id = %s LIMIT 1", [notes, userID])
def logHardware(userID, hashes, activation = False):
"""
Hardware log
USED FOR MULTIACCOUNT DETECTION
Peppy's botnet (client data) structure (new line = "|", already split)
[0] osu! version
[1] plain mac addressed, separated by "."
[2] mac addresses hash set
[3] unique ID
[4] disk ID
return -- True if hw is not banned, otherwise false
"""
# Make sure the strings are not empty
for i in hashes[2:5]:
if i == "":
log.warning("Invalid hash set ({}) for user {} in HWID check".format(hashes, userID), "bunk")
return False
# Run some HWID checks on that user if he is not restricted
if not isRestricted(userID):
# Get username
username = getUsername(userID)
# Get the list of banned or restricted users that have logged in from this or similar HWID hash set
banned = glob.db.fetchAll("""SELECT users.id as userid, hw_user.occurencies, users.username FROM hw_user
LEFT JOIN users ON users.id = hw_user.userid
WHERE hw_user.userid != %(userid)s
AND (IF(%(mac)s!='b4ec3c4334a0249dae95c284ec5983df', hw_user.mac = %(mac)s, 1) AND hw_user.unique_id = %(uid)s AND hw_user.disk_id = %(diskid)s)
AND (users.privileges & 3 != 3)""", {
"userid": userID,
"mac": hashes[2],
"uid": hashes[3],
"diskid": hashes[4],
})
for i in banned:
# Get the total numbers of logins
total = glob.db.fetch("SELECT COUNT(*) AS count FROM hw_user WHERE userid = %s LIMIT 1", [userID])
# and make sure it is valid
if total is None:
continue
total = total["count"]
# Calculate 10% of total
perc = (total*10)/100
if i["occurencies"] >= perc:
# If the banned user has logged in more than 10% of the times from this user, restrict this user
restrict(userID)
appendNotes(userID, "-- Logged in from HWID ({hwid}) used more than 10% from user {banned} ({bannedUserID}), who is banned/restricted.".format(
hwid=hashes[2:5],
banned=i["username"],
bannedUserID=i["userid"]
))
log.warning("**{user}** ({userID}) has been restricted because he has logged in from HWID _({hwid})_ used more than 10% from banned/restricted user **{banned}** ({bannedUserID}), **possible multiaccount**.".format(
user=username,
userID=userID,
hwid=hashes[2:5],
banned=i["username"],
bannedUserID=i["userid"]
), "cm")
# Update hash set occurencies
glob.db.execute("""
INSERT INTO hw_user (id, userid, mac, unique_id, disk_id, occurencies) VALUES (NULL, %s, %s, %s, %s, 1)
ON DUPLICATE KEY UPDATE occurencies = occurencies + 1
""", [userID, hashes[2], hashes[3], hashes[4]])
# Optionally, set this hash as 'used for activation'
if activation:
glob.db.execute("UPDATE hw_user SET activated = 1 WHERE userid = %s AND mac = %s AND unique_id = %s AND disk_id = %s", [userID, hashes[2], hashes[3], hashes[4]])
# Access granted, abbiamo impiegato 3 giorni
# We grant access even in case of login from banned HWID
# because we call restrict() above so there's no need to deny the access.
return True
def resetPendingFlag(userID, success=True):
"""
Remove pending flag from an user.
userID -- ID of the user
success -- if True, set USER_PUBLIC and USER_NORMAL flags too
"""
glob.db.execute("UPDATE users SET privileges = privileges & %s WHERE id = %s LIMIT 1", [~privileges.USER_PENDING_VERIFICATION, userID])
if success:
glob.db.execute("UPDATE users SET privileges = privileges | %s WHERE id = %s LIMIT 1", [(privileges.USER_PUBLIC | privileges.USER_NORMAL), userID])
def verifyUser(userID, hashes):
# Check for valid hash set
for i in hashes[2:5]:
if i == "":
log.warning("Invalid hash set ({}) for user {} while verifying the account".format(str(hashes), userID), "bunk")
return False
# Get username
username = getUsername(userID)
# Make sure there are no other accounts activated with this exact mac/unique id/hwid
match = glob.db.fetchAll("SELECT userid FROM hw_user WHERE (IF(%(mac)s != 'b4ec3c4334a0249dae95c284ec5983df', mac = %(mac)s, 1) AND unique_id = %(uid)s AND disk_id = %(diskid)s) AND userid != %(userid)s AND activated = 1 LIMIT 1", {
"mac": hashes[2],
"uid": hashes[3],
"diskid": hashes[4],
"userid": userID
})
if match:
# This is a multiaccount, restrict other account and ban this account
# Get original userID and username (lowest ID)
originalUserID = match[0]["userid"]
originalUsername = getUsername(originalUserID)
# Ban this user and append notes
ban(userID) # this removes the USER_PENDING_VERIFICATION flag too
appendNotes(userID, "-- {}'s multiaccount ({}), found HWID match while verifying account ({})".format(originalUsername, originalUserID, hashes[2:5]))
appendNotes(originalUserID, "-- Has created multiaccount {} ({})".format(username, userID))
# Restrict the original
restrict(originalUserID)
# Discord message
log.warning("User **{originalUsername}** ({originalUserID}) has been restricted because he has created multiaccount **{username}** ({userID}). The multiaccount has been banned.".format(
originalUsername=originalUsername,
originalUserID=originalUserID,
username=username,
userID=userID
), "cm")
# Disallow login
return False
else:
# No matches found, set USER_PUBLIC and USER_NORMAL flags and reset USER_PENDING_VERIFICATION flag
resetPendingFlag(userID)
log.info("User **{}** ({}) has verified his account with hash set _{}_".format(username, userID, hashes[2:5]), "cm")
# Allow login
return True
def hasVerifiedHardware(userID):
"""
userID -- id of the user
return -- True if hwid activation data is in db, otherwise false
"""
data = glob.db.fetch("SELECT id FROM hw_user WHERE userid = %s AND activated = 1 LIMIT 1", [userID])
if data is not None:
return True
return False
def cacheUserIDs():
"""Cache userIDs in glob.userIDCache, used later with getID()."""
data = glob.db.fetchAll("SELECT id, username FROM users WHERE privileges & {} > 0".format(privileges.USER_NORMAL))
for i in data:
glob.userIDCache[i["username"]] = i["id"]
def getDonorExpire(userID):
"""
Return userID's donor expiration UNIX timestamp
:param userID:
:return: donor expiration UNIX timestamp
"""
data = glob.db.fetch("SELECT donor_expire FROM users WHERE id = %s LIMIT 1", [userID])
if data is not None:
return data["donor_expire"]
return 0

View File

@ -6,19 +6,21 @@ by Joel Rosdahl, licensed under the GNU GPL 2 License.
Most of the reference code from miniircd was used for the low-level logic.
The high-level code has been rewritten to make it compatible with pep.py.
"""
import sys
import traceback
import socket
import select
import time
import re
import hashlib
from helpers import logHelper as log
import re
import select
import socket
import sys
import time
import traceback
from objects import glob
from helpers import chatHelper as chat
import raven
from common.log import logUtils as log
from helpers import chatHelper as chat
from objects import glob
class Client:
"""
IRC Client object

View File

@ -1,6 +1,7 @@
# TODO: Rewrite this shit
from common import generalUtils
from objects import glob
from helpers import generalFunctions
class banchoConfig:
"""
@ -26,8 +27,8 @@ class banchoConfig:
"""
(re)load bancho_settings from DB and set values in config array
"""
self.config["banchoMaintenance"] = generalFunctions.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'bancho_maintenance'")["value_int"])
self.config["freeDirect"] = generalFunctions.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'free_direct'")["value_int"])
self.config["banchoMaintenance"] = generalUtils.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'bancho_maintenance'")["value_int"])
self.config["freeDirect"] = generalUtils.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'free_direct'")["value_int"])
self.config["menuIcon"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'menu_icon'")["value_string"]
self.config["loginNotification"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'login_notification'")["value_string"]

View File

@ -1,6 +1,7 @@
from objects import glob
from common.log import logUtils as log
from objects import channel
from helpers import logHelper as log
from objects import glob
class channelList:
"""

View File

@ -1,79 +0,0 @@
from objects import glob
class buffer():
"""
A file buffer object.
This buffer caches data in memory and when it's full, it writes the content to a file.
"""
def __init__(self, fileName, writeType="a", maxLength=512):
"""
A file buffer object
:param fileName: Path and name of file on disk .
:param writeType: File write type. Optional. Default: "a" .
:param maxLength: Max length before writing buffer to disk. Optional. Default: 512.
"""
self.content = ""
self.length = 0
self.fileName = fileName
self.writeType = writeType
self.maxLength = maxLength
def write(self, newData):
"""
Add data to buffer.
If the total length of the data in buffer is greater than or equal to self.maxLength,
the content is written on the disk and the buffer resets
:param newData: Data to append to buffer
:return:
"""
self.content += newData
self.length += len(newData)
if self.length >= self.maxLength:
self.flush()
def flush(self):
"""
Write buffer content to disk and reset its content
:return:
"""
try:
glob.fLocks.lockFile(self.fileName)
with open(self.fileName, self.writeType) as f:
f.write(self.content)
finally:
glob.fLocks.unlockFile(self.fileName)
self.content = ""
self.length = 0
class buffersList():
"""
A list of buffers
"""
def __init__(self):
self.buffers = {}
def write(self, fileName, content):
"""
Write some data to an existing buffer in this list (or create a new one if it doesn't exist).
If the buffer is full, the data is written to the file and the buffer resets.
:param fileName: Path of file/buffer
:param content: New content
:return:
"""
if fileName not in self.buffers:
self.buffers[fileName] = buffer(fileName)
self.buffers[fileName].write(content)
def flushAll(self):
"""
Write all buffers to file and flush them
:return:
"""
for _, value in self.buffers.items():
value.flush()

View File

@ -1,20 +0,0 @@
import threading
class fileLocks:
def __init__(self):
# Dictionary containing threading.Lock s
self.locks = {}
def lockFile(self, fileName):
if fileName in self.locks:
# Acquire existing lock
self.locks[fileName].acquire()
else:
# Create new lock and acquire it
self.locks[fileName] = threading.Lock()
self.locks[fileName].acquire()
def unlockFile(self, fileName):
if fileName in self.locks:
# Release lock if it exists
self.locks[fileName].release()

View File

@ -1,11 +1,12 @@
"""FokaBot related functions"""
from helpers import userHelper
from objects import glob
from constants import actions
from constants import serverPackets
from constants import fokabotCommands
import re
from helpers import generalFunctions
from common import generalUtils
from common.constants import actions
from common.ripple import userUtils
from constants import fokabotCommands
from constants import serverPackets
from objects import glob
# Tillerino np regex, compiled only once to increase performance
npRegex = re.compile("^https?:\\/\\/osu\\.ppy\\.sh\\/b\\/(\\d*)")
@ -34,13 +35,13 @@ def fokabotResponse(fro, chan, message):
for i in fokabotCommands.commands:
# Loop though all commands
#if i["trigger"] in message:
if generalFunctions.strContains(message, i["trigger"]):
if generalUtils.strContains(message, i["trigger"]):
# message has triggered a command
# Make sure the user has right permissions
if i["privileges"] is not None:
# Rank = x
if userHelper.getPrivileges(userHelper.getID(fro)) & i["privileges"] == 0:
if userUtils.getPrivileges(userUtils.getID(fro)) & i["privileges"] == 0:
return False
# Check argument number

View File

@ -1,12 +1,14 @@
"""Global objects and variables"""
from objects import tokenList
import time
from common.ddog import datadogClient
from common.files import fileBuffer, fileLocks
from objects import channelList
from objects import matchList
from objects import fileLocks
from objects import fileBuffer
from objects import streamList
import time
from objects import tokenList
from common.web import schiavo
try:
with open("version") as f:
@ -16,6 +18,7 @@ try:
except:
VERSION = "¯\_(xd)_/¯"
DATADOG_PREFIX = "peppy"
application = None
db = None
conf = None
@ -26,6 +29,8 @@ matches = matchList.matchList()
restarting = False
fLocks = fileLocks.fileLocks()
fileBuffers = fileBuffer.buffersList()
schiavo = schiavo.schiavo()
dog = datadogClient.datadogClient()
verifiedCache = {}
cloudflare = False
chatFilters = None
@ -36,7 +41,6 @@ busyThreads = 0
debug = False
outputRequestTime = False
outputPackets = False
discord = False
gzip = False
localize = False
sentry = False

View File

@ -1,17 +1,19 @@
# TODO: Enqueue all
from constants import gameModes
import copy
from common import generalUtils
from common.constants import gameModes
from common.log import logUtils as log
from constants import dataTypes
from constants import matchModModes
from constants import matchScoringTypes
from constants import matchTeamTypes
from constants import matchModModes
from constants import slotStatuses
from objects import glob
from constants import serverPackets
from constants import dataTypes
from constants import matchTeams
from helpers import logHelper as log
from constants import serverPackets
from constants import slotStatuses
from helpers import chatHelper as chat
from helpers import generalFunctions
import copy
from objects import glob
class slot:
def __init__(self):
@ -35,7 +37,7 @@ class match:
beatmapMD5 = ""
slots = []
hostUserID = 0
gameMode = gameModes.std
gameMode = gameModes.STD
matchScoringType = matchScoringTypes.score
matchTeamType = matchTeamTypes.headToHead
matchModMode = matchModModes.normal
@ -59,7 +61,7 @@ class match:
self.mods = 0
self.matchName = matchName
if matchPassword != "":
self.matchPassword = generalFunctions.stringMd5(matchPassword)
self.matchPassword = generalUtils.stringMd5(matchPassword)
else:
self.matchPassword = ""
self.beatmapID = beatmapID
@ -487,7 +489,7 @@ class match:
newPassword -- new password string
"""
if newPassword != "":
self.matchPassword = generalFunctions.stringMd5(newPassword)
self.matchPassword = generalUtils.stringMd5(newPassword)
else:
self.matchPassword = ""

View File

@ -1,14 +1,15 @@
from constants import actions
from constants import gameModes
from helpers import userHelper
import threading
import time
import uuid
from common.constants import gameModes, actions
from common.log import logUtils as log
from common.ripple import userUtils
from constants import serverPackets
from events import logoutEvent
from helpers import logHelper as log
from objects import glob
import uuid
import time
import threading
from helpers import chatHelper as chat
from objects import glob
class token:
@ -25,11 +26,11 @@ class token:
"""
# Set stuff
self.userID = userID
self.username = userHelper.getUsername(self.userID)
self.privileges = userHelper.getPrivileges(self.userID)
self.admin = userHelper.isInPrivilegeGroup(self.userID, "developer") or userHelper.isInPrivilegeGroup(self.userID, "community manager")
self.username = userUtils.getUsername(self.userID)
self.privileges = userUtils.getPrivileges(self.userID)
self.admin = userUtils.isInPrivilegeGroup(self.userID, "developer") or userUtils.isInPrivilegeGroup(self.userID, "community manager")
self.irc = irc
self.restricted = userHelper.isRestricted(self.userID)
self.restricted = userUtils.isRestricted(self.userID)
self.loginTime = int(time.time())
self.pingTime = self.loginTime
self.timeOffset = timeOffset
@ -58,7 +59,7 @@ class token:
self.actionText = ""
self.actionMd5 = ""
self.actionMods = 0
self.gameMode = gameModes.std
self.gameMode = gameModes.STD
self.beatmapID = 0
self.rankedScore = 0
self.accuracy = 0.0
@ -78,7 +79,7 @@ class token:
# If we have a valid ip, save bancho session in DB so we can cache LETS logins
if ip != "":
userHelper.saveBanchoSession(self.userID, self.ip)
userUtils.saveBanchoSession(self.userID, self.ip)
# Join main stream
self.joinStream("main")
@ -275,7 +276,7 @@ class token:
"""
# Silence in db and token
self.silenceEndTime = int(time.time())+seconds
userHelper.silence(self.userID, seconds, reason, author)
userUtils.silence(self.userID, seconds, reason, author)
# Send silence packet to target
self.enqueue(serverPackets.silenceEndTime(seconds))
@ -316,7 +317,7 @@ class token:
def updateCachedStats(self):
"""Update all cached stats for this token"""
stats = userHelper.getUserStats(self.userID, self.gameMode)
stats = userUtils.getUserStats(self.userID, self.gameMode)
log.debug(str(stats))
if stats is None:
log.warning("Stats query returned None")
@ -336,7 +337,7 @@ class token:
If false, get the cached one. Optional. Default: False
"""
if force:
self.restricted = userHelper.isRestricted(self.userID)
self.restricted = userUtils.isRestricted(self.userID)
if self.restricted:
self.setRestricted()

View File

@ -1,9 +1,11 @@
from objects import osuToken
from objects import glob
import time
import threading
import time
from common.ripple import userUtils
from events import logoutEvent
from helpers import userHelper
from objects import glob
from objects import osuToken
class tokenList:
"""
@ -39,7 +41,7 @@ class tokenList:
if token in self.tokens:
# Delete session from DB
if self.tokens[token].ip != "":
userHelper.deleteBanchoSessions(self.tokens[token].userID, self.tokens[token].ip)
userUtils.deleteBanchoSessions(self.tokens[token].userID, self.tokens[token].ip)
# Pop token from list
self.tokens.pop(token)

64
pep.py
View File

@ -2,39 +2,36 @@
import os
import sys
import threading
from multiprocessing.pool import ThreadPool
import tornado.gen
import tornado.httpserver
import tornado.ioloop
import tornado.web
from multiprocessing.pool import ThreadPool
# Raven
from raven.contrib.tornado import AsyncSentryClient
# pep.py files
from constants import bcolors
from helpers import configHelper
from objects import glob
from objects import fokabot
from objects import banchoConfig
from objects import chatFilters
from helpers import consoleHelper
from helpers import databaseHelperNew
from helpers import generalFunctions
from helpers import logHelper as log
from helpers import userHelper
from helpers import systemHelper as system
from handlers import mainHandler
from common import generalUtils
from common.constants import bcolors
from common.db import dbConnector
from common.log import logUtils as log
from common.ripple import userUtils
from common.web import schiavo
from handlers import apiFokabotMessageHandler
from handlers import apiIsOnlineHandler
from handlers import apiOnlineUsersHandler
from handlers import apiServerStatusHandler
from handlers import ciTriggerHandler
from handlers import apiVerifiedStatusHandler
from handlers import apiFokabotMessageHandler
from handlers import ciTriggerHandler
from handlers import mainHandler
from helpers import configHelper
from helpers import consoleHelper
from helpers import systemHelper as system
from irc import ircserver
from objects import banchoConfig
from objects import chatFilters
from objects import fokabot
from objects import glob
def make_app():
return tornado.web.Application([
@ -83,7 +80,7 @@ if __name__ == "__main__":
# Connect to db
try:
consoleHelper.printNoNl("> Connecting to MySQL database...")
glob.db = databaseHelperNew.db(glob.conf.config["db"]["host"], glob.conf.config["db"]["username"], glob.conf.config["db"]["password"], glob.conf.config["db"]["database"], int(glob.conf.config["db"]["workers"]))
glob.db = dbConnector.db(glob.conf.config["db"]["host"], glob.conf.config["db"]["username"], glob.conf.config["db"]["password"], glob.conf.config["db"]["database"], int(glob.conf.config["db"]["workers"]))
consoleHelper.printNoNl(" ")
consoleHelper.printDone()
except:
@ -152,29 +149,30 @@ if __name__ == "__main__":
# Cache user ids
consoleHelper.printNoNl("> Caching user IDs... ")
userHelper.cacheUserIDs()
userUtils.cacheUserIDs()
consoleHelper.printDone()
# Localize warning
glob.localize = generalFunctions.stringToBool(glob.conf.config["localize"]["enable"])
glob.localize = generalUtils.stringToBool(glob.conf.config["localize"]["enable"])
if not glob.localize:
consoleHelper.printColored("[!] Warning! Users localization is disabled!", bcolors.YELLOW)
# Discord
glob.discord = generalFunctions.stringToBool(glob.conf.config["discord"]["enable"])
if not glob.discord:
if generalUtils.stringToBool(glob.conf.config["discord"]["enable"]):
glob.schiavo = schiavo.schiavo(glob.conf.config["discord"]["boturl"])
else:
consoleHelper.printColored("[!] Warning! Discord logging is disabled!", bcolors.YELLOW)
# Gzip
glob.gzip = generalFunctions.stringToBool(glob.conf.config["server"]["gzip"])
glob.gzip = generalUtils.stringToBool(glob.conf.config["server"]["gzip"])
glob.gziplevel = int(glob.conf.config["server"]["gziplevel"])
if not glob.gzip:
consoleHelper.printColored("[!] Warning! Gzip compression is disabled!", bcolors.YELLOW)
# Debug mode
glob.debug = generalFunctions.stringToBool(glob.conf.config["debug"]["enable"])
glob.outputPackets = generalFunctions.stringToBool(glob.conf.config["debug"]["packets"])
glob.outputRequestTime = generalFunctions.stringToBool(glob.conf.config["debug"]["time"])
glob.debug = generalUtils.stringToBool(glob.conf.config["debug"]["enable"])
glob.outputPackets = generalUtils.stringToBool(glob.conf.config["debug"]["packets"])
glob.outputRequestTime = generalUtils.stringToBool(glob.conf.config["debug"]["time"])
if glob.debug:
consoleHelper.printColored("[!] Warning! Server running in debug mode!", bcolors.YELLOW)
@ -183,7 +181,7 @@ if __name__ == "__main__":
# Set up sentry
try:
glob.sentry = generalFunctions.stringToBool(glob.conf.config["sentry"]["enable"])
glob.sentry = generalUtils.stringToBool(glob.conf.config["sentry"]["enable"])
if glob.sentry:
glob.application.sentry_client = AsyncSentryClient(glob.conf.config["sentry"]["banchodns"], release=glob.VERSION)
else:
@ -192,10 +190,10 @@ if __name__ == "__main__":
consoleHelper.printColored("[!] Error while starting sentry client! Please check your config.ini and run the server again", bcolors.RED)
# Cloudflare memes
glob.cloudflare = generalFunctions.stringToBool(glob.conf.config["server"]["cloudflare"])
glob.cloudflare = generalUtils.stringToBool(glob.conf.config["server"]["cloudflare"])
# IRC start message and console output
glob.irc = generalFunctions.stringToBool(glob.conf.config["irc"]["enable"])
glob.irc = generalUtils.stringToBool(glob.conf.config["irc"]["enable"])
if glob.irc:
# IRC port
try: