token creation call
This commit is contained in:
parent
392d9642b7
commit
550e80f91c
43
src/api.rs
43
src/api.rs
|
@ -20,13 +20,13 @@ pub fn get_user(user: models::User, uuid: Uuid) -> Result<Json<models::User>> {
|
||||||
Ok(Json(user))
|
Ok(Json(user))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[instrument]
|
||||||
#[get("/whoami")]
|
#[get("/whoami")]
|
||||||
pub fn whoami(user: models::User) -> Json<models::User> {
|
pub fn whoami(user: models::User) -> Json<models::User> {
|
||||||
Json(user)
|
Json(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(conn))]
|
#[instrument(skip(conn))]
|
||||||
#[get("/token")]
|
#[get("/token")]
|
||||||
pub fn get_tokens(user: models::User, conn: MainDatabase) -> Result<Json<Vec<models::Token>>> {
|
pub fn get_tokens(user: models::User, conn: MainDatabase) -> Result<Json<Vec<models::Token>>> {
|
||||||
use schema::tokens::dsl::*;
|
use schema::tokens::dsl::*;
|
||||||
|
@ -39,14 +39,16 @@ pub fn get_tokens(user: models::User, conn: MainDatabase) -> Result<Json<Vec<mod
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(conn))]
|
#[instrument(skip(conn))]
|
||||||
#[delete("/token/<uuid>")]
|
#[delete("/token/<uuid>")]
|
||||||
pub fn delete_token(user: models::User, conn: MainDatabase, uuid: Uuid) -> Result {
|
pub fn delete_token(user: models::User, conn: MainDatabase, uuid: Uuid) -> Result {
|
||||||
use schema::tokens::dsl::*;
|
use schema::tokens::dsl::*;
|
||||||
let uuid = uuid.into_inner();
|
let uuid = uuid.into_inner();
|
||||||
|
|
||||||
let tok: models::Token = tokens.find(uuid.clone())
|
let tok: models::Token = tokens
|
||||||
.get_result(&*conn).map_err(Error::Database)?;
|
.find(uuid.clone())
|
||||||
|
.get_result(&*conn)
|
||||||
|
.map_err(Error::Database)?;
|
||||||
|
|
||||||
if tok.user_id != user.id && !user.is_admin {
|
if tok.user_id != user.id && !user.is_admin {
|
||||||
return Err(Error::LackPermissions);
|
return Err(Error::LackPermissions);
|
||||||
|
@ -59,6 +61,20 @@ pub fn delete_token(user: models::User, conn: MainDatabase, uuid: Uuid) -> Resul
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(conn))]
|
||||||
|
#[post("/token")]
|
||||||
|
pub fn create_token(user: models::User, conn: MainDatabase) -> Result<String> {
|
||||||
|
use schema::tokens;
|
||||||
|
|
||||||
|
let tok: models::Token = diesel::insert_into(tokens::table)
|
||||||
|
.values(&models::NewToken {
|
||||||
|
user_id: user.id.clone(),
|
||||||
|
})
|
||||||
|
.get_result(&*conn).map_err(Error::Database)?;
|
||||||
|
|
||||||
|
Ok(jwt::make(user.id, tok.id)?)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("internal database error: {0}")]
|
#[error("internal database error: {0}")]
|
||||||
|
@ -70,8 +86,11 @@ pub enum Error {
|
||||||
#[error("you lack needed permissions")]
|
#[error("you lack needed permissions")]
|
||||||
LackPermissions,
|
LackPermissions,
|
||||||
|
|
||||||
#[error("internal server error")]
|
#[error("internal server error: {0}")]
|
||||||
InternalServerError(#[from] Report),
|
InternalServerError(#[from] Report),
|
||||||
|
|
||||||
|
#[error("external dependency failed: {0}")]
|
||||||
|
ExternalDependencyFailed(Report),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Responder<'a> for Error {
|
impl<'a> Responder<'a> for Error {
|
||||||
|
@ -87,11 +106,13 @@ impl<'a> Responder<'a> for Error {
|
||||||
.status(Status::Unauthorized)
|
.status(Status::Unauthorized)
|
||||||
.sized_body(Cursor::new(format!("{}", self)))
|
.sized_body(Cursor::new(format!("{}", self)))
|
||||||
.ok(),
|
.ok(),
|
||||||
Error::InternalServerError(why) => Response::build()
|
Error::InternalServerError(why) | Error::ExternalDependencyFailed(why) => {
|
||||||
.header(ContentType::Plain)
|
Response::build()
|
||||||
.status(Status::InternalServerError)
|
.header(ContentType::Plain)
|
||||||
.sized_body(Cursor::new(format!("{}", why)))
|
.status(Status::InternalServerError)
|
||||||
.ok(),
|
.sized_body(Cursor::new(format!("{}", why)))
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
86
src/main.rs
86
src/main.rs
|
@ -6,6 +6,8 @@ extern crate diesel;
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rocket_contrib;
|
extern crate rocket_contrib;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate tracing;
|
||||||
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use diesel::pg::PgConnection;
|
use diesel::pg::PgConnection;
|
||||||
|
@ -28,23 +30,24 @@ pub struct MainDatabase(PgConnection);
|
||||||
|
|
||||||
pub struct Gitea;
|
pub struct Gitea;
|
||||||
|
|
||||||
#[tracing::instrument(skip(oauth2, cookies))]
|
#[instrument(skip(oauth2, cookies))]
|
||||||
#[get("/login/gitea")]
|
#[get("/login/gitea")]
|
||||||
fn gitea_login(oauth2: OAuth2<Gitea>, mut cookies: Cookies<'_>) -> Redirect {
|
fn gitea_login(oauth2: OAuth2<Gitea>, mut cookies: Cookies<'_>) -> Redirect {
|
||||||
oauth2.get_redirect(&mut cookies, &[""]).unwrap()
|
oauth2.get_redirect(&mut cookies, &[""]).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(conn, token, cookies))]
|
#[instrument(skip(conn, token, cookies))]
|
||||||
#[get("/auth/gitea")]
|
#[get("/auth/gitea")]
|
||||||
fn gitea_callback(
|
fn gitea_callback(
|
||||||
conn: MainDatabase,
|
conn: MainDatabase,
|
||||||
token: TokenResponse<Gitea>,
|
token: TokenResponse<Gitea>,
|
||||||
mut cookies: Cookies<'_>,
|
mut cookies: Cookies<'_>,
|
||||||
) -> String {
|
) -> api::Result<String> {
|
||||||
let tok = token.access_token().to_string();
|
let tok = token.access_token().to_string();
|
||||||
let refresh = token.refresh_token().unwrap().to_string();
|
let refresh = token.refresh_token().unwrap().to_string();
|
||||||
|
|
||||||
let gitea_user = gitea::user(tok.clone()).expect("gitea api call to work");
|
let gitea_user =
|
||||||
|
gitea::user(tok.clone()).map_err(|why| api::Error::ExternalDependencyFailed(why.into()))?;
|
||||||
|
|
||||||
use schema::{
|
use schema::{
|
||||||
gitea_tokens, tokens,
|
gitea_tokens, tokens,
|
||||||
|
@ -53,47 +56,43 @@ fn gitea_callback(
|
||||||
table as users_table,
|
table as users_table,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let user: models::User = match users
|
let u: Vec<models::User> = users
|
||||||
.filter(email.eq(gitea_user.email.clone()))
|
.filter(email.eq(gitea_user.email.clone()))
|
||||||
.limit(1)
|
.limit(1)
|
||||||
.load::<models::User>(&*conn)
|
.load::<models::User>(&*conn)
|
||||||
{
|
.map_err(api::Error::Database)?;
|
||||||
Ok(u) => {
|
|
||||||
if u.len() == 0 {
|
|
||||||
let u = models::NewUser {
|
|
||||||
salutation: gitea_user.full_name,
|
|
||||||
email: gitea_user.email,
|
|
||||||
is_admin: gitea_user.is_admin,
|
|
||||||
is_locked: false,
|
|
||||||
tier: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let u: models::User = diesel::insert_into(users_table)
|
let user = if u.len() == 0 {
|
||||||
.values(&u)
|
let u = models::NewUser {
|
||||||
.get_result(&*conn)
|
salutation: gitea_user.full_name,
|
||||||
.expect("able to insert user");
|
email: gitea_user.email,
|
||||||
|
is_admin: gitea_user.is_admin,
|
||||||
|
is_locked: false,
|
||||||
|
tier: 0,
|
||||||
|
};
|
||||||
|
|
||||||
let tok = models::NewGiteaToken {
|
let u: models::User = diesel::insert_into(users_table)
|
||||||
user_id: u.id.clone(),
|
.values(&u)
|
||||||
access_token: tok,
|
.get_result(&*conn)
|
||||||
refresh_token: refresh,
|
.map_err(api::Error::Database)?;
|
||||||
};
|
|
||||||
|
|
||||||
let _: models::GiteaToken = diesel::insert_into(gitea_tokens::table)
|
let tok = models::NewGiteaToken {
|
||||||
.values(&tok)
|
user_id: u.id.clone(),
|
||||||
.get_result(&*conn)
|
access_token: tok,
|
||||||
.expect("able to insert token");
|
refresh_token: refresh,
|
||||||
|
};
|
||||||
|
|
||||||
u
|
let _: models::GiteaToken = diesel::insert_into(gitea_tokens::table)
|
||||||
} else {
|
.values(&tok)
|
||||||
tracing::info!("{} {:?} logged in", u[0].id, u[0].salutation);
|
.get_result(&*conn)
|
||||||
u[0].clone()
|
.map_err(api::Error::Database)?;
|
||||||
}
|
|
||||||
}
|
info!("new account created for {:?}", u);
|
||||||
Err(why) => {
|
|
||||||
tracing::error!("error reading from database: {}", why);
|
u
|
||||||
todo!("error response")
|
} else {
|
||||||
}
|
info!("{} {:?} logged in", u[0].id, u[0].salutation);
|
||||||
|
u[0].clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let tok: models::Token = diesel::insert_into(tokens::table)
|
let tok: models::Token = diesel::insert_into(tokens::table)
|
||||||
|
@ -102,23 +101,25 @@ fn gitea_callback(
|
||||||
})
|
})
|
||||||
.get_result(&*conn)
|
.get_result(&*conn)
|
||||||
.expect("create token information");
|
.expect("create token information");
|
||||||
tracing::info!("created new token for {} with id {}", user.id, tok.id);
|
info!("created new token for {} with id {}", user.id, tok.id);
|
||||||
|
|
||||||
let tok = jwt::make(user.id, tok.id).expect("to sign JWT");
|
let tok = jwt::make(user.id, tok.id).expect("to sign JWT");
|
||||||
// Set a private cookie with the access token
|
|
||||||
cookies.add_private(
|
cookies.add_private(
|
||||||
Cookie::build("token", tok.clone())
|
Cookie::build("token", tok.clone())
|
||||||
.same_site(SameSite::Lax)
|
.same_site(SameSite::Lax)
|
||||||
.finish(),
|
.finish(),
|
||||||
);
|
);
|
||||||
|
|
||||||
tok
|
Ok(tok)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
color_eyre::install()?;
|
color_eyre::install()?;
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
|
// XXX(Xe): This looks ineffectual, however it forces jwt::SECRET to be
|
||||||
|
// evaluated and will kill the program if JWT_SECRET is not found.
|
||||||
let _ = *jwt::SECRET;
|
let _ = *jwt::SECRET;
|
||||||
|
|
||||||
rocket::ignite()
|
rocket::ignite()
|
||||||
|
@ -131,7 +132,8 @@ fn main() -> Result<()> {
|
||||||
api::whoami,
|
api::whoami,
|
||||||
api::get_user,
|
api::get_user,
|
||||||
api::get_tokens,
|
api::get_tokens,
|
||||||
api::delete_token
|
api::delete_token,
|
||||||
|
api::create_token,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.mount("/", routes![gitea_login, gitea_callback])
|
.mount("/", routes![gitea_login, gitea_callback])
|
||||||
|
|
Loading…
Reference in New Issue