Пример #1
0
  def api_log(self, network, user, channel, req, qs, posted):
    # FIXME: Choose between bots based on network
    grep = qs.get('grep', [''])[0]
    after = qs.get('seen', [None])[0]
    limit = int(qs.get('limit', [0])[0])
    timeout = int(qs.get('timeout', [0])[0])
    if timeout:
      timeout += time.time()

    bot = self.networks[network]
    rules = bot.irc_parsed_mode(channel)
    if (rules.get('secret', False) or
        rules.get('key', False) or
        rules.get('invite_only', False)):
      if not (user and channel in user['channels']):
        # This will hide the channel key and other parameters
        for r in rules:
          if rules[r]:
            rules[r] = True
        rules['event'] = 'pleasejoin'
        return 'application/json', HttpdLite.json_encode([
          [get_timed_uid(), rules]
        ])

    data = []
    try:
      while not data:
        data = bot.irc_channel_log(channel)
        if after or grep:
          data = [x for x in data if (x[0] > after) and
                                     (not grep or
                                      grep in x[1]['nick'].lower() or
                                      grep in x[1].get('text', ''))]
        if timeout and not data:
          cond = threading.Condition()
          ev = self.event_loop.add_sleeper(timeout, cond, 'API request')
          bot.irc_watch_channel(channel, ev)
          cond.acquire()
          cond.wait()
          cond.release()
          self.event_loop.remove_sleeper(ev)
        if time.time() >= timeout:
          break
    except SelectAborted:
      pass

    if limit:
      data = data[-limit:]

    return 'application/json', HttpdLite.json_encode(data)
Пример #2
0
    def api_log(self, network, user, channel, req, qs, posted):
        # FIXME: Choose between bots based on network
        grep = qs.get('grep', [''])[0]
        after = qs.get('seen', [None])[0]
        limit = int(qs.get('limit', [0])[0])
        timeout = int(qs.get('timeout', [0])[0])
        if timeout:
            timeout += time.time()

        bot = self.networks[network]
        rules = bot.irc_parsed_mode(channel)
        if (rules.get('secret', False) or rules.get('key', False)
                or rules.get('invite_only', False)):
            if not (user and channel in user['channels']):
                # This will hide the channel key and other parameters
                for r in rules:
                    if rules[r]:
                        rules[r] = True
                rules['event'] = 'pleasejoin'
                return 'application/json', HttpdLite.json_encode(
                    [[get_timed_uid(), rules]])

        data = []
        try:
            while not data:
                data = bot.irc_channel_log(channel)
                if after or grep:
                    data = [
                        x for x in data if (x[0] > after) and (
                            not grep or grep in x[1]['nick'].lower()
                            or grep in x[1].get('text', ''))
                    ]
                if timeout and not data:
                    cond = threading.Condition()
                    ev = self.event_loop.add_sleeper(timeout, cond,
                                                     'API request')
                    bot.irc_watch_channel(channel, ev)
                    cond.acquire()
                    cond.wait()
                    cond.release()
                    self.event_loop.remove_sleeper(ev)
                if time.time() >= timeout:
                    break
        except SelectAborted:
            pass

        if limit:
            data = data[-limit:]

        return 'application/json', HttpdLite.json_encode(data)
Пример #3
0
def Configuration():
    if '--version' in sys.argv:
        print '%s' % VERSION
        sys.exit(0)

    config = {
        'work_dir': DEFAULT_PATH,
        'http_port': 4950,
        'http_host': 'localhost',
        'lang': 'en',
        'skin': 'default',
        'debug': False,
        'irc': {},
        # These are ignored, but picked up by sockschain
        'nossl': None,
        'nopyopenssl': None,
    }

    # Set work dir before loading config, all other command-line arguments
    # will override the config file.
    for arg in sys.argv[1:]:
        if arg.startswith('--work_dir='):
            config['work_dir'] = arg.split('=', 1)[1]

    try:
        fd = open(os.path.join(config['work_dir'], 'config.json'), 'rb')
        config.update(HttpdLite.json_decode(fd.read()))
    except ValueError, e:
        print 'Failed to parse config: %s' % e
        sys.exit(1)
Пример #4
0
    def api_logout(self, network, user, channel, req, qs, posted):
        del self.networks[network].users[user.uid]
        req.setCookie('muid-%s' % network, '', delete=True)

        sockfd = self.event_loop.fds_by_uid[user.uid]
        self.event_loop.sendall(sockfd, 'QUIT :Logged off\r\n')
        return 'application/json', HttpdLite.json_encode(['ok'])
Пример #5
0
def Configuration():
  if '--version' in sys.argv:
    print '%s' % VERSION
    sys.exit(0)

  config = {
    'work_dir': DEFAULT_PATH,
    'http_port': 4950,
    'http_host': 'localhost',
    'lang': 'en',
    'skin': 'default',
    'debug': False,
    'irc': {},
    # These are ignored, but picked up by sockschain
    'nossl': None,
    'nopyopenssl': None,
  }

  # Set work dir before loading config, all other command-line arguments
  # will override the config file.
  for arg in sys.argv[1:]:
    if arg.startswith('--work_dir='):
      config['work_dir'] = arg.split('=', 1)[1]

  try:
    fd = open(os.path.join(config['work_dir'], 'config.json'), 'rb')
    config.update(HttpdLite.json_decode(fd.read()))
  except ValueError, e:
    print 'Failed to parse config: %s' % e
    sys.exit(1)
Пример #6
0
  def api_logout(self, network, user, channel, req, qs, posted):
    del self.networks[network].users[user.uid]
    req.setCookie('muid-%s' % network, '', delete=True)

    sockfd = self.event_loop.fds_by_uid[user.uid]
    self.event_loop.sendall(sockfd, 'QUIT :Logged off\r\n')
    return 'application/json', HttpdLite.json_encode(['ok'])
Пример #7
0
    def handleUserLogin(self, req, page_prefix, path, qs):
        state = qs.get('state', ['/'])[0]
        network, channel = self.get_channel_from_path(state[1:])
        provider, token = req.auth_info
        profile = {'source': provider, 'home': 'The Internet'}

        # First, pull details from their on-line profile, if possible...
        try:
            if provider == 'Facebook':
                fbp = req.server.auth_handler.getFacebookProfile(token)
                profile.update({
                    'name':
                    fbp.get('name'),
                    'home':
                    fbp.get('hometown', {}).get('name', 'The Internet'),
                    'uid':
                    'fb%s' % fbp.get('id', ''),
                    'pic':
                    'https://graph.facebook.com/%s/picture' %
                    fbp.get('id', ''),
                    'url':
                    'https://www.facebook.com/%s' %
                    fbp.get('username', fbp.get('id', ''))
                })

            elif provider == 'Google':
                profile = req.server.auth_handler.getGoogleProfile(token)

            else:
                print '*** Not sure how to get profiles from %s' % provider

        except (IOError, OSError):
            # Network problems...?
            pass

        # Create a nick-name for them
        nickname = profile.get('name', 'Guest %x' % random.randint(0, 10000))
        while (len(nickname) > 15 and ' ' in nickname):
            nickname = nickname.rsplit(' ', 1)[0]
        profile['nick'] = self.dumb_down(nickname)

        # Create an IRC client, start the connection.
        client = IrcClient().irc_profile(profile).irc_channels([channel])
        self.networks[network].users[client.uid] = client
        self.connect_client(network, client)

        # Finally, set a cookie with their client's UID.
        req.setCookie('muid-%s' % network, '%s,pending' % client.uid)

        print 'Logged in: %s' % HttpdLite.json_encode(profile, indent=2)
        return req.sendRedirect(page_prefix + state)
Пример #8
0
  def handleUserLogin(self, req, page_prefix, path, qs):
    state = qs.get('state', ['/'])[0]
    network, channel = self.get_channel_from_path(state[1:])
    provider, token = req.auth_info
    profile = {
      'source': provider,
      'home': 'The Internet'
    }

    # First, pull details from their on-line profile, if possible...
    try:
      if provider == 'Facebook':
        fbp = req.server.auth_handler.getFacebookProfile(token)
        profile.update({
          'name': fbp.get('name'),
          'home': fbp.get('hometown', {}).get('name', 'The Internet'),
          'uid': 'fb%s' % fbp.get('id', ''),
          'pic': 'https://graph.facebook.com/%s/picture' % fbp.get('id', ''),
          'url': 'https://www.facebook.com/%s' % fbp.get('username',
                                                         fbp.get('id', ''))
        })

      elif provider == 'Google':
        profile = req.server.auth_handler.getGoogleProfile(token)

      else:
        print '*** Not sure how to get profiles from %s' % provider

    except (IOError, OSError):
      # Network problems...?
      pass

    # Create a nick-name for them
    nickname = profile.get('name', 'Guest %x' % random.randint(0, 10000))
    while (len(nickname) > 15 and ' ' in nickname):
      nickname = nickname.rsplit(' ', 1)[0]
    profile['nick'] = self.dumb_down(nickname)

    # Create an IRC client, start the connection.
    client = IrcClient().irc_profile(profile).irc_channels([channel])
    self.networks[network].users[client.uid] = client
    self.connect_client(network, client)

    # Finally, set a cookie with their client's UID.
    req.setCookie('muid-%s' % network, '%s,pending' % client.uid)

    print 'Logged in: %s' % HttpdLite.json_encode(profile, indent=2)
    return req.sendRedirect(page_prefix + state)
Пример #9
0
 def api_say(self, network, user, channel, req, qs, posted):
     sockfd = self.event_loop.fds_by_uid[user.uid]
     privmsg = 'PRIVMSG %s :%s\r\n' % (channel,
                                       posted['msg'][0].decode('utf-8'))
     self.event_loop.sendall(sockfd, privmsg.encode('utf-8'))
     return 'application/json', HttpdLite.json_encode(['ok'])
Пример #10
0
    def handleHttpRequest(self,
                          req,
                          scheme,
                          netloc,
                          path,
                          params,
                          query,
                          frag,
                          qs,
                          posted,
                          cookies,
                          user=None):
        if path.startswith('/'): path = path[1:]
        path_url = path
        path = urllib.unquote(path).decode('utf-8')

        # Defaults, will probably be overridden by individual response pages
        headers = []
        cachectrl = 'max-age=3600, public'
        mime_type = 'text/html'
        code = 200
        data = None

        # Clear any expired cookies, update others, record credentials
        credentials = {}
        for c, v in cookies.items():
            try:
                prefix, network = c.split('-', 1)
                muid = v.value.split(',')[0]
                if (not network in self.networks
                        or muid not in self.networks[network].users):
                    req.setCookie(c, '', delete=True)
                else:
                    log_id = v.value.split(',', 1)[1]
                    user = self.networks[network].users[muid]
                    if log_id != user.log_id:
                        req.setCookie(c, '%s,%s' % (muid, user.log_id))
                    else:
                        user.seen = time.time()
                        credentials[network] = user
            except (ValueError, KeyError):
                pass

        # Shared values for rendering templates
        page_url = req.absolute_url()
        page_prefix = '/'.join(page_url.split('/', 4)[:3])
        host = req.header('Host', 'unknown').lower()
        template = ''
        page = {
            'templates': os.path.join(self.work_dir, 'html'),
            'version': VERSION,
            'skin': host,
            'host': host,
            'page_path': '/' + path_url,
            'page_url': page_url,
        }

        # Get the actual content.
        try:
            if req.command == 'GET':

                if path == '':
                    template = self.load_template('index.html', config=page)
                    page.update(
                        {'linked_channel_list': self.renderChannelList()})

                elif path.startswith('_api/v1/'):
                    return self.handleApiRequest(req, path, qs, posted)

                elif path.startswith('join/'):
                    template, page = self.prepareChannelPage(
                        path, page, credentials)

                elif (path.startswith('_skin/') or path in ('favicon.ico', )):
                    template = self.load_template(path.split('/')[-1],
                                                  config=page)
                    mime_type = HttpdLite.GuessMimeType(path)
                    if mime_type != 'application/octet-stream' and path.endswith(
                            '.gz'):
                        headers.append(('Content-Encoding', 'gzip'))

                elif path.startswith('_authlite/') and req.auth_info:
                    return self.handleUserLogin(req, page_prefix, path, qs)

                elif path == 'robots.txt':
                    # FIXME: Have an explicit search-engine policy in settings?
                    raise NotFoundException('FIXME')

                else:
                    raise NotFoundException()

            elif req.command == 'POST':
                if path.startswith('_api/v1/'):
                    return self.handleApiRequest(req, path, qs, posted)
                else:
                    raise NotFoundException()

        except NotFoundException:
            cachectrl, code, data = 'no-cache', 404, '<h1>404 Not found</h1>\n'

        if not data:
            if '__Mutiny_Template__' in template:
                data = (template.decode('utf-8') % page).encode('utf-8')
                cachectrl = 'no-cache'
            else:
                data = template
        return req.sendResponse(data,
                                code=code,
                                mimetype=mime_type,
                                header_list=headers,
                                cachectrl=cachectrl)
Пример #11
0
        }
    if len(sys.argv) > 1:
        arg = sys.argv.pop(1)
        config['irc']['irc']['servers'] = [arg.rsplit('/', 1)[0]]
        config['irc']['irc']['channels'] = channels = {}
        for channel in arg.rsplit('/', 1)[1].split(',', 1):
            channels[channel] = {
                'description': 'IRC channel',
                'access': 'open'
            }
    if len(sys.argv) > 1:
        arg = sys.argv.pop(1)
        for channel in channels:
            channels[channel]['access'] = arg

    print 'Config is: %s' % HttpdLite.json_encode(config, indent=2)
    return config


if __name__ == "__main__":
    try:
        mutiny = Mutiny(Configuration())
    except (IndexError, ValueError, OSError, IOError):
        print '%s\n' % traceback.format_exc()
        print 'Usage: %s <nick> irc://<server:port>/<channel>' % sys.argv[0]
        print '       %s <nick> ssl://<server:port>/<channel>' % sys.argv[0]
        print
        print 'Logs and settings will be stored here: %s' % config['work_dir']
        print
        sys.exit(1)
    try:
Пример #12
0
        return req.sendResponse(data,
                                code=code,
                                mimetype=mime_type,
                                header_list=headers,
                                cachectrl=cachectrl)


if __name__ == "__main__":
    try:
        db_path = os.path.expanduser('~/.Unhosted.py')
        unhosted = Unhosted(db_path)
    except (IndexError, ValueError, OSError, IOError):
        print 'Usage: %s' % sys.argv[0]
        print
        print 'The file will create an database in: %s' % db_path
        print
        sys.exit(1)
    try:
        try:
            print 'This is Unhosted.py, listening on %s:%s' % unhosted.listen_on
            print 'Fork me on Github: https://github.com/pagekite/plugins-pyUnhosted'
            print
            HttpdLite.Server(unhosted.listen_on,
                             unhosted,
                             handler=RequestHandler).serve_forever()
        except KeyboardInterrupt:
            unhosted.stop()
    except:
        unhosted.stop()
        raise
Пример #13
0
 def api_say(self, network, user, channel, req, qs, posted):
   sockfd = self.event_loop.fds_by_uid[user.uid]
   privmsg = 'PRIVMSG %s :%s\r\n' % (channel,
                                     posted['msg'][0].decode('utf-8'))
   self.event_loop.sendall(sockfd, privmsg.encode('utf-8'))
   return 'application/json', HttpdLite.json_encode(['ok'])
Пример #14
0
      'userinfo': 'Mutiny %s' % VERSION
    }
  if len(sys.argv) > 1:
    arg = sys.argv.pop(1)
    config['irc']['irc']['servers'] = [
      arg.rsplit('/', 1)[0]
    ]
    config['irc']['irc']['channels'] = channels = {}
    for channel in arg.rsplit('/', 1)[1].split(',', 1):
      channels[channel] = {'description': 'IRC channel', 'access': 'open'}
  if len(sys.argv) > 1:
    arg = sys.argv.pop(1)
    for channel in channels:
      channels[channel]['access'] = arg

  print 'Config is: %s' % HttpdLite.json_encode(config, indent=2)
  return config


if __name__ == "__main__":
  try:
    mutiny = Mutiny(Configuration())
  except (IndexError, ValueError, OSError, IOError):
    print '%s\n' % traceback.format_exc()
    print 'Usage: %s <nick> irc://<server:port>/<channel>' % sys.argv[0]
    print '       %s <nick> ssl://<server:port>/<channel>' % sys.argv[0]
    print
    print 'Logs and settings will be stored here: %s' % config['work_dir']
    print
    sys.exit(1)
  try: