tangled
alpha
login
or
join now
kacaii.dev
/
senac-brigade-server
0
fork
atom
wip: currently rewriting the project as a full stack application
tangled.org/kacaii.dev/sigo
gleam
0
fork
atom
overview
issues
1
pulls
pipelines
:label: properly map to a `Session` error type
kacaii.dev
2 months ago
e862da7f
c4bcf9ae
+42
-50
8 changed files
expand all
collapse all
unified
split
src
app
domain
notification
get_notification_preferences.gleam
update_notification_preferences.gleam
occurrence
close_occurrence.gleam
delete_occurrence.gleam
register_new_occurrence.gleam
reopen_occurrence.gleam
user.gleam
web
socket.gleam
+3
-3
src/app/domain/notification/get_notification_preferences.gleam
···
38
38
39
39
fn handle_error(err: GetNotificationPreferencesError) -> wisp.Response {
40
40
case err {
41
41
-
AccessControl(err) -> session.handle_error(err)
41
41
+
Session(err) -> session.handle_error(err)
42
42
DatabaseError(err) -> web.handle_database_error(err)
43
43
}
44
44
}
···
49
49
) -> Result(String, GetNotificationPreferencesError) {
50
50
use token <- result.try(
51
51
session.extract(req)
52
52
-
|> result.map_error(AccessControl),
52
52
+
|> result.map_error(Session),
53
53
)
54
54
55
55
use returned <- result.try(
···
77
77
/// Querying the user notification preferences can fail
78
78
type GetNotificationPreferencesError {
79
79
/// Authentication failed
80
80
-
AccessControl(session.SessionError)
80
80
+
Session(session.SessionError)
81
81
/// An error occurred while querying the DataBase
82
82
DatabaseError(pog.QueryError)
83
83
}
+3
-3
src/app/domain/notification/update_notification_preferences.gleam
···
40
40
41
41
type UpdateNotificationPreferencesError {
42
42
/// Authentication failed
43
43
-
AccessControl(session.SessionError)
43
43
+
Session(session.SessionError)
44
44
/// Failed to query Database
45
45
DataBase(pog.QueryError)
46
46
NotFound
···
78
78
79
79
fn handle_error(err: UpdateNotificationPreferencesError) -> wisp.Response {
80
80
case err {
81
81
-
AccessControl(err) -> session.handle_error(err)
81
81
+
Session(err) -> session.handle_error(err)
82
82
DataBase(err) -> web.handle_database_error(err)
83
83
NotFound ->
84
84
"O banco de dados não retornou resultados após atualizar as preferências"
···
97
97
) {
98
98
use token <- result.try(
99
99
session.extract(req)
100
100
-
|> result.map_error(AccessControl),
100
100
+
|> result.map_error(Session),
101
101
)
102
102
103
103
use acc, #(key, value) <- list.try_fold(
+3
-3
src/app/domain/occurrence/close_occurrence.gleam
···
23
23
/// An error occurred whe naccessing the DataBase
24
24
DataBase(pog.QueryError)
25
25
/// Errors related to authentication / authorization
26
26
-
AccessControl(session.SessionError)
26
26
+
Session(session.SessionError)
27
27
}
28
28
29
29
/// Updates the `resolved_at` field of a occurrence
···
55
55
) -> Result(String, ResolveOccurrenceError) {
56
56
use _ <- result.try(
57
57
session.extract(req)
58
58
-
|> result.map_error(AccessControl),
58
58
+
|> result.map_error(Session),
59
59
)
60
60
61
61
use target <- result.try(
···
102
102
103
103
fn handle_error(err: ResolveOccurrenceError) -> wisp.Response {
104
104
case err {
105
105
-
AccessControl(err) -> session.handle_error(err)
105
105
+
Session(err) -> session.handle_error(err)
106
106
DataBase(err) -> web.handle_database_error(err)
107
107
InvalidUuid(id) ->
108
108
wisp.bad_request("Ocorrência possui Uuid inválido: " <> id)
+3
-3
src/app/domain/occurrence/delete_occurrence.gleam
···
15
15
/// Occurrence has invalid Uuid
16
16
InvalidUuid(String)
17
17
/// Authentication failed
18
18
-
AccessControl(session.SessionError)
18
18
+
Session(session.SessionError)
19
19
/// Failed to query the DataBase
20
20
DataBase(pog.QueryError)
21
21
/// Occurrence was not found in the system
···
58
58
use _ <- result.try(
59
59
// Armazenamos o UUID do usuário caso precisemos para autorização
60
60
session.extract(req)
61
61
-
|> result.map_error(AccessControl),
61
61
+
|> result.map_error(Session),
62
62
)
63
63
64
64
use returned <- result.try(
···
81
81
InvalidUuid(uuid_string) ->
82
82
// 404 Bad Request
83
83
wisp.bad_request("UUID inválido: " <> uuid_string)
84
84
-
AccessControl(err) -> session.handle_error(err)
84
84
+
Session(err) -> session.handle_error(err)
85
85
DataBase(db_err) -> web.handle_database_error(db_err)
86
86
OccurrenceNotFound(occ_uuid) -> {
87
87
// 404 not found
+3
-3
src/app/domain/occurrence/register_new_occurrence.gleam
···
86
86
87
87
type RegisterNewOccurrenceError {
88
88
/// Failed to authenticate the user
89
89
-
AccessControl(session.SessionError)
89
89
+
Session(session.SessionError)
90
90
/// Failed to access the database
91
91
DataBase(pog.QueryError)
92
92
/// Database returned no results
···
97
97
98
98
fn handle_error(err: RegisterNewOccurrenceError) -> wisp.Response {
99
99
case err {
100
100
-
AccessControl(err) -> session.handle_error(err)
100
100
+
Session(err) -> session.handle_error(err)
101
101
DataBase(err) -> web.handle_database_error(err)
102
102
FailedToAssignBrigade(id) -> {
103
103
let body = "Não foi possível designar a equipe: " <> uuid.to_string(id)
···
148
148
) -> Result(String, RegisterNewOccurrenceError) {
149
149
use token <- result.try(
150
150
session.extract(request)
151
151
-
|> result.map_error(AccessControl),
151
151
+
|> result.map_error(Session),
152
152
)
153
153
154
154
use returned <- result.try(
+3
-3
src/app/domain/occurrence/reopen_occurrence.gleam
···
23
23
/// An error occurred whe naccessing the DataBase
24
24
DataBase(pog.QueryError)
25
25
/// Errors related to authentication / authorization
26
26
-
AccessControl(session.SessionError)
26
26
+
Session(session.SessionError)
27
27
}
28
28
29
29
/// Updates the `resolved_at` field of a occurrence
···
55
55
) -> Result(String, ResolveOccurrenceError) {
56
56
use _ <- result.try(
57
57
session.extract(req)
58
58
-
|> result.map_error(AccessControl),
58
58
+
|> result.map_error(Session),
59
59
)
60
60
61
61
use target <- result.try(
···
101
101
102
102
fn handle_error(err: ResolveOccurrenceError) -> wisp.Response {
103
103
case err {
104
104
-
AccessControl(err) -> session.handle_error(err)
104
104
+
Session(err) -> session.handle_error(err)
105
105
DataBase(err) -> web.handle_database_error(err)
106
106
InvalidUuid(id) ->
107
107
wisp.bad_request("Ocorrência possui Uuid inválido: " <> id)
+8
-19
src/app/domain/user.gleam
···
11
11
import wisp
12
12
import youid/uuid
13
13
14
14
-
pub const uuid_cookie_name = "USER_ID"
15
15
-
16
16
-
/// Errors related to user access control (authentication & authorization)
17
14
pub type AccessControlError {
18
15
/// Authentication failed
19
19
-
Authentication(session.SessionError)
16
16
+
Session(session.SessionError)
20
17
/// User is authentication but lacks permissions
21
21
-
AuthorizationError(
18
18
+
NotAuthorized(
22
19
user_uuid: uuid.Uuid,
23
20
user_role: role.Role,
24
21
authorized_roles: List(role.Role),
···
31
28
InvalidRole(String)
32
29
}
33
30
34
34
-
/// Authentication-specific failures
35
35
-
pub type AuthenticationError {
36
36
-
/// Request is missing the authetication Cookie
37
37
-
MissingCookie
38
38
-
/// User doesn't have a valid UUID
39
39
-
InvalidUUID(String)
40
40
-
}
41
41
-
42
31
/// Broadcast an arbitrary message to an user
43
32
///
44
33
/// Spawns a new process
···
62
51
) -> Result(role.Role, AccessControlError) {
63
52
use token <- result.try(
64
53
session.extract(request)
65
65
-
|> result.map_error(Authentication),
54
54
+
|> result.map_error(Session),
66
55
)
67
56
68
57
// Check if that role has authorization
69
58
list.find(authorized_roles, fn(authorized) { token.user_role == authorized })
70
70
-
|> result.replace_error(AuthorizationError(
59
59
+
|> result.replace_error(NotAuthorized(
71
60
user_uuid: token.user_id,
72
61
user_role: token.user_role,
73
62
authorized_roles:,
···
76
65
77
66
pub fn handle_access_control_error(err: AccessControlError) {
78
67
case err {
79
79
-
Authentication(err) -> session.handle_error(err)
68
68
+
Session(err) -> session.handle_error(err)
80
69
DataBase(err) -> web.handle_database_error(err)
81
70
RoleNotFound ->
82
82
-
"Não foi possível confirmar o Cargo do usuário autenticado"
71
71
+
"Não foi possível confirmar o cargo do usuário"
83
72
|> wisp.Text
84
73
|> wisp.set_body(wisp.response(401), _)
85
74
86
75
InvalidRole(str) ->
87
87
-
wisp.Text("Usuário autenticado possui cargo inválido: " <> str)
76
76
+
wisp.Text("Usuário autenticado possui cargo não reconhecido: " <> str)
88
77
|> wisp.set_body(wisp.response(401), _)
89
78
90
90
-
AuthorizationError(user_uuid:, user_role:, authorized_roles:) -> {
79
79
+
NotAuthorized(user_uuid:, user_role:, authorized_roles:) -> {
91
80
json.object([
92
81
#("id", json.string(uuid.to_string(user_uuid))),
93
82
#("user_role", json.string(role.to_string_pt_br(user_role:))),
+16
-13
src/app/web/socket.gleam
···
1
1
import app/domain/notification/sql as notif_sql
2
2
import app/domain/occurrence/category
3
3
-
import app/domain/user
4
3
import app/domain/user/sql as user_sql
5
4
import app/web/context.{type Context}
5
5
+
import app/web/session
6
6
import app/web/socket/envelope
7
7
import app/web/socket/message as msg
8
8
import gleam/bit_array
···
40
40
InvalidSignature
41
41
/// The signed message could not be properly decrypted
42
42
InvalidUtf8
43
43
-
/// Session token has invalid Uuid fomat
44
44
-
InvalidUuid(String)
43
43
+
/// Session token has invalid format
44
44
+
InvalidToken(String)
45
45
/// Failed to access the DataBase
46
46
Database(pog.QueryError)
47
47
/// Content-length header is missing
···
56
56
pub fn handle_request(req: Request, ctx: Context) -> Response {
57
57
let registry = group_registry.get_registry(ctx.registry_name)
58
58
59
59
-
case extract_uuid(req, ctx) {
59
59
+
case extract_token(req, ctx) {
60
60
Error(err) -> handle_error(err)
61
61
-
Ok(user_uuid) -> handle_connection(req, ctx, user_uuid, registry)
61
61
+
Ok(token) -> handle_connection(req, ctx, token.user_id, registry)
62
62
}
63
63
}
64
64
···
288
288
}
289
289
}
290
290
291
291
-
fn extract_uuid(req: Request, ctx: Context) -> Result(uuid.Uuid, WebSocketError) {
291
291
+
fn extract_token(
292
292
+
req: Request,
293
293
+
ctx: Context,
294
294
+
) -> Result(session.Session, WebSocketError) {
292
295
let cookies = request.get_cookies(req)
293
296
let salt = <<ctx.secret_key_base:utf8>>
294
297
295
295
-
use hashed_uuid <- result.try(
296
296
-
list.key_find(cookies, user.uuid_cookie_name)
298
298
+
use hashed_token <- result.try(
299
299
+
list.key_find(cookies, session.cookie_name)
297
300
|> result.replace_error(MissingCookie),
298
301
)
299
302
300
303
use decrypted <- result.try(
301
301
-
crypto.verify_signed_message(hashed_uuid, salt)
304
304
+
crypto.verify_signed_message(hashed_token, salt)
302
305
|> result.replace_error(InvalidSignature),
303
306
)
304
307
305
305
-
use maybe_uuid_str <- result.try(
308
308
+
use session_str <- result.try(
306
309
bit_array.to_string(decrypted)
307
310
|> result.replace_error(InvalidUtf8),
308
311
)
309
312
310
310
-
uuid.from_string(maybe_uuid_str)
311
311
-
|> result.replace_error(InvalidUuid(maybe_uuid_str))
313
313
+
json.parse(session_str, session.decoder())
314
314
+
|> result.replace_error(InvalidToken(session_str))
312
315
}
313
316
314
317
// ON INIT ---------------------------------------------------------------------
···
413
416
414
417
fn handle_error(err: WebSocketError) -> Response {
415
418
case err {
416
416
-
InvalidUuid(id) -> {
419
419
+
InvalidToken(id) -> {
417
420
let body = "Usuário possui Uuid inválido: " <> id
418
421
send_response(body, 401)
419
422
}