def update(): ''' process xhr request for update to posts or messages ''' name, hashed = args.get('name', None), args.get('hash', None) update_status = status # default from outer variable if name in ('messages', 'posts'): # pylint: disable=eval-used # check outer variables # must be done before eval or it will fail logging.debug('messages: ...%s', messages[-128:]) logging.debug('messages_hash: %s', messages_hash) logging.debug('posts: %s...', posts[:128]) logging.debug('posts_hash: %s', posts_hash) if hashed and hashed != eval(name + '_hash'): update_page = eval(name).encode() elif hashed: logging.debug('%s unchanged', args['name']) update_page = b'' update_status = '304 Not Modified' else: logging.error('no hash passed to /update/') update_page = b'' update_status = '406 Not Acceptable' else: update_page = ( '<div>no updates for %s</div>' % args['name'] ).encode() update_status = '404 Not Found' return update_status, update_page
def register(username=None, email=None, gpgkey=None): ''' register kybyz account ''' if gpgkey is None: gpgkey = verify_key(email) current = registration() # see what we already have, if anything if username is None or email is None: logging.error('Usage: %s %s USERNAME EMAIL_ADDRESS', COMMAND, ARGS[0]) raise ValueError('Must specify desired username and email address') if any(current): if (username, email, gpgkey) != current: raise ValueError('Previously registered as %s %s %s' % current) logging.warning('Already registered as %s %s %s', *current) else: os.makedirs(os.path.join(CACHE, gpgkey)) os.symlink(os.path.join(CACHE, gpgkey), os.path.join(CACHE, email)) os.symlink(os.path.join(CACHE, email), os.path.join(CACHE, username)) os.symlink(os.path.join(CACHE, username), KYBYZ_HOME) logging.info('Now registered as %s %s %s', username, email, gpgkey) if CACHED.get('ircbot', None): CACHED['ircbot'].nick(username) CACHED['ircbot'].leave() # rejoin to freshen CACHED['irc_id'] CACHED['ircbot'].join() else: logging.info('registering outside of running application')
def process(args): ''' process a kybyz command ''' if args and args[0] in COMMANDS: print(eval(args[0])(*args[1:])) # pylint: disable=eval-used elif args: logging.error('must specify one of: %s', COMMANDS) else: logging.info('no command received to process')
def post(post_type, *args, returned='hashed', **kwargs): ''' make a new post from the command line or from another subroutine ''' if len(args) == 1 and JSON.match(args[0]): try: kwargs.update(json.loads(args[0])) except json.decoder.JSONDecodeError: logging.error('Post not valid JSON format: %s' % args[0]) else: logging.debug('args %s not valid JSON, using as key-value pairs', args) for arg in args: logging.debug('parsing %s', arg) kwargs.update(dict((arg.split('=', 1), ))) # override post_type if specified if post_type: kwargs.update({'type': post_type}) try: newpost = BasePost(None, **kwargs) jsonified = newpost.to_json() post_type = newpost.type hashed = kbhash(jsonified) cached = cache('.'.join((hashed, post_type)), jsonified) jsonified = newpost.to_json(for_hashing=True) hashed = kbhash(jsonified) hashcached = cache('.'.join((hashed, post_type)), jsonified) unadorned = os.path.splitext(hashcached)[0] try: os.symlink(cached, unadorned) except FileExistsError: existing = os.readlink(unadorned) if existing != cached: logging.warning('updating post %s to %s', unadorned, cached) os.unlink(unadorned) os.symlink(cached, unadorned) else: logging.debug('%s already symlinked to %s', unadorned, cached) return hashed if returned == 'hashed' else newpost except AttributeError: logging.exception('Post failed: attribute error') return None except TypeError: logging.exception('Post failed with kwargs: %s', kwargs) return None
def init(): ''' initialize application ''' logging.debug('beginning kybyz initialization') os.makedirs(CACHE, 0o700, exist_ok=True) CACHED.update(registration()._asdict()) if not CACHED['gpgkey']: username = os.getenv('KB_USERNAME', None) email = os.getenv('KB_EMAIL', None) if username and email: register(username, email) CACHED.update(registration()._asdict()) else: logging.error('need to set envvars KB_USERNAME and KB_EMAIL') CACHED['uptime'] = 0 CACHED['javascript'] = 'ERROR:javascript disabled or incompatible' logging.debug('CACHED: %s', CACHED) kybyz = threading.Thread(target=background, name='kybyz') kybyz.daemon = True kybyz.start()
def cache(path, data): ''' store data in cache for later retrieval ''' fullpath = os.path.realpath(os.path.join(KYBYZ_HOME, path)) if not fullpath.startswith(os.path.realpath(KYBYZ_HOME) + os.sep): raise ValueError('Attempt to write %s outside of app bounds' % fullpath) os.makedirs(os.path.dirname(fullpath), exist_ok=True) binary = 'b' if isinstance(data, bytes) else '' try: with open(fullpath, 'x' + binary) as outfile: outfile.write(data) except FileExistsError: existing = read(fullpath) if data != existing: logging.error('Failed to update %s from %r to %r', fullpath, existing, data) else: logging.debug('% already cached', fullpath) return fullpath