added createcert and deletecert
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
scm
|
scm
|
||||||
|
go.sum
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"scm/model"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/youmark/pkcs8"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateCert(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var requestData model.CreateCertificateRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil {
|
||||||
|
http.Error(w, "invalid JSON format", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
caCert, caKey, err := loadCertAndKey(
|
||||||
|
fmt.Sprintf(
|
||||||
|
"%s/%s/%s.crt",
|
||||||
|
os.Getenv("CERTS_PATH"),
|
||||||
|
"root",
|
||||||
|
"TolaMironcenkoCA",
|
||||||
|
),
|
||||||
|
fmt.Sprintf(
|
||||||
|
"%s/%s/%s.key",
|
||||||
|
os.Getenv("CERTS_PATH"),
|
||||||
|
"root",
|
||||||
|
"TolaMironcenkoCA",
|
||||||
|
),
|
||||||
|
requestData.CAKeyPassword,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
fmt.Println("error loading certificate and key:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: Implement create certificate endpoint
|
||||||
|
serverKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
fmt.Println("error generating server key:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
serverCert, err := createServerCert(caCert, caKey, serverKey, requestData)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
fmt.Println("error creating server certificate:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = os.Stat(fmt.Sprintf("%s/%s", os.Getenv("CERTS_PATH"), requestData.DNSNames[0]))
|
||||||
|
if err == nil {
|
||||||
|
http.Error(w, "certificate already exists", http.StatusConflict)
|
||||||
|
fmt.Println("certificate already exists")
|
||||||
|
return
|
||||||
|
} else if os.IsNotExist(err) {
|
||||||
|
err := os.Mkdir(fmt.Sprintf("%s/%s", os.Getenv("CERTS_PATH"), requestData.DNSNames[0]), 0755)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
fmt.Println("error creating directory:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
fmt.Println("error checking certificate directory:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = savePEM(fmt.Sprintf("%s/%s/%s.crt", os.Getenv("CERTS_PATH"), requestData.DNSNames[0], requestData.DNSNames[0]), "CERTIFICATE", serverCert)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
fmt.Println("error saving certificate:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = savePEM(fmt.Sprintf("%s/%s/%s.key", os.Getenv("CERTS_PATH"), requestData.DNSNames[0], requestData.DNSNames[0]), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(serverKey))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
fmt.Println("error saving private key:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "%s", `{"status": "success", "message": "Certificate created successfully"}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createServerCert(
|
||||||
|
caCert *x509.Certificate,
|
||||||
|
caKey *rsa.PrivateKey,
|
||||||
|
serverKey *rsa.PrivateKey,
|
||||||
|
certdata model.CreateCertificateRequest,
|
||||||
|
) ([]byte, error) {
|
||||||
|
// Шаблон серверного сертификата
|
||||||
|
template := x509.Certificate{
|
||||||
|
SerialNumber: big.NewInt(time.Now().Unix()),
|
||||||
|
Subject: pkix.Name{
|
||||||
|
Organization: certdata.OrganizationName,
|
||||||
|
CommonName: certdata.CommonName,
|
||||||
|
OrganizationalUnit: certdata.OrganizationUnit,
|
||||||
|
},
|
||||||
|
NotBefore: time.Now(),
|
||||||
|
NotAfter: time.Now().AddDate(1, 0, 0), // 1 год
|
||||||
|
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
|
DNSNames: certdata.DNSNames,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Создаем сертификат, подписанный CA
|
||||||
|
return x509.CreateCertificate(
|
||||||
|
rand.Reader,
|
||||||
|
&template,
|
||||||
|
caCert,
|
||||||
|
&serverKey.PublicKey,
|
||||||
|
caKey,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCertAndKey(certFile, keyFile, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||||
|
fmt.Println(certFile, keyFile)
|
||||||
|
// Загрузка корневого сертификата
|
||||||
|
caCertPEM, err := os.ReadFile(certFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
block, _ := pem.Decode(caCertPEM)
|
||||||
|
if block == nil {
|
||||||
|
return nil, nil, errors.New("failed to parse CA certificate PEM")
|
||||||
|
}
|
||||||
|
|
||||||
|
caCert, err := x509.ParseCertificate(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Загрузка зашифрованного приватного ключа
|
||||||
|
keyPEM, err := os.ReadFile(keyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
block, _ = pem.Decode(keyPEM)
|
||||||
|
if block == nil {
|
||||||
|
return nil, nil, errors.New("failed to parse CA key PEM")
|
||||||
|
}
|
||||||
|
fmt.Print(block.Type)
|
||||||
|
// Декодирование ключа с паролем
|
||||||
|
decryptedKey, err := pkcs8.ParsePKCS8PrivateKey(block.Bytes, []byte(password))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to decrypt CA key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caKey, ok := decryptedKey.(*rsa.PrivateKey)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return caCert, caKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func savePEM(filename, blockType string, data []byte) error {
|
||||||
|
file, err := os.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
err = pem.Encode(file, &pem.Block{
|
||||||
|
Type: blockType,
|
||||||
|
Bytes: data,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"scm/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DeleteCert(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var requestData model.DeleteCertRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err := os.Stat(fmt.Sprintf("%s/%s", os.Getenv("CERTS_PATH"), requestData.Domain))
|
||||||
|
if err == nil {
|
||||||
|
err = os.RemoveAll(fmt.Sprintf("%s/%s", os.Getenv("CERTS_PATH"), requestData.Domain))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "%s", `{"status": "success"}`)
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
http.Error(w, "Certificate not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: Implement delete certificate functionality
|
||||||
|
}
|
||||||
+53
-4
@@ -7,6 +7,7 @@
|
|||||||
<script src="js/bootstrap.min.js" defer></script>
|
<script src="js/bootstrap.min.js" defer></script>
|
||||||
<script src="js/theme.js" defer></script>
|
<script src="js/theme.js" defer></script>
|
||||||
<script src="js/certs.js" defer></script>
|
<script src="js/certs.js" defer></script>
|
||||||
|
<script src="js/create_cert.js" defer></script>
|
||||||
<title>Scm</title>
|
<title>Scm</title>
|
||||||
</head>
|
</head>
|
||||||
<style>
|
<style>
|
||||||
@@ -59,6 +60,15 @@
|
|||||||
+
|
+
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-primary"
|
||||||
|
id="downloadrootcert"
|
||||||
|
>
|
||||||
|
Download Root Certificate
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -89,6 +99,37 @@
|
|||||||
/>
|
/>
|
||||||
<label for="domain">Domain</label>
|
<label for="domain">Domain</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="commonname"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="commonname"
|
||||||
|
/>
|
||||||
|
<label for="commonname">Common Name</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="organizationname"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="organizationname"
|
||||||
|
/>
|
||||||
|
<label for="organizationname"
|
||||||
|
>Organization Name</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="organizationunit"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="organizationunit"
|
||||||
|
/>
|
||||||
|
<label for="organizationunit"
|
||||||
|
>Organization Unit</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-3">
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
@@ -107,8 +148,12 @@
|
|||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-primary">
|
<button
|
||||||
Save changes
|
id="createcert"
|
||||||
|
type="button"
|
||||||
|
class="btn btn-primary"
|
||||||
|
>
|
||||||
|
Create
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -127,10 +172,14 @@
|
|||||||
></button>
|
></button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="modal-body d-flex gap-3 align-items-center justify-content-center"
|
class="modal-body d-flex gap-3 align-items-start justify-content-between"
|
||||||
id="preview_ssl_content"
|
id="preview_ssl_content"
|
||||||
>
|
>
|
||||||
<div id="certinfo">
|
<div
|
||||||
|
id="certinfo"
|
||||||
|
class="border-right p-3"
|
||||||
|
style="border-right: 2px solid"
|
||||||
|
>
|
||||||
<h1 id="cert-title">Information</h1>
|
<h1 id="cert-title">Information</h1>
|
||||||
<h2>Issuer</h2>
|
<h2>Issuer</h2>
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-3">
|
||||||
|
|||||||
+84
-66
@@ -4,9 +4,9 @@ const preview = document.querySelector("#preview");
|
|||||||
var certificates = [];
|
var certificates = [];
|
||||||
|
|
||||||
const renderCards = () => {
|
const renderCards = () => {
|
||||||
cards.innerHTML = "";
|
cards.innerHTML = "";
|
||||||
certificates.map((cert) => {
|
certificates.map((cert) => {
|
||||||
cards.innerHTML += `<div class="card" style="width: 16rem">
|
cards.innerHTML += `<div class="card" style="width: 16rem">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title" style="text-align: center">
|
<h5 class="card-title" style="text-align: center">
|
||||||
<a href="${cert.href}">${cert.domain}</a>
|
<a href="${cert.href}">${cert.domain}</a>
|
||||||
@@ -41,77 +41,95 @@ const renderCards = () => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCerts = async () => {
|
const getCerts = () => {
|
||||||
fetch(window.location.origin + "/api/certs")
|
fetch(window.location.origin + "/api/certs")
|
||||||
.then((data) => data.json())
|
.then((data) => data.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
certificates = data;
|
certificates = data;
|
||||||
renderCards();
|
renderCards();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("Error fetching certificates:", error);
|
console.error("Error fetching certificates:", error);
|
||||||
alert("Failed to fetch certificates");
|
alert("Failed to fetch certificates");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
getCerts();
|
getCerts();
|
||||||
|
|
||||||
if (preview) {
|
if (preview) {
|
||||||
preview.addEventListener("show.bs.modal", (e) => {
|
preview.addEventListener("show.bs.modal", (e) => {
|
||||||
const button = e.relatedTarget;
|
const button = e.relatedTarget;
|
||||||
const recipient = button.getAttribute("data-bs-whatever");
|
const recipient = button.getAttribute("data-bs-whatever");
|
||||||
// const modalBodyTextarea = preview.querySelector(".modal-body textarea");
|
// const modalBodyTextarea = preview.querySelector(".modal-body textarea");
|
||||||
const dnsnames = button.getAttribute("data-bs-dnsnames");
|
const dnsnames = button.getAttribute("data-bs-dnsnames");
|
||||||
const notafter = button.getAttribute("data-bs-notafter");
|
const notafter = button.getAttribute("data-bs-notafter");
|
||||||
const notbefore = button.getAttribute("data-bs-notbefore");
|
const notbefore = button.getAttribute("data-bs-notbefore");
|
||||||
const issuerorganizationunit = button.getAttribute(
|
const issuerorganizationunit = button.getAttribute(
|
||||||
"data-bs-issuer-organizationunit",
|
"data-bs-issuer-organizationunit",
|
||||||
);
|
);
|
||||||
const issuerorganization = button.getAttribute(
|
const issuerorganization = button.getAttribute(
|
||||||
"data-bs-issuer-organization",
|
"data-bs-issuer-organization",
|
||||||
);
|
);
|
||||||
const issuercommonname = button.getAttribute("data-bs-issuer-commonname");
|
const issuercommonname = button.getAttribute(
|
||||||
const subjectorganizationunit = button.getAttribute(
|
"data-bs-issuer-commonname",
|
||||||
"data-bs-subject-organizationunit",
|
);
|
||||||
);
|
const subjectorganizationunit = button.getAttribute(
|
||||||
const subjectorganization = button.getAttribute(
|
"data-bs-subject-organizationunit",
|
||||||
"data-bs-subject-organization",
|
);
|
||||||
);
|
const subjectorganization = button.getAttribute(
|
||||||
const subjectcommonname = button.getAttribute("data-bs-subject-commonname");
|
"data-bs-subject-organization",
|
||||||
console.log(
|
);
|
||||||
dnsnames,
|
const subjectcommonname = button.getAttribute(
|
||||||
notafter,
|
"data-bs-subject-commonname",
|
||||||
notbefore,
|
);
|
||||||
issuerorganizationunit,
|
preview.querySelector("#raw").innerHTML = recipient.replace(
|
||||||
issuerorganization,
|
/\n/g,
|
||||||
issuercommonname,
|
"<br>",
|
||||||
);
|
);
|
||||||
preview.querySelector("#raw").innerHTML = recipient.replace(/\n/g, "<br>");
|
preview.querySelector("#dnsNames").value = dnsnames;
|
||||||
preview.querySelector("#dnsNames").value = dnsnames;
|
preview.querySelector("#notAfter").value = notafter;
|
||||||
preview.querySelector("#notAfter").value = notafter;
|
preview.querySelector("#notBefore").value = notbefore;
|
||||||
preview.querySelector("#notBefore").value = notbefore;
|
preview.querySelector("#issuerorganizationunit").value =
|
||||||
preview.querySelector("#issuerorganizationunit").value =
|
issuerorganizationunit;
|
||||||
issuerorganizationunit;
|
preview.querySelector("#issuerorganization").value = issuerorganization;
|
||||||
preview.querySelector("#issuerorganization").value = issuerorganization;
|
preview.querySelector("#issuercommonname").value = issuercommonname;
|
||||||
preview.querySelector("#issuercommonname").value = issuercommonname;
|
preview.querySelector("#subjectorganizationunit").value =
|
||||||
preview.querySelector("#subjectorganizationunit").value =
|
subjectorganizationunit;
|
||||||
subjectorganizationunit;
|
preview.querySelector("#subjectorganization").value =
|
||||||
preview.querySelector("#subjectorganization").value = subjectorganization;
|
subjectorganization;
|
||||||
preview.querySelector("#subjectcommonname").value = subjectcommonname;
|
preview.querySelector("#subjectcommonname").value = subjectcommonname;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cards.addEventListener("click", (e) => {
|
cards.addEventListener("click", (e) => {
|
||||||
if (e.target.classList.contains("delcert")) {
|
if (e.target.classList.contains("delcert")) {
|
||||||
certificates.splice(
|
if (confirm("Are you sure you want to delete this certificate?")) {
|
||||||
certificates.indexOf(
|
fetch(window.location.origin + `/api/certs/delete`, {
|
||||||
certificates.find((item) => item.id === parseInt(e.target.id)),
|
method: "POST",
|
||||||
),
|
headers: {
|
||||||
1,
|
"Content-Type": "application/json",
|
||||||
);
|
},
|
||||||
renderCards();
|
body: JSON.stringify({
|
||||||
}
|
domain: certificates.find((item) => item.id === e.target.id)
|
||||||
|
.domain,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((data) => data.json())
|
||||||
|
.then((jsondata) => {
|
||||||
|
if (jsondata.status === "success") {
|
||||||
|
getCerts();
|
||||||
|
alert("Certificate deleted successfully");
|
||||||
|
} else {
|
||||||
|
alert("Failed to delete certificate");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
alert("An error occurred while deleting the certificate");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
const domain = document.querySelector("#domain");
|
||||||
|
const commonname = document.querySelector("#commonname");
|
||||||
|
const organizationname = document.querySelector("#organizationname");
|
||||||
|
const password = document.querySelector("#password");
|
||||||
|
const organizationunit = document.querySelector("#organizationunit");
|
||||||
|
const createcert = document.querySelector("#createcert");
|
||||||
|
|
||||||
|
createcert.addEventListener("click", () => {
|
||||||
|
const domainValue = domain.value;
|
||||||
|
const commonnameValue = commonname.value;
|
||||||
|
const organizationnameValue = organizationname.value;
|
||||||
|
const passwordValue = password.value;
|
||||||
|
const organizationunitValue = organizationunit.value;
|
||||||
|
|
||||||
|
fetch(window.location.origin + "/api/certs/create", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
dns: [domainValue],
|
||||||
|
commonname: commonnameValue,
|
||||||
|
organizationname: [organizationnameValue],
|
||||||
|
organizationunit: [organizationunitValue],
|
||||||
|
password: passwordValue,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((data) => data.json())
|
||||||
|
.then((jsondata) => {
|
||||||
|
if (jsondata.status === "success") {
|
||||||
|
getCerts();
|
||||||
|
var createmodal = bootstrap.Modal.getOrCreateInstance(
|
||||||
|
document.getElementById("create_certificate"),
|
||||||
|
);
|
||||||
|
createmodal.hide();
|
||||||
|
alert("Certificate created successfully");
|
||||||
|
} else {
|
||||||
|
alert("Failed to create certificate:", jsondata.error);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
alert("An error occurred:", error);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -5,4 +5,7 @@ go 1.24.5
|
|||||||
require (
|
require (
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require golang.org/x/crypto v0.22.0 // indirect
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ func main() {
|
|||||||
|
|
||||||
http.Handle("/", api.SpaHandler(http.FS(api.Frontend)))
|
http.Handle("/", api.SpaHandler(http.FS(api.Frontend)))
|
||||||
http.HandleFunc("/api/certs", api.Certs)
|
http.HandleFunc("/api/certs", api.Certs)
|
||||||
|
http.HandleFunc("/api/certs/create", api.CreateCert)
|
||||||
|
http.HandleFunc("/api/certs/delete", api.DeleteCert)
|
||||||
|
|
||||||
if os.Getenv("ENABLE_TLS") == "true" {
|
if os.Getenv("ENABLE_TLS") == "true" {
|
||||||
e := http.ListenAndServeTLS(
|
e := http.ListenAndServeTLS(
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type CreateCertificateRequest struct {
|
||||||
|
CommonName string `json:"commonname"`
|
||||||
|
OrganizationName []string `json:"organizationname"`
|
||||||
|
OrganizationUnit []string `json:"organizationunit"`
|
||||||
|
DNSNames []string `json:"dns"`
|
||||||
|
CAKeyPassword string `json:"password"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type DeleteCertRequest struct {
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user