@@ -9,44 +9,46 @@ class SSHServer {
9
9
{
10
10
hostKeys : [ require ( 'fs' ) . readFileSync ( config . getSSHConfig ( ) . hostKey . privateKeyPath ) ] ,
11
11
authMethods : [ 'publickey' , 'password' ] ,
12
- debug : ( msg ) => {
13
- console . debug ( 'SSH Debug: ' , msg ) ;
14
- } ,
12
+ // debug: (msg) => {
13
+ // console.debug('[ SSH Debug] ', msg);
14
+ // },
15
15
} ,
16
16
this . handleClient . bind ( this ) ,
17
17
) ;
18
18
}
19
19
20
20
async handleClient ( client ) {
21
- console . log ( 'Client connected' , client ) ;
21
+ console . log ( '[SSH] Client connected' , client ) ;
22
22
client . on ( 'authentication' , async ( ctx ) => {
23
- console . log ( `Authentication attempt: ${ ctx . method } ` ) ;
23
+ console . log ( `[SSH] Authentication attempt: ${ ctx . method } ` ) ;
24
24
25
25
if ( ctx . method === 'publickey' ) {
26
26
try {
27
- console . log ( `CTX KEY: ${ JSON . stringify ( ctx . key ) } ` ) ;
27
+ console . log ( `[SSH] CTX KEY: ${ JSON . stringify ( ctx . key ) } ` ) ;
28
28
// Get the key type and key data
29
29
const keyType = ctx . key . algo ;
30
30
const keyData = ctx . key . data ;
31
31
32
32
// Format the key in the same way as stored in user's publicKeys (without comment)
33
33
const keyString = `${ keyType } ${ keyData . toString ( 'base64' ) } ` ;
34
34
35
- console . log ( `Attempting public key authentication with key: ${ keyString } ` ) ;
35
+ console . log ( `[SSH] Attempting public key authentication with key: ${ keyString } ` ) ;
36
36
37
37
// Find user by SSH key
38
38
const user = await db . findUserBySSHKey ( keyString ) ;
39
39
if ( ! user ) {
40
- console . log ( 'No user found with this SSH key' ) ;
40
+ console . log ( '[SSH] No user found with this SSH key' ) ;
41
41
ctx . reject ( ) ;
42
42
return ;
43
43
}
44
44
45
- console . log ( `Public key authentication successful for user ${ user . username } ` ) ;
45
+ console . log ( `[SSH] Public key authentication successful for user ${ user . username } ` ) ;
46
46
client . username = user . username ;
47
+ // Store the user's private key for later use with GitHub
48
+ client . userPrivateKey = ctx . key ;
47
49
ctx . accept ( ) ;
48
50
} catch ( error ) {
49
- console . error ( 'Error during public key authentication:' , error ) ;
51
+ console . error ( '[SSH] Error during public key authentication:' , error ) ;
50
52
// Let the client try the next key
51
53
ctx . reject ( ) ;
52
54
}
@@ -59,22 +61,22 @@ class SSHServer {
59
61
const bcrypt = require ( 'bcryptjs' ) ;
60
62
const isValid = await bcrypt . compare ( ctx . password , user . password ) ;
61
63
if ( isValid ) {
62
- console . log ( `Password authentication successful for user ${ ctx . username } ` ) ;
64
+ console . log ( `[SSH] Password authentication successful for user ${ ctx . username } ` ) ;
63
65
ctx . accept ( ) ;
64
66
} else {
65
- console . log ( `Password authentication failed for user ${ ctx . username } ` ) ;
67
+ console . log ( `[SSH] Password authentication failed for user ${ ctx . username } ` ) ;
66
68
ctx . reject ( ) ;
67
69
}
68
70
} else {
69
- console . log ( `User ${ ctx . username } not found or no password set` ) ;
71
+ console . log ( `[SSH] User ${ ctx . username } not found or no password set` ) ;
70
72
ctx . reject ( ) ;
71
73
}
72
74
} catch ( error ) {
73
- console . error ( 'Error during password authentication:' , error ) ;
75
+ console . error ( '[SSH] Error during password authentication:' , error ) ;
74
76
ctx . reject ( ) ;
75
77
}
76
78
} else {
77
- console . log ( 'Password authentication attempted but public key was provided' ) ;
79
+ console . log ( '[SSH] Password authentication attempted but public key was provided' ) ;
78
80
ctx . reject ( ) ;
79
81
}
80
82
} else {
@@ -84,12 +86,12 @@ class SSHServer {
84
86
} ) ;
85
87
86
88
client . on ( 'ready' , ( ) => {
87
- console . log ( `Client ready: ${ client . username } ` ) ;
89
+ console . log ( `[SSH] Client ready: ${ client . username } ` ) ;
88
90
client . on ( 'session' , this . handleSession . bind ( this ) ) ;
89
91
} ) ;
90
92
91
93
client . on ( 'error' , ( err ) => {
92
- console . error ( 'Client error:' , err ) ;
94
+ console . error ( '[SSH] Client error:' , err ) ;
93
95
} ) ;
94
96
}
95
97
@@ -100,7 +102,7 @@ class SSHServer {
100
102
const command = info . command ;
101
103
102
104
// Parse Git command
103
- console . log ( 'Command' , command ) ;
105
+ console . log ( '[SSH] Command' , command ) ;
104
106
if ( command . startsWith ( 'git-' ) ) {
105
107
// Extract the repository path from the command
106
108
// Remove quotes and 'git-' prefix, then trim any leading/trailing slashes
@@ -113,6 +115,7 @@ class SSHServer {
113
115
const req = {
114
116
method : command === 'git-upload-pack' ? 'GET' : 'POST' ,
115
117
originalUrl : repoPath ,
118
+ isSSH : true ,
116
119
headers : {
117
120
'user-agent' : 'git/2.0.0' ,
118
121
'content-type' :
@@ -121,15 +124,85 @@ class SSHServer {
121
124
} ;
122
125
123
126
try {
124
- console . log ( 'Executing chain' , req ) ;
127
+ console . log ( '[SSH] Executing chain' , req ) ;
125
128
const action = await chain . executeChain ( req ) ;
126
- stream . write ( action . getContent ( ) ) ;
127
- stream . end ( ) ;
129
+
130
+ console . log ( '[SSH] Action' , action ) ;
131
+
132
+ if ( action . error || action . blocked ) {
133
+ // If there's an error or the action is blocked, send the error message
134
+ console . log (
135
+ '[SSH] Action error or blocked' ,
136
+ action . errorMessage || action . blockedMessage ,
137
+ ) ;
138
+ stream . write ( action . errorMessage || action . blockedMessage ) ;
139
+ stream . end ( ) ;
140
+ return ;
141
+ }
142
+
143
+ // Create SSH connection to GitHub
144
+ const githubSsh = new ssh2 . Client ( ) ;
145
+
146
+ console . log ( '[SSH] Creating SSH connection to GitHub' ) ;
147
+ githubSsh . on ( 'ready' , ( ) => {
148
+ console . log ( '[SSH] Connected to GitHub' ) ;
149
+
150
+ // Execute the Git command on GitHub
151
+ githubSsh . exec ( command , { env : { GIT_PROTOCOL : 'version=2' } } , ( err , githubStream ) => {
152
+ if ( err ) {
153
+ console . error ( '[SSH] Failed to execute command on GitHub:' , err ) ;
154
+ stream . write ( err . toString ( ) ) ;
155
+ stream . end ( ) ;
156
+ return ;
157
+ }
158
+
159
+ // Pipe data between client and GitHub
160
+ stream . pipe ( githubStream ) . pipe ( stream ) ;
161
+
162
+ githubStream . on ( 'exit' , ( code ) => {
163
+ console . log ( `[SSH] GitHub command exited with code ${ code } ` ) ;
164
+ githubSsh . end ( ) ;
165
+ } ) ;
166
+ } ) ;
167
+ } ) ;
168
+
169
+ githubSsh . on ( 'error' , ( err ) => {
170
+ console . error ( '[SSH] GitHub SSH error:' , err ) ;
171
+ stream . write ( err . toString ( ) ) ;
172
+ stream . end ( ) ;
173
+ } ) ;
174
+
175
+ // Get the client's SSH key that was used for authentication
176
+ // console.log('[SSH] Session:', session);
177
+ const clientKey = session . _channel . _client . userPrivateKey ;
178
+ console . log ( '[SSH] Client key:' , clientKey ? 'Available' : 'Not available' ) ;
179
+
180
+ if ( clientKey ) {
181
+ console . log ( '[SSH] Using client key to connect to GitHub' ) ;
182
+ // Use the client's private key to connect to GitHub
183
+ githubSsh . connect ( {
184
+ host : 'github.com' ,
185
+ port : 22 ,
186
+ username : 'git' ,
187
+ privateKey : clientKey ,
188
+ } ) ;
189
+ } else {
190
+ console . log ( '[SSH] No client key available, using proxy key' ) ;
191
+ // Fallback to proxy's SSH key if no client key is available
192
+ githubSsh . connect ( {
193
+ host : 'github.com' ,
194
+ port : 22 ,
195
+ username : 'git' ,
196
+ privateKey : require ( 'fs' ) . readFileSync ( config . getSSHConfig ( ) . hostKey . privateKeyPath ) ,
197
+ } ) ;
198
+ }
128
199
} catch ( error ) {
200
+ console . error ( '[SSH] Error during SSH connection:' , error ) ;
129
201
stream . write ( error . toString ( ) ) ;
130
202
stream . end ( ) ;
131
203
}
132
204
} else {
205
+ console . log ( '[SSH] Unsupported command' , command ) ;
133
206
stream . write ( 'Unsupported command' ) ;
134
207
stream . end ( ) ;
135
208
}
@@ -139,7 +212,7 @@ class SSHServer {
139
212
start ( ) {
140
213
const port = config . getSSHConfig ( ) . port ;
141
214
this . server . listen ( port , '0.0.0.0' , ( ) => {
142
- console . log ( `SSH server listening on port ${ port } ` ) ;
215
+ console . log ( `[ SSH] Server listening on port ${ port } ` ) ;
143
216
} ) ;
144
217
}
145
218
}
0 commit comments