openproject-token 3.0.1 → 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: f959bb6247948bcf6fd18e7f09c798e5b037d1a4d62bf6e1c92781e7e2e5e4e6
4
- data.tar.gz: 9d42841010ef13874b4a3b489c1e96bb750c0650e00a94ed583008623279fbfe
3
+ metadata.gz: 9021fbc26db21370414a6f9485ed9ce847b5d5ca3a77393aaff2e2f86c50728d
4
+ data.tar.gz: 370ab48e53014a37c6cbb4bf418400864df94186bbbeba219500acedc725f70b
5
5
  SHA512:
6
- metadata.gz: a9128f8b0bc9d6cb550dc89c1d085bed523f552f53c44800b3f51819e2b386fe77d2734178bf9c66de8bbd8506de0ee21b32fe7af3362f8bc6916a93eea7ffee
7
- data.tar.gz: 3e3172042fac599e58fb80aaa569adfa697a30713eab643d5f4a085728a725d2e7e8b8561772a778266ee8bb5d3211bb6a46bce80d3987cec1fbc6bdc04d971d
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 = "3.0.1"
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,23 +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
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
57
57
 
58
58
  validates_presence_of :subscriber
59
59
  validates_presence_of :mail
60
60
  validates_presence_of :company, allow_blank: true
61
61
  validates_presence_of :domain, if: :validate_domain?
62
+ validates_inclusion_of :plan, in: -> { OpenProject::Token::AVAILABLE_PLAN_NAMES }, allow_blank: true
62
63
 
63
64
  validates_each(
64
65
  :starts_at, :issued_at, :expires_at, :notify_admins_at, :notify_users_at, :block_changes_at,
65
- allow_blank: true) do |record, attr, value|
66
-
67
- 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)
68
69
  end
69
70
 
70
71
  validates_each :restrictions, allow_nil: true do |record, attr, value|
@@ -76,19 +77,36 @@ module OpenProject
76
77
  end
77
78
 
78
79
  def will_expire?
79
- self.expires_at
80
+ expires_at
80
81
  end
81
82
 
82
83
  def will_notify_admins?
83
- self.notify_admins_at
84
+ notify_admins_at
84
85
  end
85
86
 
86
87
  def will_notify_users?
87
- self.notify_users_at
88
+ notify_users_at
88
89
  end
89
90
 
90
91
  def will_block_changes?
91
- self.block_changes_at
92
+ block_changes_at
93
+ end
94
+
95
+ def has_feature?(name)
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
92
110
  end
93
111
 
94
112
  ##
@@ -103,7 +121,7 @@ module OpenProject
103
121
  def expired?(reprieve: true)
104
122
  offset = reprieve ? reprieve_days.to_i : 0
105
123
 
106
- will_expire? && Date.today >= self.expires_at.next_day(offset)
124
+ will_expire? && Date.today >= expires_at.next_day(offset)
107
125
  end
108
126
 
109
127
  ##
@@ -113,19 +131,19 @@ module OpenProject
113
131
  def reprieve_days_left
114
132
  return nil unless reprieve_days.to_i > 0 && expired?(reprieve: false)
115
133
 
116
- (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
117
135
  end
118
136
 
119
137
  def notify_admins?
120
- will_notify_admins? && Date.today >= self.notify_admins_at
138
+ will_notify_admins? && Date.today >= notify_admins_at
121
139
  end
122
140
 
123
141
  def notify_users?
124
- will_notify_users? && Date.today >= self.notify_users_at
142
+ will_notify_users? && Date.today >= notify_users_at
125
143
  end
126
144
 
127
145
  def block_changes?
128
- will_block_changes? && Date.today >= self.block_changes_at
146
+ will_block_changes? && Date.today >= block_changes_at
129
147
  end
130
148
 
131
149
  # tokens with no version or a version lower than 2.0 don't have the attributes company or domain
@@ -152,33 +170,35 @@ module OpenProject
152
170
  def attributes
153
171
  hash = {}
154
172
 
155
- hash["version"] = self.version
156
- hash["subscriber"] = self.subscriber
157
- hash["mail"] = self.mail
158
- hash["company"] = self.company
159
- 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
160
179
 
161
- hash["issued_at"] = self.issued_at
162
- hash["starts_at"] = self.starts_at
163
- hash["expires_at"] = self.expires_at if self.will_expire?
164
- 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?
165
184
 
166
- hash["notify_admins_at"] = self.notify_admins_at if self.will_notify_admins?
167
- hash["notify_users_at"] = self.notify_users_at if self.will_notify_users?
168
- 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?
169
188
 
170
- hash["restrictions"] = self.restrictions if self.restricted?
189
+ hash["restrictions"] = restrictions if restricted?
190
+ hash["features"] = features
171
191
 
172
192
  hash
173
193
  end
174
194
 
175
- def to_json
176
- JSON.dump(self.attributes)
195
+ def to_json(*_args)
196
+ JSON.dump(attributes)
177
197
  end
178
198
 
179
199
  def from_json(json)
180
200
  load_attributes(JSON.parse(json))
181
- rescue => e
201
+ rescue StandardError => e
182
202
  raise ParseError, "Failed to load from json: #{e}"
183
203
  end
184
204
 
@@ -188,11 +208,10 @@ module OpenProject
188
208
  @parsed_domain
189
209
  end
190
210
 
191
-
192
211
  private
193
212
 
194
213
  def load_attributes(attributes)
195
- attributes = Hash[attributes.map { |k, v| [k.to_s, v] }]
214
+ attributes = attributes.transform_keys(&:to_s)
196
215
 
197
216
  @version = read_version attributes
198
217
  @subscriber = attributes["subscriber"]
@@ -202,7 +221,13 @@ module OpenProject
202
221
 
203
222
  date_attribute_keys.each do |attr|
204
223
  value = attributes[attr]
205
- 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
206
231
 
207
232
  next unless value
208
233
 
@@ -212,19 +237,26 @@ module OpenProject
212
237
  reprieve_days = attributes["reprieve_days"]
213
238
 
214
239
  if will_expire?
215
- if reprieve_days.nil? && apply_default_reprieve?(version)
216
- @reprieve_days = 7
217
- else
218
- @reprieve_days = reprieve_days.to_i
219
- end
240
+ @reprieve_days = if reprieve_days.nil? && apply_default_reprieve?(version)
241
+ 7
242
+ else
243
+ reprieve_days.to_i
244
+ end
220
245
  end
221
246
 
222
247
  restrictions = attributes["restrictions"]
223
248
 
224
- if restrictions && restrictions.is_a?(Hash)
225
- restrictions = Hash[restrictions.map { |k, v| [k.to_sym, v] }]
249
+ if restrictions.is_a?(Hash)
250
+ restrictions = restrictions.transform_keys(&:to_sym)
226
251
  @restrictions = restrictions
227
252
  end
253
+
254
+ features = attributes["features"]
255
+ if features.is_a?(Array)
256
+ @features = features.map(&:to_sym)
257
+ end
258
+
259
+ @plan = attributes["plan"].presence&.to_sym || OpenProject::Token::DEFAULT_PLAN
228
260
  end
229
261
 
230
262
  ##
@@ -261,7 +293,7 @@ module OpenProject
261
293
  end
262
294
 
263
295
  def read_domain!(input)
264
- return input if input.nil? || !(input.start_with?('/') && input.end_with?('/'))
296
+ return input if input.nil? || !(input.start_with?("/") && input.end_with?("/"))
265
297
 
266
298
  # Omit the slashes of the input
267
299
  Regexp.new input[1..-2]
@@ -276,10 +308,9 @@ module OpenProject
276
308
  end
277
309
 
278
310
  def domain_required_from_version
279
- @domain_required_from_version ||= Gem::Version.new('2.0')
311
+ @domain_required_from_version ||= Gem::Version.new("2.0")
280
312
  end
281
313
 
282
-
283
314
  ##
284
315
  # Reprieve was introduced in version 2.2.0 so could only be set
285
316
  # during generation from then onwards. All tokens before that
@@ -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: 3.0.1
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-04-17 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,35 +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
- description:
56
26
  email: info@openproject.com
57
27
  executables: []
58
28
  extensions: []
@@ -63,13 +33,14 @@ files:
63
33
  - lib/open_project/token.rb
64
34
  - lib/open_project/token/armor.rb
65
35
  - lib/open_project/token/extractor.rb
36
+ - lib/open_project/token/plans.rb
66
37
  - lib/open_project/token/version.rb
67
38
  - lib/openproject-token.rb
68
39
  homepage: https://www.openproject.org
69
40
  licenses:
70
41
  - GPL-3.0
71
- metadata: {}
72
- post_install_message:
42
+ metadata:
43
+ rubygems_mfa_required: 'true'
73
44
  rdoc_options: []
74
45
  require_paths:
75
46
  - lib
@@ -77,15 +48,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
77
48
  requirements:
78
49
  - - ">="
79
50
  - !ruby/object:Gem::Version
80
- version: '0'
51
+ version: 3.4.2
81
52
  required_rubygems_version: !ruby/object:Gem::Requirement
82
53
  requirements:
83
54
  - - ">="
84
55
  - !ruby/object:Gem::Version
85
56
  version: '0'
86
57
  requirements: []
87
- rubygems_version: 3.3.7
88
- signing_key:
58
+ rubygems_version: 3.6.5
89
59
  specification_version: 4
90
60
  summary: OpenProject EE token reader
91
61
  test_files: []