Skip to content

Commit 2b0541d

Browse files
Add proper validation that user_id is presentin the create and update requests
1 parent fc0a06a commit 2b0541d

File tree

7 files changed

+96
-27
lines changed

7 files changed

+96
-27
lines changed

notifications/lib/notifications/api/internal_api/create.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ defmodule Notifications.Api.InternalApi.Create do
1111
org_id = req.metadata.org_id
1212
creator_id = req.metadata.user_id
1313

14-
with {:ok, :valid} <- Validator.validate(req.notification),
14+
with {:ok, :valid} <- Validator.validate(req.notification, creator_id),
1515
{:ok, n} <- create_notification(org_id, creator_id, req.notification) do
1616
%CreateResponse{notification: Serialization.serialize(n)}
1717
else

notifications/lib/notifications/api/internal_api/update.ex

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ defmodule Notifications.Api.InternalApi.Update do
99

1010
def run(req) do
1111
org_id = req.metadata.org_id
12+
updater_id = req.metadata.user_id
1213

13-
with {:ok, :valid} <- Validator.validate(req.notification),
14+
with {:ok, :valid} <- Validator.validate(req.notification, updater_id),
1415
{:ok, n} <- find_by_id_or_name(org_id, req.id, req.name),
15-
{:ok, n} <- update_notification(n, req.notification) do
16+
{:ok, n} <- update_notification(n, updater_id, req.notification) do
1617
%UpdateResponse{notification: Serialization.serialize(n)}
1718
else
1819
{:error, :invalid_argument, message} ->
@@ -37,11 +38,12 @@ defmodule Notifications.Api.InternalApi.Update do
3738
# notification: existing row from database
3839
# apiresource: new notification from the API call that needs to be applied
3940
#
40-
defp update_notification(notification, apiresource) do
41+
defp update_notification(notification, updater_id, apiresource) do
4142
Repo.transaction(fn ->
4243
changes =
4344
Model.changeset(notification, %{
4445
name: apiresource.name,
46+
creator_id: updater_id,
4547
spec: Notifications.Util.Transforms.encode_spec(%{rules: apiresource.rules})
4648
})
4749

notifications/lib/notifications/api/public_api/create.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ defmodule Notifications.Api.PublicApi.Create do
1212
Logger.info("#{inspect(org_id)} #{inspect(user_id)} #{name}")
1313

1414
with {:ok, :authorized} <- Auth.can_manage?(user_id, org_id),
15-
{:ok, :valid} <- Validator.validate(notification),
15+
{:ok, :valid} <- Validator.validate(notification, user_id),
1616
{:ok, n} <- create_notification(org_id, user_id, notification) do
1717
Serialization.serialize(n)
1818
else

notifications/lib/notifications/api/public_api/update.ex

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ defmodule Notifications.Api.PublicApi.Update do
1212
Logger.info("#{inspect(org_id)} #{inspect(user_id)} #{name_or_id}")
1313

1414
with {:ok, :authorized} <- Auth.can_manage?(user_id, org_id),
15-
{:ok, :valid} <- Validator.validate(req.notification),
15+
{:ok, :valid} <- Validator.validate(req.notification, user_id),
1616
{:ok, n} <- Model.find_by_id_or_name(org_id, name_or_id),
17-
{:ok, n} <- update_notification(n, req.notification) do
17+
{:ok, n} <- update_notification(n, user_id, req.notification) do
1818
Serialization.serialize(n)
1919
else
2020
{:error, :permission_denied} ->
@@ -44,11 +44,12 @@ defmodule Notifications.Api.PublicApi.Update do
4444
# notification: existing row from database
4545
# apiresource: new notification from the API call that needs to be applied
4646
#
47-
def update_notification(notification, apiresource) do
47+
def update_notification(notification, creator_id, apiresource) do
4848
Repo.transaction(fn ->
4949
changes =
5050
Model.changeset(notification, %{
5151
name: apiresource.metadata.name,
52+
creator_id: creator_id,
5253
spec: Notifications.Util.Transforms.encode_spec(apiresource.spec)
5354
})
5455

notifications/lib/notifications/util/validator.ex

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
defmodule Notifications.Util.Validator do
22
alias Notifications.Models.Pattern
33

4-
def validate(notification) do
4+
def validate(notification, user_id) do
55
with {:ok, :valid} <- validate_regex_patterns(notification),
66
{:ok, :valid} <- validate_result_patterns(notification),
7-
{:ok, :valid} <- validate_notification_targets(notification) do
7+
{:ok, :valid} <- validate_notification_targets(notification),
8+
{:ok, :valid} <- validate_user_id(user_id) do
89
{:ok, :valid}
910
else
1011
e -> e
1112
end
1213
end
1314

15+
defp validate_user_id(user_id) do
16+
case Ecto.UUID.cast(user_id) do
17+
{:ok, _} -> {:ok, :valid}
18+
:error -> {:error, :invalid_argument, "Invalid user_id: expected a valid UUID"}
19+
end
20+
end
21+
1422
def validate_notification_targets(notification = %InternalApi.Notifications.Notification{}),
1523
do: validate_notification_targets_(notification.rules)
1624

notifications/test/notifications/api/internal_api/update_test.exs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ defmodule Notifications.Api.InternalApi.UpdateTest do
1414
{:ok, channel} = GRPC.Stub.connect("localhost:50051")
1515

1616
req = %UpdateRequest{
17-
metadata: %RequestMeta{org_id: @org_id},
17+
metadata: %RequestMeta{org_id: @org_id, user_id: @creator_id},
1818
name: "non-exist",
1919
notification: Support.Factories.Notification.internal_api_model("first")
2020
}
@@ -41,7 +41,7 @@ defmodule Notifications.Api.InternalApi.UpdateTest do
4141
})
4242

4343
req = %UpdateRequest{
44-
metadata: %RequestMeta{org_id: @org_id},
44+
metadata: %RequestMeta{org_id: @org_id, user_id: @creator_id},
4545
name: "first",
4646
notification: Support.Factories.Notification.internal_api_model("first")
4747
}
@@ -126,7 +126,7 @@ defmodule Notifications.Api.InternalApi.UpdateTest do
126126
end)
127127
end
128128

129-
test "it returns serialized notification" do
129+
test "returs error when user_id not present in metadata" do
130130
alias Notifications.Models.Notification
131131

132132
{:ok, channel} = GRPC.Stub.connect("localhost:50051")
@@ -145,6 +145,30 @@ defmodule Notifications.Api.InternalApi.UpdateTest do
145145
notification: Support.Factories.Notification.internal_api_model("first")
146146
}
147147

148+
{:error, result} = Stub.update(channel, req)
149+
150+
assert match?(%GRPC.RPCError{message: "Invalid user_id: expected a valid UUID"}, result)
151+
end
152+
153+
test "it returns serialized notification" do
154+
alias Notifications.Models.Notification
155+
156+
{:ok, channel} = GRPC.Stub.connect("localhost:50051")
157+
158+
notification = Support.Factories.Notification.internal_api_model("first")
159+
160+
{:ok, _} =
161+
Stub.create(channel, %CreateRequest{
162+
metadata: %RequestMeta{org_id: @org_id, user_id: @creator_id},
163+
notification: notification
164+
})
165+
166+
req = %UpdateRequest{
167+
metadata: %RequestMeta{org_id: @org_id, user_id: @creator_id},
168+
name: "first",
169+
notification: Support.Factories.Notification.internal_api_model("first")
170+
}
171+
148172
{:ok, %{notification: notification}} = Stub.update(channel, req)
149173

150174
assert notification.name == "first"
@@ -196,7 +220,7 @@ defmodule Notifications.Api.InternalApi.UpdateTest do
196220

197221
req =
198222
UpdateRequest.new(
199-
metadata: %RequestMeta{org_id: @org_id},
223+
metadata: %RequestMeta{org_id: @org_id, user_id: @creator_id},
200224
name: "first",
201225
notification: notif
202226
)
@@ -239,7 +263,7 @@ defmodule Notifications.Api.InternalApi.UpdateTest do
239263

240264
req =
241265
UpdateRequest.new(
242-
metadata: %RequestMeta{org_id: @org_id},
266+
metadata: %RequestMeta{org_id: @org_id, user_id: @creator_id},
243267
name: "second-notification",
244268
notification: notif
245269
)

notifications/test/notifications/util/validator_test.exs

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ defmodule Notifications.Util.ValidatorTest do
66
alias Notification.{Metadata, Spec}
77
alias Spec.Rule
88

9+
@user_id Ecto.UUID.generate()
10+
911
describe ".validate" do
1012
test "everything is valid" do
1113
n =
@@ -35,7 +37,39 @@ defmodule Notifications.Util.ValidatorTest do
3537
)
3638
)
3739

38-
assert Validator.validate(n) == {:ok, :valid}
40+
assert Validator.validate(n, @user_id) == {:ok, :valid}
41+
end
42+
43+
test "user_id is empty" do
44+
n =
45+
Notification.new(
46+
metadata: Metadata.new(name: "A"),
47+
spec:
48+
Spec.new(
49+
rules: [
50+
Rule.new(
51+
name: "Example Rule",
52+
filter:
53+
Rule.Filter.new(
54+
projects: [
55+
"/.*/"
56+
]
57+
),
58+
notify:
59+
Rule.Notify.new(
60+
slack:
61+
Rule.Notify.Slack.new(
62+
endpoint: "https://whatever.com",
63+
channels: ["#testing-hq"]
64+
)
65+
)
66+
)
67+
]
68+
)
69+
)
70+
71+
assert Validator.validate(n, "") ==
72+
{:error, :invalid_argument, "Invalid user_id: expected a valid UUID"}
3973
end
4074

4175
test "reports broken regexes" do
@@ -66,7 +100,7 @@ defmodule Notifications.Util.ValidatorTest do
66100
)
67101
)
68102

69-
assert Validator.validate(n) ==
103+
assert Validator.validate(n, @user_id) ==
70104
{:error, :invalid_argument, "Pattern /*/ is not a valid regex statement"}
71105
end
72106

@@ -101,7 +135,7 @@ defmodule Notifications.Util.ValidatorTest do
101135
)
102136
)
103137

104-
assert Validator.validate(n) ==
138+
assert Validator.validate(n, @user_id) ==
105139
{:error, :invalid_argument,
106140
"Patterns [/*/, /+dasdas/] are not valid regex statements"}
107141
end
@@ -134,7 +168,7 @@ defmodule Notifications.Util.ValidatorTest do
134168
)
135169
)
136170

137-
assert Validator.validate(n) ==
171+
assert Validator.validate(n, @user_id) ==
138172
{:error, :invalid_argument,
139173
"Value pass is not a valid result entry. Valid values are: passed, failed, canceled, stopped."}
140174
end
@@ -170,7 +204,7 @@ defmodule Notifications.Util.ValidatorTest do
170204
)
171205
)
172206

173-
assert Validator.validate(n) == {:ok, :valid}
207+
assert Validator.validate(n, @user_id) == {:ok, :valid}
174208
end
175209

176210
test "regex is valid result entry" do
@@ -201,7 +235,7 @@ defmodule Notifications.Util.ValidatorTest do
201235
)
202236
)
203237

204-
assert Validator.validate(n) == {:ok, :valid}
238+
assert Validator.validate(n, @user_id) == {:ok, :valid}
205239
end
206240

207241
test "no notify target specified => not valid" do
@@ -225,7 +259,7 @@ defmodule Notifications.Util.ValidatorTest do
225259
)
226260
)
227261

228-
assert Validator.validate(n) ==
262+
assert Validator.validate(n, @user_id) ==
229263
{:error, :invalid_argument,
230264
"A notification rule must have at least one notification target configured."}
231265
end
@@ -250,7 +284,7 @@ defmodule Notifications.Util.ValidatorTest do
250284
)
251285
)
252286

253-
assert Validator.validate(n) ==
287+
assert Validator.validate(n, @user_id) ==
254288
{:error, :invalid_argument, "A notification rule must have a notify field."}
255289
end
256290

@@ -282,7 +316,7 @@ defmodule Notifications.Util.ValidatorTest do
282316
)
283317
)
284318

285-
assert Validator.validate(n) == {:ok, :valid}
319+
assert Validator.validate(n, @user_id) == {:ok, :valid}
286320
end
287321

288322
test "only valid webhook target => valid" do
@@ -309,7 +343,7 @@ defmodule Notifications.Util.ValidatorTest do
309343
)
310344
)
311345

312-
assert Validator.validate(n) == {:ok, :valid}
346+
assert Validator.validate(n, @user_id) == {:ok, :valid}
313347
end
314348

315349
test "only valid email target => valid" do
@@ -334,7 +368,7 @@ defmodule Notifications.Util.ValidatorTest do
334368
)
335369
)
336370

337-
assert Validator.validate(n) == {:ok, :valid}
371+
assert Validator.validate(n, @user_id) == {:ok, :valid}
338372
end
339373

340374
test "valid + invalid rule => fails" do
@@ -374,7 +408,7 @@ defmodule Notifications.Util.ValidatorTest do
374408
)
375409
)
376410

377-
assert Validator.validate(n) ==
411+
assert Validator.validate(n, @user_id) ==
378412
{:error, :invalid_argument, "A notification rule must have a notify field."}
379413
end
380414
end

0 commit comments

Comments
 (0)