Update für bessere Kompatibilität
This commit is contained in:
@@ -1,4 +1,20 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"id": "jbergner_at_send.nrw--DFC59FED5CE41CC7A753E9C3C37D763B38A3894C",
|
||||||
|
"name": "Jan Bergner",
|
||||||
|
"email": "jbergner@send.nrw",
|
||||||
|
"fingerprint": "DFC59FED5CE41CC7A753E9C3C37D763B38A3894C",
|
||||||
|
"filename": "Jan-Bergner_jbergner@send.nrw-0xC37D763B38A3894C-pub.asc",
|
||||||
|
"created_at": "2026-02-19T13:00:29.6481446+01:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "tom.gilbo_at_hilden.de--7160BFBE0D520FDDA0BD3ADA5F09C4BD0EE0BE5A",
|
||||||
|
"name": "Tom Gilbo",
|
||||||
|
"email": "tom.gilbo@hilden.de",
|
||||||
|
"fingerprint": "7160BFBE0D520FDDA0BD3ADA5F09C4BD0EE0BE5A",
|
||||||
|
"filename": "public-2-.asc",
|
||||||
|
"created_at": "2026-02-19T12:57:27.4968564+01:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "max_at_send.nrw--D88C7FA9A544ECF8BCCEC6EB8F0B3E5851F2C8CC",
|
"id": "max_at_send.nrw--D88C7FA9A544ECF8BCCEC6EB8F0B3E5851F2C8CC",
|
||||||
"name": "max",
|
"name": "max",
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
=BcaJ
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
55
data/keys/public-2-.asc
Normal file
55
data/keys/public-2-.asc
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Comment: https://gopenpgp.org
|
||||||
|
Version: GopenPGP 2.9.0
|
||||||
|
|
||||||
|
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
|
||||||
|
=IwML
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
131
main.go
131
main.go
@@ -271,16 +271,38 @@ func zbase32Encode(b []byte) string {
|
|||||||
return string(out)
|
return string(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// wkdHash: z-base-32(SHA1(strings.ToLower(addr-spec))) + domain
|
// wkdHash: z-base-32(SHA1(strings.ToLower(local-part))) + domain
|
||||||
func wkdHash(email string) (hash string, domain string) {
|
func wkdHash(email string) (hash string, domain string, local string) {
|
||||||
email = strings.ToLower(strings.TrimSpace(email))
|
email = strings.TrimSpace(email)
|
||||||
parts := strings.Split(email, "@")
|
parts := strings.Split(email, "@")
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
return "", ""
|
return "", "", ""
|
||||||
}
|
}
|
||||||
domain = parts[1]
|
local = parts[0] // keep original for ?l=
|
||||||
s := sha1.Sum([]byte(email))
|
domain = strings.ToLower(parts[1])
|
||||||
return zbase32Encode(s[:]), domain
|
lp := strings.ToLower(local)
|
||||||
|
|
||||||
|
s := sha1.Sum([]byte(lp))
|
||||||
|
return zbase32Encode(s[:]), domain, local
|
||||||
|
}
|
||||||
|
|
||||||
|
func armoredToBinary(arm []byte) ([]byte, error) {
|
||||||
|
ents, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(arm))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(ents) == 0 {
|
||||||
|
return nil, fmt.Errorf("no keys in armored data")
|
||||||
|
}
|
||||||
|
|
||||||
|
var out bytes.Buffer
|
||||||
|
for _, e := range ents {
|
||||||
|
// Serialize schreibt binary OpenPGP packets (kein Armor)
|
||||||
|
if err := e.Serialize(&out); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -322,7 +344,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
// Upload with automatic fingerprint parsing
|
// Upload with automatic fingerprint parsing
|
||||||
mux.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
|
||||||
if enabled("WRITEACCESS", false) {
|
if enabled("WRITEACCESS", true) {
|
||||||
if r.Method != http.MethodPost {
|
if r.Method != http.MethodPost {
|
||||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
@@ -428,16 +450,26 @@ func main() {
|
|||||||
mux.HandleFunc("/.well-known/openpgpkey/policy", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/.well-known/openpgpkey/policy", func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, _ = w.Write([]byte("# WKD policy"))
|
_, _ = w.Write([]byte("# WKD policy\n"))
|
||||||
})
|
})
|
||||||
// direct method: /.well-known/openpgpkey/hu/<hash>
|
// direct method: /.well-known/openpgpkey/hu/<hash>
|
||||||
mux.HandleFunc("/.well-known/openpgpkey/hu/", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/.well-known/openpgpkey/hu/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
pathHash := strings.TrimPrefix(r.URL.Path, "/.well-known/openpgpkey/hu/")
|
hash := strings.TrimPrefix(r.URL.Path, "/.well-known/openpgpkey/hu/")
|
||||||
|
hash = strings.Trim(hash, "/")
|
||||||
|
|
||||||
|
// Optional: ?l=... (unverändert, percent-encoded) — nur als Hint/Check
|
||||||
|
lParam := r.URL.Query().Get("l")
|
||||||
|
|
||||||
var match *KeyRecord
|
var match *KeyRecord
|
||||||
|
var matchLocal string
|
||||||
for _, it := range st.all() {
|
for _, it := range st.all() {
|
||||||
h, _ := wkdHash(it.Email)
|
h, _, local := wkdHash(it.Email)
|
||||||
if h == pathHash {
|
if h == hash {
|
||||||
|
if lParam != "" && lParam != local {
|
||||||
|
continue
|
||||||
|
}
|
||||||
match = &it
|
match = &it
|
||||||
|
matchLocal = local
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -445,27 +477,70 @@ func main() {
|
|||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, err := os.ReadFile(filepath.Join(keysDir, match.Filename))
|
|
||||||
|
arm, err := os.ReadFile(filepath.Join(keysDir, match.Filename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/pgp-keys")
|
bin, err := armoredToBinary(arm)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "invalid stored key data", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// WKD responses are typically application/octet-stream
|
||||||
|
w.Header().Set("Content-Type", "application/octet-stream")
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*") // optional, hilft manchen Tools
|
||||||
|
if r.Method == http.MethodHead {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = matchLocal // falls du später Logging möchtest
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, _ = w.Write(data)
|
_, _ = w.Write(bin)
|
||||||
})
|
})
|
||||||
// advanced method: /openpgpkey/<domain>/hu/<hash>
|
// advanced method: /openpgpkey/<domain>/hu/<hash>
|
||||||
mux.HandleFunc("/openpgpkey/", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/.well-known/openpgpkey/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
parts := strings.Split(strings.TrimPrefix(r.URL.Path, "/openpgpkey/"), "/")
|
// Nur advanced bedienen, wenn Host = openpgpkey.<domain>
|
||||||
|
host := r.Host
|
||||||
|
if i := strings.IndexByte(host, ':'); i >= 0 {
|
||||||
|
host = host[:i]
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(strings.ToLower(host), "openpgpkey.") {
|
||||||
|
// Für die Hauptdomain sind policy + /hu/ bereits separat gemappt
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erwartet:
|
||||||
|
// /.well-known/openpgpkey/<domain>/hu/<hash>
|
||||||
|
// oder: /.well-known/openpgpkey/<domain>/policy
|
||||||
|
rest := strings.TrimPrefix(r.URL.Path, "/.well-known/openpgpkey/")
|
||||||
|
parts := strings.Split(strings.Trim(rest, "/"), "/")
|
||||||
|
if len(parts) == 2 && parts[1] == "policy" {
|
||||||
|
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = w.Write([]byte("# WKD policy\n"))
|
||||||
|
return
|
||||||
|
}
|
||||||
if len(parts) != 3 || parts[1] != "hu" {
|
if len(parts) != 3 || parts[1] != "hu" {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
domain, hash := parts[0], parts[2]
|
|
||||||
|
domain := strings.ToLower(parts[0])
|
||||||
|
hash := parts[2]
|
||||||
|
lParam := r.URL.Query().Get("l")
|
||||||
|
|
||||||
var match *KeyRecord
|
var match *KeyRecord
|
||||||
for _, it := range st.all() {
|
for _, it := range st.all() {
|
||||||
h, d := wkdHash(it.Email)
|
h, d, local := wkdHash(it.Email)
|
||||||
if h == hash && strings.EqualFold(d, domain) {
|
if h == hash && strings.EqualFold(d, domain) {
|
||||||
|
if lParam != "" && lParam != local {
|
||||||
|
continue
|
||||||
|
}
|
||||||
match = &it
|
match = &it
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -474,14 +549,26 @@ func main() {
|
|||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, err := os.ReadFile(filepath.Join(keysDir, match.Filename))
|
|
||||||
|
arm, err := os.ReadFile(filepath.Join(keysDir, match.Filename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/pgp-keys")
|
bin, err := armoredToBinary(arm)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "invalid stored key data", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/octet-stream")
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
if r.Method == http.MethodHead {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, _ = w.Write(data)
|
_, _ = w.Write(bin)
|
||||||
})
|
})
|
||||||
|
|
||||||
// --- Minimal HKP-compatible lookup ---
|
// --- Minimal HKP-compatible lookup ---
|
||||||
|
|||||||
Reference in New Issue
Block a user