@@ -13,6 +13,8 @@ import (
1313 "net"
1414 "net/http"
1515 "os"
16+ "path/filepath"
17+ "strings"
1618 "time"
1719
1820 dockertypes "github.com/docker/cli/cli/config/types"
@@ -24,6 +26,7 @@ import (
2426const (
2527 // ConnectionTimeout is the timeout for connecting to the credential socket.
2628 ConnectionTimeout = 5 * time .Second
29+ BufferSize = 4096
2730)
2831
2932// CredentialSocketPath is the path to the credential socket.
@@ -51,6 +54,10 @@ func (h FinchCredentialHelper) List() (map[string]string, error) {
5154
5255// Get retrieves credentials from the Finch daemon.
5356func (h FinchCredentialHelper ) Get (serverURL string ) (string , string , error ) {
57+ if os .Getenv ("USE_NATIVE_CREDSTORE" ) != "" {
58+ return h .getFromCredSocket (serverURL )
59+ }
60+
5461 buildID := os .Getenv ("FINCH_BUILD_ID" )
5562 if buildID == "" {
5663 return "" , "" , credentials .NewErrCredentialsNotFound ()
@@ -111,6 +118,65 @@ func (h FinchCredentialHelper) Get(serverURL string) (string, string, error) {
111118 return authConfig .Username , authConfig .Password , nil
112119}
113120
121+ func (h FinchCredentialHelper ) getFromCredSocket (serverURL string ) (string , string , error ) {
122+ credentialSocketPath := os .Getenv ("FINCH_CREDENTIAL_SOCKET" )
123+ if credentialSocketPath == "" {
124+ // detect WSL; Windows Finch uses direct fs mount instead of port forwarding
125+ if strings .Contains (os .Getenv ("PATH" ), "/mnt/c" ) || os .Getenv ("WSL_DISTRO_NAME" ) != "" {
126+ finchDir := os .Getenv ("FINCH_DIR" )
127+ if finchDir != "" {
128+ credentialSocketPath = filepath .Join (finchDir , "lima" , "data" , "finch" , "sock" , "creds.sock" )
129+ } else {
130+ return "" , "" , fmt .Errorf ("FINCH_DIR environment variable not set; cannot find mounted socket" )
131+ }
132+ } else {
133+ // reverse port forwarded sock from mac.yaml
134+ credentialSocketPath = "/run/finch-user-sockets/creds.sock"
135+ }
136+ }
137+
138+ // connect to socket
139+ conn , err := net .Dial ("unix" , credentialSocketPath )
140+ if err != nil {
141+ return "" , "" , credentials .NewErrCredentialsNotFound ()
142+ }
143+ defer conn .Close ()
144+
145+ // simple sanitize to fight injection
146+ serverURL = strings .ReplaceAll (serverURL , "\n " , "" )
147+ serverURL = strings .ReplaceAll (serverURL , "\r " , "" )
148+
149+ // send get command with URL through socket
150+ _ , err = conn .Write ([]byte ("get\n " + serverURL + "\n " ))
151+ if err != nil {
152+ return "" , "" , credentials .NewErrCredentialsNotFound ()
153+ }
154+
155+ // read response
156+ response := make ([]byte , BufferSize )
157+ n , err := conn .Read (response )
158+ if err != nil {
159+ return "" , "" , credentials .NewErrCredentialsNotFound ()
160+ }
161+
162+ // parse response into credential struct (auth config breaking)
163+ var cred struct {
164+ ServerURL string `json:"ServerURL"`
165+ Username string `json:"Username"`
166+ Secret string `json:"Secret"`
167+ }
168+ if err := json .Unmarshal (response [:n ], & cred ); err != nil {
169+ return "" , "" , credentials .NewErrCredentialsNotFound ()
170+ }
171+
172+ // Return empty credentials if no credentials found
173+ if cred .Username == "" && cred .Secret == "" {
174+ return "" , "" , credentials .NewErrCredentialsNotFound ()
175+ }
176+
177+ return cred .Username , cred .Secret , nil
178+ }
179+
114180func main () {
115181 credentials .Serve (FinchCredentialHelper {})
116- }
182+ }
0 commit comments