mirror of
https://github.com/outbackdingo/labca.git
synced 2026-01-27 10:19:34 +00:00
Add options to trigger CRL generation and upload a Root CRL (#53)
This commit is contained in:
9
checkcrl
9
checkcrl
@@ -2,6 +2,15 @@
|
||||
|
||||
set -e
|
||||
|
||||
if [ -e data/root-ca.crl ] && [ ! -e /var/www/html/crl/root-ca.crl ]; then
|
||||
cp -p data/root-ca.crl /var/www/html/crl/root-ca.crl
|
||||
touch /var/www/html/crl
|
||||
fi
|
||||
if [ -e data/root-ca.crl ] && [ data/root-ca.crl -nt /var/www/html/crl/root-ca.crl ]; then
|
||||
cp -p data/root-ca.crl /var/www/html/crl/root-ca.crl
|
||||
touch /var/www/html/crl
|
||||
fi
|
||||
|
||||
cd /var/www/html
|
||||
if [ crl/ -nt certs/index.html ]; then
|
||||
echo "Updating certs/index.html with latest CRL info..."
|
||||
|
||||
@@ -239,6 +239,14 @@ case $txt in
|
||||
nohup /labca/install -b $branch &>>$LOGFILE
|
||||
fi
|
||||
;;
|
||||
"gen-issuer-crl")
|
||||
cd /opt/boulder
|
||||
docker compose exec -i boulder ./bin/boulder crl-updater --config labca/config/crl-updater.json -runOnce -debug-addr :18021 &>>$LOGFILE
|
||||
/opt/labca/checkcrl &>>$LOGFILE
|
||||
;;
|
||||
"check-crl")
|
||||
/opt/labca/checkcrl &>>$LOGFILE
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command '$txt'. ERROR!"
|
||||
exit 1
|
||||
|
||||
@@ -183,6 +183,9 @@ rm -f test-root.p8
|
||||
|
||||
if [ -e $PKI_INT_CERT_BASE.key ]; then
|
||||
cp -p $PKI_INT_CERT_BASE.key test-ca.key
|
||||
if [ ! -e $PKI_INT_CERT_BASE.key.der ]; then
|
||||
openssl pkey -in $PKI_INT_CERT_BASE.key -out $PKI_INT_CERT_BASE.key.der -outform der
|
||||
fi
|
||||
cp -p $PKI_INT_CERT_BASE.key.der test-ca.key.der
|
||||
cp -p $PKI_INT_CERT_BASE.pem test-ca.pem
|
||||
openssl rsa -in $PKI_INT_CERT_BASE.key -pubout > test-ca.pubkey.pem 2>/dev/null || openssl ec -in $PKI_INT_CERT_BASE.key -pubout > test-ca.pubkey.pem
|
||||
@@ -190,6 +193,9 @@ if [ -e $PKI_INT_CERT_BASE.key ]; then
|
||||
fi
|
||||
if [ -e $PKI_ROOT_CERT_BASE.key ]; then
|
||||
cp -p $PKI_ROOT_CERT_BASE.key test-root.key
|
||||
if [ ! -e $PKI_ROOT_CERT_BASE.key.der ]; then
|
||||
openssl pkey -in $PKI_ROOT_CERT_BASE.key -out $PKI_ROOT_CERT_BASE.key.der -outform der
|
||||
fi
|
||||
cp -p $PKI_ROOT_CERT_BASE.key.der test-root.key.der
|
||||
openssl rsa -in $PKI_ROOT_CERT_BASE.key -pubout > test-root.pubkey.pem 2>/dev/null || openssl ec -in $PKI_ROOT_CERT_BASE.key -pubout > test-root.pubkey.pem
|
||||
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in test-root.key -out test-root.p8
|
||||
|
||||
@@ -664,7 +664,6 @@ func (ci *CertificateInfo) Create(path string, certBase string, wasCSR bool) err
|
||||
keyFileExists = false
|
||||
}
|
||||
if keyFileExists {
|
||||
// TODO: make option in GUI to trigger crl creation!
|
||||
if _, err := exeCmd("openssl ca -config " + path + "openssl.cnf -gencrl -keyfile " + path + certBase + ".key -cert " + path + certBase + ".pem -out " + path + certBase + ".crl"); err != nil {
|
||||
return reportError(err)
|
||||
}
|
||||
|
||||
126
gui/main.go
126
gui/main.go
@@ -1039,6 +1039,95 @@ func _checkUpdatesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(w).Encode(res)
|
||||
}
|
||||
|
||||
func generateCRLHandler(w http.ResponseWriter, r *http.Request, isRoot bool) {
|
||||
res := struct {
|
||||
Success bool
|
||||
Errors map[string]string
|
||||
}{Success: true, Errors: make(map[string]string)}
|
||||
|
||||
if isRoot {
|
||||
path := "data/"
|
||||
certBase := "root-ca"
|
||||
keyFileExists := true
|
||||
if _, err := os.Stat(path + certBase + ".key"); os.IsNotExist(err) {
|
||||
keyFileExists = false
|
||||
}
|
||||
if keyFileExists {
|
||||
if _, err := exeCmd("openssl ca -config " + path + "openssl.cnf -gencrl -keyfile " + path + certBase + ".key -cert " + path + certBase + ".pem -out " + path + certBase + ".crl"); err != nil {
|
||||
res.Success = false
|
||||
res.Errors["CRL"] = "Could not generate Root CRL - see logs"
|
||||
}
|
||||
} else {
|
||||
if r.Form.Get("rootkey") == "" {
|
||||
res.Success = false
|
||||
res.Errors["CRL"] = "NO_ROOT_KEY"
|
||||
} else {
|
||||
rootci := &CertificateInfo{
|
||||
IsRoot: true,
|
||||
Key: r.Form.Get("rootkey"),
|
||||
Passphrase: r.Form.Get("rootpassphrase"),
|
||||
}
|
||||
if !rootci.StoreRootKey(path) {
|
||||
res.Success = false
|
||||
res.Errors["CRL"] = rootci.Errors["Modal"]
|
||||
} else {
|
||||
// Generate CRL now that we have the key
|
||||
if _, err := exeCmd("openssl ca -config " + path + "openssl.cnf -gencrl -keyfile " + path + certBase + ".key -cert " + path + certBase + ".pem -out " + path + certBase + ".crl"); err != nil {
|
||||
res.Success = false
|
||||
res.Errors["CRL"] = "Could not generate Root CRL - see logs"
|
||||
}
|
||||
// Remove the Root Key if we want to keep it offline
|
||||
if viper.GetBool("keep_root_offline") {
|
||||
if _, err := os.Stat(path + certBase + ".key"); !os.IsNotExist(err) {
|
||||
fmt.Println("Removing private Root key from the system...")
|
||||
if _, err := exeCmd("rm " + path + certBase + ".key"); err != nil {
|
||||
log.Printf("_certCreate: error deleting root key: %v", err)
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(path + certBase + ".key.der"); !os.IsNotExist(err) {
|
||||
if _, err := exeCmd("rm " + path + certBase + ".key.der"); err != nil {
|
||||
log.Printf("_certCreate: error deleting root key (DER format): %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_hostCommand(w, r, "check-crl")
|
||||
|
||||
} else { // !isRoot
|
||||
if !_hostCommand(w, r, "gen-issuer-crl") {
|
||||
res.Success = false
|
||||
res.Errors["CRL"] = "Failed to generate CRL - see logs"
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(res)
|
||||
}
|
||||
|
||||
func uploadCRLHandler(w http.ResponseWriter, r *http.Request) {
|
||||
res := struct {
|
||||
Success bool
|
||||
Errors map[string]string
|
||||
}{Success: true, Errors: make(map[string]string)}
|
||||
|
||||
rootci := &CertificateInfo{
|
||||
IsRoot: true,
|
||||
CRL: r.Form.Get("crl"),
|
||||
}
|
||||
if !rootci.StoreCRL("data/") {
|
||||
res.Success = false
|
||||
res.Errors["CRL"] = rootci.Errors["Modal"]
|
||||
}
|
||||
|
||||
_hostCommand(w, r, "check-crl")
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(res)
|
||||
}
|
||||
|
||||
func _managePostDispatch(w http.ResponseWriter, r *http.Request, action string) bool {
|
||||
if action == "backup-restore" || action == "backup-delete" || action == "backup-now" {
|
||||
_backupHandler(w, r)
|
||||
@@ -1080,6 +1169,21 @@ func _managePostDispatch(w http.ResponseWriter, r *http.Request, action string)
|
||||
return true
|
||||
}
|
||||
|
||||
if action == "upload-root-crl" {
|
||||
uploadCRLHandler(w, r)
|
||||
return true
|
||||
}
|
||||
|
||||
if action == "gen-root-crl" {
|
||||
generateCRLHandler(w, r, true)
|
||||
return true
|
||||
}
|
||||
|
||||
if action == "gen-issuer-crl" {
|
||||
generateCRLHandler(w, r, false)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1113,6 +1217,9 @@ func _managePost(w http.ResponseWriter, r *http.Request) {
|
||||
"send-email",
|
||||
"version-check",
|
||||
"version-update",
|
||||
"upload-root-crl",
|
||||
"gen-root-crl",
|
||||
"gen-issuer-crl",
|
||||
} {
|
||||
if a == action {
|
||||
actionKnown = true
|
||||
@@ -1599,7 +1706,8 @@ func _certCreate(w http.ResponseWriter, r *http.Request, certBase string, isRoot
|
||||
|
||||
if r.Form.Get("revertroot") != "" {
|
||||
// From issuer certificate creation page it is possible to remove the root again and start over
|
||||
exeCmd("rm data/root-ca.key") // Does not necessarily exist
|
||||
exeCmd("rm data/root-ca.key") // Does not necessarily exist
|
||||
exeCmd("rm data/root-ca.key.der") // Does not necessarily exist
|
||||
if _, err := exeCmd("rm data/root-ca.pem"); err != nil {
|
||||
errorHandler(w, r, err, http.StatusInternalServerError)
|
||||
return false
|
||||
@@ -1614,13 +1722,8 @@ func _certCreate(w http.ResponseWriter, r *http.Request, certBase string, isRoot
|
||||
}
|
||||
} else if r.Form.Get("ack-rootkey") == "yes" {
|
||||
// Root Key was shown, do we need to keep it online?
|
||||
if r.Form.Get("keep-root-online") == "true" {
|
||||
sess, _ := sessionStore.Get(r, "labca")
|
||||
sess.Values["root-online"] = true
|
||||
if err := sess.Save(r, w); err != nil {
|
||||
log.Printf("cannot save session: %s\n", err)
|
||||
}
|
||||
}
|
||||
viper.Set("keep_root_offline", r.Form.Get("keep-root-online") != "true")
|
||||
viper.WriteConfig()
|
||||
|
||||
// Undo what setupHandler did when showing the public key...
|
||||
_, errPem := os.Stat("data/root-ca.pem")
|
||||
@@ -1792,13 +1895,18 @@ func _certCreate(w http.ResponseWriter, r *http.Request, certBase string, isRoot
|
||||
log.Printf("_certCreate: could not calculate IssuerNameID: %v", err)
|
||||
}
|
||||
|
||||
if session.Values["root-online"] != true {
|
||||
if viper.GetBool("keep_root_offline") {
|
||||
if _, err := os.Stat(path + "../root-ca.key"); !os.IsNotExist(err) {
|
||||
fmt.Println("Removing private Root key from the system...")
|
||||
if _, err := exeCmd("rm " + path + "../root-ca.key"); err != nil {
|
||||
log.Printf("_certCreate: error deleting root key: %v", err)
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(path + "../root-ca.key.der"); !os.IsNotExist(err) {
|
||||
if _, err := exeCmd("rm " + path + "../root-ca.key.der"); err != nil {
|
||||
log.Printf("_certCreate: error deleting root key (DER format): %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
step, we will delete the key from the system.<br/>
|
||||
When we need the key for certain operations in the future, we will ask for it.</p>
|
||||
<textarea class="form-control" rows="10" cols="80" readonly>{{ .RootKey }}</textarea>
|
||||
<input type="checkbox" id="modal-keep-root-online"> Keep the root key on the LabCA server (UNSAFE)<br/>
|
||||
<input type="checkbox" id="modal-keep-root-online"> Keep the root key on the LabCA server (INSECURE)<br/>
|
||||
{{ with .CertificateInfo.Errors.Modal }}
|
||||
<span class="error">{{ . }}</span><br/>
|
||||
{{ end }}
|
||||
@@ -199,7 +199,7 @@
|
||||
{{ if .GetRootKey }}
|
||||
<div id="modal-root-key" class="modal fade" data-backdrop="static" data-keyboard="false" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content modal-csr-content">
|
||||
<div class="modal-content modal-root-key-content">
|
||||
<h4>Root Key Required</h4>
|
||||
<p>Please provide the Root CA key file in PEM format. As soon as we are done with it, it will be removed from the system again.</p>
|
||||
<textarea class="form-control" id="modal-rootkey" rows="10" cols="80"></textarea>
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
<li class="">
|
||||
<a data-toggle="tab" href="#certs">Certificates</a>
|
||||
</li>
|
||||
<li class="">
|
||||
<a data-toggle="tab" href="#crls">CRLs</a>
|
||||
</li>
|
||||
<li class="">
|
||||
<a data-toggle="tab" href="#config">Config</a>
|
||||
</li>
|
||||
@@ -155,7 +158,12 @@
|
||||
<br/>
|
||||
<form role="form">
|
||||
<div class="form-group">
|
||||
<label for="root-cb">Export content:</label><br/>
|
||||
<p><b>Download certificates:</b><br/>
|
||||
<a href="/certs/root-ca.der">root-ca.der</a> | <a href="/certs/root-ca.pem">root-ca.pem</a><br/>
|
||||
<a href="/certs/ca-int.der">ca-int.der</a> | <a href="/certs/ca-int.pem">ca-int.pem</a>
|
||||
<hr></p>
|
||||
|
||||
<label for="root-cb">Export certificates + keys:</label><br/>
|
||||
<input type="checkbox" class="export-cb" id="root-cb" value="root"></input>
|
||||
Root Certificate (<a href="#" data-toggle="collapse" data-target="#root-details" title="View Root Certificate details"><small>Details </small><i class="fa fa-fw fa-eye" id="root-show"></i><i class="fa fa-fw fa-eye-slash hidden" id="root-hide"></i></a>)
|
||||
<pre id="root-details" class="collapse">{{ .RootDetails }}</pre>
|
||||
@@ -187,6 +195,33 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="crls">
|
||||
<br/>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-6 col-sm-8">
|
||||
<table class="table table-bordered mb15 p48">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="vmiddle">Root CRL</td>
|
||||
<td class="vmiddle">
|
||||
<button class="btn btn-outline btn-success mt5" type="button" id="gen-root-crl" title="Generate root CRL now (requires Root CA key)">Generate</button>
|
||||
<button class="btn btn-outline btn-success mt5" type="button" id="upload-root-crl" title="Upload a root CRL">Upload</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="vmiddle">Issuer CRL</td>
|
||||
<td class="vmiddle">
|
||||
<button class="btn btn-outline btn-success mt5" type="button" id="gen-issuer-crl" title="Generate root CRL now (requires Root CA key)">Generate</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<span class="hidden" id="root-crl-result"></span>
|
||||
<span class="hidden" id="issuer-crl-result"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="config">
|
||||
<br/>
|
||||
<form role="form">
|
||||
@@ -334,6 +369,40 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-root-key" class="modal fade" data-backdrop="static" data-keyboard="false" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content modal-root-key-content">
|
||||
<h4>Root Key Required</h4>
|
||||
<p>Please provide the Root CA key file in PEM format. As soon as we are done with it, it will be removed from the system again.</p>
|
||||
<textarea class="form-control" id="modal-rootkey" rows="10" cols="80" required></textarea>
|
||||
<div class="form-group">
|
||||
<label for="modal-rootpassphrase">Passphrase (optional):</label>
|
||||
<input class="form-control" type="password" id="modal-rootpassphrase" value="">
|
||||
</div>
|
||||
{{ with .CertificateInfo.Errors.Modal }}
|
||||
<span class="error">{{ . }}</span><br/>
|
||||
{{ end }}
|
||||
<input class="btn btn-default btn-reg" value="Upload" id="modal-root-key-upload"/>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" id="cancel-rootkey">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-crl" class="modal fade" data-backdrop="static" data-keyboard="false" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content modal-crl-content">
|
||||
<h4>CRL</h4>
|
||||
<p>Please provide the CRL for the Root CA.</p>
|
||||
<textarea class="form-control" id="modal-crl-val" rows="10" cols="80" required>{{ .CRL }}</textarea>
|
||||
{{ with .CertificateInfo.Errors.Modal }}
|
||||
<span class="error">{{ . }}</span><br/>
|
||||
{{ end }}
|
||||
<input class="btn btn-default btn-reg" value="OK" id="modal-crl-done"/>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" id="cancel-crl">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{ define "tail" }}
|
||||
@@ -385,6 +454,8 @@
|
||||
$(".email-error").hide();
|
||||
$("#update-email-result").hide();
|
||||
$("#send-email-result").hide();
|
||||
$("#root-crl-result").hide();
|
||||
$("#issuer-crl-result").hide();
|
||||
|
||||
if ( $(evt.target).attr("id") == "backup-now") {
|
||||
$.ajax(window.location.href, {
|
||||
@@ -778,6 +849,128 @@
|
||||
$('#modal-spinner').modal('hide');
|
||||
});
|
||||
|
||||
} else if ( $(evt.target).attr("id") == "gen-issuer-crl") {
|
||||
$.ajax(window.location.href, {
|
||||
method: "POST",
|
||||
data: {
|
||||
action: $(evt.target).attr("id"),
|
||||
},
|
||||
})
|
||||
.done(function(data) {
|
||||
$('#modal-spinner').modal('hide');
|
||||
|
||||
if (data.Success) {
|
||||
var msg = "Successfully generated Issuer CRL.<br/>";
|
||||
$("#issuer-crl-result").removeClass("hidden").removeClass("error").show().html(msg).addClass("success");
|
||||
|
||||
} else {
|
||||
console.log("***DEBUG*** 1 ", data);
|
||||
$("#issuer-crl-result").removeClass("hidden").removeClass("success").show().text(data.Errors["CRL"]).addClass("error");
|
||||
}
|
||||
})
|
||||
.fail(function(xhr, status, err) {
|
||||
$('#modal-spinner').modal('hide');
|
||||
$("#issuer-crl-result").removeClass("hidden").removeClass("success").show().html(err + "<br/>").addClass("error");
|
||||
});
|
||||
|
||||
} else if ( $(evt.target).attr("id") == "gen-root-crl") {
|
||||
$('#modal-root-key').modal('hide');
|
||||
$.ajax(window.location.href, {
|
||||
method: "POST",
|
||||
data: {
|
||||
action: $(evt.target).attr("id"),
|
||||
},
|
||||
})
|
||||
.done(function(data) {
|
||||
$('#modal-spinner').modal('hide');
|
||||
|
||||
if (data.Success) {
|
||||
var msg = "Successfully generated Root CRL.<br/>";
|
||||
$("#root-crl-result").removeClass("hidden").removeClass("error").show().html(msg).addClass("success");
|
||||
|
||||
} else if (data.Errors["CRL"] == "NO_ROOT_KEY") {
|
||||
$('#modal-root-key').modal('show');
|
||||
return false;
|
||||
|
||||
} else {
|
||||
console.log("***DEBUG*** 2 ", data);
|
||||
$("#root-crl-result").removeClass("hidden").removeClass("success").show().text(data.Errors["CRL"]).addClass("error");
|
||||
}
|
||||
})
|
||||
.fail(function(xhr, status, err) {
|
||||
$('#modal-spinner').modal('hide');
|
||||
$("#root-crl-result").removeClass("hidden").removeClass("success").show().html(err + "<br/>").addClass("error");
|
||||
});
|
||||
|
||||
} else if ( $(evt.target).attr("id") == "modal-root-key-upload") {
|
||||
$('#modal-root-key').modal('hide');
|
||||
$.ajax(window.location.href, {
|
||||
method: "POST",
|
||||
data: {
|
||||
action: 'gen-root-crl',
|
||||
rootkey: $("#modal-rootkey").val(),
|
||||
rootpassphrase: $("#modal-rootpassphrase").val(),
|
||||
},
|
||||
})
|
||||
.done(function(data) {
|
||||
$('#modal-spinner').modal('hide');
|
||||
$('.modal-backdrop').remove();
|
||||
|
||||
if (data.Success) {
|
||||
var msg = "Successfully generated Root CRL.<br/>";
|
||||
$("#root-crl-result").removeClass("hidden").removeClass("error").show().html(msg).addClass("success");
|
||||
|
||||
} else if (data.Errors["CRL"] == "NO_ROOT_KEY") {
|
||||
$('#modal-root-key').modal('show');
|
||||
return false;
|
||||
|
||||
} else {
|
||||
console.log("***DEBUG*** 3 ", data);
|
||||
$("#root-crl-result").removeClass("hidden").removeClass("success").show().text(data.Errors["CRL"]).addClass("error");
|
||||
}
|
||||
})
|
||||
.fail(function(xhr, status, err) {
|
||||
$('#modal-spinner').modal('hide');
|
||||
$("#root-crl-result").removeClass("hidden").removeClass("success").show().html(err + "<br/>").addClass("error");
|
||||
});
|
||||
|
||||
} else if ( $(evt.target).attr("id") == "upload-root-crl") {
|
||||
$('#modal-spinner').modal('hide');
|
||||
$('#modal-crl').modal('show');
|
||||
return false;
|
||||
|
||||
} else if ( $(evt.target).attr("id") == "modal-crl-done") {
|
||||
$('#modal-crl').modal('hide');
|
||||
$.ajax(window.location.href, {
|
||||
method: "POST",
|
||||
data: {
|
||||
action: 'upload-root-crl',
|
||||
crl: $("#modal-crl-val").val(),
|
||||
},
|
||||
})
|
||||
.done(function(data) {
|
||||
$('#modal-spinner').modal('hide');
|
||||
|
||||
if (data.Success) {
|
||||
var msg = "Successfully uploaded Root CRL.<br/>";
|
||||
$("#root-crl-result").removeClass("hidden").removeClass("error").show().html(msg).addClass("success");
|
||||
|
||||
} else {
|
||||
console.log("***DEBUG*** 4 ", data);
|
||||
$("#root-crl-result").removeClass("hidden").removeClass("success").show().text(data.Errors["CRL"]).addClass("error");
|
||||
}
|
||||
})
|
||||
.fail(function(xhr, status, err) {
|
||||
$('#modal-spinner').modal('hide');
|
||||
$("#root-crl-result").removeClass("hidden").removeClass("success").show().html(err + "<br/>").addClass("error");
|
||||
});
|
||||
|
||||
} else if ( $(evt.target).attr("id") == "cancel-rootkey" || $(evt.target).attr("id") == "cancel-crl") {
|
||||
$('#modal-spinner').modal('hide');
|
||||
$('#modal-crl').modal('hide');
|
||||
$('#modal-root-key').modal('hide');
|
||||
return false;
|
||||
|
||||
} else {
|
||||
$.ajax(window.location.href, {
|
||||
method: "POST",
|
||||
|
||||
Reference in New Issue
Block a user