Ability to show certs that are only in cluster memory separately in table

Ability to "upload" an existing db cert if not in the cluster
develop
Thomas Lynch 1 year ago
parent d5aabd5c1f
commit 19c3cda51b
  1. 3
      api.js
  2. 63
      controllers/certs.js
  3. 75
      pages/certs.js
  4. 6
      router.js

@ -46,6 +46,9 @@ export async function addCert(body, dispatch, errorCallback, router) {
export async function deleteCert(body, dispatch, errorCallback, router) {
return ApiCall('/forms/cert/delete', 'POST', body, dispatch, errorCallback, router, 0.5);
}
export async function uploadCert(body, dispatch, errorCallback, router) {
return ApiCall('/forms/cert/upload', 'POST', body, dispatch, errorCallback, router, 0.5);
}
// Maps
export async function getMap(mapName, dispatch, errorCallback, router) {

@ -8,7 +8,7 @@ const { dynamicResponse } = require('../util.js');
* certs page
*/
exports.certsPage = async (app, req, res) => {
const certs = await db.db.collection('certs')
const dbCerts = await db.db.collection('certs')
.find({
username: res.locals.user.username,
}, {
@ -20,11 +20,15 @@ exports.certsPage = async (app, req, res) => {
storageName: 1,
}
})
.toArray();
certs.forEach(c => c.date = c.date.toISOString())
.toArray()
dbCerts.forEach(c => c.date = c.date.toISOString());
const clusterCerts = await res.locals.dataPlane
.getAllStorageSSLCertificates()
.then(res => res.data);
return app.render(req, res, '/certs', {
csrf: req.csrfToken(),
certs,
dbCerts,
clusterCerts,
});
};
@ -33,7 +37,7 @@ exports.certsPage = async (app, req, res) => {
* certs json data
*/
exports.certsJson = async (req, res) => {
const certs = await db.db.collection('certs')
const dbCerts = await db.db.collection('certs')
.find({
username: res.locals.user.username,
}, {
@ -45,12 +49,16 @@ exports.certsJson = async (req, res) => {
storageName: 1,
}
})
.toArray();
certs.forEach(c => c.date = c.date.toISOString())
.toArray()
dbCerts.forEach(c => c.date = c.date.toISOString());
const clusterCerts = await res.locals.dataPlane
.getAllStorageSSLCertificates()
.then(res => res.data);
return res.json({
csrf: req.csrfToken(),
user: res.locals.user,
certs,
dbCerts,
clusterCerts,
});
};
@ -125,9 +133,46 @@ exports.addCert = async (req, res, next) => {
}
return dynamicResponse(req, res, 302, { redirect: '/certs' });
};
//TODO: new route to sync ssl certs throughout cluster
/**
* POST /cert/upload
* push existing db cert to cluster
*/
exports.uploadCert = async (req, res, next) => {
if (!req.body.domain || typeof req.body.domain !== 'string' || req.body.domain.length === 0
|| !res.locals.user.domains.includes(req.body.domain)) {
return dynamicResponse(req, res, 400, { error: 'Invalid input' });
}
const domain = req.body.domain.toLowerCase();
const existingCert = await db.db.collection('certs').findOne({ _id: domain, username: res.locals.user.username });
if (!existingCert || !existingCert.haproxyCert) {
return dynamicResponse(req, res, 400, { error: 'Invalid input' });
}
try {
console.log('Upload cert:', existingCert.subject, existingCert.altnames);
const fd = new FormData();
fd.append('file_upload', new Blob([existingCert.haproxyCert], { type: 'text/plain' }), `${existingCert.subject}.pem`);
const { message, description, file, storage_name: storageName } = await res.locals.fetchAll('/v2/services/haproxy/storage/ssl_certificates?force_reload=true', {
method: 'POST',
headers: { 'authorization': res.locals.dataPlane.defaults.headers.authorization },
body: fd,
});
if (message) {
return dynamicResponse(req, res, 400, { error: message });
}
} catch (e) {
return next(e);
}
return dynamicResponse(req, res, 302, { redirect: '/certs' });
};
/**
* POST /cert/delete

@ -28,7 +28,7 @@ export default function Certs(props) {
);
}
const { user, csrf, certs } = state;
const { user, csrf, dbCerts, clusterCerts } = state;
async function addCert(e) {
e.preventDefault();
@ -45,20 +45,66 @@ export default function Certs(props) {
await API.deleteCert({ _csrf: csrf, subject: e.target.subject.value }, dispatch, setError, router);
await API.getCerts(dispatch, setError, router);
}
async function uploadCert(e) {
e.preventDefault();
await API.uploadCert({ _csrf: csrf, domain: e.target.domain.value }, dispatch, setError, router);
await API.getCerts(dispatch, setError, router);
}
const certList = certs.map((d, i) => {
//TODO: refactor, to component
let creation = new Date(d.date);
const expiry = creation.setDate(creation.getDate()+90);
const daysRemaining = (Math.floor(expiry - Date.now()) / 86400000).toFixed(1)
const clusterOnlyCerts = clusterCerts
.filter(c => !dbCerts.some(dc => dc.storageName === c.storage_name))
.filter(c => !c.storage_name === 'selfsigned.pem'); //no point showing this
const clusterOnlyCertList = clusterOnlyCerts.map((c, i) => {
const approxSubject = c.storage_name
.replace('_', '.')
.substr(0, c.storage_name.length-4);
return (
<tr key={i} className="align-middle">
<tr key={'clusterOnlyCertList'+i} className="align-middle">
<td className="col-1 text-center">
<form onSubmit={deleteCert} action="/forms/cert/delete" method="post">
{/*TODO: delete non-db cert <form onSubmit={deleteCert} action="/forms/cert/delete" method="post">
<input type="hidden" name="_csrf" value={csrf} />
<input type="hidden" name="subject" value={d.subject || d._id} />
<input className="btn btn-danger" type="submit" value="×" />
</form>
</form>*/}
</td>
<td>
{approxSubject || '-'}
</td>
<td>
-
</td>
<td>
-
</td>
<td>
{c.storage_name || '-'}
</td>
</tr>
);
});
const certList = dbCerts.map((d, i) => {
//TODO: refactor, to component
let creation = new Date(d.date);
const expiry = creation.setDate(creation.getDate()+90);
const daysRemaining = (Math.floor(expiry - Date.now()) / 86400000).toFixed(1);
const inCluster = clusterCerts.some(c => c.storage_name === d.storageName);
return (
<tr key={'certList'+i} className="align-middle">
<td className="col-1 text-center">
{inCluster
? (<form onSubmit={deleteCert} action="/forms/cert/delete" method="post">
<input type="hidden" name="_csrf" value={csrf} />
<input type="hidden" name="subject" value={d.subject || d._id} />
<input className="btn btn-danger" type="submit" value="×" />
</form>)
: (<form onSubmit={uploadCert} action="/forms/cert/upload" method="post">
<input type="hidden" name="_csrf" value={csrf} />
<input type="hidden" name="domain" value={d.subject || d._id} />
<input className="btn btn-warning" type="submit" value="↑" />
</form>)
}
</td>
<td>
{d.subject || '-'}
@ -80,7 +126,7 @@ export default function Certs(props) {
</td>
</tr>
);
})
});
return (
<>
@ -118,6 +164,15 @@ export default function Certs(props) {
{certList}
{clusterOnlyCerts && clusterOnlyCerts.length > 0 && (<>
<tr className="align-middle">
<th colSpan="5">
Not in local DB:
</th>
</tr>
{clusterOnlyCertList}
</>)}
{/* Add new cert form */}
<tr className="align-middle">
<td className="col-1 text-center" colSpan="3">

@ -85,7 +85,6 @@ const testRouter = (server, app) => {
const apiInstance = api.initSync();
apiInstance.defaults.baseURL = `${firstClusterURL.origin}/v2`;
res.locals.dataPlane = apiInstance;
//console.log((await apiInstance.getAllStorageSSLCertificates().then(res => res.data)))
res.locals.dataPlaneAll = async (operationId, parameters, data, config) => {
const promiseResults = await Promise.all(clusterUrls.map(clusterUrl => {
@ -151,8 +150,8 @@ const testRouter = (server, app) => {
server.get('/domains', useSession, fetchSession, checkSession, csrfMiddleware, domainsController.domainsPage.bind(null, app));
server.get('/domains.json', useSession, fetchSession, checkSession, csrfMiddleware, domainsController.domainsJson);
server.get('/certs', useSession, fetchSession, checkSession, csrfMiddleware, certsController.certsPage.bind(null, app));
server.get('/certs.json', useSession, fetchSession, checkSession, csrfMiddleware, certsController.certsJson);
server.get('/certs', useSession, fetchSession, checkSession, useHaproxy, csrfMiddleware, certsController.certsPage.bind(null, app));
server.get('/certs.json', useSession, fetchSession, checkSession, useHaproxy, csrfMiddleware, certsController.certsJson);
//authed pages that useHaproxy
const clusterRouter = express.Router({ caseSensitive: true });
@ -165,6 +164,7 @@ const testRouter = (server, app) => {
clusterRouter.post('/domain/add', useSession, fetchSession, checkSession, useHaproxy, hasCluster, csrfMiddleware, domainsController.addDomain);
clusterRouter.post('/domain/delete', useSession, fetchSession, checkSession, hasCluster, csrfMiddleware, domainsController.deleteDomain);
clusterRouter.post('/cert/add', useSession, fetchSession, checkSession, useHaproxy, hasCluster, csrfMiddleware, certsController.addCert);
clusterRouter.post('/cert/upload', useSession, fetchSession, checkSession, useHaproxy, hasCluster, csrfMiddleware, certsController.uploadCert);
clusterRouter.post('/cert/delete', useSession, fetchSession, checkSession, hasCluster, csrfMiddleware, certsController.deleteCert);
server.use('/forms', clusterRouter);

Loading…
Cancel
Save