gitlab-license 0.0.1 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 003f891e0c79c5dad69dd13991814fd337dd842f
4
- data.tar.gz: 9a324afa2d6c474d654baddded5d8c8f06c06e2c
2
+ SHA256:
3
+ metadata.gz: 22b0a5d5cec617462fad10a954e69a8ab0cbf2234c4c666b2bce3962387627b4
4
+ data.tar.gz: 5c74cb614cca7a0501188c219fa4dd716d6158fd79cae2a9aeef698d08d90ff9
5
5
  SHA512:
6
- metadata.gz: 902fe5b33b61f2c259a638c4ed9bfdb05cade11046e4c7913557df9030e547ea29e8fa3e363208fd0d4f13b460b3300d646a78ef3d133444106aee2209d9850f
7
- data.tar.gz: 0ca91a33ad564337b64b691ddd7badb405899bc3a7b1d6d8c8e45e08397e59b4a031d30836553ea7568f9ba49ae7c7d49af86063f08e3379b58cb152f9e18161
6
+ metadata.gz: 8cbae440edf6fa10bb5944b63957e204e3fe6213d66d338b1cb7ce0428e2bdfc65a56b634a16c5832cd0039c568108a34c9f9c8b2da1f15e1427332355a2535a
7
+ data.tar.gz: ee7e2deda0d8f42d5453455a9d9d6d88f1b3a53d908f87323928151587a3640bdf3ad4fa7cb9d792639f88df00c0b934491d54e20233d0513b884135ea789ef1
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,25 @@
1
+ default:
2
+ image: "ruby:${RUBY_VERSION}"
3
+
4
+ cache:
5
+ key: "${CI_JOB_IMAGE}"
6
+ paths:
7
+ - vendor/ruby
8
+
9
+ before_script:
10
+ - ruby -v
11
+ - gem update --system --no-document
12
+ - bundle install -j $(nproc) --path vendor
13
+
14
+ test:
15
+ script:
16
+ - bundle exec rspec
17
+ parallel:
18
+ matrix:
19
+ - RUBY_VERSION: [ "3.0", "3.1", "3.2" ]
20
+
21
+ rubocop:
22
+ script:
23
+ - bundle exec rubocop
24
+ variables:
25
+ RUBY_VERSION: "3.0"
data/.rubocop.yml ADDED
@@ -0,0 +1,24 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ require: rubocop-rspec
4
+ AllCops:
5
+ TargetRubyVersion: 2.7
6
+
7
+ Metrics/BlockLength:
8
+ ExcludedMethods: ['describe', 'context']
9
+
10
+ Style/Alias:
11
+ EnforcedStyle: prefer_alias_method
12
+ Enabled: true
13
+
14
+ Style/HashEachMethods:
15
+ Enabled: true
16
+
17
+ Style/HashTransformKeys:
18
+ Enabled: true
19
+
20
+ Style/HashTransformValues:
21
+ Enabled: true
22
+
23
+ RSpec/MultipleExpectations:
24
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,90 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2023-12-21 18:05:17 -0500 using RuboCop version 0.80.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 6
10
+ Metrics/AbcSize:
11
+ Max: 60
12
+
13
+ # Offense count: 1
14
+ # Configuration parameters: CountComments, ExcludedMethods.
15
+ # ExcludedMethods: refine
16
+ Metrics/BlockLength:
17
+ Max: 26
18
+
19
+ # Offense count: 1
20
+ # Configuration parameters: CountComments.
21
+ Metrics/ClassLength:
22
+ Max: 223
23
+
24
+ # Offense count: 3
25
+ Metrics/CyclomaticComplexity:
26
+ Max: 27
27
+
28
+ # Offense count: 6
29
+ # Configuration parameters: CountComments, ExcludedMethods.
30
+ Metrics/MethodLength:
31
+ Max: 36
32
+
33
+ # Offense count: 3
34
+ Metrics/PerceivedComplexity:
35
+ Max: 28
36
+
37
+ # Offense count: 3
38
+ Style/Documentation:
39
+ Exclude:
40
+ - 'spec/**/*'
41
+ - 'test/**/*'
42
+ - 'lib/gitlab/license.rb'
43
+ - 'lib/gitlab/license/boundary.rb'
44
+ - 'lib/gitlab/license/encryptor.rb'
45
+
46
+ # Offense count: 12
47
+ # Cop supports --auto-correct.
48
+ # Configuration parameters: EnforcedStyle.
49
+ # SupportedStyles: always, always_true, never
50
+ Style/FrozenStringLiteralComment:
51
+ Exclude:
52
+ - 'Gemfile'
53
+ - 'Rakefile'
54
+ - 'bin/console'
55
+ - 'gitlab-license.gemspec'
56
+ - 'lib/gitlab/license.rb'
57
+ - 'lib/gitlab/license/boundary.rb'
58
+ - 'lib/gitlab/license/encryptor.rb'
59
+ - 'lib/gitlab/license/version.rb'
60
+ - 'spec/gitlab/license/boundary_spec.rb'
61
+ - 'spec/gitlab/license/encryptor_spec.rb'
62
+ - 'spec/gitlab/license_spec.rb'
63
+ - 'spec/spec_helper.rb'
64
+
65
+ # Offense count: 1
66
+ # Configuration parameters: MinBodyLength.
67
+ Style/GuardClause:
68
+ Exclude:
69
+ - 'lib/gitlab/license.rb'
70
+
71
+ # Offense count: 1
72
+ # Cop supports --auto-correct.
73
+ # Configuration parameters: EnforcedStyle.
74
+ # SupportedStyles: short, verbose
75
+ Style/PreferredHashMethods:
76
+ Exclude:
77
+ - 'lib/gitlab/license.rb'
78
+
79
+ # Offense count: 1
80
+ # Cop supports --auto-correct.
81
+ Style/RescueModifier:
82
+ Exclude:
83
+ - 'lib/gitlab/license.rb'
84
+
85
+ # Offense count: 28
86
+ # Cop supports --auto-correct.
87
+ # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
88
+ # URISchemes: http, https
89
+ Layout/LineLength:
90
+ Max: 104
data/README.md CHANGED
@@ -18,6 +18,19 @@ Or install it yourself as:
18
18
 
19
19
  $ gem install gitlab-license
20
20
 
21
+ ## Release
22
+
23
+ To release a new version of this gem, follow these steps:
24
+
25
+ 1. Bump the `VERSION` constant in [`lib/gitlab/license/version.rb`](https://dev.gitlab.org/gitlab/gitlab-license/-/blob/master/lib/gitlab/license/version.rb#L3). This is typically merged as part of the feature MR.
26
+ 1. Create a [new release](https://dev.gitlab.org/gitlab/gitlab-license/-/releases) in the project (e.g. `v2.1.0`). For more details on creating a new release, refer to the [documentation](https://dev.gitlab.org/help/user/project/releases/index.md#create-a-release).
27
+ 1. [Build the gem](https://guides.rubygems.org/command-reference/#gem-build) to be published: `gem build gitlab-license.gemspec`
28
+ 1. [Publish the gem](https://guides.rubygems.org/publishing) to Rubygems: `gem push gitlab-license-2.1.0.gem`
29
+ - Note you will need to be added as an owner in Rubygems in order to publish.
30
+ 1. Once published, the new version of the gem can be installed in projects that depend on `gitlab-license` like [CustomersDot](https://gitlab.com/gitlab-org/customers-gitlab-com) and [GitLab](https://gitlab.com/gitlab-org/gitlab).
31
+ - It is recommended to install the new version in both GitLab and CustomersDot to keep the versions aligned.
32
+ - This can be installed via bundler or using `gem install` directly.
33
+
21
34
  ## Usage
22
35
 
23
36
  ```ruby
@@ -48,17 +61,17 @@ license.licensee = {
48
61
  "Email" => "douwe@gitlab.com"
49
62
  }
50
63
 
51
- # The date the license was issued.
64
+ # The date the license starts.
52
65
  # Required.
53
- license.issued_at = Date.new(2015, 4, 24)
54
- # The date the license expires.
66
+ license.starts_at = Date.new(2015, 4, 24)
67
+ # The date the license expires.
55
68
  # Not required, to allow lifetime licenses.
56
69
  license.expires_at = Date.new(2016, 4, 23)
57
70
 
58
71
  # The below dates are hardcoded in the license so that you can play with the
59
72
  # period after which there are "repercussions" to license expiration.
60
73
 
61
- # The date admins will be notified about the license's pending expiration.
74
+ # The date admins will be notified about the license's pending expiration.
62
75
  # Not required.
63
76
  license.notify_admins_at = Date.new(2016, 4, 19)
64
77
 
@@ -66,11 +79,15 @@ license.notify_admins_at = Date.new(2016, 4, 19)
66
79
  # Not required.
67
80
  license.notify_users_at = Date.new(2016, 4, 23)
68
81
 
69
- # The date "changes" like code pushes, issue or merge request creation
82
+ # The date "changes" like code pushes, issue or merge request creation
70
83
  # or modification and project creation will be blocked.
71
84
  # Not required.
72
85
  license.block_changes_at = Date.new(2016, 5, 7)
73
86
 
87
+ # If this license was created due to a subscription cancellation
88
+ # Not required.
89
+ license.generated_from_cancellation? = false
90
+
74
91
  # Restrictions bundled with this license.
75
92
  # Not required, to allow unlimited-user licenses for things like educational organizations.
76
93
  license.restrictions = {
data/Rakefile CHANGED
@@ -1 +1 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
data/bin/console CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "gitlab/license"
3
+ require 'bundler/setup'
4
+ require 'gitlab/license'
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +10,5 @@ require "gitlab/license"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- require "irb"
13
+ require 'irb'
14
14
  IRB.start
@@ -1,24 +1,28 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'gitlab/license/version'
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "gitlab-license"
6
+ spec.name = 'gitlab-license'
8
7
  spec.version = Gitlab::License::VERSION
9
- spec.authors = ["Douwe Maan"]
10
- spec.email = ["douwe@gitlab.com"]
8
+ spec.authors = ['Douwe Maan', 'Stan Hu', 'Tyler Amos']
9
+ spec.email = ['douwe@gitlab.com', 'stanhu@gitlab.com', 'tamos@gitlab.com']
11
10
 
12
- spec.summary = %q{gitlab-license helps you generate, verify and enforce software licenses.}
13
- spec.homepage = "https://gitlab.com/gitlab-org/gitlab-license"
14
- spec.license = "MIT"
11
+ spec.summary = 'gitlab-license helps you generate, verify and enforce software licenses.'
12
+ spec.homepage = 'https://dev.gitlab.org/gitlab/gitlab-license'
13
+ spec.license = 'MIT'
15
14
 
16
15
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
- spec.bindir = "exe"
16
+ spec.bindir = 'exe'
18
17
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
- spec.require_paths = ["lib"]
18
+ spec.require_paths = ['lib']
20
19
 
21
- spec.add_development_dependency "bundler", "~> 1.9"
22
- spec.add_development_dependency "rake", "~> 10.0"
23
- spec.add_development_dependency "byebug"
20
+ spec.required_ruby_version = '>= 2.7.0'
21
+
22
+ spec.add_development_dependency 'bundler', '~> 2.4'
23
+ spec.add_development_dependency 'byebug'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ spec.add_development_dependency 'rspec', '~> 3.9'
26
+ spec.add_development_dependency 'rubocop', '~> 0.80.1'
27
+ spec.add_development_dependency 'rubocop-rspec', '~> 1.38.1'
24
28
  end
@@ -0,0 +1,40 @@
1
+ module Gitlab
2
+ class License
3
+ module Boundary
4
+ BOUNDARY_START = /(\A|\r?\n)-*BEGIN .+? LICENSE-*\r?\n/.freeze
5
+ BOUNDARY_END = /\r?\n-*END .+? LICENSE-*(\r?\n|\z)/.freeze
6
+
7
+ class << self
8
+ def add_boundary(data, product_name)
9
+ data = remove_boundary(data)
10
+
11
+ product_name.upcase!
12
+
13
+ pad = lambda do |message, width|
14
+ total_padding = [width - message.length, 0].max
15
+
16
+ padding = total_padding / 2.0
17
+ [
18
+ '-' * padding.ceil,
19
+ message,
20
+ '-' * padding.floor
21
+ ].join
22
+ end
23
+
24
+ [
25
+ pad.call("BEGIN #{product_name} LICENSE", 60),
26
+ data.strip,
27
+ pad.call("END #{product_name} LICENSE", 60)
28
+ ].join("\n")
29
+ end
30
+
31
+ def remove_boundary(data)
32
+ after_boundary = data.split(BOUNDARY_START).last
33
+ in_boundary = after_boundary.split(BOUNDARY_END).first
34
+
35
+ in_boundary
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,16 +1,20 @@
1
1
  module Gitlab
2
2
  class License
3
3
  class Encryptor
4
+ class Error < StandardError; end
5
+ class KeyError < Error; end
6
+ class DecryptionError < Error; end
7
+
4
8
  attr_accessor :key
5
9
 
6
10
  def initialize(key)
11
+ raise KeyError, 'No RSA encryption key provided.' if key && !key.is_a?(OpenSSL::PKey::RSA)
12
+
7
13
  @key = key
8
14
  end
9
15
 
10
16
  def encrypt(data)
11
- unless key.private?
12
- raise "Provided key is not a private key."
13
- end
17
+ raise KeyError, 'Provided key is not a private key.' unless key.private?
14
18
 
15
19
  # Encrypt the data using symmetric AES encryption.
16
20
  cipher = OpenSSL::Cipher::AES128.new(:CBC)
@@ -21,12 +25,12 @@ module Gitlab
21
25
  encrypted_data = cipher.update(data) + cipher.final
22
26
 
23
27
  # Encrypt the AES key using asymmetric RSA encryption.
24
- encrypted_key = self.key.private_encrypt(aes_key)
28
+ encrypted_key = key.private_encrypt(aes_key)
25
29
 
26
30
  encryption_data = {
27
- "data" => Base64.encode64(encrypted_data),
28
- "key" => Base64.encode64(encrypted_key),
29
- "iv" => Base64.encode64(aes_iv)
31
+ 'data' => Base64.encode64(encrypted_data),
32
+ 'key' => Base64.encode64(encrypted_key),
33
+ 'iv' => Base64.encode64(aes_iv)
30
34
  }
31
35
 
32
36
  json_data = JSON.dump(encryption_data)
@@ -34,27 +38,52 @@ module Gitlab
34
38
  end
35
39
 
36
40
  def decrypt(data)
37
- unless key.public?
38
- raise "Provided key is not a public key."
41
+ raise KeyError, 'Provided key is not a public key.' unless key.public?
42
+
43
+ json_data = Base64.decode64(data.chomp)
44
+
45
+ begin
46
+ encryption_data = JSON.parse(json_data)
47
+ rescue JSON::ParserError
48
+ raise DecryptionError, 'Encryption data is invalid JSON.'
39
49
  end
40
50
 
41
- json_data = Base64.decode64(data)
42
- encryption_data = JSON.parse(json_data)
51
+ unless %w[data key iv].all? { |key| encryption_data[key] }
52
+ raise DecryptionError, 'Required field missing from encryption data.'
53
+ end
43
54
 
44
- encrypted_data = Base64.decode64(encryption_data["data"])
45
- encrypted_key = Base64.decode64(encryption_data["key"])
46
- aes_iv = Base64.decode64(encryption_data["iv"])
55
+ encrypted_data = Base64.decode64(encryption_data['data'])
56
+ encrypted_key = Base64.decode64(encryption_data['key'])
57
+ aes_iv = Base64.decode64(encryption_data['iv'])
47
58
 
48
- # Decrypt the AES key using asymmetric RSA encryption.
49
- aes_key = self.key.public_decrypt(encrypted_key)
59
+ begin
60
+ # Decrypt the AES key using asymmetric RSA encryption.
61
+ aes_key = self.key.public_decrypt(encrypted_key)
62
+ rescue OpenSSL::PKey::RSAError
63
+ raise DecryptionError, 'AES encryption key could not be decrypted.'
64
+ end
50
65
 
51
66
  # Decrypt the data using symmetric AES encryption.
52
67
  cipher = OpenSSL::Cipher::AES128.new(:CBC)
53
68
  cipher.decrypt
54
- cipher.key = aes_key
55
- cipher.iv = aes_iv
56
69
 
57
- data = cipher.update(encrypted_data) + cipher.final
70
+ begin
71
+ cipher.key = aes_key
72
+ rescue OpenSSL::Cipher::CipherError
73
+ raise DecryptionError, 'AES encryption key is invalid.'
74
+ end
75
+
76
+ begin
77
+ cipher.iv = aes_iv
78
+ rescue OpenSSL::Cipher::CipherError
79
+ raise DecryptionError, 'AES IV is invalid.'
80
+ end
81
+
82
+ begin
83
+ data = cipher.update(encrypted_data) + cipher.final
84
+ rescue OpenSSL::Cipher::CipherError
85
+ raise DecryptionError, 'Data could not be decrypted.'
86
+ end
58
87
 
59
88
  data
60
89
  end
@@ -1,5 +1,5 @@
1
1
  module Gitlab
2
2
  class License
3
- VERSION = "0.0.1"
3
+ VERSION = '2.6.0'.freeze
4
4
  end
5
5
  end
@@ -1,89 +1,209 @@
1
- require "openssl"
2
- require "date"
3
- require "json"
4
- require "base64"
1
+ require 'openssl'
2
+ require 'date'
3
+ require 'json'
4
+ require 'base64'
5
5
 
6
- require "gitlab/license/version"
7
- require "gitlab/license/encryptor"
6
+ require 'gitlab/license/version'
7
+ require 'gitlab/license/encryptor'
8
+ require 'gitlab/license/boundary'
8
9
 
9
10
  module Gitlab
10
- class License
11
+ class License # rubocop:disable Metrics/ClassLength
12
+ class Error < StandardError; end
13
+ class ImportError < Error; end
14
+ class ValidationError < Error; end
15
+
11
16
  class << self
12
- attr_accessor :encryption_key
17
+ attr_reader :encryption_key
18
+ attr_reader :fallback_decryption_keys
13
19
  @encryption_key = nil
14
20
 
15
- def encryptor
16
- unless self.encryption_key && self.encryption_key.is_a?(OpenSSL::PKey::RSA)
17
- raise "No RSA encryption key provided."
21
+ def encryption_key=(key)
22
+ raise ArgumentError, 'No RSA encryption key provided.' if key && !key.is_a?(OpenSSL::PKey::RSA)
23
+
24
+ @encryption_key = key
25
+ @encryptor = nil
26
+ end
27
+
28
+ def fallback_decryption_keys=(keys)
29
+ unless keys
30
+ @fallback_decryption_keys = nil
31
+ return
18
32
  end
19
33
 
20
- Encryptor.new(self.encryption_key)
34
+ unless keys.is_a?(Enumerable) && keys.all? { |key| key.is_a?(OpenSSL::PKey::RSA) }
35
+ raise ArgumentError, 'Invalid fallback RSA encryption keys provided.'
36
+ end
37
+
38
+ @fallback_decryption_keys = Array(keys)
39
+ end
40
+
41
+ def encryptor
42
+ @encryptor ||= Encryptor.new(encryption_key)
21
43
  end
22
44
 
23
45
  def import(data)
24
- from_json(encryptor.decrypt(data))
46
+ raise ImportError, 'No license data.' if data.nil?
47
+
48
+ data = Boundary.remove_boundary(data)
49
+
50
+ license_json = decrypt_with_fallback_keys(data)
51
+
52
+ begin
53
+ attributes = JSON.parse(license_json)
54
+ rescue JSON::ParseError
55
+ raise ImportError, 'License data is invalid JSON.'
56
+ end
57
+
58
+ new(attributes)
25
59
  end
26
60
 
27
- def from_json(license_json)
28
- new(JSON.parse(license_json))
61
+ def decrypt_with_fallback_keys(data)
62
+ keys_to_try = Array(encryption_key)
63
+ keys_to_try += fallback_decryption_keys if fallback_decryption_keys
64
+
65
+ keys_to_try.each do |decryption_key|
66
+ decryptor = Encryptor.new(decryption_key)
67
+ return decryptor.decrypt(data)
68
+ rescue Encryptor::Error
69
+ next
70
+ end
71
+
72
+ raise ImportError, 'License data could not be decrypted.'
29
73
  end
30
74
  end
31
75
 
32
76
  attr_reader :version
33
- attr_accessor :licensee, :issued_at, :expires_at
34
- attr_accessor :notify_admins_at, :notify_users_at, :block_changes_at
35
- attr_accessor :restrictions
77
+ attr_accessor :licensee, :starts_at, :expires_at, :notify_admins_at,
78
+ :notify_users_at, :block_changes_at, :last_synced_at, :next_sync_at,
79
+ :activated_at, :restrictions, :cloud_licensing_enabled,
80
+ :offline_cloud_licensing_enabled, :auto_renew_enabled, :seat_reconciliation_enabled,
81
+ :operational_metrics_enabled, :generated_from_customers_dot,
82
+ :generated_from_cancellation, :temporary_extension, :contract_overages_allowed
83
+
84
+ alias_method :issued_at, :starts_at
85
+ alias_method :issued_at=, :starts_at=
36
86
 
37
87
  def initialize(attributes = {})
38
88
  load_attributes(attributes)
39
89
  end
40
90
 
41
91
  def valid?
42
- return false if !licensee || !licensee.is_a?(Hash) || licensee.length == 0
43
- return false if !issued_at || !issued_at.is_a?(Date)
44
- return false if expires_at && !expires_at.is_a?(Date)
45
- return false if notify_admins_at && !notify_admins_at.is_a?(Date)
46
- return false if notify_users_at && !notify_users_at.is_a?(Date)
47
- return false if block_changes_at && !block_changes_at.is_a?(Date)
48
- return false if restrictions && !restrictions.is_a?(Hash)
49
-
50
- true
92
+ if !licensee || !licensee.is_a?(Hash) || licensee.empty?
93
+ false
94
+ elsif !starts_at || !starts_at.is_a?(Date)
95
+ false
96
+ elsif !expires_at && !gl_team_license? && !jh_team_license?
97
+ false
98
+ elsif expires_at && !expires_at.is_a?(Date)
99
+ false
100
+ elsif notify_admins_at && !notify_admins_at.is_a?(Date)
101
+ false
102
+ elsif notify_users_at && !notify_users_at.is_a?(Date)
103
+ false
104
+ elsif block_changes_at && !block_changes_at.is_a?(Date)
105
+ false
106
+ elsif last_synced_at && !last_synced_at.is_a?(DateTime)
107
+ false
108
+ elsif next_sync_at && !next_sync_at.is_a?(DateTime)
109
+ false
110
+ elsif activated_at && !activated_at.is_a?(DateTime)
111
+ false
112
+ elsif restrictions && !restrictions.is_a?(Hash)
113
+ false
114
+ elsif !cloud_licensing? && offline_cloud_licensing?
115
+ false
116
+ else
117
+ true
118
+ end
51
119
  end
52
120
 
53
121
  def validate!
54
- raise "License is invalid" unless valid?
122
+ raise ValidationError, 'License is invalid' unless valid?
55
123
  end
56
124
 
57
125
  def will_expire?
58
- self.expires_at
126
+ expires_at
59
127
  end
60
128
 
61
129
  def will_notify_admins?
62
- self.notify_admins_at
130
+ notify_admins_at
63
131
  end
64
132
 
65
133
  def will_notify_users?
66
- self.notify_users_at
134
+ notify_users_at
67
135
  end
68
136
 
69
137
  def will_block_changes?
70
- self.block_changes_at
138
+ block_changes_at
139
+ end
140
+
141
+ def will_sync?
142
+ next_sync_at
143
+ end
144
+
145
+ def activated?
146
+ activated_at
71
147
  end
72
148
 
73
149
  def expired?
74
- will_expire? && Date.today >= self.expires_at
150
+ will_expire? && Date.today >= expires_at
75
151
  end
76
152
 
77
153
  def notify_admins?
78
- will_notify_admins? && Date.today >= self.notify_admins_at
154
+ will_notify_admins? && Date.today >= notify_admins_at
79
155
  end
80
156
 
81
157
  def notify_users?
82
- will_notify_users? && Date.today >= self.notify_users_at
158
+ will_notify_users? && Date.today >= notify_users_at
83
159
  end
84
160
 
85
161
  def block_changes?
86
- will_block_changes? && Date.today >= self.block_changes_at
162
+ will_block_changes? && Date.today >= block_changes_at
163
+ end
164
+
165
+ def cloud_licensing?
166
+ cloud_licensing_enabled == true
167
+ end
168
+
169
+ def offline_cloud_licensing?
170
+ offline_cloud_licensing_enabled == true
171
+ end
172
+
173
+ def contract_overages_allowed?
174
+ contract_overages_allowed == true
175
+ end
176
+
177
+ def auto_renew?
178
+ auto_renew_enabled == true
179
+ end
180
+
181
+ def seat_reconciliation?
182
+ seat_reconciliation_enabled == true
183
+ end
184
+
185
+ def operational_metrics?
186
+ operational_metrics_enabled == true
187
+ end
188
+
189
+ def generated_from_customers_dot?
190
+ generated_from_customers_dot == true
191
+ end
192
+
193
+ def generated_from_cancellation?
194
+ generated_from_cancellation == true
195
+ end
196
+
197
+ def gl_team_license?
198
+ licensee['Company'].to_s.match?(/GitLab/i) && licensee['Email'].to_s.end_with?('@gitlab.com')
199
+ end
200
+
201
+ def jh_team_license?
202
+ licensee['Company'].to_s.match?(/GitLab/i) && licensee['Email'].to_s.end_with?('@jihulab.com')
203
+ end
204
+
205
+ def temporary_extension?
206
+ temporary_extension == true
87
207
  end
88
208
 
89
209
  def restricted?(key = nil)
@@ -94,62 +214,110 @@ module Gitlab
94
214
  end
95
215
  end
96
216
 
97
- def attributes
217
+ def attributes
98
218
  hash = {}
99
219
 
100
- hash["version"] = self.version
101
- hash["licensee"] = self.licensee
220
+ hash['version'] = version
221
+ hash['licensee'] = licensee
222
+
223
+ # `issued_at` is the legacy name for starts_at.
224
+ # TODO: Move to starts_at in a next version.
225
+ hash['issued_at'] = starts_at
226
+ hash['expires_at'] = expires_at if will_expire?
102
227
 
103
- hash["issued_at"] = self.issued_at
104
- hash["expires_at"] = self.expires_at if self.will_expire?
228
+ hash['notify_admins_at'] = notify_admins_at if will_notify_admins?
229
+ hash['notify_users_at'] = notify_users_at if will_notify_users?
230
+ hash['block_changes_at'] = block_changes_at if will_block_changes?
105
231
 
106
- hash["notify_admins_at"] = self.notify_admins_at if self.will_notify_admins?
107
- hash["notify_users_at"] = self.notify_users_at if self.will_notify_users?
108
- hash["block_changes_at"] = self.block_changes_at if self.will_block_changes?
232
+ hash['next_sync_at'] = next_sync_at if will_sync?
233
+ hash['last_synced_at'] = last_synced_at if will_sync?
234
+ hash['activated_at'] = activated_at if activated?
109
235
 
110
- hash["restrictions"] = self.restrictions if self.restricted?
236
+ hash['cloud_licensing_enabled'] = cloud_licensing?
237
+ hash['offline_cloud_licensing_enabled'] = offline_cloud_licensing?
238
+ hash['auto_renew_enabled'] = auto_renew?
239
+ hash['seat_reconciliation_enabled'] = seat_reconciliation?
240
+ hash['operational_metrics_enabled'] = operational_metrics?
241
+ hash['contract_overages_allowed'] = contract_overages_allowed?
242
+
243
+ hash['generated_from_customers_dot'] = generated_from_customers_dot?
244
+ hash['generated_from_cancellation'] = generated_from_cancellation?
245
+
246
+ hash['temporary_extension'] = temporary_extension?
247
+
248
+ hash['restrictions'] = restrictions if restricted?
111
249
 
112
250
  hash
113
251
  end
114
252
 
115
- def to_json
116
- JSON.dump(self.attributes)
253
+ def to_json(*_args)
254
+ JSON.dump(attributes)
117
255
  end
118
256
 
119
- def export
257
+ def export(boundary: nil)
120
258
  validate!
121
259
 
122
- self.class.encryptor.encrypt(self.to_json)
260
+ data = self.class.encryptor.encrypt(to_json)
261
+
262
+ data = Boundary.add_boundary(data, boundary) if boundary
263
+
264
+ data
123
265
  end
124
266
 
125
267
  private
126
268
 
127
269
  def load_attributes(attributes)
128
- attributes = Hash[attributes.map { |k, v| [k.to_s, v] }]
270
+ attributes = attributes.transform_keys(&:to_s)
129
271
 
130
- version = attributes["version"] || 1
131
- unless version && version == 1
132
- raise ArgumentError, "Version is too new"
133
- end
272
+ version = attributes['version'] || 1
273
+ raise ArgumentError, 'Version is too new' unless version && version == 1
134
274
 
135
275
  @version = version
136
276
 
137
- @licensee = attributes["licensee"]
277
+ @licensee = attributes['licensee']
278
+
279
+ # `issued_at` is the legacy name for starts_at.
280
+ # TODO: Move to starts_at in a next version.
281
+ %w[issued_at expires_at notify_admins_at notify_users_at block_changes_at].each do |attr_name|
282
+ set_date_attribute(attr_name, attributes[attr_name])
283
+ end
138
284
 
139
- %w(issued_at expires_at notify_admins_at notify_users_at block_changes_at).each do |attr|
140
- value = attributes[attr]
141
- value = Date.parse(value) rescue nil if value.is_a?(String)
142
-
143
- next unless value
285
+ %w[last_synced_at next_sync_at activated_at].each do |attr_name|
286
+ set_datetime_attribute(attr_name, attributes[attr_name])
287
+ end
144
288
 
145
- send("#{attr}=", value)
289
+ %w[
290
+ cloud_licensing_enabled
291
+ offline_cloud_licensing_enabled
292
+ auto_renew_enabled
293
+ seat_reconciliation_enabled
294
+ operational_metrics_enabled
295
+ generated_from_customers_dot
296
+ generated_from_cancellation
297
+ temporary_extension
298
+ ].each do |attr_name|
299
+ public_send("#{attr_name}=", attributes[attr_name] == true)
146
300
  end
147
301
 
148
- restrictions = attributes["restrictions"]
149
- if restrictions && restrictions.is_a?(Hash)
150
- restrictions = Hash[restrictions.map { |k, v| [k.to_sym, v] }]
302
+ @contract_overages_allowed = attributes['contract_overages_allowed'] != false
303
+
304
+ restrictions = attributes['restrictions']
305
+ if restrictions&.is_a?(Hash)
306
+ restrictions = restrictions.transform_keys(&:to_sym)
151
307
  @restrictions = restrictions
152
308
  end
153
309
  end
310
+
311
+ def set_date_attribute(attr_name, value, date_class = Date)
312
+ value = date_class.parse(value) rescue nil if value.is_a?(String)
313
+
314
+ return unless value
315
+
316
+ public_send("#{attr_name}=", value)
317
+ end
318
+
319
+ def set_datetime_attribute(attr_name, value)
320
+ set_date_attribute(attr_name, value, DateTime)
321
+ end
154
322
  end
155
323
  end
metadata CHANGED
@@ -1,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-license
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Douwe Maan
8
- autorequire:
8
+ - Stan Hu
9
+ - Tyler Amos
10
+ autorequire:
9
11
  bindir: exe
10
12
  cert_chain: []
11
- date: 2015-04-29 00:00:00.000000000 Z
13
+ date: 2024-11-14 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: bundler
@@ -16,14 +18,28 @@ dependencies:
16
18
  requirements:
17
19
  - - "~>"
18
20
  - !ruby/object:Gem::Version
19
- version: '1.9'
21
+ version: '2.4'
20
22
  type: :development
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
23
25
  requirements:
24
26
  - - "~>"
25
27
  - !ruby/object:Gem::Version
26
- version: '1.9'
28
+ version: '2.4'
29
+ - !ruby/object:Gem::Dependency
30
+ name: byebug
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ type: :development
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
27
43
  - !ruby/object:Gem::Dependency
28
44
  name: rake
29
45
  requirement: !ruby/object:Gem::Requirement
@@ -39,28 +55,61 @@ dependencies:
39
55
  - !ruby/object:Gem::Version
40
56
  version: '10.0'
41
57
  - !ruby/object:Gem::Dependency
42
- name: byebug
58
+ name: rspec
43
59
  requirement: !ruby/object:Gem::Requirement
44
60
  requirements:
45
- - - ">="
61
+ - - "~>"
46
62
  - !ruby/object:Gem::Version
47
- version: '0'
63
+ version: '3.9'
48
64
  type: :development
49
65
  prerelease: false
50
66
  version_requirements: !ruby/object:Gem::Requirement
51
67
  requirements:
52
- - - ">="
68
+ - - "~>"
53
69
  - !ruby/object:Gem::Version
54
- version: '0'
55
- description:
70
+ version: '3.9'
71
+ - !ruby/object:Gem::Dependency
72
+ name: rubocop
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: 0.80.1
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - "~>"
83
+ - !ruby/object:Gem::Version
84
+ version: 0.80.1
85
+ - !ruby/object:Gem::Dependency
86
+ name: rubocop-rspec
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: 1.38.1
92
+ type: :development
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - "~>"
97
+ - !ruby/object:Gem::Version
98
+ version: 1.38.1
99
+ description:
56
100
  email:
57
101
  - douwe@gitlab.com
102
+ - stanhu@gitlab.com
103
+ - tamos@gitlab.com
58
104
  executables: []
59
105
  extensions: []
60
106
  extra_rdoc_files: []
61
107
  files:
62
108
  - ".gitignore"
109
+ - ".gitlab-ci.yml"
63
110
  - ".rspec"
111
+ - ".rubocop.yml"
112
+ - ".rubocop_todo.yml"
64
113
  - ".travis.yml"
65
114
  - Gemfile
66
115
  - LICENSE.txt
@@ -70,13 +119,14 @@ files:
70
119
  - bin/setup
71
120
  - gitlab-license.gemspec
72
121
  - lib/gitlab/license.rb
122
+ - lib/gitlab/license/boundary.rb
73
123
  - lib/gitlab/license/encryptor.rb
74
124
  - lib/gitlab/license/version.rb
75
- homepage: https://gitlab.com/gitlab-org/gitlab-license
125
+ homepage: https://dev.gitlab.org/gitlab/gitlab-license
76
126
  licenses:
77
127
  - MIT
78
128
  metadata: {}
79
- post_install_message:
129
+ post_install_message:
80
130
  rdoc_options: []
81
131
  require_paths:
82
132
  - lib
@@ -84,16 +134,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
84
134
  requirements:
85
135
  - - ">="
86
136
  - !ruby/object:Gem::Version
87
- version: '0'
137
+ version: 2.7.0
88
138
  required_rubygems_version: !ruby/object:Gem::Requirement
89
139
  requirements:
90
140
  - - ">="
91
141
  - !ruby/object:Gem::Version
92
142
  version: '0'
93
143
  requirements: []
94
- rubyforge_project:
95
- rubygems_version: 2.2.2
96
- signing_key:
144
+ rubygems_version: 3.1.6
145
+ signing_key:
97
146
  specification_version: 4
98
147
  summary: gitlab-license helps you generate, verify and enforce software licenses.
99
148
  test_files: []