1
1
package profiles
2
2
3
3
import (
4
+ "fmt"
4
5
"os"
5
- "path/filepath"
6
6
"regexp"
7
7
"strings"
8
8
"time"
@@ -14,16 +14,18 @@ import (
14
14
"github.com/go-git/go-git/v5/plumbing/transport"
15
15
"github.com/go-git/go-git/v5/plumbing/transport/http"
16
16
gitssh "github.com/go-git/go-git/v5/plumbing/transport/ssh"
17
- "github.com/kevinburke/ssh_config"
18
17
"golang.org/x/crypto/ssh"
18
+ "slv.sh/slv/internal/core/commons"
19
19
)
20
20
21
21
const (
22
22
configGitRepoKey = "repo"
23
23
configGitBranchKey = "branch"
24
24
configGitHTTPUserKey = "username"
25
25
configGitHTTPTokenKey = "token"
26
- configGitHTTPSSHKey = "ssh-key"
26
+ configGitSSHKey = "ssh-key"
27
+
28
+ gitUrlRegexPattern = `(?i)^(?:(https?|git|ssh):\/\/[\w.@\-~:/]+\.git|git@[\w.\-]+:[\w./~-]+\.git)$`
27
29
)
28
30
29
31
var gitArgs = []arg {
@@ -47,84 +49,50 @@ var gitArgs = []arg{
47
49
description : "The token to authenticate with the git repository over HTTP" ,
48
50
},
49
51
{
50
- name : configGitHTTPSSHKey ,
52
+ name : configGitSSHKey ,
51
53
sensitive : true ,
52
54
description : "The path to the SSH private key file to authenticate with the git repository over SSH" ,
53
55
},
54
56
}
55
57
56
- func expandTilde (path string ) string {
57
- if len (path ) > 0 && path [0 ] == '~' {
58
- if home , err := os .UserHomeDir (); err == nil {
59
- return filepath .Join (home , path [1 :])
60
- }
61
- }
62
- return path
63
- }
64
-
65
- func getSSHKeyFiles (uri string ) []string {
66
- pattern := regexp .MustCompile (`(?:[^@]+@)?([^:/]+)` )
67
- matches := pattern .FindStringSubmatch (uri )
68
- if len (matches ) < 2 {
69
- return nil
70
- }
71
- hostname := matches [1 ]
72
- if hostname != "" {
73
- allKeyPaths := ssh_config .GetAll (hostname , "IdentityFile" )
74
- var keyPaths []string
75
- keyPathMap := make (map [string ]struct {})
76
- for _ , keyPath := range allKeyPaths {
77
- keyPath = expandTilde (keyPath )
78
- if _ , found := keyPathMap [keyPath ]; ! found {
79
- keyPaths = append (keyPaths , keyPath )
80
- keyPathMap [keyPath ] = struct {}{}
81
- }
82
- }
83
- return keyPaths
84
- }
85
- return nil
86
- }
87
-
88
- func getGitAuth (config map [string ]string ) transport.AuthMethod {
58
+ func getGitAuth (config map [string ]string ) (auth transport.AuthMethod , err error ) {
89
59
gitUrl := config [configGitRepoKey ]
60
+ if ! regexp .MustCompile (gitUrlRegexPattern ).MatchString (gitUrl ) {
61
+ return nil , fmt .Errorf ("invalid git URL: %s" , gitUrl )
62
+ }
90
63
if strings .HasPrefix (gitUrl , "https://" ) || strings .HasPrefix (gitUrl , "http://" ) {
91
64
username := config [configGitHTTPUserKey ]
92
65
token := config [configGitHTTPTokenKey ]
93
66
if username != "" && token != "" {
94
- return & http.BasicAuth {
67
+ auth = & http.BasicAuth {
95
68
Username : username ,
96
69
Password : token ,
97
70
}
71
+ } else if username != "" || token != "" {
72
+ err = fmt .Errorf ("both username and token must be provided for HTTP authentication" )
98
73
}
99
- }
100
- if sshAgentAuth , err := gitssh .NewSSHAgentAuth ("git" ); err == nil {
101
- return sshAgentAuth
102
- }
103
- if sshKeyFile := config [configGitHTTPSSHKey ]; sshKeyFile != "" {
104
- if keyBytes , err := os .ReadFile (sshKeyFile ); err == nil {
105
- _ , err = ssh .ParsePrivateKey (keyBytes )
106
- if err == nil {
107
- auth , err := gitssh .NewPublicKeysFromFile ("git" , sshKeyFile , "" )
108
- if err == nil {
109
- return auth
74
+ } else {
75
+ if sshKey := config [configGitSSHKey ]; sshKey != "" {
76
+ var keyBytes []byte
77
+ if commons .FileExists (sshKey ) {
78
+ if keyBytes , err = os .ReadFile (sshKey ); err != nil {
79
+ return nil , fmt .Errorf ("failed to read SSH key file %s: %w" , sshKey , err )
110
80
}
81
+ config [configGitSSHKey ] = string (keyBytes )
82
+ } else {
83
+ keyBytes = []byte (sshKey )
111
84
}
112
- }
113
- }
114
- if sshKeyFiles := getSSHKeyFiles (gitUrl ); len (sshKeyFiles ) > 0 {
115
- keyPath := sshKeyFiles [0 ]
116
- keyBytes , err := os .ReadFile (keyPath )
117
- if err == nil {
118
- _ , err = ssh .ParsePrivateKey (keyBytes )
119
- if err == nil {
120
- auth , err := gitssh .NewPublicKeysFromFile ("git" , keyPath , "" )
121
- if err == nil {
122
- return auth
123
- }
85
+ if _ , err = ssh .ParsePrivateKey (keyBytes ); err != nil {
86
+ return nil , fmt .Errorf ("failed to parse SSH key: %w" , err )
87
+ }
88
+ if auth , err = gitssh .NewPublicKeys ("git" , keyBytes , "" ); err != nil {
89
+ return nil , fmt .Errorf ("failed to create SSH auth from file %s: %w" , sshKey , err )
124
90
}
91
+ } else if auth , err = gitssh .NewSSHAgentAuth ("git" ); err != nil {
92
+ return nil , fmt .Errorf ("failed to create SSH agent auth: %w" , err )
125
93
}
126
94
}
127
- return nil
95
+ return
128
96
}
129
97
130
98
func gitCommit (repo * git.Repository , msg string ) error {
@@ -158,7 +126,9 @@ func gitSetup(dir string, config map[string]string) (err error) {
158
126
cloneOptions := & git.CloneOptions {
159
127
URL : gitUrl ,
160
128
}
161
- cloneOptions .Auth = getGitAuth (config )
129
+ if cloneOptions .Auth , err = getGitAuth (config ); err != nil {
130
+ return err
131
+ }
162
132
branch := config [configGitBranchKey ]
163
133
if branch != "" {
164
134
cloneOptions .ReferenceName = plumbing .NewBranchReferenceName (branch )
@@ -177,8 +147,12 @@ func gitPull(dir string, config map[string]string) (err error) {
177
147
if err != nil {
178
148
return err
179
149
}
150
+ var auth transport.AuthMethod
151
+ if auth , err = getGitAuth (config ); err != nil {
152
+ return err
153
+ }
180
154
err = worktree .Pull (& git.PullOptions {
181
- Auth : getGitAuth ( config ) ,
155
+ Auth : auth ,
182
156
})
183
157
if err == git .NoErrAlreadyUpToDate {
184
158
return nil
@@ -194,7 +168,11 @@ func gitPush(dir string, config map[string]string, note string) (err error) {
194
168
if err = gitCommit (repo , note ); err != nil {
195
169
return err
196
170
}
171
+ var auth transport.AuthMethod
172
+ if auth , err = getGitAuth (config ); err != nil {
173
+ return err
174
+ }
197
175
return repo .Push (& git.PushOptions {
198
- Auth : getGitAuth ( config ) ,
176
+ Auth : auth ,
199
177
})
200
178
}
0 commit comments