|
|
|
@ -4,12 +4,14 @@ import Head from 'next/head'; |
|
|
|
|
import Link from 'next/link'; |
|
|
|
|
import ErrorAlert from '../components/ErrorAlert.js'; |
|
|
|
|
import * as API from '../api.js'; |
|
|
|
|
import NProgress from 'nprogress'; |
|
|
|
|
|
|
|
|
|
export default function Onboarding(props) { |
|
|
|
|
|
|
|
|
|
const router = useRouter(); |
|
|
|
|
const [state, dispatch] = useState(props); |
|
|
|
|
const [error, setError] = useState(); |
|
|
|
|
const [csrState, setCsrState] = useState(); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
if (!state.user) { |
|
|
|
@ -17,7 +19,7 @@ export default function Onboarding(props) { |
|
|
|
|
} |
|
|
|
|
}, [state.user, state.maps, router]); |
|
|
|
|
|
|
|
|
|
if (state.user == null) { |
|
|
|
|
if (state.user == null || !state.txtRecords || state.txtRecords.length === 0) { |
|
|
|
|
return ( |
|
|
|
|
<div className='d-flex flex-column'> |
|
|
|
|
{error && <ErrorAlert error={error} />} |
|
|
|
@ -31,13 +33,15 @@ export default function Onboarding(props) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const { user, maps, globalAcl, csrf, aRecords, aaaaRecords, txtRecords } = state; |
|
|
|
|
const domainAdded = user.domains.length > 0; |
|
|
|
|
const backendMap = maps && maps.find(m => m.name === 'hosts'); |
|
|
|
|
const backendAdded = backendMap && backendMap.count > 0; |
|
|
|
|
const certAdded = user.numCerts > 0; |
|
|
|
|
const domainAdded = false; //user.domains && user.domains.length > 0;
|
|
|
|
|
const backendMap = false; //maps && maps.find(m => m.name === 'hosts');
|
|
|
|
|
const backendAdded = false; //backendMap && backendMap.count > 0;
|
|
|
|
|
const certAdded = false; //user.numCerts && user.numCerts > 0;
|
|
|
|
|
|
|
|
|
|
async function finishOnboarding(e) { |
|
|
|
|
await API.finishOnboarding(dispatch, setError, router); |
|
|
|
|
async function updateOnboarding(step) { |
|
|
|
|
await API.updateOnboarding({ |
|
|
|
|
step |
|
|
|
|
}, dispatch, setError, router); |
|
|
|
|
await API.getAccount(dispatch, setError, router); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -67,6 +71,17 @@ export default function Onboarding(props) { |
|
|
|
|
e.target.reset(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async function verifyCSR(e) { |
|
|
|
|
e.preventDefault(); |
|
|
|
|
setError(null); |
|
|
|
|
await API.verifyCSR({ |
|
|
|
|
_csrf: csrf, |
|
|
|
|
csr: e.target.csr.value, |
|
|
|
|
json: true, |
|
|
|
|
}, setCsrState, setError, router); |
|
|
|
|
NProgress.done(true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return (<> |
|
|
|
|
|
|
|
|
|
<Head> |
|
|
|
@ -75,11 +90,16 @@ export default function Onboarding(props) { |
|
|
|
|
|
|
|
|
|
{error && <ErrorAlert error={error} />} |
|
|
|
|
|
|
|
|
|
<h5 className='fw-bold'>Onboarding</h5> |
|
|
|
|
|
|
|
|
|
{!user.onboarding && <div className='my-2'> |
|
|
|
|
<input onClick={finishOnboarding} className='btn btn-warning' type='submit' value='Skip Onboarding' /> |
|
|
|
|
</div>} |
|
|
|
|
<h5 className='fw-bold'> |
|
|
|
|
Onboarding |
|
|
|
|
<div className='my-2'> |
|
|
|
|
<input onClick={() => { |
|
|
|
|
if (confirm('Are you sure you want to skip onboarding?')) { |
|
|
|
|
updateOnboarding(7); |
|
|
|
|
} |
|
|
|
|
}} className='btn btn-sm btn-warning' type='submit' value='Skip Onboarding' /> |
|
|
|
|
</div> |
|
|
|
|
</h5> |
|
|
|
|
|
|
|
|
|
<div className='list-group'> |
|
|
|
|
<div className='list-group-item d-flex gap-3'> |
|
|
|
@ -94,11 +114,11 @@ export default function Onboarding(props) { |
|
|
|
|
<p>Add your first domain (i.e. <code>example.com</code>) that you want to protect with BasedFlare.</p> |
|
|
|
|
<p>You can add other domains and/or subdomains later from the "domains" page.</p> |
|
|
|
|
</span> |
|
|
|
|
<form className='d-flex mb-3' onSubmit={addDomain} action='/forms/domain/add' method='post'> |
|
|
|
|
<form className='mb-3' onSubmit={addDomain} action='/forms/domain/add' method='post'> |
|
|
|
|
<input type='hidden' name='_csrf' value={csrf} /> |
|
|
|
|
<input type='hidden' name='onboarding' value='1' /> |
|
|
|
|
<input className='btn btn-success' type='submit' value='+' disabled={domainAdded} /> |
|
|
|
|
<input className='form-control mx-3' type='text' name='domain' placeholder='domain' disabled={domainAdded} required /> |
|
|
|
|
<input className='form-control mb-3' type='text' name='domain' placeholder='domain' disabled={domainAdded} required /> |
|
|
|
|
<input className='btn btn-success' type='submit' value='Add domain' disabled={domainAdded} /> |
|
|
|
|
</form> |
|
|
|
|
</>} |
|
|
|
|
{domainAdded && (<div><strong> |
|
|
|
@ -162,36 +182,34 @@ export default function Onboarding(props) { |
|
|
|
|
<span className='pt-1 form-checked-content'> |
|
|
|
|
<strong style={{ textDecoration: backendAdded ? 'line-through' : '' }}> |
|
|
|
|
<i className='bi-hdd-network-fill pe-none me-2' width='1em' height='1em' /> |
|
|
|
|
4. Setup a backend |
|
|
|
|
4. Add a backend |
|
|
|
|
</strong> |
|
|
|
|
{!backendAdded && <> |
|
|
|
|
<span className='d-block text-body-secondary mt-3'> |
|
|
|
|
<p>Enter the backend server IP address and port in ip:port format, e.g. <code>12.34.56.78:443</code>.</p> |
|
|
|
|
<p>This is the "origin" that you want BasedFlare to proxy traffic to.</p> |
|
|
|
|
</span> |
|
|
|
|
<form onSubmit={addToMap} className='d-flex mb-3' action='/forms/map/hosts/add' method='post'> |
|
|
|
|
<form onSubmit={addToMap} className='mb-3' action='/forms/map/hosts/add' method='post'> |
|
|
|
|
<input type='hidden' name='_csrf' value={csrf} /> |
|
|
|
|
<input type='hidden' name='onboarding' value='1' /> |
|
|
|
|
<input className='btn btn-success' type='submit' value='+' |
|
|
|
|
//disabled={backendAdded}
|
|
|
|
|
/> |
|
|
|
|
<select className='form-select mx-3' name='key' defaultValue='' |
|
|
|
|
//disabled={backendAdded}
|
|
|
|
|
<select className='form-select mb-3' name='key' defaultValue='' |
|
|
|
|
disabled={backendAdded} |
|
|
|
|
required> |
|
|
|
|
<option value=''>select domain</option> |
|
|
|
|
{user.domains.map((d, i) => (<option key={'option'+i} value={d}>{d}</option>))} |
|
|
|
|
{(user.domains||[]).map((d, i) => (<option key={'option'+i} value={d}>{d}</option>))} |
|
|
|
|
</select> |
|
|
|
|
{ |
|
|
|
|
(process.env.NEXT_PUBLIC_CUSTOM_BACKENDS_ENABLED) && |
|
|
|
|
<input |
|
|
|
|
className='form-control ml-2' |
|
|
|
|
className='form-control mb-3' |
|
|
|
|
type='text' |
|
|
|
|
name='value' |
|
|
|
|
placeholder='backend ip:port' |
|
|
|
|
//disabled={backendAdded}
|
|
|
|
|
disabled={backendAdded} |
|
|
|
|
required |
|
|
|
|
/> |
|
|
|
|
} |
|
|
|
|
<input className='btn btn-success' type='submit' value='Add backend' disabled={backendAdded} /> |
|
|
|
|
</form> |
|
|
|
|
</>} |
|
|
|
|
{backendAdded && (<div><strong> |
|
|
|
@ -214,12 +232,17 @@ export default function Onboarding(props) { |
|
|
|
|
<p>Certificates last 90 days and will automatically renew when they have less than 30 days remaining.</p> |
|
|
|
|
<p>You can manage certificates later from the "HTTPS Certificates" page.</p> |
|
|
|
|
</span> |
|
|
|
|
<form className='d-flex mb-3' onSubmit={addCert} action='/forms/cert/add' method='post'> |
|
|
|
|
<form className='mb-3' onSubmit={addCert} action='/forms/cert/add' method='post'> |
|
|
|
|
<input type='hidden' name='_csrf' value={csrf} /> |
|
|
|
|
<input type='hidden' name='onboarding' value='1' /> |
|
|
|
|
<input className='btn btn-success' type='submit' value='+' disabled={certAdded} /> |
|
|
|
|
<input className='form-control mx-3' type='text' name='subject' placeholder='domain.com' disabled={certAdded} required /> |
|
|
|
|
<input className='form-control me-3' type='text' name='altnames' placeholder='www.domain.com,staging.domain.com,etc...' disabled={certAdded} required /> |
|
|
|
|
<input className='form-control mb-3' type='text' name='subject' placeholder='domain.com' disabled={certAdded} required /> |
|
|
|
|
<textarea |
|
|
|
|
className='form-control mb-3' |
|
|
|
|
name='altnames' |
|
|
|
|
placeholder={'www.domain.com\r\ntest.example.com\r\netc...'} |
|
|
|
|
rows={4} |
|
|
|
|
required /> |
|
|
|
|
<input className='btn btn-success' type='submit' value='Generate certificate' disabled={certAdded} /> |
|
|
|
|
</form> |
|
|
|
|
</>} |
|
|
|
|
{certAdded && (<div><strong> |
|
|
|
@ -232,13 +255,13 @@ export default function Onboarding(props) { |
|
|
|
|
<input className='form-check-input flex-shrink-0' type='checkbox' value='' checked={certAdded} disabled /> |
|
|
|
|
<span className='pt-1 form-checked-content'> |
|
|
|
|
<strong> |
|
|
|
|
<i className='bi-file-earmark-lock-fill pe-none me-2' width='1em' height='1em' /> |
|
|
|
|
<i className='bi-building-fill-lock pe-none me-2' width='1em' height='1em' /> |
|
|
|
|
6. Get your HTTPS CSR signed |
|
|
|
|
</strong> |
|
|
|
|
<span className='d-block text-body-secondary mt-3'> |
|
|
|
|
<p>Finally, generate a certificate signing request for your origin server(s) and have BasedFlare sign it.</p> |
|
|
|
|
<p>This allows BasedFlare servers to verify the connection to your backend and prevents trivial MITM attacks and other weaknesses that are possible with e.g self-signed certificates in CloudFlare's "flexible" or "full" ssl mode.</p> |
|
|
|
|
<ol> |
|
|
|
|
<ol className='text-break'> |
|
|
|
|
<li>Generate the private key and certificate signing request for your domains on your origin server: |
|
|
|
|
<p> |
|
|
|
|
<code>
|
|
|
|
@ -252,11 +275,32 @@ export default function Onboarding(props) { |
|
|
|
|
<li>You can then setup <code>origin.key</code> and <code>origin.crt</code>, as the key and certificate respectively, in your origin web server.</li> |
|
|
|
|
</ol> |
|
|
|
|
</span> |
|
|
|
|
<form className='d-flex mb-3' action='/forms/csr/verify' method='post'> |
|
|
|
|
<form onSubmit={verifyCSR} className='mb-3' action='/forms/csr/verify' method='post'> |
|
|
|
|
<input type='hidden' name='_csrf' value={csrf} /> |
|
|
|
|
<textarea className='form-control mx-3' name='csr' placeholder='-----BEGIN CERTIFICATE REQUEST----- ...' required /> |
|
|
|
|
<input className='btn btn-success' type='submit' value='Verify' /> |
|
|
|
|
<textarea |
|
|
|
|
className='form-control mb-3' |
|
|
|
|
name='csr' |
|
|
|
|
placeholder={'-----BEGIN CERTIFICATE REQUEST-----\n...'} |
|
|
|
|
rows={4} |
|
|
|
|
required /> |
|
|
|
|
<button className='btn btn-sm btn-success' type='submit'> |
|
|
|
|
<i className='bi-plus-lg pe-1' width='16' height='16' /> |
|
|
|
|
Verify CSR |
|
|
|
|
</button> |
|
|
|
|
</form> |
|
|
|
|
{csrState && csrState.csr && <div> |
|
|
|
|
<div className='mb-2'> |
|
|
|
|
<label className='form-label w-100'>Here's your certificate: |
|
|
|
|
<textarea |
|
|
|
|
className='form-control' |
|
|
|
|
name='csr' |
|
|
|
|
value={csrState.csr} |
|
|
|
|
rows={10} |
|
|
|
|
readOnly |
|
|
|
|
required /> |
|
|
|
|
</label> |
|
|
|
|
</div> |
|
|
|
|
</div>} |
|
|
|
|
</span> |
|
|
|
|
</div> |
|
|
|
|
<div className='list-group-item d-flex gap-3 justify-content-center'> |
|
|
|
|