Project

General

Profile

Feature #43938 » 0002-track-token-usage.patch

Vincent Robert, 2026-04-10 08:36

View differences:

app/models/token.rb
94 94

  
95 95
  # Returns the active user who owns the key for the given action
96 96
  def self.find_active_user(action, key, validity_days=nil)
97
    user = find_user(action, key, validity_days)
98
    if user && user.active?
99
      user
97
    token = find_token(action, key, validity_days)
98
    if token
99
      user = token.user
100
      if user&.active?
101
        if token.updated_on.nil? || token.updated_on <= 1.minute.ago
102
          token.update_column(:updated_on, Time.now.utc)
103
        end
104
        user
105
      end
100 106
    end
101 107
  end
102 108

  
app/views/my/_sidebar.html.erb
38 38
  <%= javascript_tag("$('#api-access-key').hide();") %>
39 39
  <p>
40 40
  <% if @user.api_token %>
41
  <%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %>
41
    <%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %><br />
42
    <% if @user.api_token.updated_on > @user.api_token.created_on %>
43
      <%= l(:label_api_access_key_last_used_on, distance_of_time_in_words(Time.now, @user.api_token.updated_on)) %>
44
    <% else %>
45
      <%= l(:label_api_access_key_never_used) %>
46
    <% end %>
42 47
  <% else %>
43
  <%= l(:label_missing_api_access_key) %>
48
    <%= l(:label_missing_api_access_key) %>
44 49
  <% end %>
45 50
  (<%= link_to l(:button_reset), my_api_key_path, :method => :post %>)
46 51
  </p>
config/locales/de.yml
434 434
  label_any_issues_not_in_project: irgendein Ticket nicht im Projekt
435 435
  label_api_access_key: API-Zugriffsschlüssel
436 436
  label_api_access_key_created_on: Der API-Zugriffsschlüssel wurde vor %{value} erstellt
437
  label_api_access_key_last_used_on: "Zuletzt verwendet: vor %{value}"
438
  label_api_access_key_never_used: Nie verwendet
437 439
  label_applied_status: Zugewiesener Status
438 440
  label_ascending: Aufsteigend
439 441
  label_ask: Nachfragen
config/locales/en.yml
1035 1035
  label_api_access_key: API access key
1036 1036
  label_missing_api_access_key: Missing an API access key
1037 1037
  label_api_access_key_created_on: "API access key created %{value} ago"
1038
  label_api_access_key_last_used_on: "Last used: %{value} ago"
1039
  label_api_access_key_never_used: Never used
1038 1040
  label_profile: Profile
1039 1041
  label_subtask: Subtask
1040 1042
  label_subtask_plural: Subtasks
config/locales/fr.yml
921 921
  label_api_access_key: Clé d'accès API
922 922
  label_missing_api_access_key: Clé d'accès API manquante
923 923
  label_api_access_key_created_on: Clé d'accès API créée il y a %{value}
924
  label_api_access_key_last_used_on: "Dernier usage : il y a %{value}"
925
  label_api_access_key_never_used: Jamais utilisée
924 926
  label_profile: Profil
925 927
  label_subtask_plural: Sous-tâches
926 928
  label_project_copy_notifications: Envoyer les notifications durant la copie du projet
config/locales/ja.yml
806 806
  label_api_access_key: APIアクセスキー
807 807
  label_missing_api_access_key: APIアクセスキーが見つかりません
808 808
  label_api_access_key_created_on: "APIアクセスキーは%{value}前に作成されました"
809
  label_api_access_key_last_used_on: "最終使用:%{value}前"
810
  label_api_access_key_never_used: 未使用
809 811
  label_subtask_plural: 子チケット
810 812
  label_project_copy_notifications: コピーしたチケットのメール通知を送信する
811 813
  label_principal_search: "ユーザーまたはグループの検索:"
test/integration/api_test/authentication_test.rb
161 161
    assert_response :success
162 162
    assert_select 'h2', :text => "#{user.initials} #{user.name}"
163 163
  end
164

  
165
  def test_api_key_usage_via_header_should_update_updated_on
166
    user = User.generate!
167
    token = Token.create!(:user => user, :action => 'api', :updated_on => 2.minutes.ago)
168
    updated = token.updated_on
169
    get '/users/current.xml', :headers => {'X-Redmine-API-Key' => token.value}
170
    assert_response :ok
171
    assert token.reload.updated_on > updated
172
  end
173

  
174
  def test_api_key_usage_via_parameter_should_update_updated_on
175
    user = User.generate!
176
    token = Token.create!(:user => user, :action => 'api', :updated_on => 2.minutes.ago)
177
    updated = token.updated_on
178
    get "/users/current.xml?key=#{token.value}"
179
    assert_response :ok
180
    assert token.reload.updated_on > updated
181
  end
182

  
183
  def test_api_key_usage_via_basic_auth_should_update_updated_on
184
    user = User.generate!
185
    token = Token.create!(:user => user, :action => 'api', :updated_on => 2.minutes.ago)
186
    updated = token.updated_on
187
    get '/users/current.xml', :headers => credentials(token.value, 'X')
188
    assert_response :ok
189
    assert token.reload.updated_on > updated
190
  end
191

  
192
  def test_failed_api_auth_should_not_update_updated_on
193
    user = User.generate!
194
    token = Token.create!(:user => user, :action => 'api', :updated_on => 2.minutes.ago)
195
    updated = token.updated_on
196
    get '/users/current.xml', :headers => {'X-Redmine-API-Key' => 'wrong_key'}
197
    assert_response :unauthorized
198
    assert_equal updated.to_i, token.reload.updated_on.to_i
199
  end
164 200
end
test/unit/token_test.rb
137 137
    token = Token.create!(:user_id => 999, :action => 'api', :created_on => 2.days.ago)
138 138
    assert_nil Token.find_token('api', token.value, 1)
139 139
  end
140

  
141
  def test_find_active_user_should_bump_updated_on_when_not_recently_updated
142
    token = Token.create!(:user_id => 1, :action => 'api', :updated_on => 2.minutes.ago)
143
    updated = token.updated_on
144
    Token.find_active_user('api', token.value)
145
    assert token.reload.updated_on > updated
146
  end
147

  
148
  def test_find_active_user_should_not_bump_updated_on_within_one_minute
149
    token = Token.create!(:user_id => 1, :action => 'api', :updated_on => 1.second.ago)
150
    updated = token.reload.updated_on
151
    Token.find_active_user('api', token.value)
152
    assert_equal updated.to_i, token.reload.updated_on.to_i
153
  end
154

  
155
  def test_find_active_user_should_bump_updated_on_for_feeds_token
156
    token = Token.create!(:user_id => 1, :action => 'feeds', :updated_on => 2.minutes.ago)
157
    updated = token.updated_on
158
    Token.find_active_user('feeds', token.value)
159
    assert token.reload.updated_on > updated
160
  end
140 161
end
(2-2/2)