@@ -8,6 +8,12 @@ import (
88 "strings"
99)
1010
11+ type ResolvePublicKeyOptions struct {
12+ KeyID string
13+ PublicKeyPath string
14+ SearchDirs []string
15+ }
16+
1117func LoadEd25519PrivateKeyFromSeedFile (path string ) (ed25519.PrivateKey , error ) {
1218 b , err := readB64URLFile (path )
1319 if err != nil {
@@ -35,20 +41,21 @@ func LoadEd25519PublicKeyFile(path string) (ed25519.PublicKey, error) {
3541 return ed25519 .PublicKey (b ), nil
3642}
3743
38- // ResolvePublicKeyByID searches for:
39- // - keys/<keyID>.pub
40- // - keys/dev/<keyID>.pub
41- func ResolvePublicKeyByID ( keyID string ) (ed25519. PublicKey , string , error ) {
42- keyID = strings . TrimSpace ( keyID )
43- if keyID == "" {
44- return nil , "" , fmt . Errorf ( "key_id is empty" )
44+ func ResolveEd25519PublicKey ( opts ResolvePublicKeyOptions ) (ed25519. PublicKey , string , error ) {
45+ if path := strings . TrimSpace ( opts . PublicKeyPath ); path != "" {
46+ pub , err := LoadEd25519PublicKeyFile ( path )
47+ if err != nil {
48+ return nil , "" , err
49+ }
50+ return pub , path , nil
4551 }
4652
47- candidates := [] string {
48- filepath . Join ( "keys" , keyID + ".pub" ),
49- filepath . Join ( "keys" , "dev " , keyID + ".pub" ),
53+ keyID := strings . TrimSpace ( opts . KeyID )
54+ if keyID == "" {
55+ return nil , "" , fmt . Errorf ( "key_id is empty" )
5056 }
5157
58+ candidates := publicKeyCandidates (keyID , opts .SearchDirs )
5259 for _ , p := range candidates {
5360 if _ , err := os .Stat (p ); err == nil {
5461 pub , err := LoadEd25519PublicKeyFile (p )
@@ -59,7 +66,55 @@ func ResolvePublicKeyByID(keyID string) (ed25519.PublicKey, string, error) {
5966 }
6067 }
6168
62- return nil , "" , fmt .Errorf ("could not resolve public key for key_id %q (looked in keys/ and keys/dev/)" , keyID )
69+ return nil , "" , fmt .Errorf ("could not resolve public key for key_id %q (looked in %s)" , keyID , strings .Join (candidates , ", " ))
70+ }
71+
72+ func ResolvePublicKeyByID (keyID string ) (ed25519.PublicKey , string , error ) {
73+ return ResolveEd25519PublicKey (ResolvePublicKeyOptions {KeyID : keyID })
74+ }
75+
76+ func DefaultPublicKeySearchDirs () []string {
77+ return []string {
78+ filepath .Join ("keys" ),
79+ filepath .Join ("keys" , "dev" ),
80+ }
81+ }
82+
83+ func publicKeyCandidates (keyID string , searchDirs []string ) []string {
84+ dirs := normalizeSearchDirs (searchDirs )
85+ out := make ([]string , 0 , len (dirs ))
86+ for _ , dir := range dirs {
87+ out = append (out , filepath .Join (dir , keyID + ".pub" ))
88+ }
89+ return out
90+ }
91+
92+ func normalizeSearchDirs (searchDirs []string ) []string {
93+ if len (searchDirs ) == 0 {
94+ return DefaultPublicKeySearchDirs ()
95+ }
96+
97+ seen := map [string ]struct {}{}
98+ out := make ([]string , 0 , len (searchDirs ))
99+
100+ for _ , dir := range searchDirs {
101+ dir = strings .TrimSpace (dir )
102+ if dir == "" {
103+ continue
104+ }
105+ dir = filepath .Clean (dir )
106+ if _ , ok := seen [dir ]; ok {
107+ continue
108+ }
109+ seen [dir ] = struct {}{}
110+ out = append (out , dir )
111+ }
112+
113+ if len (out ) == 0 {
114+ return DefaultPublicKeySearchDirs ()
115+ }
116+
117+ return out
63118}
64119
65120func readB64URLFile (path string ) ([]byte , error ) {
0 commit comments