Example #1
0
    def __init__(self, username):
        self.username = username
        """Email or user id."""

        self.auth = Authenticator(username)
        """Handles OAuth 2.0 authentication."""

        self._uri_cache = UriCache(username)
        """Cache of Spotify URIs."""

        self.me = None
        """The Spotify user information."""

        # Get authorization.
        self.auth.authenticate()

        # Get user information and validate it.
        self.me = self.get_api_v1("me")

        if not self.me:
            raise RuntimeError("Could not get account information.")

        if (self.me['email'] != username) and (self.me['id'] != username):
            raise RuntimeError(
                "\n\n\nInvalid email/user id entered!\n"
                "You entered: {}\n"
                "You signed in as: {} (email), {} (user id)".format(username,
                                                                    self.me['email'],
                                                                    self.me['id'])
            )
    def __init__(self):
        super().__init__()
        self.title("PRMSystem")
        self.main_frame = tk.Frame(self, bg="#84CEEB")
        self.main_frame.pack(fill="both", expand="true")
        self.main_frame.pack_propagate(0)
        self.geometry("1024x600")
        self.resizable(0, 0)
        self.db = PRMS_Database()
        self.alphavantage_connection = AlphaVantageAPI(api_key="")
        self.news_connection = NewsConnection("")
        self.oanda_connection = OandaConnection(account_id="", api_key="")

        self.current_page = tk.Frame()
        self.show_frame(HomePage)
        menubar = Navbar(root=self)
        tk.Tk.config(self, menu=menubar)

        self.authenticator = Authenticator(self.db)
        LoginWindow(parent=self, authenticator=self.authenticator)
        self.protocol("WM_DELETE_WINDOW", self.quit_application)
Example #3
0
    def __init__(self, filename):
        self.filename = filename
        self.auth = Authenticator()

        if os.path.exists(self.filename):
            self.db = cPickle.load(open(self.filename, 'rb'))
        else:
            self.db = {}
            self.db["accounts"] = {}
            self.db["campaigns"] = {}
            self.db["ability_cache"] = [None] * (MAX_ABILITY_CACHE + 1
                                                 )  # list of Ability dicts
            self.db["ability_cache_index"] = 0
        # Not including static json files in DB for efficiency
        if os.path.exists("weapons.json"):
            with open("weapons.json") as f:
                self.weapons = json.load(f)
        if os.path.exists("abilities.json"):
            with open("abilities.json",
                      encoding="utf8") as f:  # encoding for smart quotes
                self.abilities = json.load(f)
Example #4
0
    def handle_read(self):
        """Read all available bytes, and process as many packets as possible.
        """
        t = time()
        if self.last_report + 5 < t and self.stream.tot_bytes > 0:
            self.last_report = t
            logger.debug(
                "%s: total/wasted bytes is %d/%d (%f wasted)" %
                (self.side, self.stream.tot_bytes, self.stream.wasted_bytes,
                 100 * float(self.stream.wasted_bytes) /
                 self.stream.tot_bytes))
        self.stream.append(self.recv(4092))

        if self.out_of_sync:
            data = self.stream.read(len(self.stream))
            self.stream.packet_finished()
            if self.other_side:
                self.other_side.send(data)
            return

        try:
            packet = parse_packet(self.stream, self.msg_spec, self.side)
            while packet != None:
                rebuild = False
                if packet['msgtype'] == 0x02 and self.side == 'client':
                    # Determine which protocol message definitions to use.
                    proto_version = packet['proto_version']
                    logger.info('Client requests protocol version %d' %
                                proto_version)
                    if not proto_version in messages.protocol:
                        logger.error("Unsupported protocol version %d" %
                                     proto_version)
                        self.handle_close()
                        return
                    self.username = packet['username']
                    self.msg_spec, self.other_side.msg_spec = messages.protocol[
                        proto_version]
                    self.cipher = encryption.encryption_for_version(
                        proto_version)
                    self.other_side.cipher = self.cipher
                elif packet['msgtype'] == 0xfd:
                    self.rsa_key = encryption.decode_public_key(
                        packet['public_key'])
                    self.encoded_rsa_key = packet['public_key']
                    packet['public_key'] = encryption.encode_public_key(
                        self.other_side.rsa_key)
                    if 'challenge_token' in packet:
                        self.challenge_token = packet['challenge_token']
                        self.other_side.challenge_token = self.challenge_token
                    self.other_side.server_id = packet['server_id']
                    if check_auth:
                        packet['server_id'] = encryption.generate_server_id()
                    else:
                        packet['server_id'] = "-"
                    self.server_id = packet['server_id']
                    rebuild = True
                elif packet['msgtype'] == 0xfc and self.side == 'client':
                    self.shared_secret = encryption.decrypt_shared_secret(
                        packet['shared_secret'], self.rsa_key)
                    if (len(self.shared_secret) > 16
                            and self.cipher == encryption.RC4):
                        logger.error("Unsupported protocol version")
                        self.handle_close()
                        return
                    packet['shared_secret'] = encryption.encrypt_shared_secret(
                        self.other_side.shared_secret, self.other_side.rsa_key)
                    if 'challenge_token' in packet:
                        challenge_token = encryption.decrypt_shared_secret(
                            packet['challenge_token'], self.rsa_key)
                        if challenge_token != self.challenge_token:
                            self.kick("Invalid client reply")
                            return
                        packet[
                            'challenge_token'] = encryption.encrypt_shared_secret(
                                self.other_side.challenge_token,
                                self.other_side.rsa_key)
                    if auth:
                        logger.info("Authenticating on server")
                        auth.join_server(self.server_id,
                                         self.other_side.shared_secret,
                                         self.other_side.rsa_key)
                    if check_auth:
                        logger.info("Checking authenticity")
                        if not Authenticator.check_player(
                                self.username, self.other_side.server_id,
                                self.shared_secret, self.rsa_key):
                            self.kick("Unable to verify username")
                            return
                    rebuild = True
                elif packet['msgtype'] == 0xfc and self.side == 'server':
                    logger.debug("Starting encryption")
                    self.start_cipher()
                forward = True
                if self.plugin_mgr:
                    forwarding = self.plugin_mgr.filter(packet, self.side)
                    if forwarding and packet.modified:
                        rebuild = True
                if rebuild:
                    packet['raw_bytes'] = self.msg_spec[
                        packet['msgtype']].emit(packet)
                if forwarding and self.other_side is not None:
                    self.other_side.send(packet['raw_bytes'])
                if packet['msgtype'] == 0xfc and self.side == 'server':
                    self.other_side.start_cipher()
                # Since we know we're at a message boundary, we can inject
                # any messages in the queue.
                msgbytes = self.plugin_mgr.next_injected_msg_from(self.side)
                while self.other_side and msgbytes is not None:
                    self.other_side.send(msgbytes)
                    msgbytes = self.plugin_mgr.next_injected_msg_from(
                        self.side)

                # Attempt to parse the next packet.
                packet = parse_packet(self.stream, self.msg_spec, self.side)
        except PartialPacketException:
            pass  # Not all data for the current packet is available.
        except Exception:
            logger.error(
                "MinecraftProxy for %s caught exception, out of sync" %
                self.side)
            logger.error(traceback.format_exc())
            logger.debug("Current stream buffer: %s" % repr(self.stream.buf))
            self.out_of_sync = True
            self.stream.reset()
Example #5
0

if __name__ == "__main__":
    logging.basicConfig(level=logging.ERROR)
    (host, port, opts, pcfg) = parse_args()

    if opts.logfile:
        config_logging(opts.logfile)

    if opts.loglvl:
        logging.root.setLevel(getattr(logging, opts.loglvl.upper()))

    if opts.user:
        while True:
            password = getpass("Minecraft account password: "******"Authenticating with %s" % opts.user)
            if auth.check():
                break
            logger.error("Authentication failed")
        logger.debug("Credentials are valid")

    if opts.authenticate or opts.password_file:
        if opts.authenticate:
            credentials = minecraft_credentials()
            if credentials is None:
                logger.error("Can't find password file. " +
                             "Use --user or --password-file option instead.")
                sys.exit(1)
            user, password = credentials
        else:
Example #6
0
    def _handle_client(self, connection):
        with closing(connection[0]) as sock:
            clt_spec, srv_spec = protocol[0]
            print t.bold("\nConnected to %s:%s" % connection[1])

            print t.bold_cyan("\nExpecting Server Ping (0xfe) " +
                              "or Handshake (0x02) packet")
            packet = parse_packet(sock, clt_spec)
            if packet['msgtype'] == 0xfe:
                send_packet(sock, srv_spec, {'msgtype': 0xff,
                                             'reason': 'mc3p debugger'})
                return
            elif packet['msgtype'] != 0x02:
                raise UnexpectedPacketException(packet['msgtype'])
            if packet['proto_version'] < 38:
                print t.bold_red("Error:"),
                print "Unsupported protocol version"
                return
            username = packet['username']
            clt_spec, srv_spec = protocol[packet['proto_version']]

            print t.bold("\nGenerating RSA key pair")
            key = encryption.generate_key_pair()
            challenge = encryption.generate_challenge_token()
            server_id = encryption.generate_server_id()

            packet = {'msgtype': 0xfd,
                      'server_id': server_id,
                      'public_key': encryption.encode_public_key(key),
                      'challenge_token': challenge}
            send_packet(sock, srv_spec, packet)

            packet = parse_packet(sock, clt_spec, 0xfc)
            try:
                decrypted_token = encryption.decrypt_shared_secret(
                    packet['challenge_token'], key
                )
            except:
                decrypted_token = None
            if decrypted_token is None:
                try:
                    decrypted_token = key.decrypt(packet['challenge_token'])
                except:
                    pass
                if decrypted_token == challenge:
                    print t.bold_red("\nError:"),
                    print ("The challenge token was not padded " +
                           "correctly. See ftp://ftp.rsasecurity.com/pub/" +
                           "pkcs/pkcs-1/pkcs-1v2-1.pdf section 7.2.1 if " +
                           "your library does not support PKCS#1 padding.")
                else:
                    print t.bold_red("\nError:"),
                    print "The challenge token is not encrypted correctly.\n"
                    print PacketFormatter.bytes(decrypted_token,
                                                "Decrypted bytes: ", t.bold)
                return
            elif decrypted_token != challenge:
                print t.bold_red("\nError:"),
                print "Received challenge token does not",
                print "match the expected value.\n"
                print PacketFormatter.bytes(decrypted_token,
                                            "Received bytes: ", t.bold)
                print
                print PacketFormatter.bytes(challenge,
                                            "Expected bytes: ", t.bold)
                return
            secret = encryption.decrypt_shared_secret(packet['shared_secret'],
                                                      key)
            if secret is None:
                print t.bold_red("\nError:"),
                print ("The shared secret was not padded" +
                       "correctly. See ftp://ftp.rsasecurity.com/pub/" +
                       "pkcs/pkcs-1/pkcs-1v2-1.pdf section 7.2.1 if " +
                       "your library does not support PKCS#1 padding.")
                return
            print PacketFormatter.bytes(secret, "Shared secret: ", t.bold)
            if len(secret) != 16:
                print t.bold_red("\nError:"),
                print "The shared secret must be 16 bytes long",
                print "(received length is %s)" % len(secret)
                return

            print t.bold_cyan("\nAuthentication")
            print PacketFormatter.bytes(server_id, "Server ID:     ", t.bold)
            print PacketFormatter.bytes(secret, "Shared secret: ", t.bold)
            print PacketFormatter.bytes(encryption.encode_public_key(key),
                                        "Public key:    ", t.bold)
            print t.bold("Login hash:   "),
            print Authenticator.login_hash(server_id, secret, key)
            if Authenticator.check_player(username, server_id, secret, key):
                print t.bold_green("Success:"), "You are authenticated"
            else:
                print t.bold_yellow("Warning:"), "You are not authenticated"

            send_packet(sock, srv_spec, {'msgtype': 0xfc,
                                         'challenge_token': '',
                                         'shared_secret': ''})

            print t.bold("\nStarting AES encryption")
            clt_cipher = encryption.AES128CFB8(secret)
            srv_cipher = encryption.AES128CFB8(secret)
            backup_cipher = encryption.AES128CFB8(secret)

            parse_packet(sock, clt_spec, 0xcd, clt_cipher, backup_cipher)

            send_packet(sock, srv_spec, {'msgtype': 0x01,
                                         'eid': 1337,
                                         'level_type': 'flat',
                                         'server_mode': 0,
                                         'dimension': 0,
                                         'difficulty': 2,
                                         'unused': 0,
                                         'max_players': 20}, srv_cipher)

            if self.send_chunks:
                while True:
                    print
                    packet = parse_packet(sock, clt_spec, cipher=clt_cipher)
                    if packet['msgtype'] == 0x0d:
                        break

                x, y, z = 5, 9, 5

                send_packet(sock, srv_spec, {'msgtype': 0x06,
                                             'x': x,
                                             'y': y,
                                             'z': z}, srv_cipher)

                send_packet(sock, srv_spec, {'msgtype': 0xca,
                                             'abilities': 0b0100,
                                             'walking_speed': 25,
                                             'flying_speed': 12}, srv_cipher)

                send_packet(sock, srv_spec, {'msgtype': 0x04,
                                             'time': 0}, srv_cipher)

                send_packet(sock, srv_spec, multi_chunk_packet(), srv_cipher)

                send_packet(sock, srv_spec, {'msgtype': 0x0d,
                                             'x': x,
                                             'y': y,
                                             'stance': y + 1.5,
                                             'z': z,
                                             'yaw': 0,
                                             'pitch': 0,
                                             'on_ground': False}, srv_cipher)

                buffer = StringSocket()

                send_packet(buffer, srv_spec,
                            {'msgtype': 0x03,
                             'chat_msg': 'First message'},
                            srv_cipher)

                send_packet(buffer, srv_spec,
                            {'msgtype': 0x03,
                             'chat_msg': 'Second message'}, srv_cipher)

                sock.sendall(buffer.data)

            if self.stay_connected:
                while True:
                    packet = parse_packet(sock, clt_spec, cipher=clt_cipher,
                                          title=True)
                    if packet['msgtype'] == 0xff:
                        break
                    elif packet['msgtype'] == 0x00:
                        send_packet(buffer, srv_spec, {'msgtype': 0x00,
                                                       'id': 0}, srv_cipher)
                        break
            else:
                send_packet(sock, srv_spec,
                            {'msgtype': 0xff,
                             'reason': "Successfully logged in"}, srv_cipher)
Example #7
0

if __name__ == "__main__":
    logging.basicConfig(level=logging.ERROR)
    (host, port, opts, pcfg) = parse_args()

    if opts.logfile:
        util.config_logging(opts.logfile)

    if opts.loglvl:
        logging.root.setLevel(getattr(logging, opts.loglvl.upper()))

    if opts.user:
        while True:
            password = getpass("Minecraft account password: "******"Authenticating with %s" % opts.user)
            if auth.check():
                break
            logger.error("Authentication failed")
        logger.debug("Credentials are valid")

    if opts.authenticate or opts.password_file:
        if opts.authenticate:
            credentials = minecraft_credentials()
            if credentials is None:
                logger.error("Can't find password file. " +
                             "Use --user or --password-file option instead.")
                sys.exit(1)
            user, password = credentials
        else:
Example #8
0
__author__ = 'smileya'
from messaging import Message
from authentication import Authenticator
import urls
#https://www.facebook.com/connect/login_success.html#access_token=CAAGm0PX4ZCpsBAKAZCS8vbuNy7hE1zB0jdScFiWPLboaB1hodBvvGmX10lb4ZA51j4tZBslYOo64ckaV2bRoCsRjZBYR3L6cBvsuuMPVAcwJHks9emOPmifDEHbu0IBBOOk0bPQGgZBUF5y5bvlIze3ZBOscHTXCuJIZAIYUrWAQQKpEYKfXzCy5AHAmzpJX5F8pAYZBfAbZAco61Rh0TY7kJZB&expires_in=3857
# ok so we'll need an access token and user ID andrew.smiley.90




# so let's try to send a basic request
#guess we should commit too
auth = Authenticator("CAAGm0PX4ZCpsBAOcrXW79ctGQ5IERvBr8A2zA5jUSiObrL27Y2bN9qil4VNl5bkKvp1yN1BmcR96f977MBkFpIJQwxWBbIqWY5gfPnRzLAFEFniXrUJTJiGisaMerDXykU85YGN271qATigljzX5AWxRuvJmdcbkrsZBcD5QTIkMMXCgE0RFIdREKZASy8QainaIEpGDrAeF73PZALID", "andrew.smiley.90")
auth.login()
Example #9
0
def require_basic_auth():
    if not app.config.get('AUTHENTICATOR'):
        app.config['AUTHENTICATOR'] = Authenticator()
    if request.endpoint != "healthcheck" and not app.config['AUTHENTICATOR'].authenticate():
        return Authenticator.challenge()
Example #10
0
class SpotifyApi(object):
    """Interface to make API calls."""

    def __init__(self, username):
        self.username = username
        """Email or user id."""

        self.auth = Authenticator(username)
        """Handles OAuth 2.0 authentication."""

        self._uri_cache = UriCache(username)
        """Cache of Spotify URIs."""

        self.me = None
        """The Spotify user information."""

        # Get authorization.
        self.auth.authenticate()

        # Get user information and validate it.
        self.me = self.get_api_v1("me")

        if not self.me:
            raise RuntimeError("Could not get account information.")

        if (self.me['email'] != username) and (self.me['id'] != username):
            raise RuntimeError(
                "\n\n\nInvalid email/user id entered!\n"
                "You entered: {}\n"
                "You signed in as: {} (email), {} (user id)".format(username,
                                                                    self.me['email'],
                                                                    self.me['id'])
            )

    def get_email(self):
        return self.me['email']

    def get_id(self):
        return self.me['id']

    def get_display_name(self):
        return self.me['display_name']

    def get_username(self):
        return self.username

    def is_premium(self):
        return self.me['product'] == "premium"

    def get_market(self):
        return self.me['country']

    @common.async
    def play(self, track=None, context_uri=None, uris=None, device=None):
        """Play a Spotify track.

        Args:
            track (str, int): The track uri or position.
            context_uri (str): The context uri.
            uris (iter): Collection of uris to play.
            device (Device): A device to play.
        """
        data = {}

        # Special case when playing a set of uris.
        if uris:
            data['uris'] = uris
            if common.is_int(track):
                data["offset"] = {"position": track}
        elif context_uri:
            # Set the context that we are playing in.
            data["context_uri"] = context_uri

            if common.is_int(track):
                data["offset"] = {"position": track}
            elif isinstance(track, basestring):
                data["offset"] = {"uri": track}

        # No context given, just play the track.
        elif track is not None and not context_uri:
            if isinstance(track, basestring) and track.startswith("spotify:track"):
                data['uris'] = [track]

        params = {}
        if device and device['id']:
            params["device_id"] = device['id']

        self.put_api_v1("me/player/play", params, data)

    @common.async
    def transfer_playback(self, device, play=False):
        """Transfer playback to a different Device.

        Args:
            device (Device): The Device to transfer playback to.
            play (bool): Whether to ensure playback happens on new device.
        """
        data = {"device_ids": [device['id']],
                "play": play}
        self.put_api_v1("me/player", data=data)

    @common.async
    def pause(self):
        """Pause the player."""
        self.put_api_v1("me/player/pause")

    @common.async
    def next(self):
        """Play the next song."""
        self.post_api_v1("me/player/next")

    @common.async
    def previous(self):
        """Play the previous song."""
        self.post_api_v1("me/player/previous")

    @common.async
    def shuffle(self, shuffle):
        """Set the player to shuffle.

        Args:
            shuffle (bool): Whether to shuffle or not.
        """
        q = urllib.urlencode({"state": shuffle})
        url = "me/player/shuffle"
        self.put_api_v1(url, q)

    @common.async
    def repeat(self, repeat):
        """Set the player to repeat.

        Args:
            repeat (bool): Whether to repeat or not.
        """
        q = urllib.urlencode({"state": repeat})
        url = "me/player/repeat"
        self.put_api_v1(url, q)

    @common.async
    def volume(self, volume):
        """Set the player volume.

        Args:
            volume (int): Volume level. 0 - 100 (inclusive).
        """
        q = urllib.urlencode({"volume_percent": volume})
        url = "me/player/volume"
        self.put_api_v1(url, q)

    def get_player_state(self):
        """Returns the player state.

        The following information is returned:
            device, repeat_state, shuffle_state, context,
            timestamp, progress_ms, is_playing, item.

        Returns:
            dict: Information containing the player state.
        """
        return self.get_api_v1("me/player")

    def get_currently_playing(self):
        """Get the currently playing Track.

        Returns:
            Track: The currently playing Track or NoneTrack.
        """
        playing = self.get_api_v1("me/player/currently-playing")
        if playing:
            track = playing['item']
            if track:
                playing.update(track)
                return Track(playing)
            else:
                return NoneTrack
        else:
            return NoneTrack

    def get_user_info(self, user_id):
        """Returns a dict of the a users info.

        The following information is returned:
            display_name, external_urls, followers, href, id,
            images, type, uri.

        user_id (str): The user_id.

        Returns:
            dict: Users information.
        """
        return self.get_api_v1("users/{}".format(user_id))

    def get_devices(self):
        """Return a list of devices with Spotify players running.

        Returns:
            list: The Devices.
        """
        results = self.get_api_v1("me/player/devices")
        if results and "devices" in results:
            return tuple(Device(device) for device in results['devices'])
        else:
            return []

    def search(self, types, query, limit=20):
        """Calls Spotify's search api.

        Args:
            types (tuple): Strings of the type of search (i.e, 'artist',
                'track', 'album')
            query (str): The search query.
            limit (int): Limit of the amount of results to return per
                type of search in 'types'.

        Returns:
            dict: Collection of Artist, Album, and Track objects.
        """
        type_str = ",".join(types)
        params = {'type': type_str,
                  'q': query,
                  'limit': limit}

        results = self.get_api_v1("search", params)

        cast = {
            'artists': Artist,
            'tracks': Track,
            'albums': Album,
        }

        combined = []
        if results:
            for type in types:
                # Results are plural (i.e, 'artists', 'albums', 'tracks')
                type = type + 's'
                combined.extend([cast[type](info) for info in results[type]['items']])

        return combined

    @uri_cache
    def get_albums_from_artist(self, artist,
                               type=("album", "single", "appears_on", "compilation"),
                               market=None):
        """Get Albums from a certain Artist.

        Args:
            artist (Artist): The Artist.
            type (iter): Which types of albums to return.
            market (str): The market. Default is None which means use the account.
        Returns:
            tuple: The Albums.
        """
        q = {"include_groups": ",".join(type),
             "market": market or self.get_market(),
             "limit": 50}
        url = "artists/{}/albums".format(artist['id'])
        page = self.get_api_v1(url, q)
        albums = self.extract_page(page)

        return tuple(Album(album) for album in albums)

    @uri_cache
    def get_top_tracks_from_artist(self, artist, market=None):
        """Get top tracks from a certain Artist.

        This also returns a pseudo-track to play the Artist context.

        Args:
            artist (Artist): The Artist to get Tracks from.
            market (str): The market. Default is None which means use the account.

        Returns:
            tuple: The Tracks.
        """
        q = {"country": market or self.get_market()}
        url = "artists/{}/top-tracks".format(artist['id'])
        result = self.get_api_v1(url, q)

        if result:
            return tuple(Track(t) for t in result["tracks"])
        else:
            return []

    @uri_cache
    def get_selections_from_artist(self, artist, progress=None):
        """Return the selection from an Artist.

        This includes the top tracks and albums from the artist.

        Args:
            artist (Artist): The Artist.
            progress (Progress): Progress associated with this call.

        Returns:
            iter: The Tracks and Albums.
        """
        selections = []

        selections.extend(self.get_top_tracks_from_artist(artist))
        if selections:
            progress.set_percent(0.5)

        selections.extend(self.get_albums_from_artist(artist))
        if progress:
            progress.set_percent(1)

        return selections

    @uri_cache
    def get_all_tracks_from_artist(self, artist, progress=None):
        """Return all tracks from an Artist.

        This includes the top tracks and albums from the artist.

        Args:
            artist (Artist): The Artist.
            progress (Progress): Progress associated with this call.

        Returns:
            iter: The Tracks.
        """
        albums = self.get_albums_from_artist(artist)
        if albums:
            n = len(albums)
            tracks = []
            for i, a in enumerate(albums):
                for t in self.get_tracks_from_album(a):
                    tracks.append(Track(t))
                if progress:
                    progress.set_percent(float(i)/n)
            tracks = (t for t in tracks if artist['name'] in str(t))
            return tuple(tracks)

    @uri_cache
    def get_tracks_from_album(self, album, progress=None):
        """Get Tracks from a certain Album.

        Args:
            album (Album): The Album to get Tracks from.

        Returns:
            tuple: The Tracks.
        """
        q = {"limit": 50}
        url = "albums/{}/tracks".format(album['id'])
        page = self.get_api_v1(url, q)
        tracks = []
        for track in self.extract_page(page, progress):
            track['album'] = album
            tracks.append(Track(track))
        return tuple(tracks)

    @uri_cache
    def get_tracks_from_playlist(self, playlist, progress=None):
        """Get Tracks from a certain Playlist.

        Args:
            playlist (Playlist): The Playlist to get Tracks from.
            progress (Progress): Progress associated with this call.

        Returns:
            tuple: The Tracks.
        """
        # Special case for the "Saved" Playlist
        if playlist['uri'] == common.SAVED_TRACKS_CONTEXT_URI:
            return self._get_saved_tracks(progress)
        else:
            q = {"limit": 50}
            url = "users/{}/playlists/{}/tracks".format(playlist['owner']['id'],
                                                        playlist['id'])
            page = self.get_api_v1(url, q)
            result = [Track(track["track"]) for track in self.extract_page(page, progress)]

        return tuple(result)

    @uri_cache
    def convert_context(self, context, progress=None):
        """Convert a Context to an Album, Playlist, or Artist.

        Args:
            context (dict): The Context to convert from.
            progress (Progress): Progress associated with this call.

        Returns:
            SpotifyObject: Album, Artist, or Playlist.
        """
        context_type = context["type"]
        if context_type == "artist":
             return self.get_artist_from_context(context)
        elif context_type == common.ALL_ARTIST_TRACKS_CONTEXT_TYPE:
            return self.get_artist_from_context(context)
        elif context_type == "album":
            return self.get_album_from_context(context)
        elif context_type == "playlist":
            return self.get_playlist_from_context(context)

    @uri_cache
    def get_artist_from_context(self, context):
        """Return an Artist from a Context.

        Args:
            context (dict): The Context to convert from.

        Returns:
            Artist: The Artist.
        """
        artist_id = id_from_uri(context["uri"])
        result = self.get_api_v1("artists/{}".format(artist_id))
        return Artist(result or {})

    @uri_cache
    def get_album_from_context(self, context):
        """Return an Album from a Context.

        Args:
            context (dict): The Context to convert from.

        Returns:
            Album: The Album.
        """
        album_id = id_from_uri(context["uri"])
        result = self.get_api_v1("albums/{}".format(album_id))
        return Album(result or {})

    @uri_cache
    def get_playlist_from_context(self, context):
        """Return an Playlist from a Context.

        Args:
            context (dict): The Context to convert from.

        Returns:
            Playlist: The Playlist.
        """
        if context["uri"] == common.SAVED_TRACKS_CONTEXT_URI:
            # TODO: Consider creating a common/factory function for
            # obtaining the Saved PLaylist.
            return Playlist({
                "uri":common.SAVED_TRACKS_CONTEXT_URI,
                "name": "Saved"
                })

        playlist_id = id_from_uri(context["uri"])
        result = self.get_api_v1("playlists/{}".format(playlist_id))
        return Playlist(result or {})

    def add_track_to_playlist(self, track, playlist):
        """Add a Track to a Playlist.

        Args:
            track (Track): The Track to add.
            playlist (Playlist): The Playlist to add the Track to.

        Returns:
            tuple: The new set of Tracks with the new Track added.
        """
        # Add the track.
        if playlist['uri'] == common.SAVED_TRACKS_CONTEXT_URI:
            q = {"ids": [track['id']]}
            url = "me/tracks"
            self.put_api_v1(url, q)
        else:
            q = {"uris": [track['uri']]}
            url = "playlists/{}/tracks".format(playlist['id'])
            self.post_api_v1(url, q)

        # Clear out current Cache.
        return self.get_tracks_from_playlist(playlist, force_clear=True)

    def _get_saved_tracks(self, progress=None):
        """Get the Tracks from the "Saved" songs.

        Args:
            progress (Progress): Progress associated with this call.

        Returns:
            tuple: The Tracks.
        """
        q = {"limit": 50}
        url = "me/tracks"
        page = self.get_api_v1(url, q)
        return tuple(Track(saved["track"]) for saved in self.extract_page(page, progress))

    def get_user(self, user_id=None):
        """Return a User from an id.

        Args:
            user_id (str): The user id.

        Returns:
            User: The User.
        """
        if not user_id:
            user_id = self.get_id()

        result = self.get_api_v1("users/{}".format(user_id))
        if result:
            return User(result)
        else:
            return {}

    @uri_cache
    def get_user_playlists(self, user, progress=None):
        """Get the Playlists from the current user.

        Args:
            user (User): The User.
            progress (Progress): Progress associated with this call.

        Return:
            tuple: The Playlists.
        """
        q = {"limit": 50}
        url = "users/{}/playlists".format(user['id'])
        page = self.get_api_v1(url, q)
        return tuple([Playlist(p) for p in self.extract_page(page, progress)])

    def extract_page(self, page, progress=None):
        """Extract all items from a page.

        Args:
            page (dict): The page object.
            progress (Progress): Progress associated with this call.

        Returns:
            list: All of the items.
        """

        if page and "items" in page:
            i, n = 0, page['total']
            lists = []
            lists.extend(page['items'])
            while page['next'] is not None:
                page = self.get_api_v1(page['next'].split('/v1/')[-1])
                lists.extend(page['items'])
                if progress:
                    progress.set_percent(float(len(lists))/n)
            return lists
        else:
            return {}

    @needs_authentication
    def get_api_v1(self, endpoint, params=None):
        """Spotify v1 GET request.

        Args:
            endpoint (str): The API endpoint.
            params (dict): Query parameters (Default is None).

        Returns:
            dict: The JSON information.
        """
        headers = {"Authorization": "%s %s" % (self.auth.token_type, self.auth.access_token)}
        url = "https://api.spotify.com/v1/{}".format(endpoint)
        resp = requests.get(url, params=params, headers=headers)
        resp.raise_for_status()

        data = json.loads(common.ascii(resp.text)) if resp.text else {}
        if not data:
            logger.info("GET returned no data")

        return data

    @needs_authentication
    def put_api_v1(self, endpoint, params=None, data=None):
        """Spotify v1 PUT request.

        Args:
            endpoint (str): The API endpoint.
            params (dict): Query parameters (Default is None).
            data (dict): Body data (Default is None).

        Returns:
            Reponse: The HTTP Reponse.
        """
        headers = {"Authorization": "%s %s" % (self.auth.token_type, self.auth.access_token),
                   "Content-Type": "application/json"}
        api_url = "https://api.spotify.com/v1/{}".format(endpoint)
        resp = requests.put(api_url, headers=headers, params=params, json=data)
        resp.raise_for_status()
        return resp

    @needs_authentication
    def post_api_v1(self, endpoint, params=None):
        """Spotify v1 POST request.

        Args:
            endpoint (str): The API endpoint.
            params (dict): Query parameters (Default is None).

        Returns:
            Reponse: The HTTP Reponse.
        """
        headers = {"Authorization": "%s %s" % (self.auth.token_type, self.auth.access_token),
                   "Content-Type": "application/json"}
        api_url = "https://api.spotify.com/v1/{}".format(endpoint)
        resp = requests.post(api_url, headers=headers, params=params)
        resp.raise_for_status()
        return common.ascii(resp.text)
Example #11
0
    def handle_read(self):
        """Read all available bytes, and process as many packets as possible.
        """
        t = time()
        if self.last_report + 5 < t and self.stream.tot_bytes > 0:
            self.last_report = t
            logger.debug("%s: total/wasted bytes is %d/%d (%f wasted)" % (
                 self.side, self.stream.tot_bytes, self.stream.wasted_bytes,
                 100 * float(self.stream.wasted_bytes) / self.stream.tot_bytes))
        self.stream.append(self.recv(4092))

        if self.out_of_sync:
            data = self.stream.read(len(self.stream))
            self.stream.packet_finished()
            if self.other_side:
                self.other_side.send(data)
            return

        try:
            packet = parse_packet(self.stream, self.msg_spec, self.side)
            while packet != None:
                rebuild = False
                if packet['msgtype'] == 0x02 and self.side == 'client':
                    # Determine which protocol message definitions to use.
                    proto_version = packet['proto_version']
                    logger.info('Client requests protocol version %d' % proto_version)
                    if not proto_version in messages.protocol:
                        logger.error("Unsupported protocol version %d" % proto_version)
                        self.handle_close()
                        return
                    self.username = packet['username']
                    self.msg_spec, self.other_side.msg_spec = messages.protocol[proto_version]
                    self.cipher = encryption.encryption_for_version(proto_version)
                    self.other_side.cipher = self.cipher
                elif packet['msgtype'] == 0xfd:
                    self.rsa_key = encryption.decode_public_key(
                        packet['public_key']
                    )
                    self.encoded_rsa_key = packet['public_key']
                    packet['public_key'] = encryption.encode_public_key(
                        self.other_side.rsa_key
                    )
                    if 'challenge_token' in packet:
                        self.challenge_token = packet['challenge_token']
                        self.other_side.challenge_token = self.challenge_token
                    self.other_side.server_id = packet['server_id']
                    if check_auth:
                        packet['server_id'] = encryption.generate_server_id()
                    else:
                        packet['server_id'] = "-"
                    self.server_id = packet['server_id']
                    rebuild = True
                elif packet['msgtype'] == 0xfc and self.side == 'client':
                    self.shared_secret = encryption.decrypt_shared_secret(
                        packet['shared_secret'],
                        self.rsa_key
                    )
                    if (len(self.shared_secret) > 16 and
                        self.cipher == encryption.RC4):
                        logger.error("Unsupported protocol version")
                        self.handle_close()
                        return
                    packet['shared_secret'] = encryption.encrypt_shared_secret(
                        self.other_side.shared_secret,
                        self.other_side.rsa_key
                    )
                    if 'challenge_token' in packet:
                        challenge_token = encryption.decrypt_shared_secret(
                            packet['challenge_token'], self.rsa_key
                        )
                        if challenge_token != self.challenge_token:
                            self.kick("Invalid client reply")
                            return
                        packet['challenge_token'] = encryption.encrypt_shared_secret(
                            self.other_side.challenge_token,
                            self.other_side.rsa_key
                        )
                    if auth:
                        logger.info("Authenticating on server")
                        auth.join_server(self.server_id,
                                        self.other_side.shared_secret,
                                        self.other_side.rsa_key)
                    if check_auth:
                        logger.info("Checking authenticity")
                        if not Authenticator.check_player(
                            self.username, self.other_side.server_id,
                            self.shared_secret, self.rsa_key):
                            self.kick("Unable to verify username")
                            return
                    rebuild = True
                elif packet['msgtype'] == 0xfc and self.side == 'server':
                    logger.debug("Starting encryption")
                    self.start_cipher()
                forward = True
                if self.plugin_mgr:
                    forwarding = self.plugin_mgr.filter(packet, self.side)
                    if forwarding and packet.modified:
                        rebuild = True
                if rebuild:
                    packet['raw_bytes'] = self.msg_spec[packet['msgtype']].emit(packet)
                if forwarding and self.other_side is not None:
                    self.other_side.send(packet['raw_bytes'])
                if packet['msgtype'] == 0xfc and self.side == 'server':
                    self.other_side.start_cipher()
                # Since we know we're at a message boundary, we can inject
                # any messages in the queue.
                msgbytes = self.plugin_mgr.next_injected_msg_from(self.side)
                while self.other_side and msgbytes is not None:
                    self.other_side.send(msgbytes)
                    msgbytes = self.plugin_mgr.next_injected_msg_from(self.side)

                # Attempt to parse the next packet.
                packet = parse_packet(self.stream,self.msg_spec, self.side)
        except PartialPacketException:
            pass # Not all data for the current packet is available.
        except Exception:
            logger.error("MinecraftProxy for %s caught exception, out of sync" % self.side)
            logger.error(traceback.format_exc())
            logger.debug("Current stream buffer: %s" % repr(self.stream.buf))
            self.out_of_sync = True
            self.stream.reset()