1
2
3 package wincred
4
5 import (
6 "bytes"
7 "net/url"
8 "strings"
9
10 winc "github.com/danieljoos/wincred"
11 "github.com/docker/docker-credential-helpers/credentials"
12 "github.com/docker/docker-credential-helpers/registryurl"
13 )
14
15
16 type Wincred struct{}
17
18
19 func (h Wincred) Add(creds *credentials.Credentials) error {
20 credsLabels := []byte(credentials.CredsLabel)
21 g := winc.NewGenericCredential(creds.ServerURL)
22 g.UserName = creds.Username
23 g.CredentialBlob = []byte(creds.Secret)
24 g.Persist = winc.PersistLocalMachine
25 g.Attributes = []winc.CredentialAttribute{{Keyword: "label", Value: credsLabels}}
26
27 return g.Write()
28 }
29
30
31 func (h Wincred) Delete(serverURL string) error {
32 g, err := winc.GetGenericCredential(serverURL)
33 if g == nil {
34 return nil
35 }
36 if err != nil {
37 return err
38 }
39 return g.Delete()
40 }
41
42
43 func (h Wincred) Get(serverURL string) (string, string, error) {
44 target, err := getTarget(serverURL)
45 if err != nil {
46 return "", "", err
47 } else if target == "" {
48 return "", "", credentials.NewErrCredentialsNotFound()
49 }
50
51 g, _ := winc.GetGenericCredential(target)
52 if g == nil {
53 return "", "", credentials.NewErrCredentialsNotFound()
54 }
55
56 for _, attr := range g.Attributes {
57 if strings.Compare(attr.Keyword, "label") == 0 &&
58 bytes.Compare(attr.Value, []byte(credentials.CredsLabel)) == 0 {
59
60 return g.UserName, string(g.CredentialBlob), nil
61 }
62 }
63 return "", "", credentials.NewErrCredentialsNotFound()
64 }
65
66 func getTarget(serverURL string) (string, error) {
67 s, err := registryurl.Parse(serverURL)
68 if err != nil {
69 return serverURL, nil
70 }
71
72 creds, err := winc.List()
73 if err != nil {
74 return "", err
75 }
76
77 var targets []string
78 for i := range creds {
79 attrs := creds[i].Attributes
80 for _, attr := range attrs {
81 if attr.Keyword == "label" && bytes.Equal(attr.Value, []byte(credentials.CredsLabel)) {
82 targets = append(targets, creds[i].TargetName)
83 }
84 }
85 }
86
87 if target, found := findMatch(s, targets, exactMatch); found {
88 return target, nil
89 }
90
91 if target, found := findMatch(s, targets, approximateMatch); found {
92 return target, nil
93 }
94
95 return "", nil
96 }
97
98 func findMatch(serverUrl *url.URL, targets []string, matches func(url.URL, url.URL) bool) (string, bool) {
99 for _, target := range targets {
100 tURL, err := registryurl.Parse(target)
101 if err != nil {
102 continue
103 }
104 if matches(*serverUrl, *tURL) {
105 return target, true
106 }
107 }
108 return "", false
109 }
110
111 func exactMatch(serverURL, target url.URL) bool {
112 return serverURL.String() == target.String()
113 }
114
115 func approximateMatch(serverURL, target url.URL) bool {
116
117 if serverURL.Scheme == "" {
118 serverURL.Scheme = target.Scheme
119 }
120
121 if serverURL.Port() == "" && target.Port() != "" {
122 serverURL.Host = serverURL.Host + ":" + target.Port()
123 }
124
125 if serverURL.Path == "" {
126 serverURL.Path = target.Path
127 }
128 return serverURL.String() == target.String()
129 }
130
131
132 func (h Wincred) List() (map[string]string, error) {
133 creds, err := winc.List()
134 if err != nil {
135 return nil, err
136 }
137
138 resp := make(map[string]string)
139 for i := range creds {
140 attrs := creds[i].Attributes
141 for _, attr := range attrs {
142 if strings.Compare(attr.Keyword, "label") == 0 &&
143 bytes.Compare(attr.Value, []byte(credentials.CredsLabel)) == 0 {
144
145 resp[creds[i].TargetName] = creds[i].UserName
146 }
147 }
148
149 }
150
151 return resp, nil
152 }
153
View as plain text