Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Open sidebar
DNS Witch
Nomilo
Commits
7df4792e
Commit
7df4792e
authored
Apr 02, 2021
by
Gaël Berthaud-Müller
Browse files
improve error type
parent
b758c875
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
34 additions
and
23 deletions
+34
-23
src/models/errors.rs
src/models/errors.rs
+21
-11
src/models/users.rs
src/models/users.rs
+8
-8
src/routes/users.rs
src/routes/users.rs
+2
-2
src/routes/zones.rs
src/routes/zones.rs
+3
-2
No files found.
src/models/errors.rs
View file @
7df4792e
use
serde
::
Serialize
;
use
rocket
::
http
::
Status
;
use
rocket
::
request
::
Request
;
use
rocket
::
request
::
{
Request
,
Outcome
}
;
use
rocket
::
response
::{
self
,
Response
,
Responder
};
use
rocket_contrib
::
json
::
Json
;
use
crate
::
models
::
users
::
UserError
;
use
serde_json
::
Value
;
#[derive(Serialize,
Debug)]
pub
struct
ErrorResponse
<
T
>
{
pub
struct
ErrorResponse
{
#[serde(with
=
"StatusDef"
)]
#[serde(flatten)]
pub
status
:
Status
,
pub
message
:
String
,
#[serde(skip_serializing_if
=
"Option::is_none"
)]
pub
details
:
Option
<
T
>
pub
details
:
Option
<
Value
>
}
#[derive(Serialize)]
...
...
@@ -23,8 +25,8 @@ struct StatusDef {
reason
:
&
'static
str
,
}
impl
<
T
>
ErrorResponse
<
T
>
{
pub
fn
new
(
status
:
Status
,
message
:
String
)
->
ErrorResponse
<
T
>
{
impl
ErrorResponse
{
pub
fn
new
(
status
:
Status
,
message
:
String
)
->
ErrorResponse
{
ErrorResponse
{
status
,
message
,
...
...
@@ -32,26 +34,26 @@ impl<T> ErrorResponse<T> {
}
}
pub
fn
with_details
(
self
,
details
:
T
)
->
ErrorResponse
<
T
>
{
pub
fn
with_details
<
T
:
Serialize
>
(
self
,
details
:
T
)
->
ErrorResponse
{
ErrorResponse
{
details
:
Som
e
(
details
),
details
:
serde_json
::
to_valu
e
(
details
)
.ok
()
,
..
self
}
}
pub
fn
err
<
R
>
(
self
)
->
Result
<
R
,
ErrorResponse
<
T
>
>
{
pub
fn
err
<
R
>
(
self
)
->
Result
<
R
,
ErrorResponse
>
{
Err
(
self
)
}
}
impl
<
'r
,
T
:
Serialize
>
Responder
<
'r
,
'static
>
for
ErrorResponse
<
T
>
{
impl
<
'r
>
Responder
<
'r
,
'static
>
for
ErrorResponse
{
fn
respond_to
(
self
,
req
:
&
'r
Request
<
'_
>
)
->
response
::
Result
<
'static
>
{
let
status
=
self
.status
;
Response
::
build_from
(
Json
(
self
)
.respond_to
(
req
)
?
)
.status
(
status
)
.ok
()
}
}
impl
From
<
UserError
>
for
ErrorResponse
<
()
>
{
impl
From
<
UserError
>
for
ErrorResponse
{
fn
from
(
e
:
UserError
)
->
Self
{
match
e
{
UserError
::
NotFound
=>
ErrorResponse
::
new
(
Status
::
Unauthorized
,
"Provided credentials or token do not match any existing user"
.into
()),
...
...
@@ -66,7 +68,15 @@ impl From<UserError> for ErrorResponse<()> {
}
}
pub
fn
make_500
<
E
:
std
::
fmt
::
Debug
>
(
e
:
E
)
->
ErrorResponse
<
()
>
{
impl
<
S
>
Into
<
Outcome
<
S
,
ErrorResponse
>>
for
ErrorResponse
{
fn
into
(
self
)
->
Outcome
<
S
,
ErrorResponse
>
{
Outcome
::
Failure
((
self
.status
.clone
(),
self
))
}
}
pub
fn
make_500
<
E
:
std
::
fmt
::
Debug
>
(
e
:
E
)
->
ErrorResponse
{
println!
(
"{:?}"
,
e
);
ErrorResponse
::
new
(
Status
::
InternalServerError
,
"An unexpected error occured."
.into
())
}
src/models/users.rs
View file @
7df4792e
...
...
@@ -4,7 +4,6 @@ use diesel::result::Error as DieselError;
use
diesel_derive_enum
::
DbEnum
;
use
rocket
::{
State
,
request
::{
FromRequest
,
Request
,
Outcome
}};
use
serde
::{
Serialize
,
Deserialize
};
use
rocket
::
http
::
Status
;
use
chrono
::
serde
::
ts_seconds
;
use
chrono
::
prelude
::{
DateTime
,
Utc
};
use
chrono
::
Duration
;
...
...
@@ -21,6 +20,7 @@ use jsonwebtoken::{
use
crate
::
schema
::
*
;
use
crate
::
DbConn
;
use
crate
::
config
::
Config
;
use
crate
::
models
::
errors
::
ErrorResponse
;
const
BEARER
:
&
'static
str
=
"Bearer "
;
...
...
@@ -95,7 +95,7 @@ pub struct UserInfo {
#[rocket::async_trait]
impl
<
'r
>
FromRequest
<
'r
>
for
UserInfo
{
type
Error
=
User
Error
;
type
Error
=
Error
Response
;
async
fn
from_request
(
request
:
&
'r
Request
<
'_
>
)
->
Outcome
<
Self
,
Self
::
Error
>
{
let
auth_header
=
match
request
.headers
()
.get_one
(
AUTH_HEADER
)
{
...
...
@@ -106,7 +106,7 @@ impl<'r> FromRequest<'r> for UserInfo {
let
token
=
if
auth_header
.starts_with
(
BEARER
)
{
auth_header
.trim_start_matches
(
BEARER
)
}
else
{
return
Outcome
::
Failure
((
Status
::
BadRequest
,
UserError
::
MalformedHeader
))
return
ErrorResponse
::
from
(
UserError
::
MalformedHeader
)
.into
(
)
};
// TODO: Better error handling
...
...
@@ -116,12 +116,12 @@ impl<'r> FromRequest<'r> for UserInfo {
let
token_data
=
AuthClaims
::
decode
(
token
,
&
config
.web_app.secret
)
.map_err
(|
e
|
match
e
.into_kind
()
{
JwtErrorKind
::
ExpiredSignature
=>
(
Status
::
Unauthorized
,
UserError
::
ExpiredToken
)
,
_
=>
(
Status
::
BadRequest
,
UserError
::
BadToken
)
,
JwtErrorKind
::
ExpiredSignature
=>
UserError
::
ExpiredToken
,
_
=>
UserError
::
BadToken
,
});
let
token_data
=
match
token_data
{
Err
(
e
)
=>
return
Outcome
::
Failure
(
e
),
Err
(
e
)
=>
return
ErrorResponse
::
from
(
e
)
.into
(
),
Ok
(
data
)
=>
data
};
...
...
@@ -129,8 +129,8 @@ impl<'r> FromRequest<'r> for UserInfo {
conn
.run
(|
c
|
{
match
LocalUser
::
get_user_by_uuid
(
c
,
user_id
)
{
Err
(
UserError
::
NotFound
)
=>
Outcome
::
Failure
((
Status
::
NotFound
,
UserError
::
NotFound
)),
Err
(
e
)
=>
Outcome
::
Failure
((
Status
::
InternalServerError
,
e
)
),
Err
(
UserError
::
NotFound
)
=>
ErrorResponse
::
from
(
UserError
::
NotFound
)
.into
(
),
Err
(
e
)
=>
ErrorResponse
::
from
(
e
)
.into
(
),
Ok
(
d
)
=>
Outcome
::
Success
(
d
),
}
})
.await
...
...
src/routes/users.rs
View file @
7df4792e
...
...
@@ -13,7 +13,7 @@ pub async fn create_auth_token(
conn
:
DbConn
,
config
:
State
<
'_
,
Config
>
,
auth_request
:
Json
<
AuthTokenRequest
>
)
->
Result
<
Json
<
AuthTokenResponse
>
,
ErrorResponse
<
()
>
>
{
)
->
Result
<
Json
<
AuthTokenResponse
>
,
ErrorResponse
>
{
let
user_info
=
conn
.run
(
move
|
c
|
{
LocalUser
::
get_user_by_creds
(
c
,
&
auth_request
.username
,
&
auth_request
.password
)
...
...
@@ -27,7 +27,7 @@ pub async fn create_auth_token(
}
#[post(
"/users"
,
data
=
"<user_request>"
)]
pub
async
fn
create_user
<
'r
>
(
conn
:
DbConn
,
user_request
:
Json
<
CreateUserRequest
>
)
->
Result
<
Response
<
'r
>
,
ErrorResponse
<
()
>
>
{
pub
async
fn
create_user
<
'r
>
(
conn
:
DbConn
,
user_request
:
Json
<
CreateUserRequest
>
)
->
Result
<
Response
<
'r
>
,
ErrorResponse
>
{
// TODO: Check current user if any to check if user has permission to create users (with or without role)
let
_u
ser_info
=
conn
.run
(|
c
|
{
LocalUser
::
create_user
(
&
c
,
user_request
.into_inner
())
...
...
src/routes/zones.rs
View file @
7df4792e
...
...
@@ -16,9 +16,10 @@ use crate::DnsClient;
#[get(
"/zones/<zone>/records"
)]
pub
fn
get_zone_records
(
client
:
State
<
DnsClient
>
,
_
u
ser_info
:
UserInfo
,
user_info
:
Result
<
UserInfo
,
ErrorResponse
>
,
zone
:
String
)
->
Result
<
Json
<
Vec
<
dns
::
Record
>>
,
ErrorResponse
<
()
>>
{
)
->
Result
<
Json
<
Vec
<
dns
::
Record
>>
,
ErrorResponse
>
{
user_info
?
;
// TODO: Implement FromParam for Name
let
name
=
Name
::
from_utf8
(
&
zone
)
.unwrap
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment