1
1
const _ = require ( 'lodash' ) ;
2
2
const fs = require ( 'fs' ) ;
3
+ const https = require ( 'https' ) ;
3
4
const tempWrite = require ( 'temp-write' ) ;
4
5
const moment = require ( 'moment' ) ;
5
6
const logger = require ( '../logger' ) . ssl ;
@@ -15,6 +16,7 @@ const letsencryptConfig = '/etc/letsencrypt.ini';
15
16
const certbotCommand = 'certbot' ;
16
17
const archiver = require ( 'archiver' ) ;
17
18
const path = require ( 'path' ) ;
19
+ const { isArray } = require ( 'lodash' ) ;
18
20
19
21
function omissions ( ) {
20
22
return [ 'is_deleted' ] ;
@@ -1119,6 +1121,87 @@ const internalCertificate = {
1119
1121
} else {
1120
1122
return Promise . resolve ( ) ;
1121
1123
}
1124
+ } ,
1125
+
1126
+ testHttpsChallenge : async ( access , domains ) => {
1127
+ await access . can ( 'certificates:list' ) ;
1128
+
1129
+ if ( ! isArray ( domains ) ) {
1130
+ throw new error . InternalValidationError ( 'Domains must be an array of strings' ) ;
1131
+ }
1132
+ if ( domains . length === 0 ) {
1133
+ throw new error . InternalValidationError ( 'No domains provided' ) ;
1134
+ }
1135
+
1136
+ // Create a test challenge file
1137
+ const testChallengeDir = '/data/letsencrypt-acme-challenge/.well-known/acme-challenge' ;
1138
+ const testChallengeFile = testChallengeDir + '/test-challenge' ;
1139
+ fs . mkdirSync ( testChallengeDir , { recursive : true } ) ;
1140
+ fs . writeFileSync ( testChallengeFile , 'Success' , { encoding : 'utf8' } ) ;
1141
+
1142
+ async function performTestForDomain ( domain ) {
1143
+ logger . info ( 'Testing http challenge for ' + domain ) ;
1144
+ const url = `http://${ domain } /.well-known/acme-challenge/test-challenge` ;
1145
+ const formBody = `method=G&url=${ encodeURI ( url ) } &bodytype=T&requestbody=&headername=User-Agent&headervalue=None&locationid=1&ch=false&cc=false` ;
1146
+ const options = {
1147
+ method : 'POST' ,
1148
+ headers : {
1149
+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
1150
+ 'Content-Length' : Buffer . byteLength ( formBody )
1151
+ }
1152
+ } ;
1153
+
1154
+ const result = await new Promise ( ( resolve ) => {
1155
+
1156
+ const req = https . request ( 'https://www.site24x7.com/tools/restapi-tester' , options , function ( res ) {
1157
+ let responseBody = '' ;
1158
+
1159
+ res . on ( 'data' , ( chunk ) => responseBody = responseBody + chunk ) ;
1160
+ res . on ( 'end' , function ( ) {
1161
+ const parsedBody = JSON . parse ( responseBody + '' ) ;
1162
+ if ( res . statusCode !== 200 ) {
1163
+ logger . warn ( `Failed to test HTTP challenge for domain ${ domain } ` , res ) ;
1164
+ resolve ( undefined ) ;
1165
+ }
1166
+ resolve ( parsedBody ) ;
1167
+ } ) ;
1168
+ } ) ;
1169
+
1170
+ // Make sure to write the request body.
1171
+ req . write ( formBody ) ;
1172
+ req . end ( ) ;
1173
+ req . on ( 'error' , function ( e ) { logger . warn ( `Failed to test HTTP challenge for domain ${ domain } ` , e ) ;
1174
+ resolve ( undefined ) ; } ) ;
1175
+ } ) ;
1176
+
1177
+ if ( ! result ) {
1178
+ // Some error occurred while trying to get the data
1179
+ return 'failed' ;
1180
+ } else if ( `${ result . responsecode } ` === '200' && result . htmlresponse === 'Success' ) {
1181
+ // Server exists and has responded with the correct data
1182
+ return 'ok' ;
1183
+ } else if ( `${ result . responsecode } ` === '404' ) {
1184
+ // Server exists but responded with a 404
1185
+ return '404' ;
1186
+ } else if ( `${ result . responsecode } ` === '0' || result . reason . toLowerCase ( ) === 'host unavailable' ) {
1187
+ // Server does not exist at domain
1188
+ return 'no-host' ;
1189
+ } else {
1190
+ // Other errors
1191
+ return `other:${ result . responsecode } ` ;
1192
+ }
1193
+ }
1194
+
1195
+ const results = { } ;
1196
+
1197
+ for ( const domain of domains ) {
1198
+ results [ domain ] = await performTestForDomain ( domain ) ;
1199
+ }
1200
+
1201
+ // Remove the test challenge file
1202
+ fs . unlinkSync ( testChallengeFile ) ;
1203
+
1204
+ return results ;
1122
1205
}
1123
1206
} ;
1124
1207
0 commit comments