Skip to content

Commit 23bba32

Browse files
committed
poll every 30 seconds SSL and DNS verification states
1 parent 0c79d9f commit 23bba32

File tree

7 files changed

+74
-45
lines changed

7 files changed

+74
-45
lines changed

api/acm/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export async function requestCertificate (domain) {
1616
config.endpoint = process.env.LOCALSTACK_ENDPOINT
1717
}
1818

19+
// TODO: Research real values
1920
const acm = new AWS.ACM(config)
2021
const params = {
2122
DomainName: domain,

api/resolvers/sub.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ export default {
150150
cursor: subs.length === limit ? nextCursorEncoded(decodedCursor, limit) : null,
151151
subs
152152
}
153+
},
154+
customDomain: async (parent, { subName }, { models }) => {
155+
return models.customDomain.findUnique({ where: { subName } })
153156
}
154157
},
155158
Mutation: {

api/typeDefs/sub.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export default gql`
77
subs: [Sub!]!
88
topSubs(cursor: String, when: String, from: String, to: String, by: String, limit: Limit): Subs
99
userSubs(name: String!, cursor: String, when: String, from: String, to: String, by: String, limit: Limit): Subs
10+
customDomain(subName: String!): CustomDomain
1011
}
1112
1213
type CustomDomain {

components/territory-domains.js

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { Badge } from 'react-bootstrap'
22
import { Form, Input, SubmitButton } from './form'
3-
import { gql, useMutation } from '@apollo/client'
3+
import { gql, useMutation, useQuery } from '@apollo/client'
44
import { customDomainSchema } from '@/lib/validate'
55
import ActionTooltip from './action-tooltip'
66
import { useToast } from '@/components/toast'
7+
import { NORMAL_POLL_INTERVAL, SSR } from '@/lib/constants'
78

89
const SET_CUSTOM_DOMAIN = gql`
910
mutation SetCustomDomain($subName: String!, $domain: String!) {
@@ -15,11 +16,38 @@ const SET_CUSTOM_DOMAIN = gql`
1516
}
1617
`
1718

18-
// TODO: verification states should refresh
19+
const GET_CUSTOM_DOMAIN = gql`
20+
query CustomDomain($subName: String!) {
21+
customDomain(subName: $subName) {
22+
domain
23+
dnsState
24+
sslState
25+
verificationCname
26+
verificationCnameValue
27+
verificationTxt
28+
lastVerifiedAt
29+
}
30+
}
31+
`
32+
33+
// TODO: clean this up
1934
export default function CustomDomainForm ({ sub }) {
2035
const [setCustomDomain] = useMutation(SET_CUSTOM_DOMAIN, {
2136
refetchQueries: ['Sub']
2237
})
38+
const { data, stopPolling } = useQuery(GET_CUSTOM_DOMAIN, SSR
39+
? {}
40+
: {
41+
variables: { subName: sub.name },
42+
pollInterval: NORMAL_POLL_INTERVAL,
43+
skip: !sub || !sub.customDomain,
44+
onCompleted: (data) => {
45+
if (data?.customDomain?.sslState === 'VERIFIED' &&
46+
data?.customDomain?.dnsState === 'VERIFIED') {
47+
stopPolling()
48+
}
49+
}
50+
})
2351
const toaster = useToast()
2452

2553
const onSubmit = async ({ domain }) => {
@@ -57,7 +85,7 @@ export default function CustomDomainForm ({ sub }) {
5785
return (
5886
<Form
5987
initial={{
60-
domain: sub?.customDomain?.domain || ''
88+
domain: sub.customDomain?.domain || ''
6189
}}
6290
schema={customDomainSchema}
6391
onSubmit={onSubmit}
@@ -69,13 +97,13 @@ export default function CustomDomainForm ({ sub }) {
6997
label={
7098
<div className='d-flex align-items-center gap-2'>
7199
<span>custom domain</span>
72-
{sub?.customDomain && (
100+
{data?.customDomain && (
73101
<>
74102
<div className='d-flex align-items-center gap-2'>
75-
<ActionTooltip overlayText={new Date(sub.customDomain.lastVerifiedAt).toUTCString()}>
76-
{getStatusBadge(sub.customDomain.dnsState)}
103+
<ActionTooltip overlayText={new Date(data?.customDomain.lastVerifiedAt).toUTCString()}>
104+
{getStatusBadge(data?.customDomain.dnsState)}
77105
</ActionTooltip>
78-
{getSSLStatusBadge(sub.customDomain.sslState)}
106+
{getSSLStatusBadge(data?.customDomain.sslState)}
79107
</div>
80108
</>
81109
)}
@@ -87,7 +115,7 @@ export default function CustomDomainForm ({ sub }) {
87115
{/* TODO: toaster */}
88116
<SubmitButton variant='primary' className='mt-3'>save</SubmitButton>
89117
</div>
90-
{(sub.customDomain.dnsState === 'PENDING' || sub.customDomain.dnsState === 'FAILED') && (
118+
{(data?.customDomain.dnsState === 'PENDING' || data?.customDomain.dnsState === 'FAILED') && (
91119
<>
92120
<h6>Verify your domain</h6>
93121
<p>Add the following DNS records to verify ownership of your domain:</p>
@@ -99,23 +127,18 @@ export default function CustomDomainForm ({ sub }) {
99127
<pre>
100128
TXT:
101129
Host: @
102-
Value: ${sub.customDomain.verificationTxt}
130+
Value: ${data?.customDomain.verificationTxt}
103131
</pre>
104132
</>
105133
)}
106-
{sub.customDomain.sslState === 'PENDING' && (
134+
{data?.customDomain.sslState === 'PENDING' && (
107135
<>
108136
<h6>SSL verification pending</h6>
109-
<p>We issued an SSL certificate for your domain.</p>
137+
<p>We issued an SSL certificate for your domain. To validate it, add the following CNAME record:</p>
110138
<pre>
111139
CNAME:
112-
Host: ${sub.customDomain.verificationCname}
113-
Value: ${sub.customDomain.verificationCnameValue}
114-
</pre>
115-
<pre>
116-
TXT:
117-
Host: @
118-
Value: ${sub.customDomain.verificationTxt}
140+
Host: ${data?.customDomain.verificationCname}
141+
Value: ${data?.customDomain.verificationCnameValue}
119142
</pre>
120143
</>
121144
)}

components/territory-form.js

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -288,23 +288,24 @@ export default function TerritoryForm ({ sub }) {
288288
/>
289289
</div>
290290
</Form>
291-
<div className='w-100'>
292-
<AccordianItem
293-
header={<div style={{ fontWeight: 'bold', fontSize: '92%' }}>advanced</div>}
294-
body={
295-
<>
296-
<TerritoryDomains sub={sub} />
297-
{sub?.customDomain?.dnsState === 'VERIFIED' && sub?.customDomain?.sslState === 'VERIFIED' &&
298-
<>
299-
<BootstrapForm.Label>[NOT IMPLEMENTED] branding</BootstrapForm.Label>
300-
<div className='mb-3'>WIP</div>
301-
<BootstrapForm.Label>[NOT IMPLEMENTED] color scheme</BootstrapForm.Label>
302-
<div className='mb-3'>WIP</div>
303-
</>}
304-
</>
305-
}
306-
/>
307-
</div>
291+
{sub &&
292+
<div className='w-100'>
293+
<AccordianItem
294+
header={<div style={{ fontWeight: 'bold', fontSize: '92%' }}>advanced</div>}
295+
body={
296+
<>
297+
<TerritoryDomains sub={sub} />
298+
{sub?.customDomain?.dnsState === 'VERIFIED' && sub?.customDomain?.sslState === 'VERIFIED' &&
299+
<>
300+
<BootstrapForm.Label>[NOT IMPLEMENTED] branding</BootstrapForm.Label>
301+
<div className='mb-3'>WIP</div>
302+
<BootstrapForm.Label>[NOT IMPLEMENTED] color scheme</BootstrapForm.Label>
303+
<div className='mb-3'>WIP</div>
304+
</>}
305+
</>
306+
}
307+
/>
308+
</div>}
308309
</FeeButtonProvider>
309310
)
310311
}

lib/domains.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export async function getValidationValues (certificateArn) {
5555
}
5656
}
5757

58-
export async function verifyDomainDNS (domainName, verificationTxt, cname = 'stacker.news') {
58+
export async function verifyDomainDNS (domainName, verificationTxt, cname = 'parallel.soxa.dev') {
5959
const result = {
6060
txtValid: false,
6161
cnameValid: false,

worker/domainVerification.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,32 @@ export async function domainVerification () {
66
const models = createPrisma({ connectionParams: { connection_limit: 1 } })
77

88
try {
9-
const domains = await models.customDomain.findMany({ where: { OR: [{ dnsState: 'PENDING' }, { sslState: 'PENDING' }] } })
9+
const domains = await models.customDomain.findMany({ where: { NOT: { AND: [{ dnsState: 'VERIFIED' }, { sslState: 'VERIFIED' }] } } })
1010

1111
for (const domain of domains) {
1212
try {
1313
const data = { ...domain, lastVerifiedAt: new Date() }
1414
// DNS verification
1515
if (data.dnsState === 'PENDING' || data.dnsState === 'FAILED') {
16-
const { txtValid, cnameValid } = await verifyDomainDNS(domain.name, domain.verificationTxt)
17-
console.log(`${domain.name}: TXT ${txtValid ? 'valid' : 'invalid'}, CNAME ${cnameValid ? 'valid' : 'invalid'}`)
16+
const { txtValid, cnameValid } = await verifyDomainDNS(data.domain, domain.verificationTxt)
17+
console.log(`${data.domain}: TXT ${txtValid ? 'valid' : 'invalid'}, CNAME ${cnameValid ? 'valid' : 'invalid'}`)
1818
data.dnsState = txtValid && cnameValid ? 'VERIFIED' : 'FAILED'
1919
}
2020

2121
// SSL issuing
2222
if (data.dnsState === 'VERIFIED' && (!data.certificateArn || data.sslState === 'FAILED')) {
23-
const certificateArn = await issueDomainCertificate(domain.name)
24-
console.log(`${domain.name}: Certificate issued: ${certificateArn}`)
23+
const certificateArn = await issueDomainCertificate(data.domain)
24+
console.log(`${data.domain}: Certificate issued: ${certificateArn}`)
2525
if (certificateArn) {
2626
const sslState = await checkCertificateStatus(certificateArn)
27-
console.log(`${domain.name}: Issued certificate status: ${sslState}`)
27+
console.log(`${data.domain}: Issued certificate status: ${sslState}`)
2828
if (sslState === 'PENDING') {
2929
try {
3030
const { cname, value } = await getValidationValues(certificateArn)
3131
data.verificationCname = cname
3232
data.verificationCnameValue = value
3333
} catch (error) {
34-
console.error(`Failed to get validation values for domain ${domain.name}:`, error)
34+
console.error(`Failed to get validation values for domain ${data.domain}:`, error)
3535
}
3636
}
3737
if (sslState) data.sslState = sslState
@@ -44,14 +44,14 @@ export async function domainVerification () {
4444
// SSL checking
4545
if (data.dnsState === 'VERIFIED' && data.sslState === 'PENDING') {
4646
const sslState = await checkCertificateStatus(data.certificateArn)
47-
console.log(`${domain.name}: Certificate status: ${sslState}`)
47+
console.log(`${data.domain}: Certificate status: ${sslState}`)
4848
if (sslState) data.sslState = sslState
4949
}
5050

5151
await models.customDomain.update({ where: { id: domain.id }, data })
5252
} catch (error) {
5353
// TODO: this declares any error as a DNS verification error, we should also consider SSL verification errors
54-
console.error(`Failed to verify domain ${domain.name}:`, error)
54+
console.error(`Failed to verify domain ${domain.domain}:`, error)
5555

5656
// TODO: DNS inconcistencies can happen, we should retry at least 3 times before marking it as FAILED
5757
// Update to FAILED on any error

0 commit comments

Comments
 (0)