def m_sasl_plain(info): cli = info['source'] data = info['data'] account, authorization_id, passphrase = data.split(b'\x00') account = str(account, 'utf8') passphrase = str(passphrase, 'utf8') account_info = cli.ctx.data.get('account.{}'.format(account), None) if (account_info and 'passphrase' in account_info['credentials'] and account_info['verified']): passphrase_hash = account_info['credentials']['passphrase'] if cli.ctx.hashing.verify(passphrase, passphrase_hash): cli.account = account eventmgr_core.dispatch('account change', { 'source': cli, 'account': account, }) cli.sasl = None hostmask = cli.hostmask if hostmask is None: hostmask = '*' cli.dump_numeric('900', [ hostmask, account, 'You are now logged in as {}'.format(account) ]) cli.dump_numeric('903', ['SASL authentication successful']) return cli.dump_numeric('904', ['SASL authentication failed'])
def m_PRIVMSG(cli, ev_msg): targetlist = ev_msg["params"][0].split(",") message = ev_msg["params"][1] for target in targetlist: if target[0] != "#": cli_tg = cli.ctx.clients.get(target, None) if not cli_tg: cli.dump_numeric("401", [target, "No such nick/channel"]) continue eventmgr_core.dispatch( "client message", {"source": cli, "target": cli_tg, "target_name": target, "message": message} ) continue ch = cli.ctx.chmgr.get(target) if not ch: cli.dump_numeric("401", [target, "No such nick/channel"]) continue if not ch.can_send(cli): cli.dump_numeric("404", [ch.name, "Cannot send to channel"]) continue eventmgr_core.dispatch( "channel message", {"source": cli, "target": ch, "target_name": target, "message": message} )
def m_PRIVMSG(cli, ev_msg): targetlist = ev_msg['params'][0].split(',') message = ev_msg['params'][1] for target in targetlist: if target[0] != '#': cli_tg = cli.ctx.clients.get(target, None) if not cli_tg: cli.dump_numeric('401', [target, 'No such nick/channel']) continue eventmgr_core.dispatch( 'client message', { 'source': cli, 'target': cli_tg, 'target_name': target, 'message': message, }) continue ch = cli.ctx.chmgr.get(target) if not ch: cli.dump_numeric('401', [target, 'No such nick/channel']) continue if not ch.can_send(cli): cli.dump_numeric('404', [ch.name, 'Cannot send to channel']) continue eventmgr_core.dispatch( 'channel message', { 'source': cli, 'target': ch, 'target_name': target, 'message': message, })
def m_CAP_REQ(cli, ev_msg): cap_add = [] cap_del = [] args = ev_msg['params'][1] def dump_NAK(cli): cli.dump_numeric('CAP', ['NAK', args + ' ']) for arg in args.split(): negate = arg[0] == '-' if negate: arg = arg[1:] if arg not in caplist: dump_NAK(cli) return if negate: if arg not in cli.caps: dump_NAK(cli) return cap_del.append(arg) continue if arg in cli.caps: dump_NAK(cli) return cap_add.append(arg) cli.dump_numeric('CAP', ['ACK', ' '.join(cap_add) + ' -'.join(cap_del) + ' ']) # we accepted the changeset, so apply it info = { 'client': cli, 'caps': cap_add, } eventmgr_core.dispatch('cap add', info) info = { 'client': cli, 'caps': cap_del, } eventmgr_core.dispatch('cap del', info)
def m_CAP_REQ(cli, ev_msg): cap_add = [] cap_del = [] args = ev_msg["params"][1] def dump_NAK(cli): cli.dump_numeric("CAP", ["NAK", args + " "]) for arg in args.split(): negate = arg[0] == "-" if negate: arg = arg[1:] if arg not in caplist: dump_NAK(cli) return if negate: if arg not in cli.caps: dump_NAK(cli) return cap_del.append(arg) continue if arg in cli.caps: dump_NAK(cli) return cap_add.append(arg) cli.dump_numeric("CAP", ["ACK", " ".join(cap_add) + " -".join(cap_del) + " "]) # we accepted the changeset, so apply it info = {"client": cli, "caps": cap_add} eventmgr_core.dispatch("cap add", info) info = {"client": cli, "caps": cap_del} eventmgr_core.dispatch("cap del", info)
def m_reg_create_empty(info): cli = info['source'] cli.ctx.data.put('account.{}'.format(info['account']), { 'account': info['account'], 'credentials': { 'passphrase': cli.ctx.hashing.encrypt(info['credential']), }, 'registered_ts': cli.ctx.current_ts, 'registered_by': cli.hostmask, 'verified': True, }) cli.dump_numeric('920', [info['account'], 'Account created']) cli.account = info['account'] eventmgr_core.dispatch('account change', { 'source': cli, 'account': cli.account, }) cli.dump_numeric('900', [cli.hostmask, info['account'], 'You are now logged in as {}'.format(info['account'])]) cli.dump_numeric('903', ['Authentication successful'])
def m_AUTHENTICATE(cli, ev_msg): if len(ev_msg['params']) == 1 and ev_msg['params'][0] == '*': if getattr(cli, 'sasl', None): cli.dump_numeric('906', ['SASL authentication aborted']) cli.sasl = None else: cli.dump_numeric('904', ['SASL authentication failed']) return if getattr(cli, 'sasl', None): if len(ev_msg['params'][0]) > 400: cli.dump_numeric('905', ['SASL message too long']) cli.sasl = None return try: data = base64.b64decode(ev_msg['params'][0]) except binascii.Error: cli.dump_numeric('904', ['SASL authentication failed']) return eventmgr_core.dispatch( 'sasl authenticate {}'.format(cli.sasl.casefold()), { 'source': cli, 'mechanism': cli.sasl, 'data': data, }) else: mechanism = ev_msg['params'][0].upper() if mechanism in valid_mechanisms: cli.sasl = mechanism cli.dump_verb('AUTHENTICATE', '+') else: cli.dump_numeric('904', ['SASL authentication failed']) return
def m_REG(cli, ev_msg): params = list(ev_msg['params']) subcmd = params.pop(0).casefold() if subcmd == 'create': account = params.pop(0).casefold() if account == '*': cli.dump_numeric('922', [account, 'Invalid params: "*" is not a valid account name']) return account_data = cli.ctx.data.get('account.{}'.format(account), {}) if account_data: global verify_timeout_seconds if (account_data['verified'] or account_data['registered_ts'] + verify_timeout_seconds > cli.ctx.current_ts): cli.dump_numeric('921', [account, 'Account already exists']) return # account verify expired, delete old account if not account_data['verified']: cli.ctx.data.delete('account.{}'.format(account)) global enabled_cb_types callback = params.pop(0).casefold() if callback == '*': cb_namespace = '*' callback = None, elif ':' in callback: cb_namespace, callback = callback.split(':', 1) else: # as in the spec, default to the first advertised callback type if enabled_cb_types[0] == 'none' and len(enabled_cb_types) > 1: cb_namespace = enabled_cb_types[1] else: cb_namespace = enabled_cb_types[0] if cb_namespace not in enabled_cb_types: cli.dump_numeric('929', [account, cb_namespace, 'Callback token is invalid']) return if len(params) > 1: cred_type, credential = params[:2] elif len(params) == 1: cred_type = 'passphrase' credential = params.pop(0) else: cli.dump_numeric('461', [ev_msg['verb'], 'Not enough parameters']) return global supported_cred_types if cred_type not in supported_cred_types: cli.dump_numeric('928', [account, cred_type, 'Credential type is invalid']) return eventmgr_core.dispatch('reg callback {}'.format(cb_namespace), { 'source': cli, 'account': account, 'callback': callback, 'cb_namespace': cb_namespace, 'cred_type': cred_type, 'credential': credential, }) elif subcmd == 'verify': account = params.pop(0).casefold() account_info = cli.ctx.data.get('account.{}'.format(account), None) if account_info: if account_info['verified']: cli.dump_numeric('924', [account, 'Account already verified']) return auth_code = params.pop(0) if auth_code == account_info['auth_code']: account_info['verified'] = True del account_info['auth_code'] cli.ctx.data.put('account.{}'.format(account), account_info) cli.dump_numeric('923', [account, 'Account verification successful']) cli.account = account eventmgr_core.dispatch('account change', { 'source': cli, 'account': account, }) cli.dump_numeric('900', [cli.hostmask, account, 'You are now logged in as {}'.format(account)]) cli.dump_numeric('903', ['Authentication successful']) else: cli.dump_numeric('925', [account, 'Invalid verification code']) else: cli.dump_numeric('400', ['REG', 'VERIFY', 'Account does not exist']) else: cli.dump_numeric('400', ['REG', ev_msg['params'][0], 'Unknown subcommand'])