github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/internal/licenseutils/utils.go (about) 1 package licenseutils 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "net/http" 10 "net/url" 11 "strings" 12 13 "github.com/docker/docker/api/types" 14 "github.com/docker/licensing" 15 "github.com/docker/licensing/model" 16 "github.com/pkg/errors" 17 "github.com/sirupsen/logrus" 18 ) 19 20 // HubUser wraps a licensing client and holds key information 21 // for a user to avoid multiple lookups 22 type HubUser struct { 23 client licensing.Client 24 token string 25 User model.User 26 Orgs []model.Org 27 } 28 29 //GetOrgByID finds the org by the ID in the users list of orgs 30 func (u HubUser) GetOrgByID(orgID string) (model.Org, error) { 31 for _, org := range u.Orgs { 32 if org.ID == orgID { 33 return org, nil 34 } 35 } 36 return model.Org{}, fmt.Errorf("org %s not found", orgID) 37 } 38 39 func getClient() (licensing.Client, error) { 40 baseURI, err := url.Parse(licensingDefaultBaseURI) 41 if err != nil { 42 return nil, err 43 } 44 45 return licensing.New(&licensing.Config{ 46 BaseURI: *baseURI, 47 HTTPClient: &http.Client{}, 48 PublicKeys: licensingPublicKeys, 49 }) 50 } 51 52 // Login to the license server and return a client that can be used to look up and download license files or generate new trial licenses 53 func Login(ctx context.Context, authConfig *types.AuthConfig) (HubUser, error) { 54 lclient, err := getClient() 55 if err != nil { 56 return HubUser{}, err 57 } 58 59 // For licensing we know they must have a valid login session 60 if authConfig.Username == "" { 61 return HubUser{}, fmt.Errorf("you must be logged in to access licenses. Please use 'docker login' then try again") 62 } 63 token, err := lclient.LoginViaAuth(ctx, authConfig.Username, authConfig.Password) 64 if err != nil { 65 return HubUser{}, err 66 } 67 user, err := lclient.GetHubUserByName(ctx, authConfig.Username) 68 if err != nil { 69 return HubUser{}, err 70 } 71 orgs, err := lclient.GetHubUserOrgs(ctx, token) 72 if err != nil { 73 return HubUser{}, err 74 } 75 return HubUser{ 76 client: lclient, 77 token: token, 78 User: *user, 79 Orgs: orgs, 80 }, nil 81 82 } 83 84 // GetAvailableLicenses finds all available licenses for a given account and their orgs 85 func (u HubUser) GetAvailableLicenses(ctx context.Context) ([]LicenseDisplay, error) { 86 subs, err := u.client.ListSubscriptions(ctx, u.token, u.User.ID) 87 if err != nil { 88 return nil, err 89 } 90 for _, org := range u.Orgs { 91 orgSub, err := u.client.ListSubscriptions(ctx, u.token, org.ID) 92 if err != nil { 93 return nil, err 94 } 95 subs = append(subs, orgSub...) 96 } 97 98 // Convert the SubscriptionDetails to a more user-friendly type to render in the CLI 99 100 res := []LicenseDisplay{} 101 102 // Filter out expired licenses 103 i := 0 104 for _, s := range subs { 105 if s.State != "expired" && s.Expires != nil { 106 owner := "" 107 if s.DockerID == u.User.ID { 108 owner = u.User.Username 109 } else { 110 ownerOrg, err := u.GetOrgByID(s.DockerID) 111 if err == nil { 112 owner = ownerOrg.Orgname 113 } else { 114 owner = "unknown" 115 logrus.Debugf("Unable to lookup org ID %s: %s", s.DockerID, err) 116 } 117 } 118 comps := []string{} 119 for _, pc := range s.PricingComponents { 120 comps = append(comps, fmt.Sprintf("%s:%d", pc.Name, pc.Value)) 121 } 122 res = append(res, LicenseDisplay{ 123 Subscription: *s, 124 Num: i, 125 Owner: owner, 126 ComponentsString: strings.Join(comps, ","), 127 }) 128 i++ 129 } 130 } 131 132 return res, nil 133 } 134 135 // GenerateTrialLicense will generate a new trial license for the specified user or org 136 func (u HubUser) GenerateTrialLicense(ctx context.Context, targetID string) (*model.IssuedLicense, error) { 137 subID, err := u.client.GenerateNewTrialSubscription(ctx, u.token, targetID, u.User.Email) 138 if err != nil { 139 return nil, err 140 } 141 return u.client.DownloadLicenseFromHub(ctx, u.token, subID) 142 } 143 144 // GetIssuedLicense will download a license by ID 145 func (u HubUser) GetIssuedLicense(ctx context.Context, ID string) (*model.IssuedLicense, error) { 146 return u.client.DownloadLicenseFromHub(ctx, u.token, ID) 147 } 148 149 // LoadLocalIssuedLicense will load a local license file 150 func LoadLocalIssuedLicense(ctx context.Context, filename string) (*model.IssuedLicense, error) { 151 lclient, err := getClient() 152 if err != nil { 153 return nil, err 154 } 155 return doLoadLocalIssuedLicense(ctx, filename, lclient) 156 } 157 158 // GetLicenseSummary summarizes the license for the user 159 func GetLicenseSummary(ctx context.Context, license model.IssuedLicense) (string, error) { 160 lclient, err := getClient() 161 if err != nil { 162 return "", err 163 } 164 165 cr, err := lclient.VerifyLicense(ctx, license) 166 if err != nil { 167 return "", err 168 } 169 return lclient.SummarizeLicense(cr, license.KeyID).String(), nil 170 } 171 172 func doLoadLocalIssuedLicense(ctx context.Context, filename string, lclient licensing.Client) (*model.IssuedLicense, error) { 173 var license model.IssuedLicense 174 data, err := ioutil.ReadFile(filename) 175 if err != nil { 176 return nil, err 177 } 178 // The file may contain a leading BOM, which will choke the 179 // json deserializer. 180 data = bytes.TrimPrefix(data, []byte("\xef\xbb\xbf")) 181 182 err = json.Unmarshal(data, &license) 183 if err != nil { 184 return nil, errors.Wrap(err, "malformed license file") 185 } 186 187 _, err = lclient.VerifyLicense(ctx, license) 188 if err != nil { 189 return nil, err 190 } 191 192 return &license, nil 193 } 194 195 // ApplyLicense will store a license on the local system 196 func ApplyLicense(ctx context.Context, dclient licensing.WrappedDockerClient, license *model.IssuedLicense) error { 197 info, err := dclient.Info(ctx) 198 if err != nil { 199 return err 200 } 201 return licensing.StoreLicense(ctx, dclient, license, info.DockerRootDir) 202 }