Feature #29664 » 0002-adds-the-use_webhooks-permission.patch
| 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) |