예제 #1
0
        /// <summary>
        /// Authenticates with the server and creates all the necessary components.
        /// All of them should be initialized inside the synchronized block and MUST NOT call any method on <see cref="SpotifySession">this</see> object.
        /// </summary>
        /// <param name="credentials"><see cref="Spotify.LoginCredentials"/></param>
        /// <exception cref="MercuryException"></exception>
        private async Task Authenticate(
            [NotNull] Spotify.LoginCredentials credentials,
            [NotNull] WebsocketHandler handler)
        {
            AuthenticatePartial(credentials, false);

            using (await authLock.LockAsync())
            {
                //Initialize Services
                mercuryClient = new MercuryClient(this);
                eventService  = new EventService(this);
                tokenProvider = new TokenProvider(this);
                apiClient     = await ApiClient.BuildApiClient(this);

                dealer = new DealerClient(this, handler);
                //_audioKeyManager = new AudioKeyManager(this);
                //  _channelManager = new ChannelManager(this);
                //  _cdn = new CdnManager(this);
                // _cache = new CacheManager(_inner.Conf);
                //   _contentFeeder = new PlayableContentFeeder(this);
                authLockEventWaitHandle.Set();
            }

            receiver = new Receiver(this);

            eventService.Language(inner.PreferredLocale);
            TimeProvider.Init(this);

            Debug.WriteLine($"Authenticated as {apWelcome.CanonicalUsername}!");
            Mercury().InterestedIn("spotify:user:attributes:update", this);
            Dealer().AddMessageListener(this, "hm://connect-state/v1/connect/logout");
        }
예제 #2
0
        /// <summary>
        /// Authenticates with the server. Does not create all the components unlike <see cref="Authenticate"/>.
        /// </summary>
        /// <param name="credentials"><see cref="Spotify.LoginCredentials"/></param>
        /// <param name="removeLock">Whether <see cref="authLockEventWaitHandle"/> should be released or not.
        /// <code>false</code> for <see cref="Authenticate"/>
        /// <code>true</code> for <see cref="Reconnect"/></param>
        private void AuthenticatePartial(
            [NotNull] Spotify.LoginCredentials credentials,
            bool removeLock)
        {
            GuardAgainst.ArgumentBeingNull(recvCipher);
            GuardAgainst.ArgumentBeingNull(sendCipher);

            var clientResponseEncrypted = new ClientResponseEncrypted
            {
                LoginCredentials = credentials,
                SystemInfo       = new SystemInfo
                {
                    Os        = Os.Windows,
                    CpuFamily = CpuFamily.CpuX86,
                    SystemInformationString = "1",
                    DeviceId = inner.DeviceId
                },
                VersionString = "1.0"
            };

            SendUnchecked(MercuryPacket.Type.Login, clientResponseEncrypted.ToByteArray(), closedToken);

            var packet = Receive(conn.Result.NetworkStream, closedToken);

            switch (packet.Cmd)
            {
            case MercuryPacket.Type.APWelcome:
            {
                apWelcome = APWelcome.Parser.ParseFrom(packet.Payload);
                var bytes0X0F = new byte[20];
                (new Random()).NextBytes(bytes0X0F);
                SendUnchecked(MercuryPacket.Type.Unknown_0x0f, bytes0X0F, closedToken);

                using var preferredLocale = new MemoryStream(18 + 5);
                preferredLocale.WriteByte((byte)0x0);
                preferredLocale.WriteByte((byte)0x0);
                preferredLocale.WriteByte((byte)0x10);
                preferredLocale.WriteByte((byte)0x0);
                preferredLocale.WriteByte((byte)0x02);
                preferredLocale.Write("preferred-locale");
                preferredLocale.Write(inner.PreferredLocale);
                SendUnchecked(MercuryPacket.Type.PreferredLocale, preferredLocale.ToArray(), closedToken);
                if (removeLock)
                {
                    using (authLock.Lock())
                    {
                        authLockEventWaitHandle.Set();
                    }
                }

                try
                {
                    if (inner.Conf.StoreCredentials)
                    {
                        var jsonObj = new StoredCredentials
                        {
                            AuthenticationType = apWelcome.ReusableAuthCredentialsType,
                            Base64Credentials  = apWelcome.ReusableAuthCredentials.ToBase64(),
                            Username           = apWelcome.CanonicalUsername
                        };
                        inner.Conf.StoreCredentialsFunction(jsonObj);
                        //  ApplicationData.Current.LocalSettings.Values["auth_data"] =
                        // JsonConvert.SerializeObject(jsonObj);
                    }
                }
                catch (Exception x)
                {
                    Debug.WriteLine(x.ToString());
                    throw;
                }

                break;
            }

            case MercuryPacket.Type.AuthFailure:
                throw new SpotifyAuthenticatedException(APLoginFailed.Parser.ParseFrom(packet.Payload));

            default:
                throw new Exception("Unknown CMD 0x" + packet.Cmd);
            }
        }