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 +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 +73 -52
- data/lib/openproject-token.rb +3 -1
- metadata +7 -51
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,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
|
-
|
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
|
67
|
-
|
68
|
-
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)
|
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
|
-
|
80
|
+
expires_at
|
81
81
|
end
|
82
82
|
|
83
83
|
def will_notify_admins?
|
84
|
-
|
84
|
+
notify_admins_at
|
85
85
|
end
|
86
86
|
|
87
87
|
def will_notify_users?
|
88
|
-
|
88
|
+
notify_users_at
|
89
89
|
end
|
90
90
|
|
91
91
|
def will_block_changes?
|
92
|
-
|
92
|
+
block_changes_at
|
93
93
|
end
|
94
94
|
|
95
95
|
def has_feature?(name)
|
96
|
-
|
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 >=
|
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
|
-
(
|
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 >=
|
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 >=
|
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 >=
|
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"] =
|
161
|
-
hash["subscriber"] =
|
162
|
-
hash["mail"] =
|
163
|
-
hash["company"] =
|
164
|
-
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
|
165
179
|
|
166
|
-
hash["issued_at"] =
|
167
|
-
hash["starts_at"] =
|
168
|
-
hash["expires_at"] =
|
169
|
-
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?
|
170
184
|
|
171
|
-
hash["notify_admins_at"] =
|
172
|
-
hash["notify_users_at"] =
|
173
|
-
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?
|
174
188
|
|
175
|
-
hash["restrictions"] =
|
176
|
-
hash["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(
|
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 =
|
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
|
-
|
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
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
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
|
231
|
-
restrictions =
|
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[
|
236
|
-
if features
|
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?(
|
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(
|
311
|
+
@domain_required_from_version ||= Gem::Version.new("2.0")
|
291
312
|
end
|
292
313
|
|
293
314
|
##
|
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,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
|
-
|
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:
|
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.
|
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: []
|