Project

General

Profile

Feature #29664 » 0002-adds-the-use_webhooks-permission.patch

Jens Krämer, 2025-05-12 03:56

View differences:

app/controllers/webhooks_controller.rb
4 4
  self.main_menu = false
5 5

  
6 6
  before_action :require_login
7
  before_action :authorize
8

  
7 9
  before_action :find_webhook, only: [:edit, :update, :destroy]
8 10

  
9 11
  require_sudo_mode :create, :update, :destroy
......
56 58
  def webhooks
57 59
    User.current.webhooks
58 60
  end
61

  
62
  def authorize
63
    deny_access unless User.current.allowed_to?(:use_webhooks, nil, global: true)
64
  end
59 65
end
app/models/webhook.rb
39 39

  
40 40
  scope :active, -> { where(active: true) }
41 41

  
42
  before_validation ->(hook){ hook.projects = hook.projects.to_a.select{|p| p.visible?(hook.user) } }
42
  before_validation ->(hook){ hook.projects = hook.projects.to_a & hook.setable_projects }
43 43

  
44 44
  # Triggers the given event for the given object, scheduling qualifying hooks
45 45
  # to be called.
......
61 61
      .eager_load(:user)
62 62
      .where(users: { status: User::STATUS_ACTIVE }, projects_webhooks: { project_id: object.project_id })
63 63
      .to_a.select do |hook|
64
      hook.events.include?(event) && object.visible?(hook.user)
64
      hook.events.include?(event) && object.visible?(hook.user) && hook.user.allowed_to?(:use_webhooks, object.project)
65 65
    end
66 66
  end
67 67

  
68 68
  def setable_projects
69
    Project.visible
69
    user = self.user || User.current
70
    Project.visible(user).to_a.select{|p| user.allowed_to?(:use_webhooks, p)}
70 71
  end
71 72

  
72 73
  def setable_events
app/views/my/account.html.erb
1 1
<div class="contextual">
2 2
<%= additional_emails_link(@user) %>
3 3
<%= link_to(sprite_icon('key', l(:button_change_password)), { :action => 'password'}, :class => 'icon icon-passwd') if @user.change_password_allowed? %>
4
<%= link_to sprite_icon('webhook', l(:label_webhook_plural)), webhooks_path, class: 'icon icon-webhook' %>
4
<%= link_to sprite_icon('webhook', l(:label_webhook_plural)), webhooks_path, class: 'icon icon-webhook' if @user.allowed_to?(:use_webhooks, nil, global: true) %>
5 5
<%= call_hook(:view_my_account_contextual, :user => @user)%>
6 6
</div>
7 7

  
config/locales/de.yml
970 970
  permission_set_issues_private: Tickets als privat oder öffentlich markieren
971 971
  permission_set_notes_private: Kommentar als privat markieren
972 972
  permission_set_own_issues_private: Eigene Tickets als privat oder öffentlich markieren
973
  permission_use_webhooks: Webhooks verwenden
973 974
  permission_view_calendar: Kalender ansehen
974 975
  permission_view_changesets: Changesets ansehen
975 976
  permission_view_documents: Dokumente ansehen
config/locales/en.yml
605 605
  permission_manage_related_issues: Manage related issues
606 606
  permission_import_issues: Import issues
607 607
  permission_log_time_for_other_users: Log spent time for other users
608
  permission_use_webhooks: Use webhooks
608 609

  
609 610
  project_module_issue_tracking: Issue tracking
610 611
  project_module_time_tracking: Time tracking
lib/redmine/preparation.rb
49 49
        map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member
50 50
        map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin
51 51

  
52
        # Webhooks
53
        map.permission :use_webhooks, {}, :require => :member
54

  
52 55
        map.project_module :issue_tracking do |map|
53 56
          # Issues
54 57
          map.permission :view_issues, {:issues => [:index, :show, :issue_tab],
test/functional/webhooks_controller_test.rb
16 16
    @project = Project.find 'ecookbook'
17 17
    @dlopper = User.find_by_login 'dlopper'
18 18
    @issue = @project.issues.first
19
    @role = Role.find_by_name 'Developer'
20
    @role.permissions << :use_webhooks; @role.save!
19 21
    @hook = create_hook
20 22
    @other_hook = create_hook user: User.find_by_login('admin'), url: 'https://example.com/other/hook'
21 23
    @request.session[:user_id] = @dlopper.id
test/unit/webhook_test.rb
22 22

  
23 23
    @project = Project.find 'ecookbook'
24 24
    @dlopper = User.find_by_login 'dlopper'
25
    @role = Role.find_by_name 'Developer'
26
    @role.permissions << :use_webhooks; @role.save!
25 27
    @issue = @project.issues.first
26 28
    WebhookEndpointValidator.class_eval do
27 29
      @blocked_hosts = nil
......
68 70
    assert_raise(ActiveRecord::SerializationTypeMismatch){ Webhook.new(events: 'issue.created') }
69 71
  end
70 72

  
71
  test "should clean up project list on save" do
73
  test "should clean up project list based on permissions on save" do
74
    h = create_hook
75
    assert_equal [@project], h.projects
76
    @role.permissions.delete :use_webhooks
77
    @role.save!
78

  
79
    h.reload
80
    h.save
81
    h.reload
82
    assert_equal [], h.projects
83
  end
84

  
85
  test "should clean up project list based on project visibility on save" do
72 86
    h = create_hook
73 87
    assert_equal [@project], h.projects
74 88
    @project.memberships.destroy_all
......
80 94
    assert_equal [], h.projects
81 95
  end
82 96

  
97
  test "should filter setable projects" do
98
    assert_equal [@project], Webhook.new(user: @dlopper).setable_projects
99

  
100
    @role.permissions.delete :use_webhooks
101
    @role.save!
102
    @dlopper.reload
103
    assert_equal [], Webhook.new(user: @dlopper).setable_projects
104
  end
105

  
83 106
  test "should check ip address at run time" do
84 107
    Redmine::Configuration.with('webhook_blocklist' => ['*.example.org', '10.0.0.0/8', '192.168.0.0/16']) do
85 108
      %w[
......
109 132
    assert_equal [], Webhook.hooks_for('issue.created', @issue)
110 133
  end
111 134

  
135
  test "should check permission when looking for hooks" do
136
    hook = create_hook
137
    assert @issue.visible?(hook.user)
138
    assert_equal [hook], Webhook.hooks_for('issue.created', @issue)
139
    @role.permissions.delete :use_webhooks
140
    @role.save!
141
    assert_equal [], Webhook.hooks_for('issue.created', @issue)
142
  end
143

  
112 144
  test "should not find inactive hook" do
113 145
    hook = create_hook active: false
114 146
    assert @issue.visible?(hook.user)
(2-2/3)