feat: basic authentication.
Gotta improve it, but right now this can ping. Theoretically any client should be able to connect.
This commit is contained in:
parent
667fcca4e9
commit
67244e63b3
7 changed files with 110 additions and 7 deletions
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT * FROM users WHERE name = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "is_admin",
|
||||
"ordinal": 3,
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "fbf4d83d9836cf85d01059e679bcbf7dc463eea0579afacc0267f0f8c33640d3"
|
||||
}
|
||||
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"sqltools.useNodeRuntime": true,
|
||||
"sqltools.connections": [
|
||||
{
|
||||
"previewLimit": 50,
|
||||
"driver": "SQLite",
|
||||
"name": "rave-users",
|
||||
"database": "${workspaceFolder:rave}/users.db"
|
||||
}
|
||||
]
|
||||
}
|
||||
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -1003,6 +1003,12 @@ dependencies = [
|
|||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md5"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.4"
|
||||
|
|
@ -1398,6 +1404,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"color-eyre",
|
||||
"md5",
|
||||
"poem",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ publish = ["crates-io"]
|
|||
[dependencies]
|
||||
cfg-if = "1.0.0"
|
||||
color-eyre = "0.6.2"
|
||||
md5 = "0.7.0"
|
||||
poem = { version = "1.3.58", features = [
|
||||
"compression",
|
||||
"cookie",
|
||||
|
|
|
|||
|
|
@ -1 +1,9 @@
|
|||
-- Add migration script here
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
is_admin BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
INSERT INTO users (name, password, is_admin)
|
||||
VALUES ('admin', 'admin', TRUE);
|
||||
|
|
@ -1,8 +1,28 @@
|
|||
use crate::{authentication::Authentication, subsonic::SubsonicResponse};
|
||||
use poem::web::Data;
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
use crate::{
|
||||
authentication::Authentication,
|
||||
subsonic::{self, SubsonicResponse},
|
||||
user,
|
||||
};
|
||||
|
||||
#[poem::handler]
|
||||
pub fn ping(auth: Authentication) -> SubsonicResponse {
|
||||
dbg!(auth);
|
||||
pub async fn ping(Data(pool): Data<&SqlitePool>, auth: Authentication) -> SubsonicResponse {
|
||||
let user = user::get_user(pool, &auth.username).await;
|
||||
|
||||
SubsonicResponse::new_empty()
|
||||
match user {
|
||||
Ok(Some(u)) => {
|
||||
if u.verify(&auth.token, &auth.salt) {
|
||||
SubsonicResponse::new_empty()
|
||||
} else {
|
||||
SubsonicResponse::new_error(subsonic::Error::WrongUsernameOrPassword(None))
|
||||
}
|
||||
}
|
||||
Ok(None) => SubsonicResponse::new_error(subsonic::Error::WrongUsernameOrPassword(None)),
|
||||
Err(e) => {
|
||||
tracing::error!("Error getting user: {}", e);
|
||||
SubsonicResponse::new_error(subsonic::Error::WrongUsernameOrPassword(None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
24
src/user.rs
24
src/user.rs
|
|
@ -1,11 +1,29 @@
|
|||
use color_eyre::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct User {
|
||||
pub id: i32,
|
||||
pub created_at: time::OffsetDateTime,
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
/// I hate this. It's stored in plaintext. Why?
|
||||
pub password: String,
|
||||
password: String,
|
||||
pub is_admin: bool,
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub fn verify(&self, hashed_password: &str, salt: &str) -> bool {
|
||||
let ours = md5::compute(format!("{}{}", self.password, salt));
|
||||
let ours = format!("{ours:x}");
|
||||
|
||||
ours == hashed_password
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_user(pool: &SqlitePool, name: &str) -> Result<Option<User>> {
|
||||
Ok(
|
||||
sqlx::query_as!(User, "SELECT * FROM users WHERE name = ?", name)
|
||||
.fetch_optional(pool)
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue