openproject-token 4.0.0 → 5.0.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
2
  SHA256:
3
- metadata.gz: 26f34040f3ddbd6546761e8e6e33f5081b95550d3795dccccdf86f3610952b52
4
- data.tar.gz: d387c8130062a25183db07cbb3f43d7319836d143e3857d5271e24d99ef208eb
3
+ metadata.gz: 9021fbc26db21370414a6f9485ed9ce847b5d5ca3a77393aaff2e2f86c50728d
4
+ data.tar.gz: 370ab48e53014a37c6cbb4bf418400864df94186bbbeba219500acedc725f70b
5
5
  SHA512:
6
- metadata.gz: 7cfc8e13d23e2d50c5f769ea7482f526b92ecf6a83075ca03790c3415ecf959e073f60f611c217f7546f02b080242d3075cfc32a9185d5e69749c895aa398659
7
- data.tar.gz: bf8dd5ea2f830eeca4854560f560bcee3ccbbb6993e1d5868bf7caf40c24e0547b454e82b5aa9fde7384ac38314426cb9cac28f838197312596f6dfcf54ccc78
6
+ metadata.gz: eb330f918313dbda534b4f159d50c79645b0de2d64060134017fb6d0b5741a997a2f166fd06791626ac13f06f95d2d24551f33de6dd5c011c5ba696d7711f08a
7
+ data.tar.gz: 58c9d1c2db792f3bf1280973803c68fc244ef63b4c3cdc45cb6c82b79d8b3b5b5e97909f0480ef8d1654fa3bef8f2711ba0b27e3dfeb2a35954651048664500c
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OpenProject
2
4
  class Token
3
5
  module Armor
4
6
  class ParseError < StandardError; end
5
7
 
6
- MARKER = 'OPENPROJECT-EE TOKEN'
8
+ MARKER = "OPENPROJECT-EE TOKEN"
7
9
 
8
10
  class << self
9
11
  def header
@@ -15,19 +17,17 @@ module OpenProject
15
17
  end
16
18
 
17
19
  def encode(data)
18
- ''.tap do |s|
19
- s << header << "\n"
20
-
21
- s << data.strip << "\n"
22
-
23
- s << footer
24
- end
20
+ <<~DATA
21
+ #{header}
22
+ #{data.strip}
23
+ #{footer}
24
+ DATA
25
25
  end
26
26
 
27
27
  def decode(data)
28
28
  match = data.match /#{header}\r?\n(.+?)\r?\n#{footer}/m
29
29
  if match.nil?
30
- raise ParseError, 'Failed to parse armored text.'
30
+ raise ParseError, "Failed to parse armored text."
31
31
  end
32
32
 
33
33
  match[1]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OpenProject
2
4
  class Token
3
5
  class Extractor
@@ -40,17 +42,17 @@ module OpenProject
40
42
  end
41
43
 
42
44
  # Decrypt the data using symmetric AES encryption.
43
- cipher = OpenSSL::Cipher::AES128.new(:CBC)
45
+ cipher = OpenSSL::Cipher.new("aes-128-cbc")
44
46
  cipher.decrypt
45
47
 
46
48
  begin
47
- cipher.key = aes_key
49
+ cipher.key = aes_key
48
50
  rescue OpenSSL::Cipher::CipherError
49
51
  raise DecryptionError, "AES encryption key is invalid."
50
52
  end
51
53
 
52
54
  begin
53
- cipher.iv = aes_iv
55
+ cipher.iv = aes_iv
54
56
  rescue OpenSSL::Cipher::CipherError
55
57
  raise DecryptionError, "AES IV is invalid."
56
58
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenProject
4
+ class Token
5
+ LEGACY_ENTERPRISE_PLAN_FEATURES = %i[
6
+ baseline_comparison
7
+ board_view
8
+ conditional_highlighting
9
+ custom_actions
10
+ custom_field_hierarchies
11
+ customize_life_cycle
12
+ date_alerts
13
+ define_custom_style
14
+ edit_attribute_groups
15
+ gantt_pdf_export
16
+ grid_widget_wp_graph
17
+ ldap_groups
18
+ one_drive_sharepoint_file_storage
19
+ placeholder_users
20
+ project_list_sharing
21
+ readonly_work_packages
22
+ sso_auth_providers
23
+ team_planner_view
24
+ two_factor_authentication
25
+ virus_scanning
26
+ work_package_query_relation_columns
27
+ work_package_sharing
28
+ work_package_subject_generation
29
+ ].freeze
30
+
31
+ FEATURES_PER_PLAN = {
32
+ legacy_enterprise: LEGACY_ENTERPRISE_PLAN_FEATURES
33
+ }.freeze
34
+
35
+ AVAILABLE_PLAN_NAMES = FEATURES_PER_PLAN.keys.sort.freeze
36
+
37
+ # default plan that is assigned to a token if no plan is given (especially legacy tokens)
38
+ DEFAULT_PLAN = :legacy_enterprise
39
+ end
40
+ end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OpenProject
2
4
  class Token
3
- VERSION = "4.0.0"
5
+ VERSION = "5.0.0"
4
6
  end
5
7
  end
@@ -1,13 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "openssl"
2
4
  require "date"
3
5
  require "json"
4
6
  require "base64"
5
7
 
6
- require 'active_model'
8
+ require "active_model"
7
9
 
8
10
  require "open_project/token/version"
9
11
  require "open_project/token/extractor"
10
12
  require "open_project/token/armor"
13
+ require "open_project/token/plans"
11
14
 
12
15
  module OpenProject
13
16
  class Token
@@ -48,24 +51,21 @@ module OpenProject
48
51
 
49
52
  include ActiveModel::Validations
50
53
 
51
- attr_reader :version
52
- attr_accessor :subscriber, :mail, :company, :domain
53
- attr_accessor :starts_at, :issued_at, :expires_at
54
- attr_accessor :reprieve_days
55
- attr_accessor :notify_admins_at, :notify_users_at, :block_changes_at
56
- attr_accessor :restrictions
57
- attr_accessor :features
54
+ attr_reader :version, :plan
55
+ attr_accessor :subscriber, :mail, :company, :domain, :starts_at, :issued_at, :expires_at, :reprieve_days, :notify_admins_at,
56
+ :notify_users_at, :block_changes_at, :restrictions, :features
58
57
 
59
58
  validates_presence_of :subscriber
60
59
  validates_presence_of :mail
61
60
  validates_presence_of :company, allow_blank: true
62
61
  validates_presence_of :domain, if: :validate_domain?
62
+ validates_inclusion_of :plan, in: -> { OpenProject::Token::AVAILABLE_PLAN_NAMES }, allow_blank: true
63
63
 
64
64
  validates_each(
65
65
  :starts_at, :issued_at, :expires_at, :notify_admins_at, :notify_users_at, :block_changes_at,
66
- allow_blank: true) do |record, attr, value|
67
-
68
- record.errors.add attr, 'is not a date' if !value.is_a?(Date)
66
+ allow_blank: true
67
+ ) do |record, attr, value|
68
+ record.errors.add attr, "is not a date" if !value.is_a?(Date)
69
69
  end
70
70
 
71
71
  validates_each :restrictions, allow_nil: true do |record, attr, value|
@@ -77,23 +77,36 @@ module OpenProject
77
77
  end
78
78
 
79
79
  def will_expire?
80
- self.expires_at
80
+ expires_at
81
81
  end
82
82
 
83
83
  def will_notify_admins?
84
- self.notify_admins_at
84
+ notify_admins_at
85
85
  end
86
86
 
87
87
  def will_notify_users?
88
- self.notify_users_at
88
+ notify_users_at
89
89
  end
90
90
 
91
91
  def will_block_changes?
92
- self.block_changes_at
92
+ block_changes_at
93
93
  end
94
94
 
95
95
  def has_feature?(name)
96
- features && features.include?(name.to_sym)
96
+ available_features.include?(name.to_sym)
97
+ end
98
+
99
+ def plan=(value)
100
+ value.presence&.to_sym
101
+ end
102
+
103
+ def available_features
104
+ return @available_features if defined?(@available_features)
105
+
106
+ relevant_features = OpenProject::Token::FEATURES_PER_PLAN[plan] || []
107
+ additional_features = features || []
108
+
109
+ @available_features = (relevant_features + additional_features).uniq
97
110
  end
98
111
 
99
112
  ##
@@ -108,7 +121,7 @@ module OpenProject
108
121
  def expired?(reprieve: true)
109
122
  offset = reprieve ? reprieve_days.to_i : 0
110
123
 
111
- will_expire? && Date.today >= self.expires_at.next_day(offset)
124
+ will_expire? && Date.today >= expires_at.next_day(offset)
112
125
  end
113
126
 
114
127
  ##
@@ -118,19 +131,19 @@ module OpenProject
118
131
  def reprieve_days_left
119
132
  return nil unless reprieve_days.to_i > 0 && expired?(reprieve: false)
120
133
 
121
- (self.expires_at.next_day(reprieve_days.to_i) - Date.today).to_i
134
+ (expires_at.next_day(reprieve_days.to_i) - Date.today).to_i
122
135
  end
123
136
 
124
137
  def notify_admins?
125
- will_notify_admins? && Date.today >= self.notify_admins_at
138
+ will_notify_admins? && Date.today >= notify_admins_at
126
139
  end
127
140
 
128
141
  def notify_users?
129
- will_notify_users? && Date.today >= self.notify_users_at
142
+ will_notify_users? && Date.today >= notify_users_at
130
143
  end
131
144
 
132
145
  def block_changes?
133
- will_block_changes? && Date.today >= self.block_changes_at
146
+ will_block_changes? && Date.today >= block_changes_at
134
147
  end
135
148
 
136
149
  # tokens with no version or a version lower than 2.0 don't have the attributes company or domain
@@ -157,34 +170,35 @@ module OpenProject
157
170
  def attributes
158
171
  hash = {}
159
172
 
160
- hash["version"] = self.version
161
- hash["subscriber"] = self.subscriber
162
- hash["mail"] = self.mail
163
- hash["company"] = self.company
164
- hash["domain"] = self.domain
173
+ hash["version"] = version
174
+ hash["subscriber"] = subscriber
175
+ hash["mail"] = mail
176
+ hash["company"] = company
177
+ hash["domain"] = domain
178
+ hash["plan"] = plan
165
179
 
166
- hash["issued_at"] = self.issued_at
167
- hash["starts_at"] = self.starts_at
168
- hash["expires_at"] = self.expires_at if self.will_expire?
169
- hash["reprieve_days"] = self.reprieve_days if self.will_expire?
180
+ hash["issued_at"] = issued_at
181
+ hash["starts_at"] = starts_at
182
+ hash["expires_at"] = expires_at if will_expire?
183
+ hash["reprieve_days"] = reprieve_days if will_expire?
170
184
 
171
- hash["notify_admins_at"] = self.notify_admins_at if self.will_notify_admins?
172
- hash["notify_users_at"] = self.notify_users_at if self.will_notify_users?
173
- hash["block_changes_at"] = self.block_changes_at if self.will_block_changes?
185
+ hash["notify_admins_at"] = notify_admins_at if will_notify_admins?
186
+ hash["notify_users_at"] = notify_users_at if will_notify_users?
187
+ hash["block_changes_at"] = block_changes_at if will_block_changes?
174
188
 
175
- hash["restrictions"] = self.restrictions if self.restricted?
176
- hash["features"] = self.features
189
+ hash["restrictions"] = restrictions if restricted?
190
+ hash["features"] = features
177
191
 
178
192
  hash
179
193
  end
180
194
 
181
- def to_json
182
- JSON.dump(self.attributes)
195
+ def to_json(*_args)
196
+ JSON.dump(attributes)
183
197
  end
184
198
 
185
199
  def from_json(json)
186
200
  load_attributes(JSON.parse(json))
187
- rescue => e
201
+ rescue StandardError => e
188
202
  raise ParseError, "Failed to load from json: #{e}"
189
203
  end
190
204
 
@@ -194,11 +208,10 @@ module OpenProject
194
208
  @parsed_domain
195
209
  end
196
210
 
197
-
198
211
  private
199
212
 
200
213
  def load_attributes(attributes)
201
- attributes = Hash[attributes.map { |k, v| [k.to_s, v] }]
214
+ attributes = attributes.transform_keys(&:to_s)
202
215
 
203
216
  @version = read_version attributes
204
217
  @subscriber = attributes["subscriber"]
@@ -208,7 +221,13 @@ module OpenProject
208
221
 
209
222
  date_attribute_keys.each do |attr|
210
223
  value = attributes[attr]
211
- value = Date.parse(value) rescue nil if value.is_a?(String)
224
+ if value.is_a?(String)
225
+ value = begin
226
+ Date.parse(value)
227
+ rescue StandardError
228
+ nil
229
+ end
230
+ end
212
231
 
213
232
  next unless value
214
233
 
@@ -218,24 +237,26 @@ module OpenProject
218
237
  reprieve_days = attributes["reprieve_days"]
219
238
 
220
239
  if will_expire?
221
- if reprieve_days.nil? && apply_default_reprieve?(version)
222
- @reprieve_days = 7
223
- else
224
- @reprieve_days = reprieve_days.to_i
225
- end
240
+ @reprieve_days = if reprieve_days.nil? && apply_default_reprieve?(version)
241
+ 7
242
+ else
243
+ reprieve_days.to_i
244
+ end
226
245
  end
227
246
 
228
247
  restrictions = attributes["restrictions"]
229
248
 
230
- if restrictions && restrictions.is_a?(Hash)
231
- restrictions = Hash[restrictions.map { |k, v| [k.to_sym, v] }]
249
+ if restrictions.is_a?(Hash)
250
+ restrictions = restrictions.transform_keys(&:to_sym)
232
251
  @restrictions = restrictions
233
252
  end
234
253
 
235
- features = attributes['features']
236
- if features && features.is_a?(Array)
254
+ features = attributes["features"]
255
+ if features.is_a?(Array)
237
256
  @features = features.map(&:to_sym)
238
257
  end
258
+
259
+ @plan = attributes["plan"].presence&.to_sym || OpenProject::Token::DEFAULT_PLAN
239
260
  end
240
261
 
241
262
  ##
@@ -272,7 +293,7 @@ module OpenProject
272
293
  end
273
294
 
274
295
  def read_domain!(input)
275
- return input if input.nil? || !(input.start_with?('/') && input.end_with?('/'))
296
+ return input if input.nil? || !(input.start_with?("/") && input.end_with?("/"))
276
297
 
277
298
  # Omit the slashes of the input
278
299
  Regexp.new input[1..-2]
@@ -287,7 +308,7 @@ module OpenProject
287
308
  end
288
309
 
289
310
  def domain_required_from_version
290
- @domain_required_from_version ||= Gem::Version.new('2.0')
311
+ @domain_required_from_version ||= Gem::Version.new("2.0")
291
312
  end
292
313
 
293
314
  ##
@@ -1 +1,3 @@
1
- require 'open_project/token'
1
+ # frozen_string_literal: true
2
+
3
+ require "open_project/token"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openproject-token
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenProject GmbH
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-11-08 00:00:00.000000000 Z
10
+ date: 2025-02-28 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activemodel
@@ -24,49 +23,6 @@ dependencies:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
25
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: pry
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0.10'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0.10'
41
- - !ruby/object:Gem::Dependency
42
- name: rspec
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '3.5'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '3.5'
55
- - !ruby/object:Gem::Dependency
56
- name: debug
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- description:
70
26
  email: info@openproject.com
71
27
  executables: []
72
28
  extensions: []
@@ -77,13 +33,14 @@ files:
77
33
  - lib/open_project/token.rb
78
34
  - lib/open_project/token/armor.rb
79
35
  - lib/open_project/token/extractor.rb
36
+ - lib/open_project/token/plans.rb
80
37
  - lib/open_project/token/version.rb
81
38
  - lib/openproject-token.rb
82
39
  homepage: https://www.openproject.org
83
40
  licenses:
84
41
  - GPL-3.0
85
- metadata: {}
86
- post_install_message:
42
+ metadata:
43
+ rubygems_mfa_required: 'true'
87
44
  rdoc_options: []
88
45
  require_paths:
89
46
  - lib
@@ -91,15 +48,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
48
  requirements:
92
49
  - - ">="
93
50
  - !ruby/object:Gem::Version
94
- version: '0'
51
+ version: 3.4.2
95
52
  required_rubygems_version: !ruby/object:Gem::Requirement
96
53
  requirements:
97
54
  - - ">="
98
55
  - !ruby/object:Gem::Version
99
56
  version: '0'
100
57
  requirements: []
101
- rubygems_version: 3.4.6
102
- signing_key:
58
+ rubygems_version: 3.6.5
103
59
  specification_version: 4
104
60
  summary: OpenProject EE token reader
105
61
  test_files: []