add some kind of authorization #5
|
@ -1,4 +1,5 @@
|
||||||
-- This file should undo anything in `up.sql`
|
-- This file should undo anything in `up.sql`
|
||||||
DROP TABLE localuser;
|
DROP TABLE localuser;
|
||||||
DROP TABLE user;
|
DROP TABLE user;
|
||||||
|
DROP TABLE zone;
|
||||||
DROP TABLE user_zone;
|
DROP TABLE user_zone;
|
||||||
|
|
|
@ -1,19 +1,25 @@
|
||||||
-- Your SQL goes here
|
-- Your SQL goes here
|
||||||
CREATE TABLE localuser (
|
CREATE TABLE localuser (
|
||||||
user_id VARCHAR NOT NULL PRIMARY KEY,
|
`user_id` VARCHAR NOT NULL PRIMARY KEY,
|
||||||
username VARCHAR NOT NULL UNIQUE,
|
`username` VARCHAR NOT NULL UNIQUE,
|
||||||
password VARCHAR NOT NULL,
|
`password` VARCHAR NOT NULL,
|
||||||
|
`role` TEXT CHECK(role IN ('admin', 'zoneadmin')) NOT NULL, -- note: migrate to postgres so enum are actually a thing
|
||||||
FOREIGN KEY(user_id) REFERENCES user(id)
|
FOREIGN KEY(user_id) REFERENCES user(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE user (
|
CREATE TABLE user (
|
||||||
id VARCHAR NOT NULL PRIMARY KEY,
|
`id` VARCHAR NOT NULL PRIMARY KEY
|
||||||
role TEXT CHECK(role IN ('admin', 'zoneadmin')) NOT NULL -- note: migrate to postgres so enum are actually a thing
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE user_zone (
|
CREATE TABLE user_zone (
|
||||||
user_id VARCHAR NOT NULL,
|
`user_id` VARCHAR NOT NULL,
|
||||||
zone VARCHAR NOT NULL,
|
`zone_id` VARCHAR NOT NULL,
|
||||||
PRIMARY KEY(user_id, zone),
|
PRIMARY KEY(user_id, zone_id),
|
||||||
FOREIGN KEY(user_id) REFERENCES user(id)
|
FOREIGN KEY(user_id) REFERENCES user(id),
|
||||||
)
|
FOREIGN KEY(zone_id) REFERENCES zone(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE zone (
|
||||||
|
`id` VARCHAR NOT NULL PRIMARY KEY,
|
||||||
|
`name` VARCHAR NOT NULL UNIQUE
|
||||||
|
);
|
||||||
|
|
|
@ -24,5 +24,10 @@ async fn rocket() -> rocket::Rocket {
|
||||||
rocket::ignite()
|
rocket::ignite()
|
||||||
.manage(app_config)
|
.manage(app_config)
|
||||||
.attach(DbConn::fairing())
|
.attach(DbConn::fairing())
|
||||||
.mount("/api/v1", routes![get_zone_records, create_auth_token, create_user])
|
.mount("/api/v1", routes![
|
||||||
|
get_zone_records,
|
||||||
|
create_user_zone,
|
||||||
|
create_auth_token,
|
||||||
|
create_user
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use rocket::{Request, State, http::Status, request::{FromParam, FromRequest, Outcome}};
|
use rocket::{Request, State, http::Status, request::{FromParam, FromRequest, Outcome}};
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
use tokio::{net::TcpStream as TokioTcpStream, task};
|
use tokio::{net::TcpStream as TokioTcpStream, task};
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ use trust_dns_proto::iocompat::AsyncIoTokioAsStd;
|
||||||
|
|
||||||
use super::trust_dns_types::{self, Name};
|
use super::trust_dns_types::{self, Name};
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::models::errors::make_500;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
|
@ -251,13 +250,14 @@ impl From<trust_dns_types::Record> for Record {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct AbsoluteName(Name);
|
pub struct AbsoluteName(Name);
|
||||||
|
|
||||||
impl<'r> FromParam<'r> for AbsoluteName {
|
impl<'r> FromParam<'r> for AbsoluteName {
|
||||||
type Error = ProtoError;
|
type Error = ProtoError;
|
||||||
|
|
||||||
fn from_param(param: &'r str) -> Result<Self, Self::Error> {
|
fn from_param(param: &'r str) -> Result<Self, Self::Error> {
|
||||||
let mut name = Name::from_utf8(¶m).unwrap();
|
let mut name = Name::from_utf8(¶m)?;
|
||||||
if !name.is_fqdn() {
|
if !name.is_fqdn() {
|
||||||
name.set_fqdn(true);
|
name.set_fqdn(true);
|
||||||
}
|
}
|
||||||
|
@ -265,6 +265,21 @@ impl<'r> FromParam<'r> for AbsoluteName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for AbsoluteName {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>
|
||||||
|
{
|
||||||
|
use serde::de::Error;
|
||||||
|
|
||||||
|
String::deserialize(deserializer)
|
||||||
|
.and_then(|string|
|
||||||
|
AbsoluteName::from_param(&string)
|
||||||
|
.map_err(|e| Error::custom(e.to_string()))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Deref for AbsoluteName {
|
impl Deref for AbsoluteName {
|
||||||
type Target = Name;
|
type Target = Name;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
@ -272,6 +287,7 @@ impl Deref for AbsoluteName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct DnsClient(AsyncClient);
|
pub struct DnsClient(AsyncClient);
|
||||||
|
|
||||||
impl Deref for DnsClient {
|
impl Deref for DnsClient {
|
||||||
|
|
|
@ -56,12 +56,14 @@ impl<'r> Responder<'r, 'static> for ErrorResponse {
|
||||||
impl From<UserError> for ErrorResponse {
|
impl From<UserError> for ErrorResponse {
|
||||||
fn from(e: UserError) -> Self {
|
fn from(e: UserError) -> Self {
|
||||||
match e {
|
match e {
|
||||||
UserError::NotFound => ErrorResponse::new(Status::Unauthorized, "Provided credentials or token do not match any existing user".into()),
|
UserError::BadCreds => ErrorResponse::new(Status::Unauthorized, "Provided credentials or token do not match any existing user".into()),
|
||||||
UserError::UserExists => ErrorResponse::new(Status::Conflict, "User already exists".into()),
|
UserError::UserConflict => ErrorResponse::new(Status::Conflict, "This user already exists".into()),
|
||||||
|
UserError::NotFound => ErrorResponse::new(Status::NotFound, "User does not exist".into()),
|
||||||
UserError::BadToken => ErrorResponse::new(Status::BadRequest, "Malformed token".into()),
|
UserError::BadToken => ErrorResponse::new(Status::BadRequest, "Malformed token".into()),
|
||||||
UserError::ExpiredToken => ErrorResponse::new(Status::Unauthorized, "The provided token has expired".into()),
|
UserError::ExpiredToken => ErrorResponse::new(Status::Unauthorized, "The provided token has expired".into()),
|
||||||
UserError::MalformedHeader => ErrorResponse::new(Status::BadRequest, "Malformed authorization header".into()),
|
UserError::MalformedHeader => ErrorResponse::new(Status::BadRequest, "Malformed authorization header".into()),
|
||||||
UserError::PermissionDenied => ErrorResponse::new(Status::Forbidden, "Bearer is not authorized to access the resource".into()),
|
UserError::PermissionDenied => ErrorResponse::new(Status::Forbidden, "Bearer is not authorized to access the resource".into()),
|
||||||
|
UserError::ZoneNotFound => ErrorResponse::new(Status::NotFound, "DNS zone does not exist".into()),
|
||||||
UserError::DbError(e) => make_500(e),
|
UserError::DbError(e) => make_500(e),
|
||||||
UserError::PasswordError(e) => make_500(e)
|
UserError::PasswordError(e) => make_500(e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ use crate::schema::*;
|
||||||
use crate::DbConn;
|
use crate::DbConn;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::models::errors::{ErrorResponse, make_500};
|
use crate::models::errors::{ErrorResponse, make_500};
|
||||||
|
use crate::models::dns::AbsoluteName;
|
||||||
|
|
||||||
|
|
||||||
const BEARER: &str = "Bearer ";
|
const BEARER: &str = "Bearer ";
|
||||||
|
@ -42,7 +43,6 @@ pub enum Role {
|
||||||
#[table_name = "user"]
|
#[table_name = "user"]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub role: Role,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Queryable, Identifiable, Insertable)]
|
#[derive(Debug, Queryable, Identifiable, Insertable)]
|
||||||
|
@ -52,6 +52,22 @@ pub struct LocalUser {
|
||||||
pub user_id: String,
|
pub user_id: String,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
|
pub role: Role,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Queryable, Identifiable, Insertable)]
|
||||||
|
#[table_name = "user_zone"]
|
||||||
|
#[primary_key(user_id, zone_id)]
|
||||||
|
pub struct UserZone {
|
||||||
|
pub user_id: String,
|
||||||
|
pub zone_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Queryable, Identifiable, Insertable)]
|
||||||
|
#[table_name = "zone"]
|
||||||
|
pub struct Zone {
|
||||||
|
pub id: String,
|
||||||
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -62,6 +78,11 @@ pub struct CreateUserRequest {
|
||||||
pub role: Option<Role>
|
pub role: Option<Role>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct CreateUserZoneRequest {
|
||||||
|
pub zone: AbsoluteName,
|
||||||
|
}
|
||||||
|
|
||||||
// pub struct LdapUserAssociation {
|
// pub struct LdapUserAssociation {
|
||||||
// user_id: Uuid,
|
// user_id: Uuid,
|
||||||
// ldap_id: String
|
// ldap_id: String
|
||||||
|
@ -95,6 +116,68 @@ pub struct UserInfo {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UserInfo {
|
||||||
|
pub fn is_admin(&self) -> bool {
|
||||||
|
matches!(self.role, Role::Admin)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_admin(&self) -> Result<(), UserError> {
|
||||||
|
if self.is_admin() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(UserError::PermissionDenied)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_zone(&self, conn: &diesel::SqliteConnection, zone_name: &str) -> Result<Zone, UserError> {
|
||||||
|
use crate::schema::user_zone::dsl::*;
|
||||||
|
use crate::schema::zone::dsl::*;
|
||||||
|
|
||||||
|
let (res_zone, _): (Zone, UserZone) = zone.inner_join(user_zone)
|
||||||
|
.filter(name.eq(zone_name))
|
||||||
|
.filter(user_id.eq(&self.id))
|
||||||
|
.get_result(conn)
|
||||||
|
.map_err(|e| match e {
|
||||||
|
DieselError::NotFound => UserError::ZoneNotFound,
|
||||||
|
other => UserError::DbError(other)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(res_zone)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_zone(&self, conn: &diesel::SqliteConnection, request: CreateUserZoneRequest) -> Result<Zone, UserError> {
|
||||||
|
use crate::schema::user_zone::dsl::*;
|
||||||
|
use crate::schema::zone::dsl::*;
|
||||||
|
|
||||||
|
let zone_name = request.zone.to_utf8();
|
||||||
|
let current_zone: Zone = zone.filter(name.eq(zone_name))
|
||||||
|
.get_result(conn)
|
||||||
|
.map_err(|e| match e {
|
||||||
|
DieselError::NotFound => UserError::ZoneNotFound,
|
||||||
|
other => UserError::DbError(other)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let new_user_zone = UserZone {
|
||||||
|
zone_id: current_zone.id.clone(),
|
||||||
|
user_id: self.id.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = diesel::insert_into(user_zone)
|
||||||
|
.values(new_user_zone)
|
||||||
|
.execute(conn);
|
||||||
|
|
||||||
|
match res {
|
||||||
|
// If user has already access to the zone, safely ignore the conflit
|
||||||
|
// TODO: use 'on conflict do nothing' in postgres when we get there
|
||||||
|
Err(DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _)) => (),
|
||||||
|
Err(e) => return Err(e.into()),
|
||||||
|
Ok(_) => ()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(current_zone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[rocket::async_trait]
|
#[rocket::async_trait]
|
||||||
impl<'r> FromRequest<'r> for UserInfo {
|
impl<'r> FromRequest<'r> for UserInfo {
|
||||||
type Error = ErrorResponse;
|
type Error = ErrorResponse;
|
||||||
|
@ -140,8 +223,10 @@ impl<'r> FromRequest<'r> for UserInfo {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum UserError {
|
pub enum UserError {
|
||||||
|
ZoneNotFound,
|
||||||
NotFound,
|
NotFound,
|
||||||
UserExists,
|
UserConflict,
|
||||||
|
BadCreds,
|
||||||
BadToken,
|
BadToken,
|
||||||
ExpiredToken,
|
ExpiredToken,
|
||||||
MalformedHeader,
|
MalformedHeader,
|
||||||
|
@ -150,22 +235,18 @@ pub enum UserError {
|
||||||
PasswordError(HasherError),
|
PasswordError(HasherError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DieselError> for UserError {
|
|
||||||
fn from(e: DieselError) -> Self {
|
|
||||||
match e {
|
|
||||||
DieselError::NotFound => UserError::NotFound,
|
|
||||||
DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _) => UserError::UserExists,
|
|
||||||
other => UserError::DbError(other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<HasherError> for UserError {
|
impl From<HasherError> for UserError {
|
||||||
fn from(e: HasherError) -> Self {
|
fn from(e: HasherError) -> Self {
|
||||||
UserError::PasswordError(e)
|
UserError::PasswordError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<DieselError> for UserError {
|
||||||
|
fn from(e: DieselError) -> Self {
|
||||||
|
UserError::DbError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl LocalUser {
|
impl LocalUser {
|
||||||
pub fn create_user(conn: &diesel::SqliteConnection, user_request: CreateUserRequest) -> Result<UserInfo, UserError> {
|
pub fn create_user(conn: &diesel::SqliteConnection, user_request: CreateUserRequest) -> Result<UserInfo, UserError> {
|
||||||
use crate::schema::localuser::dsl::*;
|
use crate::schema::localuser::dsl::*;
|
||||||
|
@ -175,19 +256,19 @@ impl LocalUser {
|
||||||
|
|
||||||
let new_user = User {
|
let new_user = User {
|
||||||
id: new_user_id.clone(),
|
id: new_user_id.clone(),
|
||||||
// TODO: Use role from request
|
|
||||||
role: Role::ZoneAdmin,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_localuser = LocalUser {
|
let new_localuser = LocalUser {
|
||||||
user_id: new_user_id,
|
user_id: new_user_id,
|
||||||
username: user_request.username.clone(),
|
username: user_request.username.clone(),
|
||||||
password: make_password_with_algorithm(&user_request.password, Algorithm::Argon2),
|
password: make_password_with_algorithm(&user_request.password, Algorithm::Argon2),
|
||||||
|
// TODO: Use role from request
|
||||||
|
role: Role::ZoneAdmin,
|
||||||
};
|
};
|
||||||
|
|
||||||
let res = UserInfo {
|
let res = UserInfo {
|
||||||
id: new_user.id.clone(),
|
id: new_user.id.clone(),
|
||||||
role: new_user.role.clone(),
|
role: new_localuser.role.clone(),
|
||||||
username: new_localuser.username.clone(),
|
username: new_localuser.username.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -201,6 +282,9 @@ impl LocalUser {
|
||||||
.execute(conn)?;
|
.execute(conn)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}).map_err(|e| match e {
|
||||||
|
DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _) => UserError::UserConflict,
|
||||||
|
other => UserError::DbError(other)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
@ -217,15 +301,19 @@ impl LocalUser {
|
||||||
|
|
||||||
let (client_user, client_localuser): (User, LocalUser) = user.inner_join(localuser)
|
let (client_user, client_localuser): (User, LocalUser) = user.inner_join(localuser)
|
||||||
.filter(username.eq(request_username))
|
.filter(username.eq(request_username))
|
||||||
.get_result(conn)?;
|
.get_result(conn)
|
||||||
|
.map_err(|e| match e {
|
||||||
|
DieselError::NotFound => UserError::BadCreds,
|
||||||
|
other => UserError::DbError(other)
|
||||||
|
})?;
|
||||||
|
|
||||||
if !check_password(&request_password, &client_localuser.password)? {
|
if !check_password(&request_password, &client_localuser.password)? {
|
||||||
return Err(UserError::NotFound);
|
return Err(UserError::BadCreds);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(UserInfo {
|
Ok(UserInfo {
|
||||||
id: client_user.id,
|
id: client_user.id,
|
||||||
role: client_user.role,
|
role: client_localuser.role,
|
||||||
username: client_localuser.username,
|
username: client_localuser.username,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -236,11 +324,15 @@ impl LocalUser {
|
||||||
|
|
||||||
let (client_user, client_localuser): (User, LocalUser) = user.inner_join(localuser)
|
let (client_user, client_localuser): (User, LocalUser) = user.inner_join(localuser)
|
||||||
.filter(id.eq(request_user_id))
|
.filter(id.eq(request_user_id))
|
||||||
.get_result(conn)?;
|
.get_result(conn)
|
||||||
|
.map_err(|e| match e {
|
||||||
|
DieselError::NotFound => UserError::NotFound,
|
||||||
|
other => UserError::DbError(other)
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(UserInfo {
|
Ok(UserInfo {
|
||||||
id: client_user.id,
|
id: client_user.id,
|
||||||
role: client_user.role,
|
role: client_localuser.role,
|
||||||
username: client_localuser.username,
|
username: client_localuser.username,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,15 @@ use rocket::http::Status;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::DbConn;
|
use crate::DbConn;
|
||||||
use crate::models::errors::{ErrorResponse, make_500};
|
use crate::models::errors::{ErrorResponse, make_500};
|
||||||
use crate::models::users::{LocalUser, CreateUserRequest, AuthClaims, AuthTokenRequest, AuthTokenResponse};
|
use crate::models::users::{
|
||||||
|
UserInfo,
|
||||||
|
LocalUser,
|
||||||
|
CreateUserRequest,
|
||||||
|
CreateUserZoneRequest,
|
||||||
|
AuthClaims,
|
||||||
|
AuthTokenRequest,
|
||||||
|
AuthTokenResponse
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#[post("/users/me/token", data = "<auth_request>")]
|
#[post("/users/me/token", data = "<auth_request>")]
|
||||||
|
@ -29,7 +37,7 @@ pub async fn create_auth_token(
|
||||||
#[post("/users", data = "<user_request>")]
|
#[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)
|
// TODO: Check current user if any to check if user has permission to create users (with or without role)
|
||||||
let _user_info = conn.run(|c| {
|
conn.run(|c| {
|
||||||
LocalUser::create_user(&c, user_request.into_inner())
|
LocalUser::create_user(&c, user_request.into_inner())
|
||||||
}).await?;
|
}).await?;
|
||||||
|
|
||||||
|
@ -37,3 +45,22 @@ pub async fn create_user<'r>(conn: DbConn, user_request: Json<CreateUserRequest>
|
||||||
.status(Status::Created)
|
.status(Status::Created)
|
||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[post("/users/<user_id>/zones", data = "<user_zone_request>")]
|
||||||
|
pub async fn create_user_zone<'r>(
|
||||||
|
conn: DbConn,
|
||||||
|
user_info: Result<UserInfo, ErrorResponse>,
|
||||||
|
user_id: String,
|
||||||
|
user_zone_request: Json<CreateUserZoneRequest>
|
||||||
|
) -> Result<Response<'r>, ErrorResponse>{
|
||||||
|
user_info?.check_admin()?;
|
||||||
|
|
||||||
|
conn.run(move |c| {
|
||||||
|
let user_info = LocalUser::get_user_by_uuid(&c, user_id)?;
|
||||||
|
user_info.add_zone(&c, user_zone_request.into_inner())
|
||||||
|
}).await?;
|
||||||
|
|
||||||
|
Response::build()
|
||||||
|
.status(Status::Created)
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@ use rocket::http::Status;
|
||||||
use rocket_contrib::json::Json;
|
use rocket_contrib::json::Json;
|
||||||
|
|
||||||
use trust_dns_client::client::ClientHandle;
|
use trust_dns_client::client::ClientHandle;
|
||||||
use trust_dns_client::op::{DnsResponse, ResponseCode};
|
use trust_dns_client::op::ResponseCode;
|
||||||
use trust_dns_client::rr::{DNSClass, RecordType};
|
use trust_dns_client::rr::{DNSClass, RecordType};
|
||||||
|
|
||||||
use crate::models::dns;
|
use crate::{DbConn, models::dns};
|
||||||
use crate::models::errors::{ErrorResponse, make_500};
|
use crate::models::errors::{ErrorResponse, make_500};
|
||||||
use crate::models::users::UserInfo;
|
use crate::models::users::UserInfo;
|
||||||
|
|
||||||
|
@ -14,13 +14,22 @@ use crate::models::users::UserInfo;
|
||||||
#[get("/zones/<zone>/records")]
|
#[get("/zones/<zone>/records")]
|
||||||
pub async fn get_zone_records(
|
pub async fn get_zone_records(
|
||||||
mut client: dns::DnsClient,
|
mut client: dns::DnsClient,
|
||||||
|
conn: DbConn,
|
||||||
user_info: Result<UserInfo, ErrorResponse>,
|
user_info: Result<UserInfo, ErrorResponse>,
|
||||||
zone: dns::AbsoluteName
|
zone: dns::AbsoluteName
|
||||||
) -> Result<Json<Vec<dns::Record>>, ErrorResponse> {
|
) -> Result<Json<Vec<dns::Record>>, ErrorResponse> {
|
||||||
println!("{:#?}", user_info?);
|
|
||||||
|
|
||||||
let response: DnsResponse = {
|
let user_info = user_info?;
|
||||||
let query = client.query((*zone).clone(), DNSClass::IN, RecordType::AXFR);
|
|
||||||
|
if !user_info.is_admin() {
|
||||||
|
let zone_name = zone.clone().to_string();
|
||||||
|
conn.run(move |c| {
|
||||||
|
dbg!(user_info.get_zone(c, &zone_name))
|
||||||
|
}).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = {
|
||||||
|
let query = client.query(zone.clone(), DNSClass::IN, RecordType::AXFR);
|
||||||
query.await.map_err(make_500)?
|
query.await.map_err(make_500)?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,11 @@
|
||||||
table! {
|
table! {
|
||||||
use diesel::sql_types::*;
|
use diesel::sql_types::*;
|
||||||
|
use crate::models::users::*;
|
||||||
|
|
||||||
localuser (user_id) {
|
localuser (user_id) {
|
||||||
user_id -> Text,
|
user_id -> Text,
|
||||||
username -> Text,
|
username -> Text,
|
||||||
password -> Text,
|
password -> Text,
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table! {
|
|
||||||
use diesel::sql_types::*;
|
|
||||||
use crate::models::users::*;
|
|
||||||
|
|
||||||
user (id) {
|
|
||||||
id -> Text,
|
|
||||||
role -> RoleMapping,
|
role -> RoleMapping,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,17 +13,36 @@ table! {
|
||||||
table! {
|
table! {
|
||||||
use diesel::sql_types::*;
|
use diesel::sql_types::*;
|
||||||
|
|
||||||
user_zone (user_id, zone) {
|
user (id) {
|
||||||
|
id -> Text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table! {
|
||||||
|
use diesel::sql_types::*;
|
||||||
|
|
||||||
|
user_zone (user_id, zone_id) {
|
||||||
user_id -> Text,
|
user_id -> Text,
|
||||||
zone -> Text,
|
zone_id -> Text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table! {
|
||||||
|
use diesel::sql_types::*;
|
||||||
|
|
||||||
|
zone (id) {
|
||||||
|
id -> Text,
|
||||||
|
name -> Text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
joinable!(localuser -> user (user_id));
|
joinable!(localuser -> user (user_id));
|
||||||
joinable!(user_zone -> user (user_id));
|
joinable!(user_zone -> user (user_id));
|
||||||
|
joinable!(user_zone -> zone (zone_id));
|
||||||
|
|
||||||
allow_tables_to_appear_in_same_query!(
|
allow_tables_to_appear_in_same_query!(
|
||||||
localuser,
|
localuser,
|
||||||
user,
|
user,
|
||||||
user_zone,
|
user_zone,
|
||||||
|
zone,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue