Skip to content

Commit 305e647

Browse files
feat(notifications): add authorization before sending notification (#465)
## 📝 Description renderedtext/project-tasks#2659 ## ✅ Checklist - [x] I have tested this change - [ ] This change requires documentation update
1 parent 529ed00 commit 305e647

File tree

27 files changed

+420
-63
lines changed

27 files changed

+420
-63
lines changed

front/lib/front/models/notification.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ defmodule Front.Models.Notification do
5858

5959
def create(user_id, org_id, notification_data, _metadata \\ nil) do
6060
Watchman.benchmark("notifications.create_notification_request.duration", fn ->
61-
notification = construct_notification(notification_data)
61+
notification = construct_notification(notification_data, user_id)
6262

6363
{:ok, channel} = GRPC.Stub.connect(api_endpoint())
6464

@@ -90,7 +90,7 @@ defmodule Front.Models.Notification do
9090

9191
def update(user_id, org_id, notification_data) do
9292
Watchman.benchmark("notifications.update_notification_request.duration", fn ->
93-
notification = construct_notification(notification_data)
93+
notification = construct_notification(notification_data, user_id)
9494

9595
{:ok, channel} = GRPC.Stub.connect(api_endpoint())
9696

@@ -110,13 +110,13 @@ defmodule Front.Models.Notification do
110110
end)
111111
end
112112

113-
def construct_notification(data) do
113+
def construct_notification(data, creator_id) do
114114
rules =
115115
data.rules
116116
|> Enum.map(&construct_rule(&1))
117117

118118
PublicApi.Notification.new(
119-
metadata: PublicApi.Notification.Metadata.new(name: data.name),
119+
metadata: PublicApi.Notification.Metadata.new(name: data.name, creator_id: creator_id),
120120
spec: PublicApi.Notification.Spec.new(rules: rules)
121121
)
122122
end

front/lib/public_api/semaphore/notifications.v1alpha.pb.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,16 @@ defmodule Semaphore.Notifications.V1alpha.Notification.Metadata do
2222
name: String.t(),
2323
id: String.t(),
2424
create_time: integer,
25-
update_time: integer
25+
update_time: integer,
26+
creator_id: String.t()
2627
}
27-
defstruct [:name, :id, :create_time, :update_time]
28+
defstruct [:name, :id, :create_time, :update_time, :creator_id]
2829

2930
field(:name, 1, type: :string)
3031
field(:id, 2, type: :string)
3132
field(:create_time, 3, type: :int64)
3233
field(:update_time, 4, type: :int64)
34+
field(:creator_id, 5, type: :string)
3335
end
3436

3537
defmodule Semaphore.Notifications.V1alpha.Notification.Spec do

notifications/config/config.exs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ config :logger, :console,
1313

1414
import_config "_silent_lager.exs"
1515

16-
config :notifications, rbac_endpoint: "localhost:50052"
17-
config :notifications, secrethub_endpoint: "localhost:50052" # sobelow_skip ["Config.Secrets"]
18-
1916
config :notifications, ecto_repos: [Notifications.Repo]
2017

2118
import_config "#{config_env()}.exs"

notifications/config/test.exs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,12 @@ config :junit_formatter,
88
include_filename?: true,
99
include_file_line?: true
1010

11+
config :notifications, rbac_endpoint: "localhost:50052"
12+
config :notifications, secrethub_endpoint: "localhost:50052" # sobelow_skip ["Config.Secrets"]
13+
config :notifications, pipeline_endpoint: "localhost:50052" # sobelow_skip ["Config.Secrets"]
14+
config :notifications, projecthub_endpoint: "localhost:50052" # sobelow_skip ["Config.Secrets"]
15+
config :notifications, repo_proxy_endpoint: "localhost:50052" # sobelow_skip ["Config.Secrets"]
16+
config :notifications, workflow_endpoint: "localhost:50052" # sobelow_skip ["Config.Secrets"]
17+
config :notifications, organization_endpoint: "localhost:50052" # sobelow_skip ["Config.Secrets"]
18+
1119
config :notifications, Notifications.Repo, pool: Ecto.Adapters.SQL.Sandbox

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

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

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

13-
with {:ok, :valid} <- Validator.validate(req.notification),
14-
{:ok, n} <- create_notification(org_id, req.notification) do
14+
with {:ok, :valid} <- Validator.validate(req.notification, creator_id),
15+
{:ok, n} <- create_notification(org_id, creator_id, req.notification) do
1516
%CreateResponse{notification: Serialization.serialize(n)}
1617
else
1718
{:error, :invalid_argument, message} ->
@@ -27,12 +28,13 @@ defmodule Notifications.Api.InternalApi.Create do
2728
end
2829
end
2930

30-
defp create_notification(org_id, notification) do
31+
defp create_notification(org_id, creator_id, notification) do
3132
Repo.transaction(fn ->
3233
n =
3334
Models.Notification.new(
3435
org_id,
3536
notification.name,
37+
creator_id,
3638
Notifications.Util.Transforms.encode_spec(%{rules: notification.rules})
3739
)
3840

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: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ 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),
16-
{:ok, n} <- create_notification(org_id, notification) do
15+
{:ok, :valid} <- Validator.validate(notification, user_id),
16+
{:ok, n} <- create_notification(org_id, user_id, notification) do
1717
Serialization.serialize(n)
1818
else
1919
{:error, :permission_denied} ->
@@ -34,12 +34,13 @@ defmodule Notifications.Api.PublicApi.Create do
3434
end
3535
end
3636

37-
def create_notification(org_id, notification) do
37+
def create_notification(org_id, creator_id, notification) do
3838
Repo.transaction(fn ->
3939
n =
4040
Models.Notification.new(
4141
org_id,
4242
notification.metadata.name,
43+
creator_id,
4344
Notifications.Util.Transforms.encode_spec(notification.spec)
4445
)
4546

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/auth.ex

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@ defmodule Notifications.Auth do
1212
authorize(user_id, org_id, "organization.notifications.manage")
1313
end
1414

15-
defp authorize(user_id, org_id, permission) do
16-
req = Request.new(user_id: user_id, org_id: org_id)
15+
def can_view_project?(user_id, org_id, project_id) do
16+
authorize(user_id, org_id, project_id, "project.view")
17+
end
18+
19+
defp authorize(user_id, org_id, permission), do: authorize(user_id, org_id, "", permission)
20+
21+
defp authorize(user_id, org_id, project_id, permission) do
22+
req = Request.new(user_id: user_id, org_id: org_id, project_id: project_id)
1723
endpoint = Application.fetch_env!(:notifications, :rbac_endpoint)
1824
{:ok, channel} = GRPC.Stub.connect(endpoint)
1925

notifications/lib/notifications/models/notification.ex

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,18 @@ defmodule Notifications.Models.Notification do
1212
has_many(:rules, Notifications.Models.Rule, on_delete: :delete_all)
1313

1414
field(:org_id, :binary_id)
15+
field(:creator_id, :binary_id)
1516
field(:name, :string)
1617
field(:spec, :map)
1718

1819
timestamps()
1920
end
2021

21-
def new(org_id, name, spec) do
22+
def new(org_id, name, creator_id, spec) do
2223
%__MODULE__{}
2324
|> changeset(%{
2425
org_id: org_id,
26+
creator_id: creator_id,
2527
name: name,
2628
spec: spec
2729
})
@@ -78,8 +80,8 @@ defmodule Notifications.Models.Notification do
7880

7981
def changeset(notification, params \\ %{}) do
8082
notification
81-
|> cast(params, [:org_id, :name, :spec])
82-
|> validate_required([:org_id, :name, :spec])
83+
|> cast(params, [:org_id, :creator_id, :name, :spec])
84+
|> validate_required([:org_id, :creator_id, :name, :spec])
8385
|> valid_name_format(params)
8486
|> unique_constraint(
8587
:unique_names,

0 commit comments

Comments
 (0)