Browse Source

feat: basic user token check

master
hole-thu 3 years ago
parent
commit
e4fbbb1b7b
  1. 2
      migrations/2022-03-15-061041_create_users/down.sql
  2. 9
      migrations/2022-03-15-061041_create_users/up.sql
  3. 36
      src/api/mod.rs
  4. 16
      src/models.rs
  5. 14
      src/schema.rs
  6. 25
      tools/migdb.py

2
migrations/2022-03-15-061041_create_users/down.sql

@ -0,0 +1,2 @@
-- This file should undo anything in `up.sql`
DROP TABLE users

9
migrations/2022-03-15-061041_create_users/up.sql

@ -0,0 +1,9 @@
-- Your SQL goes here
CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY,
name VARCHAR NOT NULL UNIQUE,
token VARCHAR NOT NULL UNIQUE,
is_admin BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE INDEX users_toekn_idx ON users (`token`);

36
src/api/mod.rs

@ -1,8 +1,9 @@
use crate::models::*;
use crate::random_hasher::RandomHasher; use crate::random_hasher::RandomHasher;
use rocket::http::Status; use rocket::http::Status;
use rocket::request::{self, FromRequest, Request}; use rocket::request::{self, FromRequest, Request};
use rocket::serde::json::{Value, json};
use rocket::response::{self, Responder}; use rocket::response::{self, Responder};
use rocket::serde::json::{json, Value};
#[catch(401)] #[catch(401)]
pub fn catch_401_error() -> Value { pub fn catch_401_error() -> Value {
@ -21,31 +22,32 @@ pub struct CurrentUser {
impl<'r> FromRequest<'r> for CurrentUser { impl<'r> FromRequest<'r> for CurrentUser {
type Error = (); type Error = ();
async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> { async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
let token = request.headers().get_one("User-Token"); if let Some(token) = request.headers().get_one("User-Token") {
match token { let conn = establish_connection();
Some(t) => request::Outcome::Success(CurrentUser { if let Some(user) = User::get_by_token(&conn, token) {
return request::Outcome::Success(CurrentUser {
namehash: request namehash: request
.rocket() .rocket()
.state::<RandomHasher>() .state::<RandomHasher>()
.unwrap() .unwrap()
.hash_with_salt(t), .hash_with_salt(&user.name),
is_admin: t == "admin", // TODO is_admin: user.is_admin,
}), });
None => request::Outcome::Failure((Status::Unauthorized, ())),
} }
} }
request::Outcome::Failure((Status::Unauthorized, ()))
}
} }
pub enum PolicyError { pub enum PolicyError {
IsReported, IsReported,
IsDeleted, IsDeleted,
NotAllowed NotAllowed,
} }
pub enum APIError { pub enum APIError {
DbError(diesel::result::Error), DbError(diesel::result::Error),
PcError(PolicyError) PcError(PolicyError),
} }
impl APIError { impl APIError {
@ -57,20 +59,20 @@ impl APIError {
impl<'r> Responder<'r, 'static> for APIError { impl<'r> Responder<'r, 'static> for APIError {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> { fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
match self { match self {
APIError::DbError(e) => APIError::DbError(e) => json!({
json!({
"code": -1, "code": -1,
"msg": e.to_string() "msg": e.to_string()
}).respond_to(req), })
APIError::PcError(e) => .respond_to(req),
json!({ APIError::PcError(e) => json!({
"code": -1, "code": -1,
"msg": match e { "msg": match e {
PolicyError::IsReported => "内容被举报,处理中", PolicyError::IsReported => "内容被举报,处理中",
PolicyError::IsDeleted => "内容被删除", PolicyError::IsDeleted => "内容被删除",
PolicyError::NotAllowed => "不允许的操作", PolicyError::NotAllowed => "不允许的操作",
} }
}).respond_to(req), })
.respond_to(req),
} }
} }
} }

16
src/models.rs

@ -4,7 +4,7 @@ use chrono::NaiveDateTime;
use diesel::{insert_into, Connection, ExpressionMethods, QueryDsl, RunQueryDsl, SqliteConnection}; use diesel::{insert_into, Connection, ExpressionMethods, QueryDsl, RunQueryDsl, SqliteConnection};
use std::env; use std::env;
use crate::schema::posts; use crate::schema::*;
type MR<T> = Result<T, diesel::result::Error>; type MR<T> = Result<T, diesel::result::Error>;
@ -80,3 +80,17 @@ impl Post {
insert_into(posts::table).values(&new_post).execute(conn) insert_into(posts::table).values(&new_post).execute(conn)
} }
} }
#[derive(Queryable, Debug)]
pub struct User {
pub id: i32,
pub name: String,
pub token: String,
pub is_admin: bool,
}
impl User {
pub fn get_by_token(conn: &SqliteConnection, token: &str) -> Option<Self> {
users::table.filter(users::token.eq(token)).first(conn).ok()
}
}

14
src/schema.rs

@ -15,3 +15,17 @@ table! {
allow_search -> Bool, allow_search -> Bool,
} }
} }
table! {
users (id) {
id -> Integer,
name -> Text,
token -> Text,
is_admin -> Bool,
}
}
allow_tables_to_appear_in_same_query!(
posts,
users,
);

25
tools/migdb.py

@ -1,9 +1,13 @@
import sqlite3 import sqlite3
from datetime import datetime from datetime import datetime
def mig_post(db_old, db_new): db_old = sqlite3.connect('hole.db')
db_new = sqlite3.connect('hole_v2.db')
c_old = db_old.cursor() c_old = db_old.cursor()
c_new = db_new.cursor() c_new = db_new.cursor()
def mig_post():
rs = c_old.execute( rs = c_old.execute(
'SELECT id, name_hash, content, cw, author_title, ' 'SELECT id, name_hash, content, cw, author_title, '
'likenum, n_comments, timestamp, comment_timestamp, ' 'likenum, n_comments, timestamp, comment_timestamp, '
@ -25,13 +29,22 @@ def mig_post(db_old, db_new):
) )
db_new.commit() db_new.commit()
c_old.close()
c_new.close() def mig_user():
rs = c_old.execute('SELECT name, token FROM user')
for r in rs:
c_new.execute(
'INSERT OR REPLACE INTO users(name, token) VALUES(?, ?)',
r
)
db_new.commit()
if __name__ == '__main__': if __name__ == '__main__':
db_old = sqlite3.connect('hole.db') # mig_post()
db_new = sqlite3.connect('hole_v2.db') mig_user()
mig_post(db_old, db_new) c_old.close()
c_new.close()

Loading…
Cancel
Save