Skip to content

Commit 4dfd4fb

Browse files
Merge pull request #79 from epochtalk/board-controller-authorizations
Board controller authorizations
2 parents 55c7cc0 + 0564914 commit 4dfd4fb

File tree

6 files changed

+423
-55
lines changed

6 files changed

+423
-55
lines changed

lib/epochtalk_server_web/controllers/board.ex

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ defmodule EpochtalkServerWeb.Controllers.Board do
1616
Used to retrieve categorized boards
1717
"""
1818
def by_category(conn, attrs) do
19-
with stripped <- Validate.cast(attrs, "stripped", :boolean, default: false),
19+
with :ok <- ACL.allow!(conn, "boards.allCategories"),
20+
stripped <- Validate.cast(attrs, "stripped", :boolean, default: false),
2021
user_priority <- ACL.get_user_priority(conn),
2122
board_mapping <- BoardMapping.all(stripped: stripped),
2223
board_moderators <- BoardModerator.all(),
@@ -36,8 +37,11 @@ defmodule EpochtalkServerWeb.Controllers.Board do
3637
Used to find a specific board
3738
"""
3839
def find(conn, attrs) do
39-
with id <- Validate.cast(attrs, "id", :integer, required: true),
40+
with :ok <- ACL.allow!(conn, "boards.find"),
41+
id <- Validate.cast(attrs, "id", :integer, required: true),
4042
user_priority <- ACL.get_user_priority(conn),
43+
{:can_read, {:ok, true}} <-
44+
{:can_read, Board.get_read_access_by_id(id, user_priority)},
4145
board_mapping <- BoardMapping.all(),
4246
board_moderators <- BoardModerator.all(),
4347
{:board, [_board]} <-
@@ -49,8 +53,22 @@ defmodule EpochtalkServerWeb.Controllers.Board do
4953
user_priority: user_priority
5054
})
5155
else
52-
{:board, []} -> ErrorHelpers.render_json_error(conn, 400, "Error, board does not exist")
53-
_ -> ErrorHelpers.render_json_error(conn, 400, "Error, cannot fetch boards")
56+
# if user can't read board, return 404, user doesn't need to know hidden board exists
57+
{:can_read, {:ok, false}} ->
58+
ErrorHelpers.render_json_error(
59+
conn,
60+
404,
61+
"Board not found"
62+
)
63+
64+
{:can_read, {:error, :board_does_not_exist}} ->
65+
ErrorHelpers.render_json_error(conn, 400, "Error, board does not exist")
66+
67+
{:board, []} ->
68+
ErrorHelpers.render_json_error(conn, 400, "Error, board does not exist")
69+
70+
_ ->
71+
ErrorHelpers.render_json_error(conn, 400, "Error, cannot fetch boards")
5472
end
5573
end
5674

test/epochtalk_server/models/mention_test.exs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,10 @@ defmodule Test.EpochtalkServer.Models.Mention do
7272
assert result["mentioned_ids"] == []
7373
end
7474

75-
@tag :banned
76-
test "given a user without acl permission, errors", %{thread: thread} do
77-
{:ok, user} = EpochtalkServer.Models.User.by_username("user")
78-
75+
test "given a user without acl permission, errors", %{
76+
thread: thread,
77+
users: %{private_user: user}
78+
} do
7979
attrs = %{
8080
"thread" => thread.id,
8181
"title" => "title",

test/epochtalk_server/session_test.exs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ defmodule Test.EpochtalkServer.Session do
253253
@tag :banned
254254
test "without remember me, handles baninfo ttl and ban_expiration (< 1 day ttl)", %{
255255
conn: conn,
256-
user_attrs: %{user: user_attrs},
257-
users: %{user: user}
256+
user_attrs: %{banned_user: user_attrs},
257+
users: %{banned_user: user}
258258
} do
259259
pre_ban_baninfo_ttl = Redix.command!(:redix, ["TTL", "user:#{user.id}:baninfo"])
260260

@@ -284,8 +284,8 @@ defmodule Test.EpochtalkServer.Session do
284284
@tag :banned
285285
test "with remember me, handles baninfo ttl and ban_expiration (< 4 weeks ttl)", %{
286286
conn: conn,
287-
user_attrs: %{user: user_attrs},
288-
users: %{user: user}
287+
user_attrs: %{banned_user: user_attrs},
288+
users: %{banned_user: user}
289289
} do
290290
pre_ban_baninfo_ttl = Redix.command!(:redix, ["TTL", "user:#{user.id}:baninfo"])
291291

@@ -447,7 +447,7 @@ defmodule Test.EpochtalkServer.Session do
447447
assert banned_resource_user.ban_expiration == @max_date
448448
end
449449

450-
@tag [authenticated: true, banned: true]
450+
@tag [authenticated: :banned, banned: true]
451451
test "given a banned user's id, when user is unbanned, deletes banned role", %{
452452
conn: conn,
453453
authed_user: authed_user

test/epochtalk_server_web/controllers/board_test.exs

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ defmodule Test.EpochtalkServerWeb.Controllers.Board do
3030
end
3131

3232
describe "by_category/2" do
33+
@tag authenticated: :private
34+
test "when authenticated with invalid permissions, raises InvalidPermission error", %{
35+
conn: conn
36+
} do
37+
assert_raise InvalidPermission,
38+
~r/^Forbidden, invalid permissions to perform this action/,
39+
fn ->
40+
get(conn, Routes.board_path(conn, :by_category))
41+
end
42+
end
43+
3344
test "finds all active boards", %{
3445
conn: conn,
3546
category: category,
@@ -130,7 +141,23 @@ defmodule Test.EpochtalkServerWeb.Controllers.Board do
130141
assert response["message"] == "Error, board does not exist"
131142
end
132143

133-
test "given an existing id, finds a board", %{conn: conn, parent_board: board} do
144+
test "when unauthenticated, given an existing id above read access, errors", %{
145+
conn: conn,
146+
admin_board: admin_board
147+
} do
148+
response =
149+
conn
150+
|> get(Routes.board_path(conn, :find, admin_board.id))
151+
|> json_response(404)
152+
153+
assert response["error"] == "Not Found"
154+
assert response["message"] == "Board not found"
155+
end
156+
157+
test "when unauthenticated, given an existing id within read access, finds a board", %{
158+
conn: conn,
159+
parent_board: board
160+
} do
134161
response =
135162
conn
136163
|> get(Routes.board_path(conn, :find, board.id))
@@ -146,6 +173,73 @@ defmodule Test.EpochtalkServerWeb.Controllers.Board do
146173
assert response["disable_post_edit"] == board.meta["disable_post_edit"]
147174
assert response["disable_signature"] == board.meta["disable_signature"]
148175
end
176+
177+
@tag :authenticated
178+
test "when authenticated, given an existing id above read access, errors", %{
179+
conn: conn,
180+
admin_board: admin_board
181+
} do
182+
response =
183+
conn
184+
|> get(Routes.board_path(conn, :find, admin_board.id))
185+
|> json_response(404)
186+
187+
assert response["error"] == "Not Found"
188+
assert response["message"] == "Board not found"
189+
end
190+
191+
@tag :authenticated
192+
test "when authenticated, given an existing id at read access, finds board", %{
193+
conn: conn,
194+
parent_board: board
195+
} do
196+
response =
197+
conn
198+
|> get(Routes.board_path(conn, :find, board.id))
199+
|> json_response(200)
200+
201+
assert response["name"] == board.name
202+
end
203+
204+
@tag authenticated: :admin
205+
test "when authenticated as admin, given an existing id at read access, finds board", %{
206+
conn: conn,
207+
admin_board: admin_board
208+
} do
209+
response =
210+
conn
211+
|> get(Routes.board_path(conn, :find, admin_board.id))
212+
|> json_response(200)
213+
214+
assert response["name"] == admin_board.name
215+
end
216+
217+
@tag authenticated: :admin
218+
test "when authenticated as admin, given an existing id above read access, errors", %{
219+
conn: conn,
220+
super_admin_board: super_admin_board
221+
} do
222+
response =
223+
conn
224+
|> get(Routes.board_path(conn, :find, super_admin_board.id))
225+
|> json_response(404)
226+
227+
assert response["error"] == "Not Found"
228+
assert response["message"] == "Board not found"
229+
end
230+
231+
@tag authenticated: :super_admin
232+
test "when authenticated as super admin, given an existing id at read access, finds board", %{
233+
conn: conn,
234+
super_admin_board: super_admin_board
235+
} do
236+
response =
237+
conn
238+
|> get(Routes.board_path(conn, :find, super_admin_board.id))
239+
|> json_response(200)
240+
241+
assert response["name"] == super_admin_board.name
242+
end
149243
end
150244

151245
describe "slug_to_id/2" do

test/seed/users.exs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,38 @@ test_admin_user_username = "admin"
88
test_admin_user_email = "[email protected]"
99
test_admin_user_password = "password"
1010

11+
test_global_mod_user_username = "globalmod"
12+
test_global_mod_user_email = "[email protected]"
13+
test_global_mod_user_password = "password"
14+
15+
test_mod_user_username = "mod"
16+
test_mod_user_email = "[email protected]"
17+
test_mod_user_password = "password"
18+
1119
test_user_username = "user"
1220
test_user_email = "[email protected]"
1321
test_user_password = "password"
1422

23+
test_patroller_user_username = "patroller"
24+
test_patroller_user_email = "[email protected]"
25+
test_patroller_user_password = "password"
26+
27+
test_newbie_user_username = "newbie"
28+
test_newbie_user_email = "[email protected]"
29+
test_newbie_user_password = "password"
30+
31+
test_banned_user_username = "banned"
32+
test_banned_user_email = "[email protected]"
33+
test_banned_user_password = "password"
34+
35+
test_anonymous_user_username = "anonymous"
36+
test_anonymous_user_email = "[email protected]"
37+
test_anonymous_user_password = "password"
38+
39+
test_private_user_username = "private"
40+
test_private_user_email = "[email protected]"
41+
test_private_user_password = "password"
42+
1543
test_no_login_user_username = "no_login"
1644
test_no_login_user_email = "[email protected]"
1745
test_no_login_user_password = "password"
@@ -30,12 +58,62 @@ build(:user,
3058
)
3159
|> with_role_id(2)
3260

61+
build(:user,
62+
username: test_global_mod_user_username,
63+
email: test_global_mod_user_email,
64+
password: test_global_mod_user_password
65+
)
66+
|> with_role_id(3)
67+
68+
build(:user,
69+
username: test_mod_user_username,
70+
email: test_mod_user_email,
71+
password: test_mod_user_password
72+
)
73+
|> with_role_id(4)
74+
3375
build(:user,
3476
username: test_user_username,
3577
email: test_user_email,
3678
password: test_user_password
3779
)
3880

81+
build(:user,
82+
username: test_patroller_user_username,
83+
email: test_patroller_user_email,
84+
password: test_patroller_user_password
85+
)
86+
|> with_role_id(6)
87+
88+
build(:user,
89+
username: test_newbie_user_username,
90+
email: test_newbie_user_email,
91+
password: test_newbie_user_password
92+
)
93+
|> with_role_id(7)
94+
95+
# TODO(akinsey): actually ban the user, this user only has banned role
96+
build(:user,
97+
username: test_banned_user_username,
98+
email: test_banned_user_email,
99+
password: test_banned_user_password
100+
)
101+
|> with_role_id(8)
102+
103+
build(:user,
104+
username: test_anonymous_user_username,
105+
email: test_anonymous_user_email,
106+
password: test_anonymous_user_password
107+
)
108+
|> with_role_id(9)
109+
110+
build(:user,
111+
username: test_private_user_username,
112+
email: test_private_user_email,
113+
password: test_private_user_password
114+
)
115+
|> with_role_id(10)
116+
39117
build(:user,
40118
username: test_no_login_user_username,
41119
email: test_no_login_user_email,

0 commit comments

Comments
 (0)