1
1
import createPrisma from '@/lib/create-prisma'
2
- import { verifyDomainDNS , issueDomainCertificate , checkCertificateStatus , getValidationValues } from '@/lib/domain-verification'
2
+ import { verifyDomainDNS , issueDomainCertificate , checkCertificateStatus , getValidationValues , deleteCertificate } from '@/lib/domain-verification'
3
3
4
- export async function domainVerification ( { data : { domainId } , boss } ) {
4
+ export async function domainVerification ( { id : jobId , data : { domainId } , boss } ) {
5
5
// establish connection to database
6
6
const models = createPrisma ( { connectionParams : { connection_limit : 1 } } )
7
7
try {
@@ -13,25 +13,44 @@ export async function domainVerification ({ data: { domainId }, boss }) {
13
13
}
14
14
15
15
// start verification process
16
- const result = await verifyDomain ( domain , boss )
16
+ const result = await verifyDomain ( domain )
17
+ console . log ( `domain verification result: ${ JSON . stringify ( result ) } ` )
17
18
18
19
// update the domain with the result
19
20
await models . customDomain . update ( {
20
21
where : { id : domainId } ,
21
- data : { ... domain , ... result }
22
+ data : result
22
23
} )
23
24
24
25
// if the result is PENDING it means we still have to verify the domain
25
26
// if it's not PENDING, we stop the verification process.
26
27
if ( result . status === 'PENDING' ) {
27
28
// we still need to verify the domain, schedule the job to run again in 5 minutes
28
29
const jobId = await boss . send ( 'domainVerification' , { domainId } , {
29
- startAfter : 1000 * 60 * 5 // start the job after 5 minutes
30
+ startAfter : 60 * 5 , // start the job after 5 minutes
31
+ retryLimit : 3 ,
32
+ retryDelay : 30 // on critical errors, retry every 5 minutes
30
33
} )
31
34
console . log ( `domain ${ domain . domain } is still pending verification, created job with ID ${ jobId } to run in 5 minutes` )
32
35
}
33
36
} catch ( error ) {
34
37
console . error ( `couldn't verify domain with ID ${ domainId } : ${ error . message } ` )
38
+
39
+ // get the job details to get the retry count
40
+ const jobDetails = await boss . getJobById ( jobId )
41
+ console . log ( `job details: ${ JSON . stringify ( jobDetails ) } ` )
42
+ // if we couldn't verify the domain, put it on hold if it exists and delete any related verification jobs
43
+ if ( jobDetails ?. retrycount >= 3 ) {
44
+ console . log ( `couldn't verify domain with ID ${ domainId } for the third time, putting it on hold if it exists and deleting any related domain verification jobs` )
45
+ await models . customDomain . update ( { where : { id : domainId } , data : { status : 'HOLD' } } )
46
+ // delete any related domain verification jobs
47
+ await models . $queryRaw `
48
+ DELETE FROM pgboss.job
49
+ WHERE name = 'domainVerification'
50
+ AND data->>'domainId' = ${ domainId } ::TEXT`
51
+ }
52
+
53
+ throw error
35
54
}
36
55
}
37
56
@@ -67,7 +86,7 @@ async function verifyDomain (domain) {
67
86
if ( dnsState === 'VERIFIED' && ! sslArn ) {
68
87
sslArn = await issueDomainCertificate ( domain . domain )
69
88
if ( sslArn ) {
70
- console . log ( `SSL certificate issued for ${ domain . domain } with ARN ${ sslArn } , will verify with ACM in 5 minutes ` )
89
+ console . log ( `SSL certificate issued for ${ domain . domain } with ARN ${ sslArn } , will verify with ACM` )
71
90
} else {
72
91
console . log ( `couldn't issue SSL certificate for ${ domain . domain } , will retry certificate issuance in 5 minutes` )
73
92
}
@@ -78,9 +97,9 @@ async function verifyDomain (domain) {
78
97
let acmValidationCname = verification . ssl . cname || null
79
98
let acmValidationValue = verification . ssl . value || null
80
99
if ( sslArn && ! acmValidationCname && ! acmValidationValue ) {
81
- const { cname , value } = await getValidationValues ( sslArn )
82
- acmValidationCname = cname
83
- acmValidationValue = value
100
+ const values = await getValidationValues ( sslArn )
101
+ acmValidationCname = values ?. cname || null
102
+ acmValidationValue = values ?. value || null
84
103
if ( acmValidationCname && acmValidationValue ) {
85
104
console . log ( `Validation values retrieved for ${ domain . domain } , will check ACM validation status` )
86
105
} else {
@@ -91,7 +110,7 @@ async function verifyDomain (domain) {
91
110
// step 4: check if the certificate is validated by ACM
92
111
// if DNS is verified and we have a SSL certificate
93
112
// it can happen that we just issued the certificate and it's not yet validated by ACM
94
- if ( dnsState === 'VERIFIED' && sslArn && sslState !== 'VERIFIED' ) {
113
+ if ( sslArn && sslState !== 'VERIFIED' ) {
95
114
sslState = await checkCertificateStatus ( sslArn )
96
115
switch ( sslState ) {
97
116
case 'VERIFIED' :
@@ -114,13 +133,20 @@ async function verifyDomain (domain) {
114
133
// if the domain has failed in some way and it's been 48 hours, put it on hold
115
134
if ( status !== 'ACTIVE' && domain . createdAt < new Date ( Date . now ( ) - 1000 * 60 * 60 * 24 * 2 ) ) {
116
135
status = 'HOLD'
136
+ // we stopped domain verification, delete the certificate as it will expire after 72 hours anyway
137
+ if ( sslArn ) {
138
+ console . log ( `domain ${ domain . domain } is on hold, deleting certificate as it will expire after 72 hours` )
139
+ const result = await deleteCertificate ( sslArn )
140
+ console . log ( `delete certificate attempt for ${ domain . domain } , result: ${ JSON . stringify ( result ) } ` )
141
+ }
117
142
}
118
143
119
144
return {
120
145
lastVerifiedAt,
121
146
status,
122
147
verification : {
123
148
dns : {
149
+ ...verification . dns ,
124
150
state : dnsState
125
151
} ,
126
152
ssl : {
0 commit comments