blueprints.invites: more complete errors

This commit is contained in:
Luna 2018-12-06 00:00:36 -03:00
parent b5ac6e258e
commit 78be4c6fab
1 changed files with 67 additions and 24 deletions

View File

@ -9,7 +9,7 @@ from logbook import Logger
from ..auth import token_check from ..auth import token_check
from ..schemas import validate, INVITE from ..schemas import validate, INVITE
from ..enums import ChannelType from ..enums import ChannelType
from ..errors import BadRequest from ..errors import BadRequest, Forbidden
from .guilds import create_guild_settings from .guilds import create_guild_settings
from ..utils import async_map from ..utils import async_map
@ -20,31 +20,32 @@ from litecord.blueprints.checks import (
log = Logger(__name__) log = Logger(__name__)
bp = Blueprint('invites', __name__) bp = Blueprint('invites', __name__)
# TODO: Ban handling
async def use_invite(user_id, invite_code):
"""Try using an invite"""
inv = await app.db.fetchrow("""
SELECT guild_id, created_at, max_age, uses, max_uses
FROM invites
WHERE code = $1
""", invite_code)
if inv is None:
raise BadRequest('Unknown invite')
if inv['max_age'] is not 0:
now = datetime.datetime.utcnow()
delta_sec = (now - inv['created_at']).total_seconds()
if delta_sec > inv['max_age']: class UnknownInvite(BadRequest):
await delete_invite(invite_code) error_code = 10006
raise BadRequest('Unknown invite (expiried)')
if inv['max_uses'] is not -1 and inv['uses'] > inv['max_uses']:
await delete_invite(invite_code)
raise BadRequest('Unknown invite (too many uses)')
guild_id = inv['guild_id'] class InvalidInvite(Forbidden):
error_code = 50020
def gen_inv_code() -> str:
"""Generate an invite code.
This is a primitive and does not guarantee uniqueness.
"""
# TODO: should we really be depending on os.urandom?
raw = os.urandom(7)
raw = base64.b64encode(raw).decode()
raw = raw.replace('/', '')
raw = raw.replace('+', '')
return raw[:7]
async def invite_precheck(user_id: int, guild_id: int):
"""pre-check invite use in the context of a guild."""
joined = await app.db.fetchval(""" joined = await app.db.fetchval("""
SELECT joined_at SELECT joined_at
@ -55,6 +56,42 @@ async def use_invite(user_id, invite_code):
if joined is not None: if joined is not None:
raise BadRequest('You are already in the guild') raise BadRequest('You are already in the guild')
banned = await app.db.fetchval("""
SELECT reason
FROM bans
WHERE user_id = $1 AND guild_id = $2
""", user_id, guild_id)
if banned is not None:
raise InvalidInvite('You are banned.')
async def use_invite(user_id, invite_code):
"""Try using an invite"""
inv = await app.db.fetchrow("""
SELECT guild_id, created_at, max_age, uses, max_uses
FROM invites
WHERE code = $1
""", invite_code)
if inv is None:
raise UnknownInvite('Unknown invite')
if inv['max_age'] is not 0:
now = datetime.datetime.utcnow()
delta_sec = (now - inv['created_at']).total_seconds()
if delta_sec > inv['max_age']:
await delete_invite(invite_code)
raise InvalidInvite('Invite is expired')
if inv['max_uses'] is not -1 and inv['uses'] > inv['max_uses']:
await delete_invite(invite_code)
raise InvalidInvite('Too many uses')
guild_id = inv['guild_id']
await invite_precheck(user_id, guild_id)
await app.db.execute(""" await app.db.execute("""
INSERT INTO members (user_id, guild_id) INSERT INTO members (user_id, guild_id)
VALUES ($1, $2) VALUES ($1, $2)
@ -97,6 +134,7 @@ async def use_invite(user_id, invite_code):
await app.dispatcher.dispatch_user_guild( await app.dispatcher.dispatch_user_guild(
user_id, guild_id, 'GUILD_CREATE', guild) user_id, guild_id, 'GUILD_CREATE', guild)
@bp.route('/channels/<int:channel_id>/invites', methods=['POST']) @bp.route('/channels/<int:channel_id>/invites', methods=['POST'])
async def create_invite(channel_id): async def create_invite(channel_id):
user_id = await token_check() user_id = await token_check()
@ -107,11 +145,16 @@ async def create_invite(channel_id):
await channel_perm_check(user_id, channel_id, 'create_invites') await channel_perm_check(user_id, channel_id, 'create_invites')
chantype = await app.storage.get_chan_type(channel_id) chantype = await app.storage.get_chan_type(channel_id)
# can't create invites for channels that aren't text
# or voice.
# TODO: once group dms are in, this should change to account.
if chantype not in (ChannelType.GUILD_TEXT.value, if chantype not in (ChannelType.GUILD_TEXT.value,
ChannelType.GUILD_VOICE.value): ChannelType.GUILD_VOICE.value):
raise BadRequest('Invalid channel type') raise BadRequest('Invalid channel type')
invite_code = base64.b64encode(hashlib.md5(os.urandom(64)).digest()).decode("utf-8").replace("/", "").replace("+", "")[:7] invite_code = gen_inv_code()
await app.db.execute( await app.db.execute(
""" """