package trialer import ( "bytes" "context" "crypto/ed25519" "encoding/json" "io" "net/http" "time" "github.com/google/uuid" "golang.org/x/xerrors" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/enterprise/coderd/license" ) // New creates a handler that can issue trial licenses! func New(db database.Store, url string, keys map[string]ed25519.PublicKey) func(ctx context.Context, body codersdk.LicensorTrialRequest) error { return func(ctx context.Context, body codersdk.LicensorTrialRequest) error { deploymentID, err := db.GetDeploymentID(ctx) if err != nil { return xerrors.Errorf("get deployment id: %w", err) } body.DeploymentID = deploymentID data, err := json.Marshal(body) if err != nil { return xerrors.Errorf("marshal: %w", err) } req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(data)) if err != nil { return xerrors.Errorf("create license request: %w", err) } res, err := http.DefaultClient.Do(req) if err != nil { return xerrors.Errorf("perform license request: %w", err) } defer res.Body.Close() if res.StatusCode > 300 { body, err := io.ReadAll(res.Body) if err != nil { return xerrors.Errorf("read license response: %w", err) } // This is the format of the error response from // the license server. var msg struct { Error string `json:"error"` } err = json.Unmarshal(body, &msg) if err != nil { return xerrors.Errorf("unmarshal error: %w", err) } return xerrors.New(msg.Error) } raw, err := io.ReadAll(res.Body) if err != nil { return xerrors.Errorf("read license: %w", err) } rawClaims, err := license.ParseRaw(string(raw), keys) if err != nil { return xerrors.Errorf("parse license: %w", err) } exp, ok := rawClaims["exp"].(float64) if !ok { return xerrors.New("invalid license missing exp claim") } expTime := time.Unix(int64(exp), 0) claims, err := license.ParseClaims(string(raw), keys) if err != nil { return xerrors.Errorf("parse claims: %w", err) } id, err := uuid.Parse(claims.ID) if err != nil { return xerrors.Errorf("parse uuid: %w", err) } _, err = db.InsertLicense(ctx, database.InsertLicenseParams{ UploadedAt: dbtime.Now(), JWT: string(raw), Exp: expTime, UUID: id, }) if err != nil { return xerrors.Errorf("insert license: %w", err) } return nil } }