You have an active professional license.
@@ -155,56 +100,5 @@ function professionalPlan(userCount: number, seats: number, trial: boolean, vali
);
};
- // seats === 0 means unlimited number of users
- const aboveLimit: boolean = seats === 0 ? false : userCount > seats;
-
- const licenseTitle = () => {
- const expDate = new Date(validUntil);
- if (typeof expDate.getTime !== "function") {
- return trial ? additionalLicenseInfo("Trial") : additionalLicenseInfo("Paid");
- } else {
- return additionalLicenseInfo(
- "Expires on " +
- expDate.toLocaleDateString("en-DB", { year: "numeric", month: "short", day: "numeric" }),
- );
- }
- };
-
- return [licenseLevel("Professional"), licenseTitle(), alertMessage(aboveLimit)];
-}
-
-function communityPlan(userCount: number, seats: number, fallbackAllowed: boolean): ReactElement[] {
- const alertMessage = (aboveLimit: boolean) => {
- if (aboveLimit) {
- return fallbackAllowed ? (
-
-
No active license. You are using community edition.
-
-
-
-
- ) : (
-
- No active license. You have exceeded the usage limit.
-
-
- );
- } else {
- return (
-
- You are using the free community edition.
-
-
-
-
- );
- }
- };
-
- // seats === 0 means unlimited number of users
- const aboveLimit: boolean = seats === 0 ? false : userCount > seats;
-
- return [licenseLevel("Community"), additionalLicenseInfo("Free"), alertMessage(aboveLimit)];
+ return [licenseLevel("Professional"), additionalLicenseInfo("Paid"), alertMessage()];
}
diff --git a/components/gitpod-protocol/src/license-protocol.ts b/components/gitpod-protocol/src/license-protocol.ts
index 144b5cfe757ed5..3f3ddb4bf4e9d8 100644
--- a/components/gitpod-protocol/src/license-protocol.ts
+++ b/components/gitpod-protocol/src/license-protocol.ts
@@ -7,23 +7,10 @@
export interface LicenseValidationResult {
valid: boolean;
msg?: string;
- issue?: LicenseIssue;
}
-export type LicenseIssue = "seats-exhausted";
-
export interface LicenseInfo {
- key: string;
- seats: number;
userCount?: number;
- valid: boolean;
- validUntil: string;
- plan?: string;
- features?: string[];
- enabledFeatures?: string[];
- type?: string;
- errorMsg?: string;
- fallbackAllowed: boolean;
}
export interface GetLicenseInfoResult {
@@ -31,14 +18,8 @@ export interface GetLicenseInfoResult {
licenseInfo: LicenseInfo;
}
-export enum LicenseFeature {
- CreateSnapshot = "create-snapshot",
- // room for more
-}
-
export interface LicenseService {
validateLicense(): Promise
;
getLicenseInfo(): Promise;
adminGetLicense(): Promise;
- licenseIncludesFeature(feature: LicenseFeature): Promise;
}
diff --git a/components/licensor/.gitignore b/components/licensor/.gitignore
deleted file mode 100644
index 82178c016ed678..00000000000000
--- a/components/licensor/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-private_key.pem
-public_key.pem
diff --git a/components/licensor/BUILD.yaml b/components/licensor/BUILD.yaml
deleted file mode 100644
index 11f74c5ba8d11b..00000000000000
--- a/components/licensor/BUILD.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-packages:
- - name: lib
- type: go
- srcs:
- - "go.mod"
- - "go.sum"
- - "ee/pkg/**/*.go"
- config:
- packaging: library
- - name: app
- type: go
- srcs:
- - "go.mod"
- - "go.sum"
- - "**/*.go"
- - "*.go"
diff --git a/components/licensor/ee/cmd/genkey.go b/components/licensor/ee/cmd/genkey.go
deleted file mode 100644
index 4224866ab52b5b..00000000000000
--- a/components/licensor/ee/cmd/genkey.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package cmd
-
-import (
- "crypto/rand"
- "crypto/rsa"
- "crypto/x509"
- "encoding/pem"
- "os"
-
- "github.com/spf13/cobra"
-)
-
-// genkeyCmd represents the genkey command
-var genkeyCmd = &cobra.Command{
- Use: "genkey",
- Short: "Generates a public/private key for signing licenses",
- RunE: func(cmd *cobra.Command, args []string) error {
- priv, err := rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- return err
- }
-
- privf, err := os.Create("private_key.pem")
- if err != nil {
- return err
- }
- defer privf.Close()
- err = pem.Encode(privf, &pem.Block{
- Type: "PRIVATE KEY",
- Bytes: x509.MarshalPKCS1PrivateKey(priv),
- })
- if err != nil {
- return err
- }
-
- pubf, err := os.Create("public_key.pem")
- if err != nil {
- return err
- }
- defer pubf.Close()
- err = pem.Encode(pubf, &pem.Block{
- Type: "PUBLIC KEY",
- Bytes: x509.MarshalPKCS1PublicKey(&priv.PublicKey),
- })
- if err != nil {
- return err
- }
-
- return nil
- },
-}
-
-func init() {
- rootCmd.AddCommand(genkeyCmd)
-
- // Here you will define your flags and configuration settings.
-
- // Cobra supports Persistent Flags which will work for this command
- // and all subcommands, e.g.:
- // genkeyCmd.PersistentFlags().String("foo", "", "A help for foo")
-
- // Cobra supports local flags which will only run when this command
- // is called directly, e.g.:
- // genkeyCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
-}
diff --git a/components/licensor/ee/cmd/root.go b/components/licensor/ee/cmd/root.go
deleted file mode 100644
index ddb92884813334..00000000000000
--- a/components/licensor/ee/cmd/root.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package cmd
-
-import (
- "fmt"
- "os"
-
- "github.com/spf13/cobra"
-)
-
-// rootCmd represents the base command when called without any subcommands
-var rootCmd = &cobra.Command{
- Use: "licensor",
- Short: "CLI for signing licenses",
-}
-
-// Execute adds all child commands to the root command and sets flags appropriately.
-// This is called by main.main(). It only needs to happen once to the rootCmd.
-func Execute() {
- if err := rootCmd.Execute(); err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-}
diff --git a/components/licensor/ee/cmd/sign.go b/components/licensor/ee/cmd/sign.go
deleted file mode 100644
index 25e376ef0b338e..00000000000000
--- a/components/licensor/ee/cmd/sign.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package cmd
-
-import (
- "crypto/x509"
- "encoding/pem"
- "fmt"
- "os"
- "time"
-
- "github.com/spf13/cobra"
- "golang.org/x/xerrors"
-
- "github.com/gitpod-io/gitpod/licensor/ee/pkg/licensor"
-)
-
-// signCmd represents the sign command
-var signCmd = &cobra.Command{
- Use: "sign",
- Short: "Signs a license",
- RunE: func(cmd *cobra.Command, args []string) error {
- keyfn, _ := cmd.Flags().GetString("key")
-
- fc, err := os.ReadFile(keyfn)
- if err != nil {
- return err
- }
- block, _ := pem.Decode(fc)
- if block == nil {
- return xerrors.Errorf("no PEM encoded key found in %s", keyfn)
- }
- if block.Type != "PRIVATE KEY" {
- return xerrors.Errorf("unknown PEM block type %s", block.Type)
- }
- priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
- if err != nil {
- return err
- }
-
- var (
- domain, _ = cmd.Flags().GetString("domain")
- id, _ = cmd.Flags().GetString("id")
- level, _ = cmd.Flags().GetString("level")
- seats, _ = cmd.Flags().GetInt("seats")
- validFor, _ = cmd.Flags().GetDuration("valid-for")
- )
- if domain == "" {
- return xerrors.Errorf("--domain is mandatory")
- }
- if id == "" {
- return xerrors.Errorf("--id is mandatory")
- }
- if level == "" {
- return xerrors.Errorf("--level is mandatory")
- }
- if seats < 0 {
- return xerrors.Errorf("--seats must be positive")
- }
- if validFor <= 0 {
- return xerrors.Errorf("--valid-for must be positive")
- }
-
- lvl, ok := licensor.NamedLevel[level]
- if !ok {
- return xerrors.Errorf("invalid license level: %s", level)
- }
-
- l := licensor.LicensePayload{
- Domain: domain,
- ID: id,
- Seats: seats,
- Level: lvl,
- ValidUntil: time.Now().Add(validFor),
- }
-
- res, err := licensor.Sign(l, priv)
- if err != nil {
- return err
- }
-
- fmt.Println(string(res))
- return nil
- },
-}
-
-func init() {
- rootCmd.AddCommand(signCmd)
-
- signCmd.Flags().String("domain", "", "domain for which the license is valid")
- signCmd.Flags().String("id", "", "ID of the license")
- signCmd.Flags().String("level", "enterprise", "license level, must be one of team, enterprise")
- signCmd.Flags().Int("seats", 5, "number of seats the license is valid for")
- signCmd.Flags().StringP("key", "k", "private_key.pem", "path to the private key to sign the license with")
- signCmd.Flags().Duration("valid-for", 365*24*time.Hour, "time the license is valid for")
-}
diff --git a/components/licensor/ee/cmd/validate.go b/components/licensor/ee/cmd/validate.go
deleted file mode 100644
index bee8a0c92faba3..00000000000000
--- a/components/licensor/ee/cmd/validate.go
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package cmd
-
-import (
- "encoding/json"
- "fmt"
- "io"
- "os"
-
- "github.com/spf13/cobra"
- "golang.org/x/xerrors"
-
- "github.com/gitpod-io/gitpod/licensor/ee/pkg/licensor"
-)
-
-// validateCmd represents the validate command
-var validateCmd = &cobra.Command{
- Use: "validate [license]",
- Short: "Validates a license - reads from stdin if no argument is provided",
- Args: cobra.MaximumNArgs(1),
- RunE: func(cmd *cobra.Command, args []string) (err error) {
- domain, _ := cmd.Flags().GetString("domain")
- licensorType, _ := cmd.Flags().GetString("licensor")
-
- var e *licensor.Evaluator
- switch licensorType {
- case string(licensor.LicenseTypeReplicated):
- e = licensor.NewReplicatedEvaluator()
- default:
- var lic []byte
- if len(args) == 0 {
- lic, err = io.ReadAll(os.Stdin)
- if err != nil {
- return err
- }
- } else {
- lic = []byte(args[0])
- }
-
- e = licensor.NewGitpodEvaluator(lic, domain)
- }
-
- if msg, valid := e.Validate(); !valid {
- return xerrors.Errorf(msg)
- }
-
- b, _ := json.MarshalIndent(e.Inspect(), "", " ")
- fmt.Println(string(b))
- return nil
- },
-}
-
-func init() {
- rootCmd.AddCommand(validateCmd)
- validateCmd.Flags().String("domain", "", "domain to evaluate the license against")
- validateCmd.Flags().String("licensor", "gitpod", "licensor to use")
-}
diff --git a/components/licensor/ee/pkg/licensor/gitpod.go b/components/licensor/ee/pkg/licensor/gitpod.go
deleted file mode 100644
index 0b30524704c1a1..00000000000000
--- a/components/licensor/ee/pkg/licensor/gitpod.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package licensor
-
-import (
- "crypto"
- "crypto/rsa"
- "crypto/sha256"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "time"
-)
-
-// NewGitpodEvaluator produces a new license evaluator from a license key
-func NewGitpodEvaluator(key []byte, domain string) (res *Evaluator) {
- if len(key) == 0 {
- // fallback to the default license
- return &Evaluator{
- lic: defaultLicense,
- allowFallback: true,
- plan: LicenseTypeCommunity,
- }
- }
-
- deckey := make([]byte, base64.StdEncoding.DecodedLen(len(key)))
- n, err := base64.StdEncoding.Decode(deckey, key)
- if err != nil {
- return &Evaluator{invalid: fmt.Sprintf("cannot decode key: %q", err)}
- }
- deckey = deckey[:n]
-
- var lic licensePayload
- err = json.Unmarshal(deckey, &lic)
- if err != nil {
- return &Evaluator{invalid: fmt.Sprintf("cannot unmarshal key: %q", err)}
- }
-
- keyWoSig, err := json.Marshal(lic.LicensePayload)
- if err != nil {
- return &Evaluator{invalid: fmt.Sprintf("cannot remarshal key: %q", err)}
- }
- hashed := sha256.Sum256(keyWoSig)
-
- for _, k := range publicKeys {
- err = rsa.VerifyPKCS1v15(k, crypto.SHA256, hashed[:], lic.Signature)
- if err == nil {
- break
- }
- }
- if err != nil {
- return &Evaluator{invalid: fmt.Sprintf("cannot verify key: %q", err)}
- }
-
- if !matchesDomain(lic.Domain, domain) {
- return &Evaluator{invalid: "wrong domain"}
- }
-
- if lic.ValidUntil.Before(time.Now()) {
- return &Evaluator{invalid: "not valid anymore"}
- }
-
- return &Evaluator{
- lic: lic.LicensePayload,
- allowFallback: false, // Gitpod licenses cannot fallback - assume these are always paid-for
- plan: LicenseTypePaid, // This essentially means "paid" license
- }
-}
diff --git a/components/licensor/ee/pkg/licensor/keys.go b/components/licensor/ee/pkg/licensor/keys.go
deleted file mode 100644
index 9c4f7fe289db77..00000000000000
--- a/components/licensor/ee/pkg/licensor/keys.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package licensor
-
-import (
- "crypto/rsa"
- "crypto/x509"
- "encoding/pem"
- "fmt"
-)
-
-var (
- keys = [][]byte{
- // Demo key - remove before publishing this code
- []byte(`-----BEGIN PUBLIC KEY-----
-MIIBCgKCAQEAtHhBNA9J7mh301CMP4Hfvv0OLMWDG3FjwR9nUAg3z5SFYnUz4tnP
-NB7gDFNXUIUpetKUyyoAwAWwQsu4/zt9XDg6G25jiHZ/inEfI3xQV2tUhJm+zVLg
-7RCUpVjbUZthaIhGyYm0Oa/Lqa8q/hInqP/Hlvgga+yfBurrYyhdaJFWpgF/m2ha
-yFgEEE/427F/BP/qNfJN+v/ojtsJMM81/jGWH6Tm0bxoWa5nQPsGF7h0MjLc5pYp
-NOrioO8lNSNu1Fz8cYwATxmdgA+0scS/pXyNcP1U9ELjpUAXaUdhthViQ4d5hXj2
-48DoltWJYg1Vgjj2eeYKr7JiJjrXlZoaFwIDAQAB
------END PUBLIC KEY-----`),
- // TOOD: add trial license key here
- // TODO: add actual production license key here
- }
-)
-
-var publicKeys []*rsa.PublicKey
-
-func init() {
- publicKeys = make([]*rsa.PublicKey, len(keys))
- for i, pk := range keys {
- block, _ := pem.Decode(pk)
- if block == nil {
- panic("invalid public licensor key")
- }
- if block.Type != "PUBLIC KEY" {
- panic(fmt.Sprintf("unknown PEM block type %s", block.Type))
- }
-
- var err error
- publicKeys[i], err = x509.ParsePKCS1PublicKey(block.Bytes)
- if err != nil {
- panic(err)
- }
- }
-}
diff --git a/components/licensor/ee/pkg/licensor/licensor.go b/components/licensor/ee/pkg/licensor/licensor.go
deleted file mode 100644
index ed2bcb8e7ae5dd..00000000000000
--- a/components/licensor/ee/pkg/licensor/licensor.go
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package licensor
-
-import (
- "crypto"
- "crypto/rand"
- "crypto/rsa"
- "crypto/sha256"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "os"
- "strings"
- "time"
-)
-
-type LicenseType string
-
-const (
- LicenseTypeGitpod LicenseType = "gitpod"
- LicenseTypeReplicated LicenseType = "replicated"
-)
-
-// LicenseSubscriptionLevel is initialized to have a standard license plan
-// between replicated and gitpod licenses
-type LicenseSubscriptionLevel string
-
-const (
- LicenseTypeCommunity LicenseSubscriptionLevel = "community"
- LicenseTypePaid LicenseSubscriptionLevel = "prod"
- LicenseTypeTrial LicenseSubscriptionLevel = "trial"
- LicenseTypeDevelopment LicenseSubscriptionLevel = "dev"
-)
-
-// LicenseData has type specific info about the license
-type LicenseData struct {
- Type LicenseType `json:"type"`
- Payload LicensePayload `json:"payload"`
- Plan LicenseSubscriptionLevel `json:"plan"`
- FallbackAllowed bool `json:"fallbackAllowed"`
-}
-
-// LicensePayload is the actual license content
-type LicensePayload struct {
- ID string `json:"id"`
- Domain string `json:"domain"`
- Level LicenseLevel `json:"level"`
- ValidUntil time.Time `json:"validUntil"`
- // Type LicenseType `json:"type"`
-
- // Seats == 0 means there's no seat limit
- Seats int `json:"seats"`
-
- // CustomerID is used to identify installations in installation analytics
- CustomerID string `json:"customerID,omitempty"`
-}
-
-type licensePayload struct {
- LicensePayload
- Signature []byte `json:"signature"`
-}
-
-// LicenseLevel determine feature availability -
-type LicenseLevel int
-
-const (
- // This exists for historical reasons - it is now the same as LevelEnterprise
- LevelTeam LicenseLevel = 0
-
- // LevelEnterprise enables enterprise features,
- // which applies after buying a license
- LevelEnterprise LicenseLevel = 1
-)
-
-// NamedLevel maps level names to the actual level
-var NamedLevel map[string]LicenseLevel = map[string]LicenseLevel{
- "team": LevelTeam,
- "enterprise": LevelEnterprise,
-}
-
-// Feature denotes a feature that can be enabled using a license key
-type Feature string
-
-const (
- // FeatureAdminDashboard enables the admin dashboard API
- FeatureAdminDashboard Feature = "admin-dashboard"
- // FeaturePrebuild enables prebuilds
- FeaturePrebuild Feature = "prebuild"
- // FeatureSetTimeout enables custom timeouts for workspaces
- FeatureSetTimeout Feature = "set-timeout"
- // FeatureSnapshot enables snapshot support
- FeatureSnapshot Feature = "snapshot"
- // FeatureWorkspaceSharing enables live workspace sharing
- FeatureWorkspaceSharing Feature = "workspace-sharing"
-)
-
-type featureSet map[Feature]struct{}
-
-type allowance struct {
- Features featureSet
-
- // Total prebuild time that can be used at a certain level.
- // If zero the prebuild time is unlimited.
- PrebuildTime time.Duration
-}
-
-var allowanceMap = map[LicenseLevel]allowance{
- LevelTeam: {
- Features: featureSet{
- FeatureAdminDashboard: struct{}{},
- },
- },
- LevelEnterprise: {
- PrebuildTime: 0,
- Features: featureSet{
- FeaturePrebuild: struct{}{},
-
- FeatureAdminDashboard: struct{}{},
- FeatureSetTimeout: struct{}{},
- FeatureSnapshot: struct{}{},
- FeatureWorkspaceSharing: struct{}{},
- },
- },
-}
-
-func (lvl LicenseLevel) allowance() allowance {
- a, ok := allowanceMap[lvl]
- if !ok {
- fmt.Fprintf(os.Stderr, "invalid license level %d - allowing nothing", lvl)
- return allowance{}
- }
-
- return a
-}
-
-// Fallback license is used when the instance exceeds the number of licenses - it allows limited access
-var fallbackLicense = LicensePayload{
- ID: "fallback-license",
- Level: LevelEnterprise,
- Seats: 0,
- // Domain, ValidUntil are free for all
-}
-
-// Default license is used when no valid license is given - it allows full access up to 10 users
-var defaultLicense = LicensePayload{
- ID: "default-license",
- Level: LevelEnterprise,
- Seats: 0,
- // Domain, ValidUntil are free for all
-}
-
-// we match domains only for `gitpod` license and not with replicated license.
-// In the case of replicated this ensures faster client onboarding
-func matchesDomain(pattern, domain string) bool {
- if pattern == "" {
- return true
- }
- if domain == pattern {
- return true
- }
-
- if strings.HasPrefix(pattern, "*.") && len(pattern) > 2 {
- domainSuffix := pattern[1:]
- if strings.HasSuffix(domain, domainSuffix) {
- return true
- }
- }
-
- return false
-}
-
-// Evaluator determines what a license allows for
-type Evaluator struct {
- invalid string
- allowFallback bool // Paid licenses cannot fallback and prevent additional signups
- lic LicensePayload
- plan LicenseSubscriptionLevel // Specifies if it is a community/free plan or paid plan
-}
-
-// Validate returns false if the license isn't valid and a message explaining why that is.
-func (e *Evaluator) Validate() (msg string, valid bool) {
- if e.invalid == "" {
- return "", true
- }
-
- return e.invalid, false
-}
-
-// Enabled determines if a feature is enabled by the license
-func (e *Evaluator) Enabled(feature Feature, seats int) bool {
- if e.invalid != "" {
- return false
- }
-
- var ok bool
- if e.hasEnoughSeats(seats) {
- // License has enough seats available - evaluate this license
- _, ok = e.lic.Level.allowance().Features[feature]
- } else if e.allowFallback {
- // License has run out of seats - use the fallback license
- _, ok = fallbackLicense.Level.allowance().Features[feature]
- }
-
- return ok
-}
-
-// hasEnoughSeats returns true if the license supports at least the give amount of seats
-func (e *Evaluator) hasEnoughSeats(seats int) bool {
- if e.invalid != "" {
- return false
- }
-
- return e.lic.Seats == 0 || seats <= e.lic.Seats
-}
-
-// HasEnoughSeats is the public method to hasEnoughSeats. Will use fallback license if allowable
-func (e *Evaluator) HasEnoughSeats(seats int) bool {
- if e.invalid != "" {
- return false
- }
-
- if !e.allowFallback {
- return e.hasEnoughSeats(seats)
- }
- // There is always more space if can use a fallback license
- return true
-}
-
-// Inspect returns the license information this evaluator holds.
-// This function is intended for transparency/debugging purposes only and must
-// never be used to determine feature eligibility under a license. All code making
-// those kinds of decisions must be part of the Evaluator.
-func (e *Evaluator) Inspect() LicensePayload {
- return e.lic
-}
-
-func (e *Evaluator) LicenseData() LicenseData {
- data := LicenseData{
- Type: LicenseType(e.GetLicenseType()),
- Payload: e.Inspect(),
- FallbackAllowed: e.allowFallback,
- Plan: e.plan,
- }
-
- return data
-}
-
-func (e *Evaluator) GetLicenseType() string {
- return os.Getenv("GITPOD_LICENSE_TYPE")
-}
-
-// Sign signs a license so that it can be used with the evaluator
-func Sign(l LicensePayload, priv *rsa.PrivateKey) (res []byte, err error) {
- rawl, err := json.Marshal(l)
- if err != nil {
- return nil, err
- }
- hashed := sha256.Sum256(rawl)
-
- sig, err := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, hashed[:])
- if err != nil {
- return nil, err
- }
-
- resl, err := json.Marshal(licensePayload{
- LicensePayload: l,
- Signature: sig,
- })
- if err != nil {
- return nil, err
- }
-
- res = make([]byte, base64.StdEncoding.EncodedLen(len(resl)))
- base64.StdEncoding.Encode(res, resl)
- return res, nil
-}
diff --git a/components/licensor/ee/pkg/licensor/licensor_test.go b/components/licensor/ee/pkg/licensor/licensor_test.go
deleted file mode 100644
index c1a6e47e32f4f7..00000000000000
--- a/components/licensor/ee/pkg/licensor/licensor_test.go
+++ /dev/null
@@ -1,480 +0,0 @@
-// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package licensor
-
-import (
- "bytes"
- "crypto/rand"
- "crypto/rsa"
- "encoding/json"
- "io/ioutil"
- "net/http"
- "testing"
- "time"
-)
-
-const (
- seats = 5
- domain = "foobar.com"
- someID = "730d5134-768c-4a05-b7cd-ecf3757cada9"
- replicatedLicenseUrl = "http://kotsadm:3000/license/v1/license"
-)
-
-type licenseTest struct {
- Name string
- License *LicensePayload
- Validate func(t *testing.T, eval *Evaluator)
- Type LicenseType
- NeverExpires bool
- ReplicatedLicenseType *LicenseSubscriptionLevel
-}
-
-// roundTripFunc .
-type roundTripFunc func(req *http.Request) *http.Response
-
-// roundTrip .
-func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
- return f(req), nil
-}
-
-// newTestClient returns *http.Client with Transport replaced to avoid making real calls
-func newTestClient(fn roundTripFunc) *http.Client {
- return &http.Client{
- Transport: roundTripFunc(fn),
- }
-}
-
-func (test *licenseTest) Run(t *testing.T) {
- t.Run(test.Name, func(t *testing.T) {
- var eval *Evaluator
- if test.Type == LicenseTypeGitpod {
- if test.NeverExpires {
- t.Fatal("gitpod licenses must have an expiry date")
- }
-
- if test.License == nil {
- eval = NewGitpodEvaluator(nil, "")
- } else {
- priv, err := rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- t.Fatalf("cannot generate key: %q", err)
- }
- publicKeys = []*rsa.PublicKey{&priv.PublicKey}
- lic, err := Sign(*test.License, priv)
- if err != nil {
- t.Fatalf("cannot sign license: %q", err)
- }
-
- eval = NewGitpodEvaluator(lic, domain)
- }
- } else if test.Type == LicenseTypeReplicated {
- client := newTestClient(func(req *http.Request) *http.Response {
- act := req.URL.String()
- if act != "http://kotsadm:3000/license/v1/license" {
- t.Fatalf("invalid kotsadm url match: expected %s, got %v", replicatedLicenseUrl, act)
- }
-
- payload, err := json.Marshal(replicatedLicensePayload{
- LicenseType: func() LicenseSubscriptionLevel {
- if test.ReplicatedLicenseType == nil {
- return LicenseTypePaid
- }
- return *test.ReplicatedLicenseType
- }(),
- ExpirationTime: func() *time.Time {
- if test.License != nil {
- return &test.License.ValidUntil
- }
- if !test.NeverExpires {
- t := time.Now().Add(-6 * time.Hour)
- return &t
- }
- return nil
- }(),
- Fields: []replicatedFields{
- {
- Field: "domain",
- Value: func() string {
- if test.License != nil {
- return test.License.Domain
- }
- return domain
- }(),
- },
- {
- Field: "seats",
- Value: func() int {
- if test.License != nil {
- return test.License.Seats
- }
- return seats
- }(),
- },
- },
- })
- if err != nil {
- t.Fatalf("failed to convert payload: %v", err)
- }
-
- return &http.Response{
- StatusCode: 200,
- Body: ioutil.NopCloser(bytes.NewBuffer(payload)),
- Header: make(http.Header),
- }
- })
-
- if test.License == nil {
- eval = newReplicatedEvaluator(client)
- } else {
- eval = newReplicatedEvaluator(client)
- }
- } else {
- t.Fatalf("unknown license type: '%s'", test.Type)
- }
-
- test.Validate(t, eval)
- })
-}
-
-func TestSeats(t *testing.T) {
- tests := []struct {
- Name string
- Licensed int
- Probe int
- WithinLimits bool
- DefaultLicense bool
- InvalidLicense bool
- LicenseType LicenseType
- NeverExpires bool
- }{
- {"Gitpod: unlimited seats", 0, 1000, true, false, false, LicenseTypeGitpod, false},
- {"Gitpod: within limited seats", 50, 40, true, false, false, LicenseTypeGitpod, false},
- {"Gitpod: within limited seats (edge)", 50, 50, true, false, false, LicenseTypeGitpod, false},
- {"Gitpod: beyond limited seats", 50, 150, false, false, false, LicenseTypeGitpod, false},
- {"Gitpod: beyond limited seats (edge)", 50, 51, false, false, false, LicenseTypeGitpod, false},
- {"Gitpod: invalid license", 50, 50, false, false, true, LicenseTypeGitpod, false},
- {"Gitpod: within default license seats", 0, 7, true, true, false, LicenseTypeGitpod, false},
- {"Gitpod: within default license seats (edge)", 0, 10, true, true, false, LicenseTypeGitpod, false},
- {"Gitpod: beyond default license seats", 0, 11, true, true, false, LicenseTypeGitpod, false},
-
- // correctly missing the default license tests as Replicated always has a license
- {"Replicated: unlimited seats", 0, 1000, true, false, false, LicenseTypeReplicated, false},
- {"Replicated: within limited seats", 50, 40, true, false, false, LicenseTypeReplicated, false},
- {"Replicated: within limited seats (edge)", 50, 50, true, false, false, LicenseTypeReplicated, false},
- {"Replicated: beyond limited seats", 50, 150, false, false, false, LicenseTypeReplicated, false},
- {"Replicated: beyond limited seats (edge)", 50, 51, false, false, false, LicenseTypeReplicated, false},
- {"Replicated: invalid license", 50, 50, true, false, true, LicenseTypeReplicated, false},
- {"Replicated: beyond default license seats", 0, 11, true, true, false, LicenseTypeReplicated, false},
-
- {"Replicated: unlimited seats", 0, 1000, true, false, false, LicenseTypeReplicated, true},
- {"Replicated: within limited seats", 50, 40, true, false, false, LicenseTypeReplicated, true},
- {"Replicated: within limited seats (edge)", 50, 50, true, false, false, LicenseTypeReplicated, true},
- {"Replicated: beyond limited seats", 50, 150, false, false, false, LicenseTypeReplicated, true},
- {"Replicated: beyond limited seats (edge)", 50, 51, false, false, false, LicenseTypeReplicated, true},
- {"Replicated: invalid license", 50, 50, true, false, true, LicenseTypeReplicated, true},
- {"Replicated: beyond default license seats", 0, 11, false, true, false, LicenseTypeReplicated, true},
- {"Replicated: invalid license within default seats", 50, 5, true, false, true, LicenseTypeReplicated, false},
- }
-
- for _, test := range tests {
- validUntil := time.Now().Add(6 * time.Hour)
- if test.InvalidLicense {
- validUntil = time.Now().Add(-6 * time.Hour)
- }
-
- lt := licenseTest{
- Name: test.Name,
- License: &LicensePayload{
- ID: someID,
- Domain: domain,
- Level: LevelTeam,
- Seats: test.Licensed,
- ValidUntil: validUntil,
- },
- Validate: func(t *testing.T, eval *Evaluator) {
- withinLimits := eval.hasEnoughSeats(test.Probe)
- if withinLimits != test.WithinLimits {
- t.Errorf("hasEnoughSeats did not behave as expected: lic=%d probe=%d expected=%v actual=%v", test.Licensed, test.Probe, test.WithinLimits, withinLimits)
- }
- },
- Type: test.LicenseType,
- NeverExpires: test.NeverExpires,
- }
- if test.DefaultLicense {
- lt.License = nil
- }
- lt.Run(t)
- }
-}
-
-func TestFeatures(t *testing.T) {
- replicatedCommunity := LicenseTypeCommunity
- replicatedPaid := LicenseTypePaid
-
- tests := []struct {
- Name string
- DefaultLicense bool
- Level LicenseLevel
- Features []Feature
- LicenseType LicenseType
- UserCount int
- ReplicatedLicenseType *LicenseSubscriptionLevel
- }{
- {"Gitpod (in seats): no license", true, LicenseLevel(0), []Feature{
- FeatureAdminDashboard,
- FeatureSetTimeout,
- FeatureWorkspaceSharing,
- FeatureSnapshot,
- FeaturePrebuild,
- }, LicenseTypeGitpod, 10, nil},
- {"Gitpod (in seats): invalid license level", false, LicenseLevel(666), []Feature{}, LicenseTypeGitpod, seats, nil},
- {"Gitpod (in seats): enterprise license", false, LevelEnterprise, []Feature{
- FeatureAdminDashboard,
- FeatureSetTimeout,
- FeatureWorkspaceSharing,
- FeatureSnapshot,
- FeaturePrebuild,
- }, LicenseTypeGitpod, seats, nil},
-
- {"Gitpod (over seats): no license", true, LicenseLevel(0), []Feature{
- FeatureAdminDashboard,
- FeatureSetTimeout,
- FeatureWorkspaceSharing,
- FeatureSnapshot,
- FeaturePrebuild,
- }, LicenseTypeGitpod, 11, nil},
- {"Gitpod (over seats): invalid license level", false, LicenseLevel(666), []Feature{}, LicenseTypeGitpod, seats + 1, nil},
- {"Gitpod (over seats): enterprise license", false, LevelEnterprise, []Feature{}, LicenseTypeGitpod, seats + 1, nil},
-
- {"Replicated (in seats): invalid license level", false, LicenseLevel(666), []Feature{
- FeatureAdminDashboard,
- FeatureSetTimeout,
- FeatureWorkspaceSharing,
- FeatureSnapshot,
- FeaturePrebuild,
- }, LicenseTypeReplicated, seats, &replicatedPaid},
- {"Replicated (in seats): enterprise license", false, LevelEnterprise, []Feature{
- FeatureAdminDashboard,
- FeatureSetTimeout,
- FeatureWorkspaceSharing,
- FeatureSnapshot,
- FeaturePrebuild,
- }, LicenseTypeReplicated, seats, &replicatedPaid},
-
- {"Replicated (over seats - no fallback): invalid license level", true, LicenseLevel(666), []Feature{
- FeatureAdminDashboard,
- FeatureSetTimeout,
- FeatureWorkspaceSharing,
- FeatureSnapshot,
- FeaturePrebuild,
- }, LicenseTypeReplicated, seats + 1, &replicatedPaid},
- {"Replicated (over seats - no fallback): enterprise license", true, LevelEnterprise, []Feature{
- FeatureAdminDashboard,
- FeatureSetTimeout,
- FeatureWorkspaceSharing,
- FeatureSnapshot,
- FeaturePrebuild,
- }, LicenseTypeReplicated, seats + 1, &replicatedPaid},
-
- {"Replicated (over seats - fallback): invalid license level", false, LicenseLevel(666), []Feature{
- FeatureAdminDashboard,
- FeatureSetTimeout,
- FeatureWorkspaceSharing,
- FeatureSnapshot,
- FeaturePrebuild,
- }, LicenseTypeReplicated, seats + 1, &replicatedCommunity},
- {"Replicated (over seats - fallback): enterprise license", false, LevelEnterprise, []Feature{
- FeatureAdminDashboard,
- FeatureSetTimeout,
- FeatureWorkspaceSharing,
- FeatureSnapshot,
- FeaturePrebuild,
- }, LicenseTypeReplicated, seats + 1, &replicatedCommunity},
- }
-
- for _, test := range tests {
- lic := &LicensePayload{
- ID: someID,
- Domain: domain,
- Level: test.Level,
- Seats: seats,
- ValidUntil: time.Now().Add(6 * time.Hour),
- }
- if test.DefaultLicense {
- lic = nil
- }
- lt := licenseTest{
- Name: test.Name,
- License: lic,
- ReplicatedLicenseType: test.ReplicatedLicenseType,
- Validate: func(t *testing.T, eval *Evaluator) {
- unavailableFeatures := featureSet{}
- for f := range allowanceMap[LevelEnterprise].Features {
- unavailableFeatures[f] = struct{}{}
- }
- for _, f := range test.Features {
- delete(unavailableFeatures, f)
-
- if !eval.Enabled(f, test.UserCount) {
- t.Errorf("license does not enable %s, but should", f)
- }
- }
-
- for f := range unavailableFeatures {
- if eval.Enabled(f, test.UserCount) {
- t.Errorf("license not enables %s, but shouldn't", f)
- }
- }
- },
- Type: test.LicenseType,
- }
- lt.Run(t)
- }
-}
-
-func TestEvalutorKeys(t *testing.T) {
- tests := []struct {
- Name string
- Keygen func() ([]*rsa.PublicKey, *rsa.PrivateKey, error)
- EvalDomain string
- Validation string
- ValidFor time.Duration
- }{
- {
- Name: "single valid key",
- Keygen: func() ([]*rsa.PublicKey, *rsa.PrivateKey, error) {
- priv, err := rsa.GenerateKey(rand.Reader, 512)
- if err != nil {
- return nil, nil, err
- }
- return []*rsa.PublicKey{&priv.PublicKey}, priv, nil
- },
- },
- {
- Name: "single valid key but wrong domain",
- Keygen: func() ([]*rsa.PublicKey, *rsa.PrivateKey, error) {
- priv, err := rsa.GenerateKey(rand.Reader, 512)
- if err != nil {
- return nil, nil, err
- }
- return []*rsa.PublicKey{&priv.PublicKey}, priv, nil
- },
- EvalDomain: "wrong-" + domain,
- Validation: "wrong domain",
- },
- {
- Name: "single valid key but outdated",
- ValidFor: -6 * time.Hour,
- Keygen: func() ([]*rsa.PublicKey, *rsa.PrivateKey, error) {
- priv, err := rsa.GenerateKey(rand.Reader, 512)
- if err != nil {
- return nil, nil, err
- }
- return []*rsa.PublicKey{&priv.PublicKey}, priv, nil
- },
- Validation: "not valid anymore",
- },
- {
- Name: "multiple valid keys",
- Keygen: func() (pks []*rsa.PublicKey, priv *rsa.PrivateKey, err error) {
- pks = make([]*rsa.PublicKey, 3)
- for i := 0; i < len(pks); i++ {
- priv, err = rsa.GenerateKey(rand.Reader, 512)
- if err != nil {
- return nil, nil, err
- }
- pks[i] = &priv.PublicKey
- }
- return pks, priv, nil
- },
- },
- {
- Name: "multiple wrong keys",
- Keygen: func() (pks []*rsa.PublicKey, priv *rsa.PrivateKey, err error) {
- pks = make([]*rsa.PublicKey, 3)
- for i := 0; i < len(pks); i++ {
- priv, err = rsa.GenerateKey(rand.Reader, 512)
- if err != nil {
- return nil, nil, err
- }
- pks[i] = &priv.PublicKey
- }
-
- priv, err = rsa.GenerateKey(rand.Reader, 512)
- if err != nil {
- return nil, nil, err
- }
-
- return pks, priv, nil
- },
- Validation: "cannot verify key: \"crypto/rsa: verification error\"",
- },
- }
-
- for _, test := range tests {
- t.Run(test.Name, func(t *testing.T) {
- pks, priv, err := test.Keygen()
- if err != nil {
- t.Fatalf("cannot generate keys: %q", err)
- }
- if test.ValidFor == 0 {
- test.ValidFor = 24 * time.Hour
- }
-
- publicKeys = pks
- lic, err := Sign(LicensePayload{
- ID: someID,
- Domain: domain,
- Level: LevelEnterprise,
- Seats: 5,
- ValidUntil: time.Now().Add(test.ValidFor),
- }, priv)
- if err != nil {
- t.Fatalf("cannot sign test license: %q", err)
- }
-
- dom := domain
- if test.EvalDomain != "" {
- dom = test.EvalDomain
- }
-
- var errmsg string
- e := NewGitpodEvaluator(lic, dom)
- if msg, valid := e.Validate(); !valid {
- errmsg = msg
- }
- if errmsg != test.Validation {
- t.Errorf("unepxected validation result: expected \"%s\", got \"%s\"", test.Validation, errmsg)
- }
- })
- }
-}
-
-func TestMatchesDomain(t *testing.T) {
- tests := []struct {
- Name string
- Pattern string
- Domain string
- Matches bool
- }{
- {Name: "no domain pattern", Pattern: "", Domain: "foobar.com", Matches: true},
- {Name: "exact match", Pattern: "foobar.com", Domain: "foobar.com", Matches: true},
- {Name: "exact mismatch", Pattern: "foobar.com", Domain: "does-not-match.com", Matches: false},
- {Name: "direct pattern match", Pattern: "*.foobar.com", Domain: "foobar.com", Matches: false},
- {Name: "pattern sub match", Pattern: "*.foobar.com", Domain: "foo.foobar.com", Matches: true},
- {Name: "direct pattern mismatch", Pattern: "*.foobar.com", Domain: "does-not-match.com", Matches: false},
- {Name: "pattern sub mismatch", Pattern: "*.foobar.com", Domain: "foo.does-not-match.com", Matches: false},
- {Name: "invalid pattern sub", Pattern: "foo.*.foobar.com", Domain: "foo.foobar.com", Matches: false},
- {Name: "invalid pattern empty", Pattern: "*.", Domain: "foobar.com", Matches: false},
- }
- for _, test := range tests {
- t.Run(test.Name, func(t *testing.T) {
- act := matchesDomain(test.Pattern, test.Domain)
- if act != test.Matches {
- t.Errorf("unexpected domain match: expected %v, got %v", test.Matches, act)
- }
- })
- }
-}
diff --git a/components/licensor/ee/pkg/licensor/replicated.go b/components/licensor/ee/pkg/licensor/replicated.go
deleted file mode 100644
index 0be7016d4a465f..00000000000000
--- a/components/licensor/ee/pkg/licensor/replicated.go
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package licensor
-
-import (
- "encoding/json"
- "fmt"
- "net/http"
- "time"
-)
-
-const (
- replicatedLicenseApiEndpoint = "http://kotsadm:3000/license/v1/license"
- replicatedLicenseApiTimeout = 5 * time.Second
-)
-
-type replicatedFields struct {
- Field string `json:"field"`
- Title string `json:"title"`
- Type string `json:"type"`
- Value interface{} `json:"value"` // This is of type "fieldType"
-}
-
-// replicatedLicensePayload exists to convert the JSON structure to a LicensePayload
-type replicatedLicensePayload struct {
- LicenseID string `json:"license_id"`
- InstallationID string `json:"installation_id"`
- Assignee string `json:"assignee"`
- ReleaseChannel string `json:"release_channel"`
- LicenseType LicenseSubscriptionLevel `json:"license_type"`
- ExpirationTime *time.Time `json:"expiration_time,omitempty"` // Not set if license never expires
- Fields []replicatedFields `json:"fields"`
-}
-
-type ReplicatedEvaluator struct {
- invalid string
- lic LicensePayload
- plan LicenseSubscriptionLevel
- allowFallback bool
-}
-
-func (e *ReplicatedEvaluator) Enabled(feature Feature) bool {
- if e.invalid != "" {
- return false
- }
-
- _, ok := e.lic.Level.allowance().Features[feature]
- return ok
-}
-
-func (e *ReplicatedEvaluator) HasEnoughSeats(seats int) bool {
- if e.invalid != "" {
- return false
- }
-
- return e.lic.Seats == 0 || seats <= e.lic.Seats
-}
-
-func (e *ReplicatedEvaluator) LicenseData() LicenseData {
- data := LicenseData{
- Type: LicenseTypeReplicated,
- Payload: e.Inspect(),
- FallbackAllowed: e.allowFallback,
- Plan: e.plan,
- }
-
- return data
-}
-
-func (e *ReplicatedEvaluator) Inspect() LicensePayload {
- return e.lic
-}
-
-func (e *ReplicatedEvaluator) Validate() (msg string, valid bool) {
- if e.invalid == "" {
- return "", true
- }
-
- return e.invalid, false
-}
-
-// defaultReplicatedLicense this is the default license if call fails
-func defaultReplicatedLicense() *Evaluator {
-
- return &Evaluator{
- lic: defaultLicense,
- allowFallback: true,
- plan: LicenseTypeCommunity,
- }
-}
-
-// newReplicatedEvaluator exists to allow mocking of client
-func newReplicatedEvaluator(client *http.Client) (res *Evaluator) {
- resp, err := client.Get(replicatedLicenseApiEndpoint)
- if err != nil {
- return &Evaluator{invalid: fmt.Sprintf("cannot query kots admin, %q", err)}
- }
- defer resp.Body.Close()
-
- var replicatedPayload replicatedLicensePayload
- err = json.NewDecoder(resp.Body).Decode(&replicatedPayload)
- if err != nil {
- return &Evaluator{invalid: fmt.Sprintf("cannot decode json data, %q", err)}
- }
-
- lic := LicensePayload{
- ID: replicatedPayload.LicenseID,
- Level: LevelEnterprise,
- }
-
- // Search for the fields
- for _, i := range replicatedPayload.Fields {
- switch i.Field {
- case "domain":
- lic.Domain = i.Value.(string)
-
- case "seats":
- lic.Seats = int(i.Value.(float64))
-
- case "customerId":
- lic.CustomerID = i.Value.(string)
- }
- }
-
- if replicatedPayload.ExpirationTime != nil {
- lic.ValidUntil = *replicatedPayload.ExpirationTime
-
- if lic.ValidUntil.Before(time.Now()) {
- return defaultReplicatedLicense()
- }
- }
-
- return &Evaluator{
- lic: lic,
- allowFallback: replicatedPayload.LicenseType == LicenseTypeCommunity, // Only community licenses are allowed to fallback
- plan: replicatedPayload.LicenseType,
- }
-}
-
-// NewReplicatedEvaluator gets the license data from the kots admin panel
-func NewReplicatedEvaluator() (res *Evaluator) {
- return newReplicatedEvaluator(&http.Client{Timeout: replicatedLicenseApiTimeout})
-}
diff --git a/components/licensor/go.mod b/components/licensor/go.mod
deleted file mode 100644
index bd34a5255b6c1c..00000000000000
--- a/components/licensor/go.mod
+++ /dev/null
@@ -1,17 +0,0 @@
-module github.com/gitpod-io/gitpod/licensor
-
-go 1.19
-
-require (
- github.com/32leaves/bel v1.0.1
- github.com/sirupsen/logrus v1.8.1
- github.com/spf13/cobra v1.4.0
- golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
-)
-
-require (
- github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 // indirect
- github.com/inconshreveable/mousetrap v1.0.0 // indirect
- github.com/spf13/pflag v1.0.5 // indirect
- golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
-)
diff --git a/components/licensor/go.sum b/components/licensor/go.sum
deleted file mode 100644
index 400eed306b7c6c..00000000000000
--- a/components/licensor/go.sum
+++ /dev/null
@@ -1,30 +0,0 @@
-github.com/32leaves/bel v1.0.1 h1:AfZmt2haMfMQYM3eznUV40Ni3oc3tnrwtpI0KNx6K9g=
-github.com/32leaves/bel v1.0.1/go.mod h1:Fx5kdWaCVbhMfvP4WWobqwyMUlUT4Z9BMBb54yA518U=
-github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1 h1:GDQdwm/gAcJcLAKQQZGOJ4knlw+7rfEQQcmwTbt4p5E=
-github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
-github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg=
-github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
-github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 h1:ux/56T2xqZO/3cP1I2F86qpeoYPCOzk+KF/UH/Ar+lk=
-github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
-github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
-github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
-github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
-github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/components/licensor/main.go b/components/licensor/main.go
deleted file mode 100644
index 3cdf5b32f8f556..00000000000000
--- a/components/licensor/main.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-// @deprecated
-
-package main
-
-import "github.com/gitpod-io/gitpod/licensor/ee/cmd"
-
-func main() {
- cmd.Execute()
-}
diff --git a/components/licensor/typescript/.gitignore b/components/licensor/typescript/.gitignore
deleted file mode 100644
index 79ba2909837fe0..00000000000000
--- a/components/licensor/typescript/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-build
-liblicensor.*
diff --git a/components/licensor/typescript/BUILD.yaml b/components/licensor/typescript/BUILD.yaml
deleted file mode 100644
index 738b32654108aa..00000000000000
--- a/components/licensor/typescript/BUILD.yaml
+++ /dev/null
@@ -1,22 +0,0 @@
-packages:
- - name: lib
- type: yarn
- srcs:
- - "ee/*.go"
- - "ee/src/*"
- - "*.gyp"
- - package.json
- deps:
- - components/licensor:lib
- prep:
- - ["rm", "-f", "ee/lib/liblicensor.a"]
- - ["go", "mod", "init", "licensor"]
- - ["go", "mod", "edit", "-replace", "github.com/gitpod-io/gitpod/licensor=./components-licensor--lib"]
- - ["yarn", "preinstall"]
- config:
- packaging: library
- dontTest: true
- commands:
- build: ["yarn", "build"]
- yarnLock: ${coreYarnLockBase}/../yarn.lock
- tsconfig: tsconfig.json
diff --git a/components/licensor/typescript/binding.gyp b/components/licensor/typescript/binding.gyp
deleted file mode 100644
index 1eeafcda8d1c46..00000000000000
--- a/components/licensor/typescript/binding.gyp
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- 'targets': [
- {
- 'target_name': 'licensor',
- # import all necessary source files
- 'sources': [
- 'ee/lib/liblicensor.h', # this file was generated by go build
- 'ee/src/module.cc'
- ],
- # libraries are relative to the 'build' directory
- 'libraries': [ '../ee/lib/liblicensor.a' ] # this file was also generated by go build
- }
- ]
-}
\ No newline at end of file
diff --git a/components/licensor/typescript/ee/genapi.go b/components/licensor/typescript/ee/genapi.go
deleted file mode 100644
index 7523fcd65981cd..00000000000000
--- a/components/licensor/typescript/ee/genapi.go
+++ /dev/null
@@ -1,104 +0,0 @@
-//go:build genapi
-// +build genapi
-
-package main
-
-import (
- "os"
- "sort"
-
- "github.com/32leaves/bel"
-
- "github.com/gitpod-io/gitpod/licensor/ee/pkg/licensor"
-)
-
-const (
- defaultSrcPath = "../../ee/pkg/licensor"
- leewaySrcPath = "../components-licensor--lib/ee/pkg/licensor"
-
- preamble = `/**
- * Copyright (c) 2022 Gitpod GmbH. All rights reserved.
- * Licensed under the GNU Affero General Public License (AGPL).
- * See License.AGPL.txt in the project root for license information.
- */
-
-// generated using github.com/32leaves/bel
-// DO NOT MODIFY`
-)
-
-func main() {
- var pth = defaultSrcPath
- if _, err := os.Stat(leewaySrcPath); err == nil {
- pth = leewaySrcPath
- }
-
- var res []bel.TypescriptType
- handler, err := bel.NewParsedSourceEnumHandler(pth)
- if err != nil {
- panic(err)
- }
- ts, err := bel.Extract(struct {
- Feature licensor.Feature
- }{}, bel.WithEnumerations(handler))
- if err != nil {
- panic(err)
- }
- for _, t := range ts {
- if t.Name == "" {
- continue
- }
- res = append(res, t)
- }
-
- ts, err = bel.Extract(licensor.LicensePayload{}, bel.WithEnumerations(handler))
- if err != nil {
- panic(err)
- }
- for _, t := range ts {
- if t.Name == "" {
- continue
- }
-
- if t.Name == "LicensePayload" {
- for i, m := range t.Members {
- if m.Name == "validUntil" {
- t.Members[i].Type.Name = "string"
- }
- }
- }
-
- res = append(res, t)
- }
-
- ts, err = bel.Extract(licensor.LicenseData{}, bel.WithEnumerations(handler))
- if err != nil {
- panic(err)
- }
- for _, t := range ts {
- if t.Name == "" {
- continue
- }
-
- if t.Name == "LicenseData" {
- for i, m := range t.Members {
- if m.Name == "payload" {
- t.Members[i].Type.Name = "LicensePayload"
- }
- }
- }
-
- res = append(res, t)
- }
-
- sort.Slice(res, func(i, j int) bool { return res[i].Name < res[j].Name })
-
- f, err := os.Create("src/api.ts")
- if err != nil {
- panic(err)
- }
- defer f.Close()
- bel.Render(res,
- bel.GenerateOutputTo(f),
- bel.GeneratePreamble(preamble),
- )
-}
diff --git a/components/licensor/typescript/ee/main.go b/components/licensor/typescript/ee/main.go
deleted file mode 100644
index 8ad053289c5c25..00000000000000
--- a/components/licensor/typescript/ee/main.go
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-package main
-
-import (
- "C"
- "encoding/json"
- "os"
-
- log "github.com/sirupsen/logrus"
-
- "github.com/gitpod-io/gitpod/licensor/ee/pkg/licensor"
-)
-
-var (
- instances map[int]*licensor.Evaluator = make(map[int]*licensor.Evaluator)
- nextID int = 1
-)
-
-// Init initializes the global license evaluator from an environment variable
-//
-//export Init
-func Init(key *C.char, domain *C.char) (id int) {
- id = nextID
- switch os.Getenv("GITPOD_LICENSE_TYPE") {
- case string(licensor.LicenseTypeReplicated):
- instances[id] = licensor.NewReplicatedEvaluator()
- default:
- instances[id] = licensor.NewGitpodEvaluator([]byte(C.GoString(key)), C.GoString(domain))
- }
- nextID++
-
- return id
-}
-
-// GetLicenseData returns the info about license for the admin dashboard
-//
-//export GetLicenseData
-func GetLicenseData(id int) (licData *C.char, ok bool) {
- e, ok := instances[id]
- if !ok {
- return
- }
-
- b, err := json.Marshal(e.LicenseData())
- if err != nil {
- log.WithError(err).Warn("GetLicenseData(): cannot retrieve license data")
- return nil, false
- }
-
- return C.CString(string(b)), true
-
-}
-
-// Validate returns false if the license isn't valid and a message explaining why that is.
-//
-//export Validate
-func Validate(id int) (msg *C.char, valid bool) {
- e, ok := instances[id]
- if !ok {
- return C.CString("invalid instance ID"), false
- }
-
- gmsg, valid := e.Validate()
- return C.CString(gmsg), valid
-}
-
-// Enabled returns true if a license enables a feature
-//
-//export Enabled
-func Enabled(id int, feature *C.char, seats int) (enabled, ok bool) {
- e, ok := instances[id]
- if !ok {
- return
- }
-
- return e.Enabled(licensor.Feature(C.GoString(feature)), seats), true
-}
-
-// HasEnoughSeats returns true if the license supports at least the given number of seats.
-//
-//export HasEnoughSeats
-func HasEnoughSeats(id int, seats int) (permitted, ok bool) {
- e, ok := instances[id]
- if !ok {
- return
- }
-
- return e.HasEnoughSeats(seats), true
-}
-
-// Inspect returns the license information this evaluator holds.
-//
-//export Inspect
-func Inspect(id int) (lic *C.char, ok bool) {
- e, ok := instances[id]
- if !ok {
- return
- }
-
- b, err := json.Marshal(e.Inspect())
- if err != nil {
- log.WithError(err).Warn("Inspect(): cannot marshal license payload")
- return nil, false
- }
-
- return C.CString(string(b)), true
-}
-
-// Dispose removes/disposes an instance formerly created using Init. If the id does not exist, nothing happens.
-//
-//export Dispose
-func Dispose(id int) {
- delete(instances, id)
-}
-
-// required to build
-func main() {}
diff --git a/components/licensor/typescript/ee/src/api.ts b/components/licensor/typescript/ee/src/api.ts
deleted file mode 100644
index 6a06ca3a57dc64..00000000000000
--- a/components/licensor/typescript/ee/src/api.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Copyright (c) 2022 Gitpod GmbH. All rights reserved.
- * Licensed under the GNU Affero General Public License (AGPL).
- * See License.AGPL.txt in the project root for license information.
- */
-// generated using github.com/32leaves/bel
-// DO NOT MODIFY
-export enum Feature {
- FeatureAdminDashboard = "admin-dashboard",
- FeaturePrebuild = "prebuild",
- FeatureSetTimeout = "set-timeout",
- FeatureSnapshot = "snapshot",
- FeatureWorkspaceSharing = "workspace-sharing",
-}
-export interface LicenseData {
- type: LicenseType
- payload: LicensePayload
- plan: LicenseSubscriptionLevel
- fallbackAllowed: boolean
-}
-
-export enum LicenseLevel {
- LevelTeam = 0,
- LevelEnterprise = 1,
-}
-export interface LicensePayload {
- id: string
- domain: string
- level: LicenseLevel
- validUntil: string
- seats: number
- customerID?: string
-}
-
-export enum LicenseSubscriptionLevel {
- LicenseTypeCommunity = "community",
- LicenseTypePaid = "prod",
- LicenseTypeTrial = "trial",
- LicenseTypeDevelopment = "dev",
-}
-export enum LicenseType {
- LicenseTypeGitpod = "gitpod",
- LicenseTypeReplicated = "replicated",
-}
diff --git a/components/licensor/typescript/ee/src/index.ts b/components/licensor/typescript/ee/src/index.ts
deleted file mode 100644
index 3c5f2696b66f6f..00000000000000
--- a/components/licensor/typescript/ee/src/index.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Copyright (c) 2022 Gitpod GmbH. All rights reserved.
- * Licensed under the GNU Affero General Public License (AGPL).
- * See License.AGPL.txt in the project root for license information.
- */
-
-import { injectable, inject, postConstruct } from "inversify";
-import { init, Instance, dispose, isEnabled, hasEnoughSeats, inspect, validate, getLicenseData } from "./nativemodule";
-import { Feature, LicensePayload, LicenseData } from "./api";
-
-export const LicenseKeySource = Symbol("LicenseKeySource");
-
-export interface LicenseKeySource {
- // getKey returns a license key
- getKey(): Promise<{
- key: string;
- domain: string;
- }>;
-}
-
-@injectable()
-export class LicenseEvaluator {
- @inject(LicenseKeySource) protected keySource: LicenseKeySource;
- protected instanceID: Instance;
-
- @postConstruct()
- protected async init() {
- const { key, domain } = await this.keySource.getKey();
- this.instanceID = init(key, domain);
-
- const { msg, valid } = validate(this.instanceID);
- if (!valid) {
- console.error(`invalid license: falling back to default`, { domain, msg });
- } else {
- console.log("enterprise license accepted", this.inspect());
- }
- }
-
- public async reloadLicense() {
- this.dispose();
- await this.init();
- }
-
- public validate(): { msg?: string; valid: boolean } {
- const v = validate(this.instanceID);
- if (v.valid) {
- return { valid: true };
- }
- return { msg: v.msg, valid: false };
- }
-
- public isEnabled(feature: Feature, seats: number): boolean {
- return isEnabled(this.instanceID, feature, seats);
- }
-
- public hasEnoughSeats(seats: number): boolean {
- return hasEnoughSeats(this.instanceID, seats);
- }
-
- public inspect(): LicensePayload {
- return JSON.parse(inspect(this.instanceID));
- }
-
- public getLicenseData(): LicenseData {
- return JSON.parse(getLicenseData(this.instanceID));
- }
-
- public dispose() {
- dispose(this.instanceID);
- }
-}
diff --git a/components/licensor/typescript/ee/src/module.cc b/components/licensor/typescript/ee/src/module.cc
deleted file mode 100644
index efa9e6ffb75b83..00000000000000
--- a/components/licensor/typescript/ee/src/module.cc
+++ /dev/null
@@ -1,262 +0,0 @@
-// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
-// Licensed under the GNU Affero General Public License (AGPL).
-// See License.AGPL.txt in the project root for license information.
-
-
-
-#include
-// include the header file generated from the Go build
-#include "../lib/liblicensor.h"
-
-using v8::Number;
-using v8::FunctionCallbackInfo;
-using v8::Isolate;
-using v8::Context;
-using v8::Local;
-using v8::Object;
-using v8::Value;
-using v8::Exception;
-using v8::String;
-using v8::Boolean;
-using v8::NewStringType;
-using v8::PropertyAttribute;
-
-// Extracts a C string from a V8 Utf8Value.
-const char* ToCString(const v8::String::Utf8Value& value) {
- return *value ? *value : "";
-}
-
-void InitM(const FunctionCallbackInfo &args) {
- Isolate *isolate = args.GetIsolate();
-
- if (args.Length() < 2) {
- isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "wrong number of arguments").ToLocalChecked()));
- return;
- }
-
- if (!args[0]->IsString()) {
- isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "argument 0 must be a string").ToLocalChecked()));
- return;
- }
- if (!args[1]->IsString() || args[1]->IsUndefined() || args[1]->IsNull()) {
- isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "argument 1 must be a string").ToLocalChecked()));
- return;
- }
-
- String::Utf8Value nkey(args.GetIsolate(), args[0]);
- const char* ckey = ToCString(nkey);
- char* key = const_cast(ckey);
-
- String::Utf8Value ndomain(args.GetIsolate(), args[1]);
- if (ndomain.length() == 0) {
- isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "domain must not be empty").ToLocalChecked()));
- return;
- }
- const char* cdomain = ToCString(ndomain);
- char* domain = const_cast(cdomain);
-
- // Call exported Go function, which returns a C string
- GoInt id = Init(key, domain);
-
- // return the value
- args.GetReturnValue().Set(Number::New(isolate, id));
-}
-
-void ValidateM(const FunctionCallbackInfo &args) {
- Isolate *isolate = args.GetIsolate();
- Local context = isolate->GetCurrentContext();
-
- if (args.Length() < 1) {
- isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "wrong number of arguments").ToLocalChecked()));
- return;
- }
- if (!args[0]->IsNumber() || args[0]->IsUndefined()) {
- isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "argument 0 must be a number").ToLocalChecked()));
- return;
- }
-
- double rid = args[0]->NumberValue(context).FromMaybe(0);
- int id = static_cast(rid);
-
- Validate_return r = Validate(id);
-
- Local