def register(): if not request.is_json: return jsonify(msg='missing request data'), 400 data = request.get_json() if 'user' not in data: return jsonify(msg='missing user in request'), 400 if 'pasw' not in data: return jsonify(msg='missing pasw in request'), 400 user = data['user'] if store.get(f'hash:{user}'): return jsonify(msg='user already exists'), 403 pasw = data['pasw'] if len(user) > 64: return jsonify(msg='username too long'), 400 if len(pasw) > 64: return jsonify(msg='password too long, max 64'), 400 if len(pasw) < 8: return jsonify(msg='password too short, min 8'), 400 hash = ph.hash(pasw) store.set(f'hash:{user}', hash) return jsonify(cooldown=app.config['CD_TIME'], access_token=create_access_token(user)), 200
def login(): if not request.is_json: return jsonify(msg='missing request data'), 400 data = request.get_json() if 'user' not in data: return jsonify(msg='missing user in request'), 400 if 'pasw' not in data: return 'missing pasw in request', 400 user = data['user'] pasw = data['pasw'] hash = store.get(f'hash:{user}') if not hash: return jsonify(msg="user doesn't exists"), 404 try: ph.verify(hash, pasw) except: return jsonify(msg='wrong pasw'), 401 log.debug(hash) if ph.check_needs_rehash(hash.decode('utf-8')): hash = ph.hash(pasw) store.set(f'hash:{user}', hash) return jsonify(cooldown=app.config['CD_TIME'], access_token=create_access_token(user)), 200
def configuration(state): global XSIZE global YSIZE global CDTIME XSIZE = state.app.config['BOARD_XSIZE'] YSIZE = state.app.config['BOARD_YSIZE'] CDTIME = state.app.config['CD_TIME'] data = store.get('board') if not data or len(data) < XSIZE*YSIZE: # temp TODO: update this board = store.bitfield('board') for x in range(XSIZE): for y in range(YSIZE): pixel = store.zrevrange(f"pixel:timestamp:{x}:{y}",0,0) color = store.hget(f"pixel:{pixel}",'color') or 0xff board.set('u8', f"#{x+y*XSIZE}", color) board.execute()
def draw(): data = request.get_json() if not data: return jsonify(msg='missing request data, json body not found'), 400 if 'coord' not in data: return jsonify(msg='missing coordinates'), 400 if 'x' not in data['coord'] or 'y' not in data['coord']: return jsonify(msg='wrong coordinates format'), 400 user = get_jwt_identity() # check cooldown if store.get(f"lock:{user}") is not None: return jsonify(msg='in cooldown, draw not available'), 403 store.setex(f"lock:{user}",CDTIME,'_') # pixel id pid = store.incr('pixel:id') x = data['coord']['x'] y = data['coord']['y'] timestamp = int(time()) color = data['color'] if not isinstance(x,int) or not isinstance(y, int): return jsonify(msg='wrong coordinate format, should be integers'), 400 if not x < XSIZE or not x >= 0: return jsonify(msg=f'x coordinate out of range, should be between 0 and {XSIZE - 1}'), 400 if not y < YSIZE or not y >= 0: return jsonify(msg=f'x coordinate out of range, should be between 0 and {YSIZE - 1}'), 400 if not isinstance(color,int): return jsonify(msg='wrong color format, should be integer'), 400 if not color < 256 and color >= 0: return jsonify(msg='color exceeded allowed value, should be between 0 and 255'), 400 pixel = { 'id': pid, 'timestamp' : timestamp, 'user' : user, 'coord' : data['coord'], 'color' : color, } # notify all connected clients socket.emit('post', pixel, namespace=f"/pixel", broadcast=True) log.debug(f"drawn pixel:{pid}{pixel}") # update the board board = store.bitfield('board') board.set('u8', f"#{x+y*XSIZE}", color) board.execute() #TODO: use mongodb instead of redis for persistence # flattened pixel object _pixel = { 'id': pid, 'timestamp' : timestamp, 'user': user, 'coord': f"{x}:{y}", 'color': color, } # pixel store store.hmset(f"pixel:{pid}", _pixel) # pixel indeces store.zadd(f"pixel:timestamp:{x}:{y}", {pid:timestamp}) return jsonify(pixel=pixel), 200
def get_board(): data = store.get('board') or b'' data = data.ljust(XSIZE * YSIZE, b'\xff') return jsonify(board=b64encode(data).decode('utf-8')), 200