Exemple #1
0
    def __init__(self, auth, host=DEFAULT_MOJANG_API_HOST):
        self.auth = auth
        self.api = APIHost(host)

        if self.auth.accessToken:
            bearer =  "Bearer " + self.auth.accessToken
            self.api.headers["Authorization"] = bearer
Exemple #2
0
    def __init__(self, username, clientToken=None, accessToken=None,
                 host=HOST_YGGDRASIL, agent=MINECRAFT_AGENT_V1):

        self.api = APIHost(host)
        self.username = username
        self.user = None
        self.agent = agent
        self.clientToken = clientToken
        self.accessToken = accessToken
        self.selectedProfile = None
Exemple #3
0
    def __init__(self, auth, host=DEFAULT_REALMS_HOST,
                 version=DEFAULT_REALMS_VERSION):

        # compose the necessary cookies from data in the auth object
        self.auth = auth
        sid =  "token:%s:%s" % (auth.accessToken, auth.selectedProfile["id"])
        user = auth.selectedProfile["name"]

        self.api = APIHost(host)
        self.api.cookies.set("sid", sid)
        self.api.cookies.set("user", user)
        self.api.cookies.set("version", version)
Exemple #4
0
class SessionAPI(object):
    """
    A thin wrapper for the the session portion of the Mojang API

    References
    ----------
    * http://wiki.vg/Mojang_API
    """

    def __init__(self, auth, host=DEFAULT_MOJANG_SESSION_HOST):
        self.auth = auth
        self.api = APIHost(host)

        if self.auth.accessToken:
            bearer =  "Bearer " + self.auth.accessToken
            self.api.headers["Authorization"] = bearer


    def profile_info(self, uuid):
        data = self.api.get("/session/minecraft/profile/%s" % uuid)

        if data:
            props = data.get("properties", ())
            for prop in props:
                if prop["name"] == "textures":
                    # we'll transform this particular named property
                    # value since we know it's actually JSON
                    val = prop.get("value")
                    val = b64decode(val)
                    val = loads(val)
                    prop["value"] = val
                    break

        return data


    def blocked_servers(self):
        return self.api.get("/blockedservers")
Exemple #5
0
    def load(self, filename):
        """
        set the state of this session to the what is represented in the
        JSON data stored in filename. Errors (access, malformed JSON,
        etc) while loading will be propagated.
        """

        with open(filename) as fd:
            session = load(fd)

        if "host" in session:
            host = session.pop("host")
            self.api = APIHost(host)

        self.__dict__.update(session)
Exemple #6
0
class StatusAPI(object):
    """
    A thin wrapper for the the status portion of the Mojang API

    References
    ----------
    * http://wiki.vg/Mojang_API
    """

    def __init__(self, auth, host=DEFAULT_MOJANG_STATUS_HOST):
        self.auth = auth # unused, maybe useful in the future.
        self.api = APIHost(host)


    def check(self):
        resp = self.api.get("/check")
        return resp
Exemple #7
0
class Authentication(object):
    """
    A thin wrapper for the Mojang authentiation scheme, 'Yggdrasil'

    References
    ----------
    * http://wiki.vg/Authentication
    """

    def __init__(self, username, clientToken=None, accessToken=None,
                 host=HOST_YGGDRASIL, agent=MINECRAFT_AGENT_V1):

        self.api = APIHost(host)
        self.username = username
        self.user = None
        self.agent = agent
        self.clientToken = clientToken
        self.accessToken = accessToken
        self.selectedProfile = None


    def authenticate(self, password):
        """
        generate an accessToken for this session
        """

        payload = { "username": self.username,
                    "password": password,
                    "requestUser": True }

        if self.agent:
            payload["agent"] = self.agent

        if self.clientToken:
            payload["clientToken"] = self.clientToken

        try:
            ret = self.api.post("/authenticate", payload)

        except HTTPError as err:
            # if it's just a 403, that means the auth was wrong, so
            # it's simple failure. Any other kind of error is a
            # different kind of problem, so we'll propagate it up.

            if err.response.status_code == 403:
                return False
            else:
                raise

        else:
            self.clientToken = ret["clientToken"]
            self.accessToken = ret["accessToken"]
            self.selectedProfile = ret.get("selectedProfile")
            self.user = ret.get("user")

            return True


    def refresh(self):
        """
        ensure that this session remains valid. May result in a new
        accessToken.
        """

        payload = { "accessToken": self.accessToken,
                    "clientToken": self.clientToken,
                    "requestUser": True }

        try:
            ret = self.api.post("/refresh", payload)

        except HTTPError as err:
            # a 403 just means the session was completely invalid,
            # which is expected behavior in many circumstances. In
            # that case, we just return False. Any other error gets
            # propagated up.

            if err.response.status_code == 403:
                return False
            else:
                raise

        else:
            self.clientToken = ret["clientToken"]
            self.accessToken = ret["accessToken"]
            self.selectedProfile = ret.get("selectedProfile")
            self.user = ret.get("user")

            return True


    def validate(self):
        """
        check that the session is currently valid, and can be used to
        perform other actions. An invalid session will need to be
        renewed or a full re-auth may be required.
        """

        if not self.accessToken:
            return False

        payload = { "accessToken": self.accessToken, }

        try:
            ret = self.api.post("/validate", payload)

        except HTTPError as err:
            # one again, 403 is an expected possibility. Everything
            # else is wonky.

            if err.response.status_code == 403:
                return False
            else:
                raise

        else:
            return True


    def signout(self, password):
        """
        invalidates all sessions against the specified account
        """

        payload = { "username": self.username,
                    "password": password, }

        try:
            ret = self.api.post("/signout", payload)

        except HTTPError as err:
            # 403 means bad username/password in this case
            if err.response.status_code == 403:
                return False
            else:
                raise

        else:
            return True


    def invalidate(self):
        """
        invalidates the current session
        """

        if not self.accessToken:
            return None

        payload = { "accessToken": self.accessToken,
                    "clientToken": self.clientToken, }

        # even if we're already invalidated, this won't raise an
        # HTTPError, so we won't try to filter out a 403
        ret = self.api.post("/invalidate", payload)

        self.accessToken = None
        return True


    def load(self, filename):
        """
        set the state of this session to the what is represented in the
        JSON data stored in filename. Errors (access, malformed JSON,
        etc) while loading will be propagated.
        """

        with open(filename) as fd:
            session = load(fd)

        if "host" in session:
            host = session.pop("host")
            self.api = APIHost(host)

        self.__dict__.update(session)


    def save(self, filename):
        """
        save the state of this session to JSON data and write it to
        filename
        """

        session = dict(self.__dict__)
        session["host"] = self.api._host
        del session["api"]

        with open(filename, "w") as fd:
            dump(session, fd)


    def ensureClientToken(self):
        """
        generate a clientToken for this session if one doesn't already
        exist
        """

        if not self.clientToken:
            self.clientToken = generate_clientToken()
Exemple #8
0
class MojangAPI(object):
    """
    A thin wrapper for the the core portion of the Mojang API

    References
    ----------
    * http://wiki.vg/Mojang_API
    """

    def __init__(self, auth, host=DEFAULT_MOJANG_API_HOST):
        self.auth = auth
        self.api = APIHost(host)

        if self.auth.accessToken:
            bearer =  "Bearer " + self.auth.accessToken
            self.api.headers["Authorization"] = bearer


    def username_to_uuid(self, username, at_time=0):
        return self.api.get("/users/profiles/minecraft/%s?at=%i" %
                            (username, at_time))


    def uuid_name_history(self, uuid):
        return self.api.get("/user/profiles/%s/names" % uuid)


    def playernames_to_uuids(self, playernames):
        return self.api.post("/profiles/minecraft", list(playernames))


    def change_skin(self, uuid, skin_url, slim=False):
        payload = {"model": "slim" if slim else "",
                   "url": skin_url}

        return self.api.post_encoded("/user/profile/%s/skin" % uuid)


    def upload_skin(self, uuid, skin_stream, slim=False):
        payload = {"model": "slim" if slim else "",
                   "file": ("harambe.png", skin_stream, "image/png")}

        return self.api.post_form("/user/profile/%s/skin" % uuid, payload)


    def upload_skin_filename(self, uuid, skin_filename, slim=False):
        with open(skin_filename) as skin_stream:
            return upload_skin(self, uuid, skin_stream, slim)


    def reset_skin(self, uuid):
        return self.api.delete("/user/profile/%s/skin" % uuid)


    def whoami(self):
        return self.api.get("/user")


    def statistics(self, which=DEFAULT_STATISTICS):
        which = {"metricKeys": list(which)}
        return self.api.post("/orders/statistics", which)
Exemple #9
0
 def __init__(self, auth, host=DEFAULT_MOJANG_STATUS_HOST):
     self.auth = auth # unused, maybe useful in the future.
     self.api = APIHost(host)
Exemple #10
0
class RealmsAPI(object):
    """
    A thin wrapper for the Mojang Realms API

    References
    ----------
    * http://wiki.vg/Realms_API
    """

    def __init__(self, auth, host=DEFAULT_REALMS_HOST,
                 version=DEFAULT_REALMS_VERSION):

        # compose the necessary cookies from data in the auth object
        self.auth = auth
        sid =  "token:%s:%s" % (auth.accessToken, auth.selectedProfile["id"])
        user = auth.selectedProfile["name"]

        self.api = APIHost(host)
        self.api.cookies.set("sid", sid)
        self.api.cookies.set("user", user)
        self.api.cookies.set("version", version)


    def mco_available(self):
        return self.api.get("/mco/available")


    def mco_client_outdated(self):
        return self.api.get("/mco/client/outdated")


    def mco_tos_agree(self):
        return self.api.post("/mco/tos/agreed")


    def realm_list(self):
        """
        List the realms available for the given account auth
        """

        return self.api.get("/worlds")


    def realm_info(self, realm_id):
        """
        Information about a specific realm by ID
        """

        return self.api.get("/worlds/%i" % realm_id)


    def realm_join(self, realm_id):
        """
        Wakes up a realm so that it can be joined, returns a string
        specifying the IP_ADDRESS:PORT of the running server
        """

        return self.api.get("/worlds/%i/join" % realm_id)


    def realm_backups(self, realm_id):
        """
        Show the backups available for the given realm ID
        """

        return self.api.get("/worlds/%i/backups" % realm_id)


    def realm_world_url(self, realm_id, world):
        """
        Show the download URL for the latest world backup for the given
        realm ID
        """

        return self.api.get("/worlds/%i/slot/%i/download" % (realm_id, world))


    def realm_ops_list(self, realm_id):
        return self.api.get("/ops/%i" % realm_id)


    def realm_subscription(self, realm_id):
        return self.api.get("/subscriptions/%i" % realm_id)