Update für bessere Kompatibilität
This commit is contained in:
131
main.go
131
main.go
@@ -271,16 +271,38 @@ func zbase32Encode(b []byte) string {
|
||||
return string(out)
|
||||
}
|
||||
|
||||
// wkdHash: z-base-32(SHA1(strings.ToLower(addr-spec))) + domain
|
||||
func wkdHash(email string) (hash string, domain string) {
|
||||
email = strings.ToLower(strings.TrimSpace(email))
|
||||
// wkdHash: z-base-32(SHA1(strings.ToLower(local-part))) + domain
|
||||
func wkdHash(email string) (hash string, domain string, local string) {
|
||||
email = strings.TrimSpace(email)
|
||||
parts := strings.Split(email, "@")
|
||||
if len(parts) != 2 {
|
||||
return "", ""
|
||||
return "", "", ""
|
||||
}
|
||||
domain = parts[1]
|
||||
s := sha1.Sum([]byte(email))
|
||||
return zbase32Encode(s[:]), domain
|
||||
local = parts[0] // keep original for ?l=
|
||||
domain = strings.ToLower(parts[1])
|
||||
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() {
|
||||
@@ -322,7 +344,7 @@ func main() {
|
||||
})
|
||||
// Upload with automatic fingerprint parsing
|
||||
mux.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
|
||||
if enabled("WRITEACCESS", false) {
|
||||
if enabled("WRITEACCESS", true) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
@@ -428,16 +450,26 @@ func main() {
|
||||
mux.HandleFunc("/.well-known/openpgpkey/policy", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("# WKD policy"))
|
||||
_, _ = w.Write([]byte("# WKD policy\n"))
|
||||
})
|
||||
// direct method: /.well-known/openpgpkey/hu/<hash>
|
||||
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 matchLocal string
|
||||
for _, it := range st.all() {
|
||||
h, _ := wkdHash(it.Email)
|
||||
if h == pathHash {
|
||||
h, _, local := wkdHash(it.Email)
|
||||
if h == hash {
|
||||
if lParam != "" && lParam != local {
|
||||
continue
|
||||
}
|
||||
match = &it
|
||||
matchLocal = local
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -445,27 +477,70 @@ func main() {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
data, err := os.ReadFile(filepath.Join(keysDir, match.Filename))
|
||||
|
||||
arm, err := os.ReadFile(filepath.Join(keysDir, match.Filename))
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
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.Write(data)
|
||||
_, _ = w.Write(bin)
|
||||
})
|
||||
// advanced method: /openpgpkey/<domain>/hu/<hash>
|
||||
mux.HandleFunc("/openpgpkey/", func(w http.ResponseWriter, r *http.Request) {
|
||||
parts := strings.Split(strings.TrimPrefix(r.URL.Path, "/openpgpkey/"), "/")
|
||||
mux.HandleFunc("/.well-known/openpgpkey/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// 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" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
domain, hash := parts[0], parts[2]
|
||||
|
||||
domain := strings.ToLower(parts[0])
|
||||
hash := parts[2]
|
||||
lParam := r.URL.Query().Get("l")
|
||||
|
||||
var match *KeyRecord
|
||||
for _, it := range st.all() {
|
||||
h, d := wkdHash(it.Email)
|
||||
h, d, local := wkdHash(it.Email)
|
||||
if h == hash && strings.EqualFold(d, domain) {
|
||||
if lParam != "" && lParam != local {
|
||||
continue
|
||||
}
|
||||
match = &it
|
||||
break
|
||||
}
|
||||
@@ -474,14 +549,26 @@ func main() {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
data, err := os.ReadFile(filepath.Join(keysDir, match.Filename))
|
||||
|
||||
arm, err := os.ReadFile(filepath.Join(keysDir, match.Filename))
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
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.Write(data)
|
||||
_, _ = w.Write(bin)
|
||||
})
|
||||
|
||||
// --- Minimal HKP-compatible lookup ---
|
||||
|
||||
Reference in New Issue
Block a user