From c72ca7874738bb519d59f9458153f1d3368439c0 Mon Sep 17 00:00:00 2001 From: Robin Thellend Date: Thu, 12 Dec 2024 09:35:59 -0800 Subject: [PATCH 1/5] Simplify the PKI client-side code and remove the service worker. --- CHANGELOG.md | 6 + proxy/internal/pki/certs.html | 7 +- proxy/internal/pki/certs.js | 79 ++++++------- proxy/internal/pki/clientwasm/impl/impl.go | 70 ++++++----- .../internal/pki/clientwasm/impl/impl_test.go | 19 +-- proxy/internal/pki/clientwasm/main.go | 109 ++++++++---------- proxy/internal/pki/http.go | 2 +- proxy/internal/pki/style.css | 3 + proxy/internal/pki/sw.js | 88 -------------- 9 files changed, 146 insertions(+), 237 deletions(-) delete mode 100644 proxy/internal/pki/sw.js diff --git a/CHANGELOG.md b/CHANGELOG.md index ecdfabc..d78a086 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # TLSPROXY Release Notes +## next + +### :wrench: Misc + +* Simplify the PKI client-side code and remove the service worker. + ## v0.14.0 ### :star2: New feature diff --git a/proxy/internal/pki/certs.html b/proxy/internal/pki/certs.html index 3be7bae..c8c8bd8 100644 --- a/proxy/internal/pki/certs.html +++ b/proxy/internal/pki/certs.html @@ -6,6 +6,7 @@ + @@ -103,10 +104,10 @@

Option 1

Label:
DNS Name:
-
Password:
-
Re-type Password:
+
Password:
+
Re-type Password:
- +
diff --git a/proxy/internal/pki/certs.js b/proxy/internal/pki/certs.js index cab1f9f..afbb8fd 100644 --- a/proxy/internal/pki/certs.js +++ b/proxy/internal/pki/certs.js @@ -21,6 +21,20 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +'use strict'; + +window.pkiApp = {}; +pkiApp.ready = new Promise(resolve => { + pkiApp.pkiwasmIsReady = () => { + console.log('PKI WASM is ready'); + resolve(); + }; +}); + +const go = new Go(); +WebAssembly.instantiateStreaming(fetch('?get=static&file=pki.wasm.bz2'), go.importObject) + .then(r => go.run(r.instance)); + function requestCert(csr) { fetch('?get=requestCert', { method: 'POST', @@ -91,7 +105,8 @@ function hideForm() { document.getElementById('csrform').style.display = 'none'; window.location.reload(); } -function generateKeyAndCert(f) { +function generateKeyAndCert(b) { + let f = b.form; if (f.pw1.value.length < 6) { alert('Password must be at least 6 characters'); return; @@ -101,51 +116,29 @@ function generateKeyAndCert(f) { return; } const pw = f.pw1.value; - const fmt = f.format.value; - const kty = f.keytype.value; - const label = f.label.value; - const dns = f.dnsname.value; f.pw1.value = ''; f.pw2.value = ''; - const path = window.location.pathname + '/generateKeyAndCert'; - navigator.serviceWorker.register('?get=static&file=sw.js', {scope: path}) - .then(r => r.update()) - .then(r => { - console.log('Service worker ready'); - document.getElementById('csrform').style.display = 'none'; - const f = document.createElement('form'); - f.setAttribute('method', 'post'); - f.setAttribute('action', path); - let p = document.createElement('input'); - p.setAttribute('type', 'hidden'); - p.setAttribute('name', 'password'); - p.setAttribute('value', pw); - f.appendChild(p); - p = document.createElement('input'); - p.setAttribute('type', 'hidden'); - p.setAttribute('name', 'format'); - p.setAttribute('value', fmt); - f.appendChild(p); - p = document.createElement('input'); - p.setAttribute('type', 'hidden'); - p.setAttribute('name', 'keytype'); - p.setAttribute('value', kty); - f.appendChild(p); - p = document.createElement('input'); - p.setAttribute('type', 'hidden'); - p.setAttribute('name', 'label'); - p.setAttribute('value', label); - f.appendChild(p); - p = document.createElement('input'); - p.setAttribute('type', 'hidden'); - p.setAttribute('name', 'dnsname'); - p.setAttribute('value', dns); - f.appendChild(p); - document.body.appendChild(f); - f.submit(); - }) - .catch(err => console.error('Service worker update failed', err)) + + pkiApp.ready + .then(() => { + b.disabled = true; + document.body.classList.add('waiting'); + return pkiApp.getCertificate({ + 'keytype': f.keytype.value, + 'format': f.format.value, + 'password': pw, + 'label': f.label.value, + 'dnsname': f.dnsname.value, + }); + }) + .then(() => window.location.reload()) + .catch(err => { + b.disabled = false; + document.body.classList.remove('waiting'); + console.error('getCertificate failed', err); + }); } + function showView(sn) { fetch('?get=downloadCert&sn='+encodeURIComponent(sn)) .then(resp => { diff --git a/proxy/internal/pki/clientwasm/impl/impl.go b/proxy/internal/pki/clientwasm/impl/impl.go index 5e0989b..7efebcb 100644 --- a/proxy/internal/pki/clientwasm/impl/impl.go +++ b/proxy/internal/pki/clientwasm/impl/impl.go @@ -25,14 +25,16 @@ package impl import ( "bytes" - "crypto" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/hex" + "encoding/json" "encoding/pem" "errors" "fmt" + "io" + "net/http" "strings" "golang.org/x/crypto/openpgp" @@ -41,30 +43,40 @@ import ( "github.com/c2FmZQ/tlsproxy/proxy/internal/pki/keys" ) -var ( - privateKeys map[int]keyData -) - -type keyData struct { - key crypto.PrivateKey - format string - password string -} - -func MakeCSR(id int, keyType, format, label, dnsname, password string) ([]byte, error) { +func GetCertificate(url, keyType, format, label, dnsname, password string) (data []byte, contentType, filename string, err error) { privKey, err := keys.GenerateKey(keyType) if err != nil { - return nil, err + return nil, "", "", err + } + csr, err := makeCSR(privKey, label, dnsname) + if err != nil { + return nil, "", "", err + } + req, err := http.NewRequest("POST", url, bytes.NewReader(csr)) + if err != nil { + return nil, "", "", err + } + req.Header.Set("content-type", "application/x-pem-file") + req.Header.Set("x-csrf-check", "1") + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, "", "", err + } + defer resp.Body.Close() + var reqResult struct { + Cert string `json:"cert"` + Result string `json:"result"` } - if privateKeys == nil { - privateKeys = make(map[int]keyData) + if err := json.NewDecoder(&io.LimitedReader{R: resp.Body, N: 102400}).Decode(&reqResult); err != nil { + return nil, "", "", err } - privateKeys[id] = keyData{ - key: privKey, - format: format, - password: password, + if reqResult.Result != "ok" { + return nil, "", "", fmt.Errorf("result: %s", reqResult.Result) } + return makeResponse(privKey, []byte(reqResult.Cert), format, password) +} +func makeCSR(privKey any, label, dnsname string) ([]byte, error) { templ := &x509.CertificateRequest{ Subject: pkix.Name{CommonName: label}, } @@ -78,29 +90,25 @@ func MakeCSR(id int, keyType, format, label, dnsname, password string) ([]byte, return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: raw}), nil } -func MakeResponse(id int, pemCert string) ([]byte, string, string, error) { - block, _ := pem.Decode([]byte(pemCert)) +func makeResponse(privKey any, pemCert []byte, format, password string) ([]byte, string, string, error) { + block, _ := pem.Decode(pemCert) if block == nil || block.Type != "CERTIFICATE" { - return nil, "", "", errors.New("invalid pem certificate") + return nil, "", "", fmt.Errorf("invalid pem certificate: %q", pemCert) } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { return nil, "", "", errors.New("invalid certificate") } sn := hex.EncodeToString(cert.SerialNumber.Bytes()) - kd, ok := privateKeys[id] - if !ok { - return nil, "", "", errors.New("invalid id") - } - delete(privateKeys, id) - switch kd.format { + + switch format { case "gpg": - b, err := x509.MarshalPKCS8PrivateKey(kd.key) + b, err := x509.MarshalPKCS8PrivateKey(privKey) if err != nil { return nil, "", "", fmt.Errorf("x509.MarshalPKCS8PrivateKey: %v\n", err) } var buf bytes.Buffer - w, err := openpgp.SymmetricallyEncrypt(&buf, []byte(kd.password), &openpgp.FileHints{FileName: sn + ".pem", ModTime: cert.NotBefore}, nil) + w, err := openpgp.SymmetricallyEncrypt(&buf, []byte(password), &openpgp.FileHints{FileName: sn + ".pem", ModTime: cert.NotBefore}, nil) if err != nil { return nil, "", "", fmt.Errorf("openpgp.SymmetricallyEncrypt: %v\n", err) } @@ -117,7 +125,7 @@ func MakeResponse(id int, pemCert string) ([]byte, string, string, error) { case "p12": enc := pkcs12.Modern.WithIterations(250000) - p12, err := enc.Encode(kd.key, cert, nil, kd.password) + p12, err := enc.Encode(privKey, cert, nil, password) if err != nil { return nil, "", "", fmt.Errorf("pkcs12.Encode: %v", err) } diff --git a/proxy/internal/pki/clientwasm/impl/impl_test.go b/proxy/internal/pki/clientwasm/impl/impl_test.go index 2762710..484807c 100644 --- a/proxy/internal/pki/clientwasm/impl/impl_test.go +++ b/proxy/internal/pki/clientwasm/impl/impl_test.go @@ -32,10 +32,11 @@ import ( "math/big" "testing" "time" + + "github.com/c2FmZQ/tlsproxy/proxy/internal/pki/keys" ) func TestKeyTypeFormat(t *testing.T) { - count := 0 for _, tc := range []struct { keyType string format string @@ -50,10 +51,14 @@ func TestKeyTypeFormat(t *testing.T) { {keyType: "rsa-2048", format: "p12", contentType: "application/x-pkcs12", ext: ".p12"}, {keyType: "ed25519", format: "gpg", dnsName: "example.com", contentType: "application/octet-stream", ext: ".pem.gpg"}, } { - count++ - csrPEM, err := MakeCSR(count, tc.keyType, tc.format, tc.label, tc.dnsName, "foo") + privKey, err := keys.GenerateKey(tc.keyType) + if err != nil { + t.Fatalf("GenerateKey: %v", err) + } + + csrPEM, err := makeCSR(privKey, tc.label, tc.dnsName) if err != nil { - t.Fatalf("MakeCSR: %v", err) + t.Fatalf("makeCSR: %v", err) } block, _ := pem.Decode(csrPEM) if block == nil { @@ -68,7 +73,7 @@ func TestKeyTypeFormat(t *testing.T) { t.Fatalf("x509.ParseCertificateRequest: %v", err) } - _, privKey, err := ed25519.GenerateKey(rand.Reader) + _, caKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("ed25519.GenerateKey: %v", err) } @@ -86,13 +91,13 @@ func TestKeyTypeFormat(t *testing.T) { KeyUsage: x509.KeyUsageDataEncipherment | x509.KeyUsageDigitalSignature, BasicConstraintsValid: true, } - raw, err := x509.CreateCertificate(rand.Reader, templ, templ, cr.PublicKey, privKey) + raw, err := x509.CreateCertificate(rand.Reader, templ, templ, cr.PublicKey, caKey) if err != nil { t.Fatalf("x509.CreateCertificate: %v", err) } cert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: raw}) - _, contentType, fileName, err := MakeResponse(count, string(cert)) + _, contentType, fileName, err := makeResponse(privKey, cert, tc.format, "foo") if err != nil { t.Fatalf("MakeResponse: %v", err) } diff --git a/proxy/internal/pki/clientwasm/main.go b/proxy/internal/pki/clientwasm/main.go index 86a6b3d..e2cc5d8 100644 --- a/proxy/internal/pki/clientwasm/main.go +++ b/proxy/internal/pki/clientwasm/main.go @@ -29,17 +29,11 @@ package main import ( "fmt" - "net/url" "syscall/js" "github.com/c2FmZQ/tlsproxy/proxy/internal/pki/clientwasm/impl" ) -var ( - jsUint8Array = js.Global().Get("Uint8Array") - jsResponse = js.Global().Get("Response") -) - func main() { pkiApp := js.Global().Get("pkiApp") if pkiApp.Type() != js.TypeObject { @@ -49,74 +43,61 @@ func main() { if ready.Type() != js.TypeFunction { panic("pkiApp.pkiwasmIsReady not found") } - pkiApp.Set("makeCertificateRequest", js.FuncOf(makeCSR)) - pkiApp.Set("makeResponse", js.FuncOf(makeResponse)) + pkiApp.Set("getCertificate", js.FuncOf(getCertificate)) ready.Invoke() <-make(chan struct{}) } -func makeCSR(this js.Value, args []js.Value) any { - // arg0: id (a unique ID to match makeCSR with makeP12) - // arg2: application/x-www-form-urlencoded arguments - if len(args) != 2 || args[0].Type() != js.TypeNumber || args[1].Type() != js.TypeString { - fmt.Println("makeCertificateRequest: unexpected arguments") - return js.Undefined() - } - form, err := url.ParseQuery(args[1].String()) - if err != nil { - fmt.Printf("ParseQuery(%q): %v\n", args[1].String(), err) - return js.Undefined() - } - keyType := form.Get("keytype") - if keyType == "" { - keyType = "ecdsa-p256" - } - format := form.Get("format") - if format == "" { - format = "gpg" +func getCertificate(this js.Value, args []js.Value) (result any) { + defer func() { + switch v := result.(type) { + case error: + jsErr := js.Global().Get("Error").New(fmt.Sprintf("Start: %v", v)) + result = js.Global().Get("Promise").Call("reject", jsErr) + default: + } + }() + if len(args) != 1 || args[0].Type() != js.TypeObject { + return fmt.Errorf("getCertificate: unexpected arguments") } - password := form.Get("password") - if password == "" { - fmt.Println("password is missing") - return js.Undefined() - } - resp, err := impl.MakeCSR(args[0].Int(), keyType, format, form.Get("label"), form.Get("dnsname"), password) - if err != nil { - fmt.Println(err) - return js.Undefined() - } - return Uint8ArrayFromBytes(resp) -} + arg := args[0] + keyType := arg.Get("keytype").String() + format := arg.Get("format").String() + password := arg.Get("password").String() + label := arg.Get("label").String() + dnsName := arg.Get("dnsname").String() + url := js.Global().Get("location").Get("pathname").String() + "?get=requestCert" -func makeResponse(this js.Value, args []js.Value) any { - // arg0: id (the same id used with makeCSR) - // arg1: the pem-encoded cert - if len(args) != 2 || args[0].Type() != js.TypeNumber || args[1].Type() != js.TypeString { - fmt.Println("makeResponse: unexpected argument") - return js.Undefined() - } - body, contentType, fileName, err := impl.MakeResponse(args[0].Int(), args[1].String()) - if err != nil { - fmt.Println(err) - return js.Undefined() - } + return js.Global().Get("Promise").New(js.FuncOf( + func(this js.Value, args []js.Value) any { + resolve := args[0] + reject := args[1] + go func() { + data, contentType, filename, err := impl.GetCertificate(url, keyType, format, label, dnsName, password) + if err != nil { + reject.Invoke(js.Global().Get("Error").New(err.Error())) + return + } + opts := js.Global().Get("Object").New() + opts.Set("type", contentType) + blob := js.Global().Get("Blob").New(js.Global().Get("Array").New(Uint8ArrayFromBytes(data)), opts) - return jsResponse.New( - Uint8ArrayFromBytes(body), - js.ValueOf(map[string]any{ - "status": 200, - "statusText": "OK", - "headers": map[string]any{ - "content-type": contentType, - "content-disposition": `attachment; filename="` + fileName + `"`, - "cache-control": "private, no-store", - }, - }), - ) + a := js.Global().Get("document").Call("createElement", "a") + a.Set("href", js.Global().Get("URL").Call("createObjectURL", blob)) + a.Call("setAttribute", "download", js.ValueOf(filename)) + el := js.Global().Get("document").Get("body") + el.Call("appendChild", a) + a.Call("click") + el.Call("removeChild", a) + resolve.Invoke() + }() + return nil + }, + )) } func Uint8ArrayFromBytes(in []byte) js.Value { - out := jsUint8Array.New(js.ValueOf(len(in))) + out := js.Global().Get("Uint8Array").New(js.ValueOf(len(in))) js.CopyBytesToJS(out, in) return out } diff --git a/proxy/internal/pki/http.go b/proxy/internal/pki/http.go index dadb055..96164e0 100644 --- a/proxy/internal/pki/http.go +++ b/proxy/internal/pki/http.go @@ -52,7 +52,7 @@ import ( var embedCerts string var certsTemplate *template.Template -//go:embed certs.js sw.js style.css pki.wasm.bz2 wasm_exec.js +//go:embed certs.js style.css pki.wasm.bz2 wasm_exec.js var staticFiles embed.FS var staticEtags map[string]string diff --git a/proxy/internal/pki/style.css b/proxy/internal/pki/style.css index 8d3f76f..3abeb00 100644 --- a/proxy/internal/pki/style.css +++ b/proxy/internal/pki/style.css @@ -1,6 +1,9 @@ body { margin: 2rem; } +body.waiting, body.waiting a:hover, body.waiting * { + cursor: wait !important; +} h1 { font-size: 150%; } diff --git a/proxy/internal/pki/sw.js b/proxy/internal/pki/sw.js deleted file mode 100644 index 4966400..0000000 --- a/proxy/internal/pki/sw.js +++ /dev/null @@ -1,88 +0,0 @@ -// MIT License -// -// Copyright (c) 2023 TTBT Enterprises LLC -// Copyright (c) 2023 Robin Thellend -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -'use strict'; - -self.importScripts('?get=static&file=wasm_exec.js'); - -self.pkiApp = {}; -self.pkiApp.ready = new Promise(resolve => { - pkiApp.pkiwasmIsReady = () => { - console.log('PKI WASM is ready'); - resolve(); - }; -}); - -const go = new Go(); -WebAssembly.instantiateStreaming(fetch('?get=static&file=pki.wasm.bz2'), go.importObject) - .then(r => go.run(r.instance)); - -self.addEventListener('activate', event => { - event.waitUntil(self.clients.claim()); -}); - -self.addEventListener('fetch', event => { - if (event.request.method !== 'POST') { - throw new Error('unexpected method'); - } - event.respondWith(generateKeyAndCert(event.request.body)); -}); - -let keyCount = 0; -async function generateKeyAndCert(body) { - await self.pkiApp.ready; - const count = ++keyCount; - - const reader = body.getReader(); - const buf = []; - while (true) { - let {done, value} = await reader.read(); - if (value) buf.push(...value); - if (done) break; - } - const formdata = new TextDecoder().decode(new Uint8Array(buf)); - - console.log('Making CSR'); - const csr = self.pkiApp.makeCertificateRequest(count, formdata); - - console.log('Fetching Cert'); - const resp = await fetch('?get=requestCert', { - method: 'POST', - headers: { - 'content-type': 'application/x-pem-file', - 'x-csrf-check': '1', - }, - body: csr, - }); - if (resp.status !== 200 || resp.headers.get('content-type') !== 'application/json') { - console.log('response is not json', resp); - throw new Error('unexpected server response'); - } - const r = await resp.json(); - if (r.result !== 'ok') { - throw new Error('unexpected server response'); - } - - console.log('Package key and cert'); - return self.pkiApp.makeResponse(count, r.cert); -} From 33c0a1edb62e83d7da7a12f2985594b7dac50fd8 Mon Sep 17 00:00:00 2001 From: Robin Thellend Date: Thu, 12 Dec 2024 11:39:42 -0800 Subject: [PATCH 2/5] Load wasm only if needed. Select client/server. --- proxy/internal/pki/certs.html | 6 +++++- proxy/internal/pki/certs.js | 18 ++++++++++++++++-- proxy/internal/pki/style.css | 6 ++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/proxy/internal/pki/certs.html b/proxy/internal/pki/certs.html index c8c8bd8..619a3fe 100644 --- a/proxy/internal/pki/certs.html +++ b/proxy/internal/pki/certs.html @@ -103,7 +103,11 @@

Option 1

Label:
-
DNS Name:
+
Usage:
+
+
DNS Name:
Password:
Re-type Password:
diff --git a/proxy/internal/pki/certs.js b/proxy/internal/pki/certs.js index afbb8fd..19f1b8b 100644 --- a/proxy/internal/pki/certs.js +++ b/proxy/internal/pki/certs.js @@ -32,8 +32,7 @@ pkiApp.ready = new Promise(resolve => { }); const go = new Go(); -WebAssembly.instantiateStreaming(fetch('?get=static&file=pki.wasm.bz2'), go.importObject) - .then(r => go.run(r.instance)); +let wasmLoaded = false; function requestCert(csr) { fetch('?get=requestCert', { @@ -99,12 +98,23 @@ function downloadCert(sn) { window.location = '?get=downloadCert&sn='+encodeURIComponent(sn); } function showForm() { + if (!wasmLoaded) { + WebAssembly.instantiateStreaming(fetch('?get=static&file=pki.wasm.bz2'), go.importObject).then(r => go.run(r.instance)); + wasmLoaded = true; + } document.getElementById('csrform').style.display = 'block'; } function hideForm() { document.getElementById('csrform').style.display = 'none'; window.location.reload(); } +function selectUsage(e) { + const isServer = e.options[e.selectedIndex].value === 'server'; + for (const e of document.querySelectorAll('.dnsinput')) { + if (isServer) e.classList.add('selected'); + else e.classList.remove('selected'); + } +} function generateKeyAndCert(b) { let f = b.form; if (f.pw1.value.length < 6) { @@ -115,6 +125,10 @@ function generateKeyAndCert(b) { alert('Passwords don\'t match'); return; } + if (f.usage.options[f.usage.selectedIndex].value === 'server' && f.dnsname.value === '') { + alert('DNS Name is required'); + return; + } const pw = f.pw1.value; f.pw1.value = ''; f.pw2.value = ''; diff --git a/proxy/internal/pki/style.css b/proxy/internal/pki/style.css index 3abeb00..ba5bb82 100644 --- a/proxy/internal/pki/style.css +++ b/proxy/internal/pki/style.css @@ -101,3 +101,9 @@ textarea { .table2>div { padding: 0.25rem; } +.dnsinput { + display: none; +} +.dnsinput.selected { + display: block; +} From 87f9b2d283c6cd26cb30b9ecd98db586332085a4 Mon Sep 17 00:00:00 2001 From: Robin Thellend Date: Thu, 12 Dec 2024 11:43:41 -0800 Subject: [PATCH 3/5] sanity check --- proxy/internal/pki/http.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/internal/pki/http.go b/proxy/internal/pki/http.go index 96164e0..3d68d72 100644 --- a/proxy/internal/pki/http.go +++ b/proxy/internal/pki/http.go @@ -365,7 +365,7 @@ func (m *PKIManager) handleRequestCert(w http.ResponseWriter, req *http.Request) return } defer req.Body.Close() - body, err := io.ReadAll(req.Body) + body, err := io.ReadAll(io.LimitedReader{R: req.Body, N: 102400}) if err != nil { m.opts.Logger.Errorf("ERR body: %v", err) http.Error(w, "internal error", http.StatusInternalServerError) From c4a5a3db20fe1f1dd89514a4e9fce06c151acb71 Mon Sep 17 00:00:00 2001 From: Robin Thellend Date: Thu, 12 Dec 2024 11:46:33 -0800 Subject: [PATCH 4/5] oops --- proxy/internal/pki/http.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/internal/pki/http.go b/proxy/internal/pki/http.go index 3d68d72..14d6988 100644 --- a/proxy/internal/pki/http.go +++ b/proxy/internal/pki/http.go @@ -365,7 +365,7 @@ func (m *PKIManager) handleRequestCert(w http.ResponseWriter, req *http.Request) return } defer req.Body.Close() - body, err := io.ReadAll(io.LimitedReader{R: req.Body, N: 102400}) + body, err := io.ReadAll(&io.LimitedReader{R: req.Body, N: 102400}) if err != nil { m.opts.Logger.Errorf("ERR body: %v", err) http.Error(w, "internal error", http.StatusInternalServerError) From 5641770c8a475c5c240bf1c47897b77df5fb7d16 Mon Sep 17 00:00:00 2001 From: Robin Thellend Date: Thu, 12 Dec 2024 11:57:42 -0800 Subject: [PATCH 5/5] show errors --- proxy/internal/pki/certs.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/proxy/internal/pki/certs.js b/proxy/internal/pki/certs.js index 19f1b8b..02cb726 100644 --- a/proxy/internal/pki/certs.js +++ b/proxy/internal/pki/certs.js @@ -133,23 +133,25 @@ function generateKeyAndCert(b) { f.pw1.value = ''; f.pw2.value = ''; + const oldb = b.textContent; + b.disabled = true; + b.textContent = 'working...'; + document.body.classList.add('waiting'); pkiApp.ready - .then(() => { - b.disabled = true; - document.body.classList.add('waiting'); - return pkiApp.getCertificate({ - 'keytype': f.keytype.value, - 'format': f.format.value, - 'password': pw, - 'label': f.label.value, - 'dnsname': f.dnsname.value, - }); - }) + .then(() => pkiApp.getCertificate({ + 'keytype': f.keytype.value, + 'format': f.format.value, + 'password': pw, + 'label': f.label.value, + 'dnsname': f.dnsname.value, + })) .then(() => window.location.reload()) .catch(err => { b.disabled = false; + b.textContent = oldb; document.body.classList.remove('waiting'); console.error('getCertificate failed', err); + alert('Request failed: '+err.message); }); }