@@ -13,6 +13,7 @@ import utils from "../lib/utils.js";
1313import { ssl as logger } from "../logger.js" ;
1414import certificateModel from "../models/certificate.js" ;
1515import tokenModel from "../models/token.js" ;
16+ import userModel from "../models/user.js" ;
1617import internalAuditLog from "./audit-log.js" ;
1718import internalHost from "./host.js" ;
1819import internalNginx from "./nginx.js" ;
@@ -81,7 +82,7 @@ const internalCertificate = {
8182 Promise . resolve ( {
8283 permission_visibility : "all" ,
8384 } ) ,
84- token : new tokenModel ( ) ,
85+ token : tokenModel ( ) ,
8586 } ,
8687 { id : certificate . id } ,
8788 )
@@ -118,10 +119,7 @@ const internalCertificate = {
118119 data . nice_name = data . domain_names . join ( ", " ) ;
119120 }
120121
121- const certificate = await certificateModel
122- . query ( )
123- . insertAndFetch ( data )
124- . then ( utils . omitRow ( omissions ( ) ) ) ;
122+ const certificate = await certificateModel . query ( ) . insertAndFetch ( data ) . then ( utils . omitRow ( omissions ( ) ) ) ;
125123
126124 if ( certificate . provider === "letsencrypt" ) {
127125 // Request a new Cert from LE. Let the fun begin.
@@ -139,12 +137,19 @@ const internalCertificate = {
139137 // 2. Disable them in nginx temporarily
140138 await internalCertificate . disableInUseHosts ( inUseResult ) ;
141139
140+ const user = await userModel . query ( ) . where ( "is_deleted" , 0 ) . andWhere ( "id" , data . owner_user_id ) . first ( ) ;
141+ if ( ! user || ! user . email ) {
142+ throw new error . ValidationError (
143+ "A valid email address must be set on your user account to use Let's Encrypt" ,
144+ ) ;
145+ }
146+
142147 // With DNS challenge no config is needed, so skip 3 and 5.
143148 if ( certificate . meta ?. dns_challenge ) {
144149 try {
145150 await internalNginx . reload ( ) ;
146151 // 4. Request cert
147- await internalCertificate . requestLetsEncryptSslWithDnsChallenge ( certificate ) ;
152+ await internalCertificate . requestLetsEncryptSslWithDnsChallenge ( certificate , user . email ) ;
148153 await internalNginx . reload ( ) ;
149154 // 6. Re-instate previously disabled hosts
150155 await internalCertificate . enableInUseHosts ( inUseResult ) ;
@@ -159,9 +164,9 @@ const internalCertificate = {
159164 try {
160165 await internalNginx . generateLetsEncryptRequestConfig ( certificate ) ;
161166 await internalNginx . reload ( ) ;
162- setTimeout ( ( ) => { } , 5000 )
167+ setTimeout ( ( ) => { } , 5000 ) ;
163168 // 4. Request cert
164- await internalCertificate . requestLetsEncryptSsl ( certificate ) ;
169+ await internalCertificate . requestLetsEncryptSsl ( certificate , user . email ) ;
165170 // 5. Remove LE config
166171 await internalNginx . deleteLetsEncryptRequestConfig ( certificate ) ;
167172 await internalNginx . reload ( ) ;
@@ -204,13 +209,12 @@ const internalCertificate = {
204209 data . meta = _ . assign ( { } , data . meta || { } , certificate . meta ) ;
205210
206211 // Add to audit log
207- await internalAuditLog
208- . add ( access , {
209- action : "created" ,
210- object_type : "certificate" ,
211- object_id : certificate . id ,
212- meta : data ,
213- } ) ;
212+ await internalAuditLog . add ( access , {
213+ action : "created" ,
214+ object_type : "certificate" ,
215+ object_id : certificate . id ,
216+ meta : data ,
217+ } ) ;
214218
215219 return certificate ;
216220 } ,
@@ -248,13 +252,12 @@ const internalCertificate = {
248252 }
249253
250254 // Add to audit log
251- await internalAuditLog
252- . add ( access , {
253- action : "updated" ,
254- object_type : "certificate" ,
255- object_id : row . id ,
256- meta : _ . omit ( data , [ "expires_on" ] ) , // this prevents json circular reference because expires_on might be raw
257- } ) ;
255+ await internalAuditLog . add ( access , {
256+ action : "updated" ,
257+ object_type : "certificate" ,
258+ object_id : row . id ,
259+ meta : _ . omit ( data , [ "expires_on" ] ) , // this prevents json circular reference because expires_on might be raw
260+ } ) ;
258261
259262 return savedRow ;
260263 } ,
@@ -268,7 +271,7 @@ const internalCertificate = {
268271 * @return {Promise }
269272 */
270273 get : async ( access , data ) => {
271- const accessData = await access . can ( "certificates:get" , data . id )
274+ const accessData = await access . can ( "certificates:get" , data . id ) ;
272275 const query = certificateModel
273276 . query ( )
274277 . where ( "is_deleted" , 0 )
@@ -367,12 +370,9 @@ const internalCertificate = {
367370 throw new error . ItemNotFoundError ( data . id ) ;
368371 }
369372
370- await certificateModel
371- . query ( )
372- . where ( "id" , row . id )
373- . patch ( {
374- is_deleted : 1 ,
375- } ) ;
373+ await certificateModel . query ( ) . where ( "id" , row . id ) . patch ( {
374+ is_deleted : 1 ,
375+ } ) ;
376376
377377 // Add to audit log
378378 row . meta = internalCertificate . cleanMeta ( row . meta ) ;
@@ -435,10 +435,7 @@ const internalCertificate = {
435435 * @returns {Promise }
436436 */
437437 getCount : async ( userId , visibility ) => {
438- const query = certificateModel
439- . query ( )
440- . count ( "id as count" )
441- . where ( "is_deleted" , 0 ) ;
438+ const query = certificateModel . query ( ) . count ( "id as count" ) . where ( "is_deleted" , 0 ) ;
442439
443440 if ( visibility !== "all" ) {
444441 query . andWhere ( "owner_user_id" , userId ) ;
@@ -501,12 +498,10 @@ const internalCertificate = {
501498 * @param {Access } access
502499 * @param {Object } data
503500 * @param {Array } data.domain_names
504- * @param {String } data.meta.letsencrypt_email
505- * @param {Boolean } data.meta.letsencrypt_agree
506501 * @returns {Promise }
507502 */
508503 createQuickCertificate : async ( access , data ) => {
509- return internalCertificate . create ( access , {
504+ return await internalCertificate . create ( access , {
510505 provider : "letsencrypt" ,
511506 domain_names : data . domain_names ,
512507 meta : data . meta ,
@@ -652,7 +647,7 @@ const internalCertificate = {
652647 const certData = { } ;
653648
654649 try {
655- const result = await utils . execFile ( "openssl" , [ "x509" , "-in" , certificateFile , "-subject" , "-noout" ] )
650+ const result = await utils . execFile ( "openssl" , [ "x509" , "-in" , certificateFile , "-subject" , "-noout" ] ) ;
656651 // Examples:
657652 // subject=CN = *.jc21.com
658653 // subject=CN = something.example.com
@@ -739,9 +734,10 @@ const internalCertificate = {
739734 /**
740735 * Request a certificate using the http challenge
741736 * @param {Object } certificate the certificate row
737+ * @param {String } email the email address to use for registration
742738 * @returns {Promise }
743739 */
744- requestLetsEncryptSsl : async ( certificate ) => {
740+ requestLetsEncryptSsl : async ( certificate , email ) => {
745741 logger . info (
746742 `Requesting LetsEncrypt certificates for Cert #${ certificate . id } : ${ certificate . domain_names . join ( ", " ) } ` ,
747743 ) ;
@@ -760,7 +756,7 @@ const internalCertificate = {
760756 "--authenticator" ,
761757 "webroot" ,
762758 "--email" ,
763- certificate . meta . letsencrypt_email ,
759+ email ,
764760 "--preferred-challenges" ,
765761 "dns,http" ,
766762 "--domains" ,
@@ -779,9 +775,10 @@ const internalCertificate = {
779775
780776 /**
781777 * @param {Object } certificate the certificate row
778+ * @param {String } email the email address to use for registration
782779 * @returns {Promise }
783780 */
784- requestLetsEncryptSslWithDnsChallenge : async ( certificate ) => {
781+ requestLetsEncryptSslWithDnsChallenge : async ( certificate , email ) => {
785782 await installPlugin ( certificate . meta . dns_provider ) ;
786783 const dnsPlugin = dnsPlugins [ certificate . meta . dns_provider ] ;
787784 logger . info (
@@ -807,7 +804,7 @@ const internalCertificate = {
807804 `npm-${ certificate . id } ` ,
808805 "--agree-tos" ,
809806 "--email" ,
810- certificate . meta . letsencrypt_email ,
807+ email ,
811808 "--domains" ,
812809 certificate . domain_names . join ( "," ) ,
813810 "--authenticator" ,
@@ -847,7 +844,7 @@ const internalCertificate = {
847844 * @returns {Promise }
848845 */
849846 renew : async ( access , data ) => {
850- await access . can ( "certificates:update" , data )
847+ await access . can ( "certificates:update" , data ) ;
851848 const certificate = await internalCertificate . get ( access , data ) ;
852849
853850 if ( certificate . provider === "letsencrypt" ) {
@@ -860,11 +857,9 @@ const internalCertificate = {
860857 `${ internalCertificate . getLiveCertPath ( certificate . id ) } /fullchain.pem` ,
861858 ) ;
862859
863- const updatedCertificate = await certificateModel
864- . query ( )
865- . patchAndFetchById ( certificate . id , {
866- expires_on : moment ( certInfo . dates . to , "X" ) . format ( "YYYY-MM-DD HH:mm:ss" ) ,
867- } ) ;
860+ const updatedCertificate = await certificateModel . query ( ) . patchAndFetchById ( certificate . id , {
861+ expires_on : moment ( certInfo . dates . to , "X" ) . format ( "YYYY-MM-DD HH:mm:ss" ) ,
862+ } ) ;
868863
869864 // Add to audit log
870865 await internalAuditLog . add ( access , {
@@ -1159,7 +1154,9 @@ const internalCertificate = {
11591154 return "no-host" ;
11601155 }
11611156 // Other errors
1162- logger . info ( `HTTP challenge test failed for domain ${ domain } because code ${ result . responsecode } was returned` ) ;
1157+ logger . info (
1158+ `HTTP challenge test failed for domain ${ domain } because code ${ result . responsecode } was returned` ,
1159+ ) ;
11631160 return `other:${ result . responsecode } ` ;
11641161 }
11651162
@@ -1201,7 +1198,7 @@ const internalCertificate = {
12011198
12021199 getLiveCertPath : ( certificateId ) => {
12031200 return `/etc/letsencrypt/live/npm-${ certificateId } ` ;
1204- }
1201+ } ,
12051202} ;
12061203
12071204export default internalCertificate ;
0 commit comments