Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Fix WASM `certkitInspect` missing timeout and panic recovery — add 30s context timeout and `recover()` to prevent unhandled goroutine panics ([`2b8cb8c`])
- Fix `showStatus` style leak in web UI — error-red text color persisted after a subsequent processing status update ([`2b8cb8c`])
- Fix `ekuOIDNames` missing Microsoft Server Gated Crypto and Netscape Server Gated Crypto OIDs — CSR EKU display now matches certificate EKU display ([`2b8cb8c`])
- Fix AIA `progressTotal` double-counting certs whose issuer fetch fails — the same cert appeared in both `processed` and `queue` sets, inflating the progress bar total ([#64])

### Tests

- Add tests for all `dn.go` exported functions: `FormatEKUs`, `FormatEKUOIDs`, `FormatKeyUsage`, `FormatKeyUsageBitString`, `ParseOtherNameSANs`, and `FormatDN` certificate round-trip (31 test cases) ([`2b8cb8c`])
- Add tests for `ResolveInspectAIA` — no-certs passthrough, all-resolved passthrough, intermediate fetching, fetcher errors, and deduplication ([`2b8cb8c`])
- Add tests for CSR extension parsing — Key Usage and Extended Key Usage extraction from raw ASN.1 extensions ([`2b8cb8c`])

## [0.8.0] - 2026-02-22

### Added
Expand Down Expand Up @@ -586,6 +595,7 @@ Initial release.
[0.1.1]: https://github.com/sensiblebit/certkit/compare/v0.1.0...v0.1.1
[0.1.0]: https://github.com/sensiblebit/certkit/releases/tag/v0.1.0

[`2b8cb8c`]: https://github.com/sensiblebit/certkit/commit/2b8cb8c
[`392878a`]: https://github.com/sensiblebit/certkit/commit/392878a
[`e70e8e5`]: https://github.com/sensiblebit/certkit/commit/e70e8e5
[`0fa55af`]: https://github.com/sensiblebit/certkit/commit/0fa55af
Expand Down
22 changes: 17 additions & 5 deletions cmd/wasm/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ package main
import (
"context"
"encoding/json"
"fmt"
"log/slog"
"strings"
"syscall/js"
"time"

"github.com/sensiblebit/certkit"
"github.com/sensiblebit/certkit/internal"
Expand Down Expand Up @@ -38,6 +41,12 @@ func inspectFiles(_ js.Value, args []js.Value) any {
resolve := promiseArgs[0]
reject := promiseArgs[1]
go func() {
defer func() {
if r := recover(); r != nil {
reject.Invoke(js.Global().Get("Error").New(fmt.Sprintf("internal error: %v", r)))
}
}()

var allResults []internal.InspectResult
for i := range length {
file := filesArg.Index(i)
Expand All @@ -55,14 +64,16 @@ func inspectFiles(_ js.Value, args []js.Value) any {
}

// Resolve missing intermediates via AIA before trust annotation.
ctx := context.Background()
allResults, _ = internal.ResolveInspectAIA(ctx, allResults, jsFetchURL)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
allResults, aiaWarnings := internal.ResolveInspectAIA(ctx, allResults, jsFetchURL)
for _, w := range aiaWarnings {
slog.Warn("AIA resolution", "warning", w)
}

// Annotate trust for certificates.
if err := internal.AnnotateInspectTrust(allResults); err != nil {
// Non-fatal: trust annotation failure just means
// Expired/Trusted fields won't be set.
_ = err
slog.Debug("trust annotation failed", "error", err)
}

jsonBytes, err := json.Marshal(allResults)
Expand All @@ -74,6 +85,7 @@ func inspectFiles(_ js.Value, args []js.Value) any {
}()
return nil
})
// Promise.New calls the executor synchronously; release immediately after.
p := js.Global().Get("Promise").New(handler)
handler.Release()
return p
Expand Down
16 changes: 9 additions & 7 deletions dn.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ func FormatEKUs(ekus []x509.ExtKeyUsage) []string {
// Used for parsing EKU from raw ASN.1 extensions (e.g. in CSRs where Go
// does not populate typed fields).
var ekuOIDNames = map[string]string{
"1.3.6.1.5.5.7.3.1": "Server Authentication",
"1.3.6.1.5.5.7.3.2": "Client Authentication",
"1.3.6.1.5.5.7.3.3": "Code Signing",
"1.3.6.1.5.5.7.3.4": "Email Protection",
"1.3.6.1.5.5.7.3.8": "Time Stamping",
"1.3.6.1.5.5.7.3.9": "OCSP Signing",
"2.5.29.37.0": "Any",
"1.3.6.1.5.5.7.3.1": "Server Authentication",
"1.3.6.1.5.5.7.3.2": "Client Authentication",
"1.3.6.1.5.5.7.3.3": "Code Signing",
"1.3.6.1.5.5.7.3.4": "Email Protection",
"1.3.6.1.5.5.7.3.8": "Time Stamping",
"1.3.6.1.5.5.7.3.9": "OCSP Signing",
"1.3.6.1.4.1.311.10.3.3": "Microsoft Server Gated Crypto",
"2.16.840.1.113730.4.1": "Netscape Server Gated Crypto",
"2.5.29.37.0": "Any",
}

// FormatEKUOIDs returns human-readable names for EKU OIDs extracted from
Expand Down
Loading