@@ -20,35 +20,6 @@ public final class GitHubCopilotExtension: BuiltinExtension {
2020 extensionUsage. isSuggestionServiceInUse || extensionUsage. isChatServiceInUse
2121 }
2222
23- public struct AuthToken : Codable {
24- public let user : String
25- public let oauth_token : String
26- public let githubAppId : String
27- }
28-
29- public static var authToken : AuthToken ? {
30- guard let urls = try ? GitHubCopilotBaseService . createFoldersIfNeeded ( )
31- else { return nil }
32- let path = urls. supportURL
33- . appendingPathComponent ( " undefined " )
34- . appendingPathComponent ( " .config " )
35- . appendingPathComponent ( " github-copilot " )
36- . appendingPathComponent ( " apps.json " ) . path
37- guard FileManager . default. fileExists ( atPath: path) else { return nil }
38-
39- do {
40- let data = try Data ( contentsOf: URL ( fileURLWithPath: path) )
41- let json = try JSONSerialization
42- . jsonObject ( with: data, options: [ ] ) as? [ String : [ String : String ] ]
43- guard let firstEntry = json? . values. first else { return nil }
44- let jsonData = try JSONSerialization . data ( withJSONObject: firstEntry, options: [ ] )
45- return try JSONDecoder ( ) . decode ( AuthToken . self, from: jsonData)
46- } catch {
47- Logger . gitHubCopilot. error ( error. localizedDescription)
48- return nil
49- }
50- }
51-
5223 let workspacePool : WorkspacePool
5324
5425 let serviceLocator : ServiceLocatorType
@@ -180,3 +151,101 @@ class ServiceLocator: ServiceLocatorType {
180151 }
181152}
182153
154+ extension GitHubCopilotExtension {
155+ public struct Token : Codable {
156+ // let codesearch: Bool
157+ public let individual : Bool
158+ public let endpoints : Endpoints
159+ public let chat_enabled : Bool
160+ public let sku : String
161+ // public let copilotignore_enabled: Bool
162+ // public let limited_user_quotas: String?
163+ public let tracking_id : String
164+ // public let xcode: Bool
165+ // public let limited_user_reset_date: String?
166+ // public let telemetry: String
167+ // public let prompt_8k: Bool
168+ public let token : String
169+ // public let nes_enabled: Bool
170+ // public let vsc_electron_fetcher_v2: Bool
171+ // public let code_review_enabled: Bool
172+ // public let annotations_enabled: Bool
173+ // public let chat_jetbrains_enabled: Bool
174+ // public let xcode_chat: Bool
175+ // public let refresh_in: Int
176+ // public let snippy_load_test_enabled: Bool
177+ // public let trigger_completion_after_accept: Bool
178+ public let expires_at : Int
179+ // public let public_suggestions: String
180+ // public let code_quote_enabled: Bool
181+
182+ public struct Endpoints : Codable {
183+ public let api : String
184+ public let proxy : String
185+ public let telemetry : String
186+ public let origin_tracker : String
187+ }
188+ }
189+
190+ struct AuthInfo : Codable {
191+ public let user : String
192+ public let oauth_token : String
193+ public let githubAppId : String
194+ }
195+
196+ static var authInfo : AuthInfo ? {
197+ guard let urls = try ? GitHubCopilotBaseService . createFoldersIfNeeded ( )
198+ else { return nil }
199+ let path = urls. supportURL
200+ . appendingPathComponent ( " undefined " )
201+ . appendingPathComponent ( " .config " )
202+ . appendingPathComponent ( " github-copilot " )
203+ . appendingPathComponent ( " apps.json " ) . path
204+ guard FileManager . default. fileExists ( atPath: path) else { return nil }
205+
206+ do {
207+ let data = try Data ( contentsOf: URL ( fileURLWithPath: path) )
208+ let json = try JSONSerialization
209+ . jsonObject ( with: data, options: [ ] ) as? [ String : [ String : String ] ]
210+ guard let firstEntry = json? . values. first else { return nil }
211+ let jsonData = try JSONSerialization . data ( withJSONObject: firstEntry, options: [ ] )
212+ return try JSONDecoder ( ) . decode ( AuthInfo . self, from: jsonData)
213+ } catch {
214+ Logger . gitHubCopilot. error ( error. localizedDescription)
215+ return nil
216+ }
217+ }
218+
219+ @MainActor
220+ static var cachedToken : Token ?
221+
222+ public static func fetchToken( ) async throws -> Token {
223+ guard let authToken = authInfo? . oauth_token
224+ else { throw GitHubCopilotError . notLoggedIn }
225+
226+ let oldToken = await MainActor . run { cachedToken }
227+ if let oldToken {
228+ let expiresAt = Date ( timeIntervalSince1970: TimeInterval ( oldToken. expires_at) )
229+ if expiresAt > Date ( ) {
230+ return oldToken
231+ }
232+ }
233+
234+ let url = URL ( string: " https://api.github.com/copilot_internal/v2/token " ) !
235+ var request = URLRequest ( url: url)
236+ request. httpMethod = " GET "
237+ request. setValue ( " token \( authToken) " , forHTTPHeaderField: " authorization " )
238+ request. setValue ( " unknown-editor/0 " , forHTTPHeaderField: " editor-version " )
239+ request. setValue ( " unknown-editor-plugin/0 " , forHTTPHeaderField: " editor-plugin-version " )
240+ request. setValue ( " 1.236.0 " , forHTTPHeaderField: " copilot-language-server-version " )
241+ request. setValue ( " GithubCopilot/1.236.0 " , forHTTPHeaderField: " user-agent " )
242+ request. setValue ( " */* " , forHTTPHeaderField: " accept " )
243+ request. setValue ( " gzip,deflate,br " , forHTTPHeaderField: " accept-encoding " )
244+
245+ let ( data, _) = try await URLSession . shared. data ( for: request)
246+ let newToken = try JSONDecoder ( ) . decode ( Token . self, from: data)
247+ await MainActor . run { cachedToken = newToken }
248+ return newToken
249+ }
250+ }
251+
0 commit comments