feat(db): basic application relations
This commit is contained in:
parent
935ea5555d
commit
b0fe35f69e
|
@ -1253,11 +1253,13 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"futures",
|
"futures",
|
||||||
|
"rand 0.8.5",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tide",
|
"tide",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-postgres",
|
"tokio-postgres",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1452,6 +1454,7 @@ dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fallible-iterator",
|
"fallible-iterator",
|
||||||
"postgres-protocol",
|
"postgres-protocol",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2200,6 +2203,28 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.12",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"uuid-macro-internal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid-macro-internal"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9881bea7cbe687e36c9ab3b778c36cd0487402e270304e8b1296d5085303c1a2"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.55",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "value-bag"
|
name = "value-bag"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
|
|
|
@ -11,5 +11,7 @@ async-std = { version = "1.8.0", features = ["attributes"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
tokio = { version = "1.37.0", features = ["full"] }
|
tokio = { version = "1.37.0", features = ["full"] }
|
||||||
tokio-postgres = "0.7.10"
|
tokio-postgres = { version = "0.7.10", features = ["with-uuid-1"] }
|
||||||
futures = "0.3.30"
|
futures = "0.3.30"
|
||||||
|
uuid = { verion = "1.0.0", features = ["v4", "fast-rng", "macro-diagnostics"] }
|
||||||
|
rand = "0.8.5"
|
||||||
|
|
72
src/db.rs
72
src/db.rs
|
@ -1,33 +1,102 @@
|
||||||
use std::time::Duration;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
pub struct OAuthApplication {
|
||||||
|
pub client_id: Uuid,
|
||||||
|
pub client_secret: crate::misc::U256,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OAuthApplication {
|
||||||
|
// TEST: functionality
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { client_id: Uuid::new_v4(), client_secret: crate::misc::random_256() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from(client_id: Uuid, client_secret: crate::misc::U256) -> Self {
|
||||||
|
Self { client_id, client_secret }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OAuthScope {
|
||||||
|
pub scope_id: Uuid,
|
||||||
|
pub scope_desc: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OAuthScope {
|
||||||
|
// TEST: functionality
|
||||||
|
pub fn new(description: String) -> Self {
|
||||||
|
Self { scope_id: Uuid::new_v4(), scope_desc: description }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from(scope_id: Uuid, scope_desc: String) -> Self {
|
||||||
|
Self { scope_id, scope_desc }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper struct for Postgres database with APIs related to OAuth database operations.
|
||||||
pub struct OAuthDatabase {
|
pub struct OAuthDatabase {
|
||||||
client: tokio_postgres::Client,
|
client: tokio_postgres::Client,
|
||||||
handle: tokio::task::JoinHandle<Result<(), tokio_postgres::Error>>,
|
handle: tokio::task::JoinHandle<Result<(), tokio_postgres::Error>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OAuthDatabase {
|
impl OAuthDatabase {
|
||||||
|
/// Establish a new connection to a database.
|
||||||
pub async fn connect(host: &str, port: u16, user: &str, password: &str, db_name: &str) -> Result<Self, tokio_postgres::Error> {
|
pub async fn connect(host: &str, port: u16, user: &str, password: &str, db_name: &str) -> Result<Self, tokio_postgres::Error> {
|
||||||
let (client, connection) = tokio_postgres::connect(format!("host={} port={} user={} password={} dbname={}", host, port, user, password, db_name).as_str(), tokio_postgres::NoTls).await?;
|
let (client, connection) = tokio_postgres::connect(format!("host={} port={} user={} password={} dbname={}", host, port, user, password, db_name).as_str(), tokio_postgres::NoTls).await?;
|
||||||
Ok(Self::new(client, connection).await?)
|
Ok(Self::new(client, connection).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attach a connection to a new `OAuthDatabase` instance.
|
||||||
pub async fn new(client: tokio_postgres::Client, connection: tokio_postgres::Connection<tokio_postgres::Socket, tokio_postgres::tls::NoTlsStream>) -> Result<Self, tokio_postgres::Error> {
|
pub async fn new(client: tokio_postgres::Client, connection: tokio_postgres::Connection<tokio_postgres::Socket, tokio_postgres::tls::NoTlsStream>) -> Result<Self, tokio_postgres::Error> {
|
||||||
let handle = tokio::spawn(connection);
|
let handle = tokio::spawn(connection);
|
||||||
let obj = Self { client, handle };
|
let obj = Self { client, handle };
|
||||||
Ok(obj)
|
Ok(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform arbitrary SQL operations on the database. This method shouldn't be called directly
|
||||||
|
/// by other modules. This method has the same signature with
|
||||||
|
/// `tokio_postgres::Client::execute`.
|
||||||
async fn psql_execute<T: ?Sized + tokio_postgres::ToStatement>(&mut self, query: &T, params: &[&(dyn tokio_postgres::types::ToSql + Sync)]) -> Result<u64, tokio_postgres::Error> {
|
async fn psql_execute<T: ?Sized + tokio_postgres::ToStatement>(&mut self, query: &T, params: &[&(dyn tokio_postgres::types::ToSql + Sync)]) -> Result<u64, tokio_postgres::Error> {
|
||||||
self.client.execute(query, params).await
|
self.client.execute(query, params).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform arbitrary SQL operations on the database (with return value). This method shouldn't be called directly
|
||||||
|
/// by other modules. This method has the same signature with `tokio_postgres::Client::query`.
|
||||||
async fn psql_query<T: ?Sized + tokio_postgres::ToStatement>(&mut self, query: &T, params: &[&(dyn tokio_postgres::types::ToSql + Sync)]) -> Result<Vec<tokio_postgres::Row>, tokio_postgres::Error> {
|
async fn psql_query<T: ?Sized + tokio_postgres::ToStatement>(&mut self, query: &T, params: &[&(dyn tokio_postgres::types::ToSql + Sync)]) -> Result<Vec<tokio_postgres::Row>, tokio_postgres::Error> {
|
||||||
self.client.query(query, params).await
|
self.client.query(query, params).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Disconnect from the current database. The instance will become invalid since then.
|
||||||
pub fn disconnect(&mut self) {
|
pub fn disconnect(&mut self) {
|
||||||
self.handle.abort();
|
self.handle.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initialize the database.
|
||||||
|
pub async fn init(&mut self) -> Result<(), tokio_postgres::Error> {
|
||||||
|
// TEST: functionality
|
||||||
|
self.psql_execute("create table Applications(client_id uuid primary key, client_secret bytea)", &[]).await?;
|
||||||
|
self.psql_execute("create table Scopes(scope_id uuid primary key, scope_desc text)", &[]).await?;
|
||||||
|
// TODO: OAuthApplicationAccess struct
|
||||||
|
self.psql_execute("create table ApplicationAccess(access_id uuid primary key, client_id uuid, scope_id uuid)", &[]).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register an application.
|
||||||
|
/// Applicant: client
|
||||||
|
pub async fn trusted_register_application(&mut self) -> Result<OAuthApplication, tokio_postgres::Error> {
|
||||||
|
// TEST: functionality
|
||||||
|
let app = OAuthApplication::new();
|
||||||
|
self.psql_execute("insert into Applications (client_id, client_secret) values ($1, $2)", &[&app.client_id, &&app.client_secret[..]]).await?;
|
||||||
|
Ok(app)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a scope.
|
||||||
|
/// Applicant: Resource
|
||||||
|
pub async fn trusted_register_scope(&mut self, description: String) -> Result<OAuthScope, tokio_postgres::Error> {
|
||||||
|
// TEST: functionality
|
||||||
|
let scope = OAuthScope::new(description);
|
||||||
|
self.psql_execute("insert into Scopes (scope_id, scope_desc) values ($1, $2)", &[&scope.scope_id, &scope.scope_desc]).await?;
|
||||||
|
Ok(scope)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -61,7 +130,6 @@ pub mod db_tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read(&mut self) -> Result<Vec<DBTestEntryType>, tokio_postgres::Error> {
|
pub async fn read(&mut self) -> Result<Vec<DBTestEntryType>, tokio_postgres::Error> {
|
||||||
// TODO:
|
|
||||||
let v = self.d.psql_query("select * from rust_test", &[]).await?;
|
let v = self.d.psql_query("select * from rust_test", &[]).await?;
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
for row in v {
|
for row in v {
|
||||||
|
|
|
@ -2,6 +2,7 @@ use tide::Request;
|
||||||
use tide::prelude::*;
|
use tide::prelude::*;
|
||||||
|
|
||||||
mod db;
|
mod db;
|
||||||
|
mod misc;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct Test {
|
struct Test {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
pub type U256 = [u8; 8];
|
||||||
|
|
||||||
|
pub fn random_256() -> U256 {
|
||||||
|
let mut res = [0; 8];
|
||||||
|
for x in &mut res {
|
||||||
|
*x = rand::random::<i8>() as u8;
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
Loading…
Reference in New Issue