11import { ChildProcess , spawn } from 'child_process' ;
2- import http from 'http' ;
32import os from 'os' ;
43import path from 'path' ;
54import { setTimeout } from 'timers/promises' ;
65
6+ import Electron from 'electron' ;
7+
78import K3sHelper from '@pkg/backend/k3sHelper' ;
89import Logging from '@pkg/utils/logging' ;
910import paths from '@pkg/utils/paths' ;
@@ -19,7 +20,6 @@ export class Steve {
1920
2021 private isRunning : boolean ;
2122 private httpsPort = 0 ;
22- private httpPort = 0 ;
2323
2424 private constructor ( ) {
2525 this . isRunning = false ;
@@ -41,9 +41,8 @@ export class Steve {
4141 * @description Starts the Steve API if one is not already running.
4242 * Returns only after Steve is ready to accept connections.
4343 * @param httpsPort The HTTPS port for Steve to listen on.
44- * @param httpPort The HTTP port for Steve to listen on.
4544 */
46- public async start ( httpsPort : number , httpPort : number ) {
45+ public async start ( httpsPort : number ) {
4746 const { pid } = this . process || { } ;
4847
4948 if ( this . isRunning && pid ) {
@@ -53,7 +52,6 @@ export class Steve {
5352 }
5453
5554 this . httpsPort = httpsPort ;
56- this . httpPort = httpPort ;
5755
5856 const osSpecificName = / ^ w i n / i. test ( os . platform ( ) ) ? 'steve.exe' : 'steve' ;
5957 const stevePath = path . join ( paths . resources , os . platform ( ) , 'internal' , osSpecificName ) ;
@@ -76,7 +74,7 @@ export class Steve {
7674 '--https-listen-port' ,
7775 String ( httpsPort ) ,
7876 '--http-listen-port' ,
79- String ( httpPort ) ,
77+ '0' , // Disable HTTP support; it does not work correctly anyway.
8078 ] ,
8179 { env } ,
8280 ) ;
@@ -129,7 +127,7 @@ export class Steve {
129127 }
130128
131129 if ( await this . isPortReady ( ) ) {
132- console . debug ( `Steve is ready after ${ attempt } attempt(s)` ) ;
130+ console . debug ( `Steve is ready after ${ attempt } / ${ maxAttempts } attempt(s)` ) ;
133131
134132 return ;
135133 }
@@ -149,24 +147,43 @@ export class Steve {
149147 * schema controller has registered it.
150148 */
151149 private isPortReady ( ) : Promise < boolean > {
150+ // Steve's HTTP port just redirects to HTTPS, so we might as well go to the
151+ // HTTPS port directly. We will need to ignore certificate errors; however,
152+ // neither the NodeJS stack nor Electron.net.request() would pass through
153+ // the `Electron.app.on('certificate-error', ...)` handler, so we cannot use
154+ // the normal certificate handling for this health check. Instead, we
155+ // create a temporary session with a certificate verify proc that ignores
156+ // errors, and use that session for the health check request.
152157 return new Promise ( ( resolve ) => {
153- const req = http . request ( {
158+ const session = Electron . session . fromPartition ( 'steve-healthcheck' , { cache : false } ) ;
159+
160+ session . setCertificateVerifyProc ( ( request , callback ) => {
161+ if ( request . hostname === '127.0.0.1' ) {
162+ // We do not have any more information to narrow down the certificate;
163+ // given that we're doing this in a private partition, it should be
164+ // safe to allow all localhost certificates. In particular, we do not
165+ // get access to the port number, and all the Steve certificates have
166+ // generic fields (e.g. subject).
167+ callback ( 0 ) ;
168+ } else {
169+ // Unexpected request; not sure how this could happen in a new session,
170+ // but we can at least pretend to do the right thing.
171+ callback ( - 3 ) ; // Use Chromium's default verification.
172+ }
173+ } ) ;
174+
175+ const req = Electron . net . request ( {
176+ protocol : 'https:' ,
154177 hostname : '127.0.0.1' ,
155- port : this . httpPort ,
178+ port : this . httpsPort ,
156179 path : '/v1/namespaces' ,
157180 method : 'GET' ,
158- timeout : 1000 ,
159- agent : false ,
160- } , ( res ) => {
161- res . resume ( ) ;
162- resolve ( res . statusCode === 200 ) ;
181+ redirect : 'error' ,
182+ session,
163183 } ) ;
164184
185+ req . on ( 'response' , ( res ) => resolve ( res . statusCode === 200 ) ) ;
165186 req . on ( 'error' , ( ) => resolve ( false ) ) ;
166- req . on ( 'timeout' , ( ) => {
167- req . destroy ( ) ;
168- resolve ( false ) ;
169- } ) ;
170187 req . end ( ) ;
171188 } ) ;
172189 }
0 commit comments