1010
1111/* eslint-disable header/header */
1212
13+ import * as https from 'https' ;
1314import * as k8s from '@kubernetes/client-node' ;
1415import * as fs from 'fs-extra' ;
1516import { inject , injectable } from 'inversify' ;
@@ -67,6 +68,28 @@ export class GithubServiceImpl implements GithubService {
6768 }
6869
6970 private async fetchGithubUser ( token : string ) : Promise < { user : GithubUser ; scopes : string [ ] } > {
71+ try {
72+ this . logger . info ( 'Github Service: fetching GitHub user using fetch...' ) ;
73+ const result = await this . fetchGithubUserWithFetch ( token ) ;
74+ this . logger . info ( 'Github Service: successfully fetched GitHub user using fetch' ) ;
75+
76+ return result ;
77+ } catch ( fetchError : any ) {
78+ this . logger . warn ( `Github Service: fetch failed: ${ fetchError . message } ${ fetchError . cause ? ` (cause: ${ fetchError . cause . message } )` : '' } ` ) ;
79+ try {
80+ this . logger . info ( 'Github Service: falling back to https module...' ) ;
81+ const result = await this . fetchGithubUserWithHttps ( token ) ;
82+ this . logger . info ( 'Github Service: successfully fetched GitHub user using https fallback' ) ;
83+
84+ return result ;
85+ } catch ( httpsError : any ) {
86+ this . logger . error ( `Github Service: https fallback also failed: ${ httpsError . message } ` ) ;
87+ throw httpsError ;
88+ }
89+ }
90+ }
91+
92+ private async fetchGithubUserWithFetch ( token : string ) : Promise < { user : GithubUser ; scopes : string [ ] } > {
7093 const response = await fetch ( 'https://api.github.com/user' , {
7194 headers : { Authorization : `Bearer ${ token } ` } ,
7295 } ) ;
@@ -83,6 +106,44 @@ export class GithubServiceImpl implements GithubService {
83106 return { user, scopes } ;
84107 }
85108
109+ private fetchGithubUserWithHttps ( token : string ) : Promise < { user : GithubUser ; scopes : string [ ] } > {
110+ return new Promise ( ( resolve , reject ) => {
111+ const req = https . request ( 'https://api.github.com/user' , {
112+ method : 'GET' ,
113+ headers : {
114+ 'Authorization' : `Bearer ${ token } ` ,
115+ 'User-Agent' : 'che-code' ,
116+ 'Accept' : 'application/json' ,
117+ } ,
118+ } , ( res ) => {
119+ const chunks : Buffer [ ] = [ ] ;
120+ res . on ( 'data' , ( chunk : Buffer ) => chunks . push ( chunk ) ) ;
121+ res . on ( 'end' , ( ) => {
122+ const body = Buffer . concat ( chunks ) . toString ( ) ;
123+ if ( ! res . statusCode || res . statusCode < 200 || res . statusCode >= 300 ) {
124+ reject ( new Error ( `GitHub user request failed: ${ res . statusCode } ${ res . statusMessage } - ${ body } ` ) ) ;
125+ return ;
126+ }
127+ try {
128+ const user = JSON . parse ( body ) as GithubUser ;
129+ const scopesHeader = res . headers [ 'x-oauth-scopes' ] ?? '' ;
130+ const scopes = ( Array . isArray ( scopesHeader ) ? scopesHeader [ 0 ] : scopesHeader )
131+ . split ( ', ' )
132+ . map ( scope => scope . trim ( ) )
133+ . filter ( scope => scope . length > 0 ) ;
134+ resolve ( { user, scopes } ) ;
135+ } catch ( err ) {
136+ reject ( err ) ;
137+ }
138+ } ) ;
139+ res . on ( 'error' , reject ) ;
140+ } ) ;
141+ req . setTimeout ( 60 * 1000 ) ;
142+ req . on ( 'error' , reject ) ;
143+ req . end ( ) ;
144+ } ) ;
145+ }
146+
86147 async persistDeviceAuthToken ( token : string ) : Promise < void > {
87148 this . token = token ;
88149 this . logger . info ( `Github Service: adding token to the device-authentication secret...` ) ;
0 commit comments