Example #1
0
def before_request() -> None:
    global config
    g.cache = Cache(app,
                    config={
                        'CACHE_TYPE': 'filesystem',
                        'CACHE_DIR': config['cache_dir'],
                    })
    if request.endpoint in ['jsx', 'static']:
        # This is just serving cached compiled frontends, skip loading from DB
        return

    g.config = config
    g.data = Data(config)
    g.sessionID = None
    g.userID = None
    try:
        aes = AESCipher(config['secret_key'])
        sessionID = aes.decrypt(request.cookies.get('SessionID'))
    except Exception:
        sessionID = None
    g.sessionID = sessionID
    if sessionID is not None:
        g.userID = g.data.local.user.from_session(sessionID)
    else:
        g.userID = None
Example #2
0
def main() -> None:
    parser = argparse.ArgumentParser(
        description=
        "A utility for working with databases created with this codebase.")
    parser.add_argument(
        "operation",
        help=
        "Operation to perform, options include 'create', 'generate', 'upgrade', 'change-password', 'add-admin' and 'remove-admin'.",
        type=str,
    )
    parser.add_argument(
        "-u",
        "--username",
        help="Username of user to add/remove admin rights for.",
        type=str,
    )
    parser.add_argument(
        "-m",
        "--message",
        help="Message to use for auto-generated migration scripts.",
        type=str,
    )
    parser.add_argument(
        "-e",
        "--allow-empty",
        help=
        "Allow empty migration script to be generated. Useful for data-only migrations.",
        action='store_true',
    )
    parser.add_argument("-c",
                        "--config",
                        help="Core configuration. Defaults to server.yaml",
                        type=str,
                        default="server.yaml")
    args = parser.parse_args()

    config = yaml.safe_load(open(args.config))
    config['database']['engine'] = Data.create_engine(config)
    try:
        if args.operation == "create":
            create(config)
        elif args.operation == "generate":
            generate(config, args.message, args.allow_empty)
        elif args.operation == "upgrade":
            upgrade(config)
        elif args.operation == "add-admin":
            add_admin(config, args.username)
        elif args.operation == "remove-admin":
            remove_admin(config, args.username)
        elif args.operation == 'change-password':
            change_password(config, args.username)
        else:
            raise Exception(f"Unknown operation '{args.operation}'")
    except DBCreateException as e:
        print(str(e))
        sys.exit(1)
Example #3
0
def remove_admin(config: Dict[str, Any], username: Optional[str]) -> None:
    if username is None:
        raise Exception('Please provide a username!')
    data = Data(config)
    userid = data.local.user.from_username(username)
    if userid is None:
        raise Exception('User not found!')
    user = data.local.user.get_user(userid)
    user.admin = False
    data.local.user.put_user(user)
    print(f'User {username} lost admin rights.')
Example #4
0
def add_admin(config: Dict[str, Any], username: Optional[str]) -> None:
    if username is None:
        raise Exception('Please provide a username!')
    data = Data(config)
    userid = data.local.user.from_username(username)
    if userid is None:
        raise Exception('User not found!')
    user = data.local.user.get_user(userid)
    user.admin = True
    data.local.user.put_user(user)
    print('User {} gained admin rights.'.format(username))
Example #5
0
def generate(config: Dict[str, Any], message: Optional[str],
             allow_empty: bool) -> None:
    if message is None:
        raise Exception('Please provide a message!')
    data = Data(config)
    data.generate(message, allow_empty)
    data.close()
Example #6
0
def change_password(config: Dict[str, Any], username: Optional[str]) -> None:
    if username is None:
        raise Exception('Please provide a username!')
    password1 = getpass.getpass('Password: '******'Re-enter password: '******'Passwords don\'t match!')
    data = Data(config)
    userid = data.local.user.from_username(username)
    if userid is None:
        raise Exception('User not found!')
    data.local.user.update_password(userid, password1)
    print(f'User {username} changed password.')
Example #7
0
def before_request() -> None:
    global config

    g.config = config
    g.data = Data(config)
    g.authorized = False

    authkey = request.headers.get('Authorization')
    if authkey is not None:
        try:
            authtype, authtoken = authkey.split(' ', 1)
        except ValueError:
            authtype = None
            authtoken = None

        if authtype.lower() == 'token':
            g.authorized = g.data.local.api.validate_client(authtoken)
Example #8
0
def run_scheduled_work(config: Dict[str, Any]) -> None:
    data = Data(config)

    # Only run scheduled work for enabled components
    enabled_factories: List[Any] = []
    enabled_caches: List[Any] = []
    if config.get('support', {}).get(GameConstants.IIDX, False):
        enabled_factories.append(IIDXFactory)
        enabled_caches.append(IIDXCache)
    if config.get('support', {}).get(GameConstants.POPN_MUSIC, False):
        enabled_factories.append(PopnMusicFactory)
        enabled_caches.append(PopnMusicCache)
    if config.get('support', {}).get(GameConstants.JUBEAT, False):
        enabled_factories.append(JubeatFactory)
        enabled_caches.append(JubeatCache)
    if config.get('support', {}).get(GameConstants.BISHI_BASHI, False):
        enabled_factories.append(BishiBashiFactory)
        enabled_caches.append(BishiBashiCache)
    if config.get('support', {}).get(GameConstants.DDR, False):
        enabled_factories.append(DDRFactory)
        enabled_caches.append(DDRCache)
    if config.get('support', {}).get(GameConstants.SDVX, False):
        enabled_factories.append(SoundVoltexFactory)
        enabled_caches.append(SoundVoltexCache)
    if config.get('support', {}).get(GameConstants.REFLEC_BEAT, False):
        enabled_factories.append(ReflecBeatFactory)
        enabled_caches.append(ReflecBeatCache)
    if config.get('support', {}).get(GameConstants.MUSECA, False):
        enabled_factories.append(MusecaFactory)
        enabled_caches.append(MusecaCache)

    # First, run any backend scheduled work
    for factory in enabled_factories:
        factory.run_scheduled_work(data, config)  # type: ignore

    # Now, warm the caches for the frontend
    for cache in enabled_caches:
        cache.preload(data, config)  # type: ignore

    # Now, possibly delete old log entries
    keep_duration = config.get('event_log_duration', 0)
    if keep_duration > 0:
        # Calculate timestamp of events we should delete
        oldest_event = Time.now() - keep_duration
        data.local.network.delete_events(oldest_event)
Example #9
0
def run_scheduled_work(config: Dict[str, Any]) -> None:
    data = Data(config)

    # Only run scheduled work for enabled components
    enabled_factories: List[Any] = []
    enabled_caches: List[Any] = []
    if config.get('support', {}).get(GameConstants.IIDX, False):
        enabled_factories.append(IIDXFactory)
        enabled_caches.append(IIDXCache)
    if config.get('support', {}).get(GameConstants.POPN_MUSIC, False):
        enabled_factories.append(PopnMusicFactory)
        enabled_caches.append(PopnMusicCache)
    if config.get('support', {}).get(GameConstants.JUBEAT, False):
        enabled_factories.append(JubeatFactory)
        enabled_caches.append(JubeatCache)
    if config.get('support', {}).get(GameConstants.BISHI_BASHI, False):
        enabled_factories.append(BishiBashiFactory)
        enabled_caches.append(BishiBashiCache)
    if config.get('support', {}).get(GameConstants.DDR, False):
        enabled_factories.append(DDRFactory)
        enabled_caches.append(DDRCache)
    if config.get('support', {}).get(GameConstants.SDVX, False):
        enabled_factories.append(SoundVoltexFactory)
        enabled_caches.append(SoundVoltexCache)
    if config.get('support', {}).get(GameConstants.REFLEC_BEAT, False):
        enabled_factories.append(ReflecBeatFactory)
        enabled_caches.append(ReflecBeatCache)
    if config.get('support', {}).get(GameConstants.MUSECA, False):
        enabled_factories.append(MusecaFactory)
        enabled_caches.append(MusecaCache)

    # First, run any backend scheduled work
    for factory in enabled_factories:
        factory.run_scheduled_work(data, config)  # type: ignore

    # Now, warm the caches for the frontend
    for cache in enabled_caches:
        cache.preload(data, config)  # type: ignore
Example #10
0
def create(config: Dict[str, Any]) -> None:
    data = Data(config)
    data.create()
    data.close()
Example #11
0
def upgrade(config: Dict[str, Any]) -> None:
    data = Data(config)
    data.upgrade()
    data.close()
Example #12
0
def load_config(filename: str) -> None:
    global config

    config.update(yaml.safe_load(open(filename)))  # type: ignore
    config['database']['engine'] = Data.create_engine(config)
    app.secret_key = config['secret_key']
Example #13
0
        factory.run_scheduled_work(data, config)  # type: ignore

    # Now, warm the caches for the frontend
    for cache in enabled_caches:
        cache.preload(data, config)  # type: ignore

    # Now, possibly delete old log entries
    keep_duration = config.get('event_log_duration', 0)
    if keep_duration > 0:
        # Calculate timestamp of events we should delete
        oldest_event = Time.now() - keep_duration
        data.local.network.delete_events(oldest_event)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description="A scheduler for work that needs to be done periodically.")
    parser.add_argument("-c",
                        "--config",
                        help="Core configuration. Defaults to server.yaml",
                        type=str,
                        default="server.yaml")
    args = parser.parse_args()

    # Set up global configuration
    config = yaml.safe_load(open(args.config))  # type: ignore
    config['database']['engine'] = Data.create_engine(config)

    # Run out of band work
    run_scheduled_work(config)
Example #14
0
def receive_request(path: str) -> Response:
    proto = EAmuseProtocol()
    remote_address = request.headers.get('x-remote-address', None)
    compression = request.headers.get('x-compress', None)
    encryption = request.headers.get('x-eamuse-info', None)
    req = proto.decode(
        compression,
        encryption,
        request.data,
    )

    if req is None:
        # Nothing to do here
        return Response("Unrecognized packet!", 500)
    if req.name in {'soapenv:Envelope', 'soap:Envelope', 'methodCall'}:
        # We get lots of spam from random bots trying to SOAP
        # us up, so ignore this shit.
        return Response("Unrecognized packet!", 500)

    # Create and format config
    global config
    requestconfig = copy.copy(config)
    requestconfig['client'] = {
        'address': remote_address or request.remote_addr,
    }

    dataprovider = Data(requestconfig)
    try:
        dispatch = Dispatch(requestconfig, dataprovider, True)
        resp = dispatch.handle(req)

        if resp is None:
            # Nothing to do here
            dataprovider.local.network.put_event(
                'unhandled_packet',
                {
                    'request': str(req),
                },
            )
            return Response("No response generated", 404)

        compression = None

        data = proto.encode(
            compression,
            encryption,
            resp,
        )

        response = make_response(data)

        # Some old clients are case-sensitive, even though http spec says these
        # shouldn't matter, so capitalize correctly.
        if compression:
            response.headers['X-Compress'] = compression
        else:
            response.headers['X-Compress'] = 'none'
        if encryption:
            response.headers['X-Eamuse-Info'] = encryption

        return response
    except UnrecognizedPCBIDException as e:
        dataprovider.local.network.put_event(
            'unauthorized_pcbid',
            {
                'pcbid': e.pcbid,
                'model': e.model,
                'ip': e.ip,
            },
        )
        return Response("Unauthorized client", 403)
    except Exception:
        stack = traceback.format_exc()
        print(stack)
        dataprovider.local.network.put_event(
            'exception',
            {
                'service': 'xrpc',
                'request': str(req),
                'traceback': stack,
            },
        )
        return Response("Crash when handling packet!", 500)
    finally:
        dataprovider.close()
Example #15
0
def load_config(filename: str) -> None:
    global config

    config.update(yaml.safe_load(open(filename)))
    config['database']['engine'] = Data.create_engine(config)