activity_notification 2.6.1 → 2.7.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/README.md +3 -5
- data/app/controllers/activity_notification/notifications_api_controller.rb +19 -7
- data/app/controllers/activity_notification/notifications_controller.rb +17 -2
- data/app/controllers/activity_notification/subscriptions_api_controller.rb +5 -1
- data/docs/Functions.md +16 -0
- data/lib/activity_notification/apis/notification_api.rb +1 -1
- data/lib/activity_notification/apis/subscription_api.rb +1 -1
- data/lib/activity_notification/common.rb +18 -0
- data/lib/activity_notification/config.rb +10 -0
- data/lib/activity_notification/orm/dynamoid.rb +1 -1
- data/lib/activity_notification/version.rb +1 -1
- data/lib/generators/templates/activity_notification.rb +8 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bafe2d6977f08838087612f2d58947783a2e6add85633d85abe024cbe3a8041b
|
|
4
|
+
data.tar.gz: '095b581d3e475f27bfd186265083ea42f953b9b7c992c963fbb5fdd40cedd96e'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f6c687e0c9df39d2950bd2f2b2f2da4e10b95404315e09a9c91b8002cbaf98140a33877700c5c5b8a36b46f3387658caba039c722a91664b52d56ec29eac47d8
|
|
7
|
+
data.tar.gz: a9ebe7817f6c78fceb53e5ce0adee2b20e7b964e97c5ad812933a2d097d42f3d1617a29d26b0b07225309d56ebb2168fdcf64bd26c4d3478523ed6d1354de0ff
|
data/README.md
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
# ActivityNotification
|
|
2
2
|
|
|
3
|
-
[](https://github.com/simukappu/activity_notification/actions/workflows/build.yml)
|
|
4
|
-
[](https://coveralls.io/github/simukappu/activity_notification?branch=master)
|
|
5
|
-
[](https://depfu.com/repos/simukappu/activity_notification)
|
|
6
|
-
[](http://inch-ci.org/github/simukappu/activity_notification)
|
|
7
3
|
[](https://rubygems.org/gems/activity_notification)
|
|
8
4
|
[](https://rubygems.org/gems/activity_notification)
|
|
9
|
-
[](https://github.com/simukappu/activity_notification/actions/workflows/build.yml)
|
|
6
|
+
[](https://coveralls.io/github/simukappu/activity_notification?branch=master)
|
|
7
|
+
[](MIT-LICENSE)
|
|
10
8
|
|
|
11
9
|
*activity_notification* provides integrated user activity notifications for [Ruby on Rails](https://rubyonrails.org). You can easily use it to configure multiple notification targets and make activity notifications with notifiable models, like adding comments, responding etc.
|
|
12
10
|
|
|
@@ -135,14 +135,26 @@ module ActivityNotification
|
|
|
135
135
|
# Returns options for notification JSON
|
|
136
136
|
# @api protected
|
|
137
137
|
def notification_json_options
|
|
138
|
+
include_options =
|
|
139
|
+
if ActivityNotification.config.restrict_api_response_fields
|
|
140
|
+
{
|
|
141
|
+
target: { only: [:id], methods: [:printable_type, :printable_target_name] },
|
|
142
|
+
notifiable: { only: [:id], methods: [:printable_type] },
|
|
143
|
+
group: { only: [:id], methods: [:printable_type, :printable_group_name] },
|
|
144
|
+
notifier: { only: [:id], methods: [:printable_type, :printable_notifier_name] },
|
|
145
|
+
group_members: { only: [:id] }
|
|
146
|
+
}
|
|
147
|
+
else
|
|
148
|
+
{
|
|
149
|
+
target: { methods: [:printable_type, :printable_target_name] },
|
|
150
|
+
notifiable: { methods: [:printable_type] },
|
|
151
|
+
group: { methods: [:printable_type, :printable_group_name] },
|
|
152
|
+
notifier: { methods: [:printable_type, :printable_notifier_name] },
|
|
153
|
+
group_members: {}
|
|
154
|
+
}
|
|
155
|
+
end
|
|
138
156
|
{
|
|
139
|
-
include:
|
|
140
|
-
target: { methods: [:printable_type, :printable_target_name] },
|
|
141
|
-
notifiable: { methods: [:printable_type] },
|
|
142
|
-
group: { methods: [:printable_type, :printable_group_name] },
|
|
143
|
-
notifier: { methods: [:printable_type, :printable_notifier_name] },
|
|
144
|
-
group_members: {}
|
|
145
|
-
},
|
|
157
|
+
include: include_options,
|
|
146
158
|
methods: [:notifiable_path, :printable_notifiable_name, :group_member_notifier_count, :group_notification_count]
|
|
147
159
|
}
|
|
148
160
|
end
|
|
@@ -47,7 +47,7 @@ module ActivityNotification
|
|
|
47
47
|
# @option params [String] :reload ('true') Whether notification index will be reloaded
|
|
48
48
|
# @return [Response] JavaScript view for ajax request or redirects to back as default
|
|
49
49
|
def open_all
|
|
50
|
-
@opened_notifications = @target.open_all_notifications(
|
|
50
|
+
@opened_notifications = @target.open_all_notifications(bulk_action_options)
|
|
51
51
|
return_back_or_ajax
|
|
52
52
|
end
|
|
53
53
|
|
|
@@ -70,7 +70,7 @@ module ActivityNotification
|
|
|
70
70
|
# @option params [String] :reload ('true') Whether notification index will be reloaded
|
|
71
71
|
# @return [Response] JavaScript view for ajax request or redirects to back as default
|
|
72
72
|
def destroy_all
|
|
73
|
-
@destroyed_notifications = @target.destroy_all_notifications(
|
|
73
|
+
@destroyed_notifications = @target.destroy_all_notifications(bulk_action_options)
|
|
74
74
|
set_index_options
|
|
75
75
|
load_index if params[:reload].to_s.to_boolean(true)
|
|
76
76
|
return_back_or_ajax
|
|
@@ -152,6 +152,21 @@ module ActivityNotification
|
|
|
152
152
|
validate_target(@notification = Notification.with_target.find(params[:id]))
|
|
153
153
|
end
|
|
154
154
|
|
|
155
|
+
# Builds a permitted options hash for bulk actions (open_all / destroy_all)
|
|
156
|
+
# from request parameters.
|
|
157
|
+
# Only known-safe filter keys are permitted here. Request parameters must
|
|
158
|
+
# never be forwarded to the model layer as-is, because :custom_filter is
|
|
159
|
+
# passed straight to ActiveRecord's where as a raw SQL fragment and would
|
|
160
|
+
# allow SQL injection from untrusted input.
|
|
161
|
+
# @api protected
|
|
162
|
+
# @return [Hash] permitted options for bulk actions
|
|
163
|
+
def bulk_action_options
|
|
164
|
+
params.permit(:filter, :limit, :reverse, :without_grouping, :with_group_members,
|
|
165
|
+
:filtered_by_type, :filtered_by_group_type, :filtered_by_group_id, :filtered_by_key,
|
|
166
|
+
:later_than, :earlier_than, :routing_scope, :devise_default_routes, ids: [])
|
|
167
|
+
.to_h.symbolize_keys
|
|
168
|
+
end
|
|
169
|
+
|
|
155
170
|
# Sets options to load notification index from request parameters.
|
|
156
171
|
# @api protected
|
|
157
172
|
# @return [Hash] options to load notification index
|
|
@@ -171,7 +171,11 @@ module ActivityNotification
|
|
|
171
171
|
# Returns include option for subscription JSON
|
|
172
172
|
# @api protected
|
|
173
173
|
def subscription_json_include_option
|
|
174
|
-
|
|
174
|
+
if ActivityNotification.config.restrict_api_response_fields
|
|
175
|
+
{ target: { only: [:id], methods: [:printable_type, :printable_target_name] } }.freeze
|
|
176
|
+
else
|
|
177
|
+
[:target].freeze
|
|
178
|
+
end
|
|
175
179
|
end
|
|
176
180
|
|
|
177
181
|
# Returns methods option for subscription JSON
|
data/docs/Functions.md
CHANGED
|
@@ -709,6 +709,22 @@ When you want to use REST API backend integrated with Devise authentication, see
|
|
|
709
709
|
|
|
710
710
|
You can see [sample single page application](/spec/rails_app/app/javascript/) using [Vue.js](https://vuejs.org) as a part of example Rails application. This sample application works with *activity_notification* REST API backend.
|
|
711
711
|
|
|
712
|
+
#### Securing the REST API
|
|
713
|
+
|
|
714
|
+
The REST API endpoints do not authenticate requests on their own. Authenticating requests and authorizing access to a target's notifications and subscriptions is the responsibility of your application. The recommended way is to use the *:with_devise* option so that only the authenticated resource can access its own records. See [REST API backend with Devise Token Auth](#rest-api-backend-with-devise-token-auth) for the setup. The controllers shipped for *:with_devise* return HTTP 403 for a target that does not belong to the authenticated resource.
|
|
715
|
+
|
|
716
|
+
By default, notification and subscription responses embed the associated records (target, notifiable, notifier, group, group members and subscription target) with all of their database columns. When those associated records are your user model, the response can include columns you may not want to expose to the frontend, such as authentication identifiers. Two options are available to reduce this exposure.
|
|
717
|
+
|
|
718
|
+
The simplest option is to enable *config.restrict_api_response_fields*, which restricts every embedded associated record to its *id* and *printable_\** method values instead of all columns. It is disabled by default to preserve the existing response shape:
|
|
719
|
+
|
|
720
|
+
```ruby
|
|
721
|
+
ActivityNotification.configure do |config|
|
|
722
|
+
config.restrict_api_response_fields = true
|
|
723
|
+
end
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
If you need finer control over the response shape, override the serialization options in your own API controllers instead. *ActivityNotification::NotificationsApiController#notification_json_options* and *ActivityNotification::SubscriptionsApiController#subscription_json_include_option* are protected methods that you can override to return only the fields your frontend consumes.
|
|
727
|
+
|
|
712
728
|
#### API reference as OpenAPI Specification
|
|
713
729
|
|
|
714
730
|
*activity_notification* provides API reference as [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification).
|
|
@@ -135,7 +135,7 @@ module ActivityNotification
|
|
|
135
135
|
filtered_notifications = filtered_notifications.earlier_than(Time.iso8601(options[:earlier_than]))
|
|
136
136
|
end
|
|
137
137
|
if options.has_key?(:custom_filter)
|
|
138
|
-
filtered_notifications = filtered_notifications.where(options[:custom_filter])
|
|
138
|
+
filtered_notifications = filtered_notifications.where(ActivityNotification.validate_custom_filter(options[:custom_filter]))
|
|
139
139
|
end
|
|
140
140
|
filtered_notifications
|
|
141
141
|
}
|
|
@@ -31,7 +31,7 @@ module ActivityNotification
|
|
|
31
31
|
filtered_subscriptions = filtered_subscriptions.filtered_by_key(options[:filtered_by_key])
|
|
32
32
|
end
|
|
33
33
|
if options.has_key?(:custom_filter)
|
|
34
|
-
filtered_subscriptions = filtered_subscriptions.where(options[:custom_filter])
|
|
34
|
+
filtered_subscriptions = filtered_subscriptions.where(ActivityNotification.validate_custom_filter(options[:custom_filter]))
|
|
35
35
|
end
|
|
36
36
|
filtered_subscriptions
|
|
37
37
|
}
|
|
@@ -47,6 +47,24 @@ module ActivityNotification
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
# Validates a :custom_filter value before it is passed to the ORM query layer.
|
|
51
|
+
# A String is rejected because ActiveRecord's where treats a String as a raw
|
|
52
|
+
# SQL fragment, which allows SQL injection when the value originates from
|
|
53
|
+
# untrusted input. The documented and supported forms are an Array of a SQL
|
|
54
|
+
# fragment with bind parameters (e.g. ["created_at >= ?", time]) or a Hash of
|
|
55
|
+
# conditions, both of which are safe.
|
|
56
|
+
# @param [Array, Hash] custom_filter Custom filter value
|
|
57
|
+
# @return [Array, Hash] The same value when it is safe to use
|
|
58
|
+
# @raise [ArgumentError] When custom_filter is a raw SQL String
|
|
59
|
+
def self.validate_custom_filter(custom_filter)
|
|
60
|
+
if custom_filter.is_a?(String)
|
|
61
|
+
raise ArgumentError,
|
|
62
|
+
":custom_filter must be an array of a SQL fragment and bind parameters " \
|
|
63
|
+
"(e.g. [\"created_at >= ?\", time]) or a hash of conditions, not a raw SQL string"
|
|
64
|
+
end
|
|
65
|
+
custom_filter
|
|
66
|
+
end
|
|
67
|
+
|
|
50
68
|
# Casts to indifferent hash
|
|
51
69
|
# @param [ActionController::Parameters, Hash] hash
|
|
52
70
|
# @return [HashWithIndifferentAccess] Converted indifferent hash
|
|
@@ -240,6 +240,15 @@ module ActivityNotification
|
|
|
240
240
|
# @return [Boolean] Whether activity_notification internally rescues optional target errors.
|
|
241
241
|
attr_accessor :rescue_optional_target_errors
|
|
242
242
|
|
|
243
|
+
# @overload restrict_api_response_fields
|
|
244
|
+
# Returns whether the REST API restricts embedded associated records to their id and printable_* method values
|
|
245
|
+
# @return [Boolean] Whether the REST API restricts embedded associated records to their id and printable_* method values.
|
|
246
|
+
# @overload restrict_api_response_fields=(value)
|
|
247
|
+
# Sets whether the REST API restricts embedded associated records (target, notifiable, notifier, group, group members and subscription target) in JSON responses to their id and printable_* method values instead of all database columns. This is an opt-in hardening option to avoid exposing columns the frontend does not need (e.g. authentication identifiers on an associated user record). It is disabled by default to preserve the existing response shape.
|
|
248
|
+
# @param [Boolean] restrict_api_response_fields The new restrict_api_response_fields
|
|
249
|
+
# @return [Boolean] Whether the REST API restricts embedded associated records to their id and printable_* method values.
|
|
250
|
+
attr_accessor :restrict_api_response_fields
|
|
251
|
+
|
|
243
252
|
# Initialize configuration for ActivityNotification.
|
|
244
253
|
# These configuration can be overridden in initializer.
|
|
245
254
|
# @return [Config] A new instance of Config
|
|
@@ -272,6 +281,7 @@ module ActivityNotification
|
|
|
272
281
|
@notification_channel_prefix = 'activity_notification_channel'
|
|
273
282
|
@notification_api_channel_prefix = 'activity_notification_api_channel'
|
|
274
283
|
@rescue_optional_target_errors = true
|
|
284
|
+
@restrict_api_response_fields = false
|
|
275
285
|
end
|
|
276
286
|
|
|
277
287
|
# Sets ORM name for ActivityNotification (:active_record, :mongoid or :dynamodb)
|
|
@@ -332,7 +332,7 @@ module Dynamoid # :nodoc: all
|
|
|
332
332
|
filtered_notifications = filtered_notifications.earlier_than(Time.iso8601(options[:earlier_than]))
|
|
333
333
|
end
|
|
334
334
|
if options.has_key?(:custom_filter)
|
|
335
|
-
filtered_notifications = filtered_notifications.where(options[:custom_filter])
|
|
335
|
+
filtered_notifications = filtered_notifications.where(ActivityNotification.validate_custom_filter(options[:custom_filter]))
|
|
336
336
|
end
|
|
337
337
|
filtered_notifications
|
|
338
338
|
end
|
|
@@ -121,4 +121,12 @@ ActivityNotification.configure do |config|
|
|
|
121
121
|
# See https://github.com/simukappu/activity_notification/issues/155 for more details.
|
|
122
122
|
config.rescue_optional_target_errors = true
|
|
123
123
|
|
|
124
|
+
# Configure if the REST API restricts embedded associated records in JSON responses.
|
|
125
|
+
# When set true, associated records (target, notifiable, notifier, group, group members
|
|
126
|
+
# and subscription target) are serialized with only their id and printable_* method values
|
|
127
|
+
# instead of all database columns, to avoid exposing columns the frontend does not need.
|
|
128
|
+
# Note that authentication and authorization of the REST API is still the responsibility of
|
|
129
|
+
# your application (see the :with_devise routing option). Default value is false.
|
|
130
|
+
# config.restrict_api_response_fields = false
|
|
131
|
+
|
|
124
132
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activity_notification
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shota Yamazaki
|
|
@@ -311,7 +311,7 @@ description: Integrated user activity notifications for Ruby on Rails. Provides
|
|
|
311
311
|
to configure multiple notification targets and make activity notifications with
|
|
312
312
|
notifiable models, like adding comments, responding etc.
|
|
313
313
|
email:
|
|
314
|
-
- shota.yamazaki.
|
|
314
|
+
- shota.yamazaki.work@gmail.com
|
|
315
315
|
executables: []
|
|
316
316
|
extensions: []
|
|
317
317
|
extra_rdoc_files: []
|