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 +4 -4
- data/lib/open_project/token/armor.rb +9 -9
- data/lib/open_project/token/extractor.rb +5 -3
- data/lib/open_project/token/plans.rb +40 -0
- data/lib/open_project/token/version.rb +3 -1
- data/lib/open_project/token.rb +79 -48
- data/lib/openproject-token.rb +3 -1
- metadata +7 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9021fbc26db21370414a6f9485ed9ce847b5d5ca3a77393aaff2e2f86c50728d
|
4
|
+
data.tar.gz: 370ab48e53014a37c6cbb4bf418400864df94186bbbeba219500acedc725f70b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 =
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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,
|
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
|
45
|
+
cipher = OpenSSL::Cipher.new("aes-128-cbc")
|
44
46
|
cipher.decrypt
|
45
47
|
|
46
48
|
begin
|
47
|
-
cipher.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
|
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
|
data/lib/open_project/token.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
66
|
-
|
67
|
-
record.errors.add attr,
|
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
|
-
|
80
|
+
expires_at
|
80
81
|
end
|
81
82
|
|
82
83
|
def will_notify_admins?
|
83
|
-
|
84
|
+
notify_admins_at
|
84
85
|
end
|
85
86
|
|
86
87
|
def will_notify_users?
|
87
|
-
|
88
|
+
notify_users_at
|
88
89
|
end
|
89
90
|
|
90
91
|
def will_block_changes?
|
91
|
-
|
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 >=
|
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
|
-
(
|
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 >=
|
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 >=
|
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 >=
|
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"] =
|
156
|
-
hash["subscriber"] =
|
157
|
-
hash["mail"] =
|
158
|
-
hash["company"] =
|
159
|
-
hash["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"] =
|
162
|
-
hash["starts_at"] =
|
163
|
-
hash["expires_at"] =
|
164
|
-
hash["reprieve_days"] =
|
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"] =
|
167
|
-
hash["notify_users_at"] =
|
168
|
-
hash["block_changes_at"] =
|
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"] =
|
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(
|
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 =
|
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
|
-
|
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
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
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
|
225
|
-
restrictions =
|
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?(
|
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(
|
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
|
data/lib/openproject-token.rb
CHANGED
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
|
+
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:
|
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
|
-
|
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:
|
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.
|
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: []
|