@@ -7,12 +7,12 @@ import SwiftOTP
77private typealias Task = _Concurrency . Task
88
99private enum TOTPGenerator {
10- static func generate( serverTimeSeconds: Int ) -> String ? {
11- let secretCipher = [ 12 , 56 , 76 , 33 , 88 , 44 , 88 , 33 , 78 , 78 , 11 , 66 , 22 , 22 , 55 , 69 , 54 ]
10+ static func generate( secretCipher : [ UInt8 ] , serverTimeSeconds: Int ) -> String ? {
11+ // let secretCipher = [12, 56, 76, 33, 88, 44, 88, 33, 78, 78, 11, 66, 22, 22, 55, 69, 54]
1212
1313 var processed = [ UInt8] ( )
1414 for (i, byte) in secretCipher. enumerated ( ) {
15- processed. append ( UInt8 ( byte ^ ( i % 33 + 9 ) ) )
15+ processed. append ( UInt8 ( byte ^ UInt8 ( i % 33 + 9 ) ) )
1616 }
1717
1818 let processedStr = processed. map { String ( $0) } . joined ( )
@@ -48,23 +48,42 @@ struct SpotifyAccessToken: Codable {
4848 struct ServerTime : Codable {
4949 var serverTime : Int
5050 }
51-
51+ struct SecretKeyEntry : Codable {
52+ let version : Int
53+ let secret : String
54+ }
5255 enum Error : Swift . Error {
5356 case totpGenerationFailed
5457 }
55-
56- let serverTimeRequest = URLRequest ( url: . init( string: " https://open.spotify.com/server-time " ) !)
58+ let secretKeyURL = URL ( string : " https://raw.githubusercontent.com/Thereallo1026/spotify-secrets/refs/heads/main/secrets/secrets.json " ) !
59+ let serverTimeRequest = URLRequest ( url: . init( string: " https://open.spotify.com/api/ server-time " ) !)
5760 let serverTimeData = try await URLSession . shared. data ( for: serverTimeRequest) . 0
5861 let serverTime = try JSONDecoder ( ) . decode ( ServerTime . self, from: serverTimeData) . serverTime
59-
60- guard let totp = TOTPGenerator . generate ( serverTimeSeconds: serverTime) else {
62+ let ( data, _) = try await URLSession . shared. data ( from: secretKeyURL)
63+ let secretEntries = try JSONDecoder ( ) . decode ( [ SecretKeyEntry ] . self, from: data)
64+ guard let lastEntry = secretEntries. last else {
6165 throw Error . totpGenerationFailed
6266 }
63-
64- let url = URL ( string: " https://open.spotify.com/get_access_token?reason=transport&productType=web_player&totpVer=5&ts= \( Int ( Date ( ) . timeIntervalSince1970) ) &totp= \( totp) " ) !
65- var request = URLRequest ( url: url)
67+ guard let totp = TOTPGenerator . generate ( secretCipher: . init( lastEntry. secret. utf8) , serverTimeSeconds: serverTime) else {
68+ throw Error . totpGenerationFailed
69+ }
70+ let tokenURL = URL ( string: " https://open.spotify.com/api/token " ) !
71+ let params : [ String : String ] = [
72+ " reason " : " transport " ,
73+ " productType " : " web-player " ,
74+ " totp " : totp,
75+ " totpVer " : lastEntry. version. description,
76+ " ts " : String ( Int ( Date ( ) . timeIntervalSince1970) ) ,
77+ ]
78+ var components = URLComponents ( url: tokenURL, resolvingAgainstBaseURL: false ) !
79+ components. queryItems = params. map { URLQueryItem ( name: $0. key, value: $0. value) }
80+
81+ var request = URLRequest ( url: components. url!)
82+ request. httpMethod = " GET "
6683 request. setValue ( " sp_dc= \( cookie) " , forHTTPHeaderField: " Cookie " )
84+ request. setValue ( " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 " , forHTTPHeaderField: " User-Agent " )
6785 let accessTokenData = try await URLSession . shared. data ( for: request) . 0
86+ try print ( JSONSerialization . jsonObject ( with: accessTokenData) )
6887 return try JSONDecoder ( ) . decode ( SpotifyAccessToken . self, from: accessTokenData)
6988 }
7089}
@@ -214,7 +233,11 @@ public final class SpotifyLoginManager: NSObject, @unchecked Sendable {
214233 }
215234
216235 await secureStorage. setCookie ( cookie)
217- try await requestAccessToken ( )
236+ do {
237+ try await requestAccessToken ( )
238+ } catch {
239+ print ( error)
240+ }
218241 await MainActor . run {
219242 loginWindowController. close ( )
220243 }
0 commit comments