2019-10-31 22:00:36 +08:00
|
|
|
use chrono::serde::ts_seconds;
|
|
|
|
use chrono::{DateTime, Utc};
|
|
|
|
use heed::types::{SerdeBincode, Str};
|
2019-10-31 22:24:47 +08:00
|
|
|
use rand::seq::SliceRandom;
|
2019-10-31 22:00:36 +08:00
|
|
|
use serde::{Deserialize, Serialize};
|
2020-01-16 00:10:33 +08:00
|
|
|
use tide::{Request, Response};
|
2019-10-31 22:00:36 +08:00
|
|
|
|
|
|
|
use crate::error::{ResponseError, SResult};
|
2020-01-16 00:10:33 +08:00
|
|
|
use crate::helpers::tide::RequestExt;
|
2019-10-31 22:00:36 +08:00
|
|
|
use crate::models::token::ACL::*;
|
|
|
|
use crate::models::token::*;
|
|
|
|
use crate::Data;
|
|
|
|
|
|
|
|
fn generate_api_key() -> String {
|
2019-10-31 22:24:47 +08:00
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
let sample = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
|
|
sample
|
|
|
|
.choose_multiple(&mut rng, 40)
|
|
|
|
.map(|c| *c as char)
|
|
|
|
.collect()
|
2019-10-31 22:00:36 +08:00
|
|
|
}
|
|
|
|
|
2020-01-16 00:10:33 +08:00
|
|
|
pub async fn list(ctx: Request<Data>) -> SResult<Response> {
|
2019-10-31 22:00:36 +08:00
|
|
|
ctx.is_allowed(Admin)?;
|
|
|
|
|
|
|
|
let db = &ctx.state().db;
|
2020-01-16 23:58:57 +08:00
|
|
|
let reader = db.main_read_txn()?;
|
2019-10-31 22:00:36 +08:00
|
|
|
|
|
|
|
let common_store = db.common_store();
|
|
|
|
|
|
|
|
let mut response: Vec<Token> = Vec::new();
|
|
|
|
|
|
|
|
let iter = common_store
|
2020-01-16 23:58:57 +08:00
|
|
|
.prefix_iter::<_, Str, SerdeBincode<Token>>(&reader, TOKEN_PREFIX_KEY)?;
|
2019-10-31 22:00:36 +08:00
|
|
|
|
|
|
|
for result in iter {
|
2020-01-16 23:58:57 +08:00
|
|
|
let (_, token) = result?;
|
2019-10-31 22:00:36 +08:00
|
|
|
response.push(token);
|
|
|
|
}
|
|
|
|
|
2020-01-16 00:10:33 +08:00
|
|
|
Ok(tide::Response::new(200).body_json(&response).unwrap())
|
2019-10-31 22:00:36 +08:00
|
|
|
}
|
|
|
|
|
2020-01-16 00:10:33 +08:00
|
|
|
pub async fn get(ctx: Request<Data>) -> SResult<Response> {
|
2019-10-31 22:00:36 +08:00
|
|
|
ctx.is_allowed(Admin)?;
|
|
|
|
let request_key = ctx.url_param("key")?;
|
|
|
|
|
|
|
|
let db = &ctx.state().db;
|
2020-01-16 23:58:57 +08:00
|
|
|
let reader = db.main_read_txn()?;
|
2019-10-31 22:00:36 +08:00
|
|
|
|
|
|
|
let token_key = format!("{}{}", TOKEN_PREFIX_KEY, request_key);
|
|
|
|
|
|
|
|
let token_config = db
|
|
|
|
.common_store()
|
2020-01-16 23:58:57 +08:00
|
|
|
.get::<_, Str, SerdeBincode<Token>>(&reader, &token_key)?
|
2019-10-31 22:00:36 +08:00
|
|
|
.ok_or(ResponseError::not_found(format!(
|
|
|
|
"token key: {}",
|
|
|
|
token_key
|
|
|
|
)))?;
|
|
|
|
|
2020-01-16 00:10:33 +08:00
|
|
|
Ok(tide::Response::new(200).body_json(&token_config).unwrap())
|
2019-10-31 22:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
|
|
|
pub struct CreatedRequest {
|
|
|
|
description: String,
|
|
|
|
acl: Vec<ACL>,
|
|
|
|
indexes: Vec<Wildcard>,
|
|
|
|
#[serde(with = "ts_seconds")]
|
|
|
|
expires_at: DateTime<Utc>,
|
|
|
|
}
|
|
|
|
|
2020-01-16 00:10:33 +08:00
|
|
|
pub async fn create(mut ctx: Request<Data>) -> SResult<Response> {
|
2019-10-31 22:00:36 +08:00
|
|
|
ctx.is_allowed(Admin)?;
|
|
|
|
|
|
|
|
let data: CreatedRequest = ctx.body_json().await.map_err(ResponseError::bad_request)?;
|
|
|
|
|
|
|
|
let key = generate_api_key();
|
|
|
|
let token_key = format!("{}{}", TOKEN_PREFIX_KEY, key);
|
|
|
|
|
|
|
|
let token_definition = Token {
|
|
|
|
key,
|
|
|
|
description: data.description,
|
|
|
|
acl: data.acl,
|
|
|
|
indexes: data.indexes,
|
|
|
|
expires_at: data.expires_at,
|
|
|
|
created_at: Utc::now(),
|
|
|
|
updated_at: Utc::now(),
|
|
|
|
revoked: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
let db = &ctx.state().db;
|
2020-01-16 23:58:57 +08:00
|
|
|
let mut writer = db.main_write_txn()?;
|
2019-10-31 22:00:36 +08:00
|
|
|
|
2020-01-16 23:58:57 +08:00
|
|
|
db.common_store().put::<_, Str, SerdeBincode<Token>>(&mut writer, &token_key, &token_definition)?;
|
2019-10-31 22:00:36 +08:00
|
|
|
|
2020-01-16 23:58:57 +08:00
|
|
|
writer.commit()?;
|
2020-01-16 00:10:33 +08:00
|
|
|
Ok(tide::Response::new(201).body_json(&token_definition).unwrap())
|
2019-10-31 22:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
|
|
|
pub struct UpdatedRequest {
|
|
|
|
description: Option<String>,
|
|
|
|
acl: Option<Vec<ACL>>,
|
|
|
|
indexes: Option<Vec<Wildcard>>,
|
2019-11-21 18:38:21 +08:00
|
|
|
expires_at: Option<DateTime<Utc>>,
|
|
|
|
revoked: Option<bool>,
|
2019-10-31 22:00:36 +08:00
|
|
|
}
|
|
|
|
|
2020-01-16 00:10:33 +08:00
|
|
|
pub async fn update(mut ctx: Request<Data>) -> SResult<Response> {
|
2019-10-31 22:00:36 +08:00
|
|
|
ctx.is_allowed(Admin)?;
|
|
|
|
let request_key = ctx.url_param("key")?;
|
|
|
|
|
|
|
|
let data: UpdatedRequest = ctx.body_json().await.map_err(ResponseError::bad_request)?;
|
|
|
|
|
|
|
|
let db = &ctx.state().db;
|
2020-01-16 23:58:57 +08:00
|
|
|
let mut writer = db.main_write_txn()?;
|
2019-10-31 22:00:36 +08:00
|
|
|
|
|
|
|
let common_store = db.common_store();
|
|
|
|
|
|
|
|
let token_key = format!("{}{}", TOKEN_PREFIX_KEY, request_key);
|
|
|
|
|
|
|
|
let mut token_config = common_store
|
2020-01-16 23:58:57 +08:00
|
|
|
.get::<_, Str, SerdeBincode<Token>>(&writer, &token_key)?
|
2019-10-31 22:00:36 +08:00
|
|
|
.ok_or(ResponseError::not_found(format!(
|
|
|
|
"token key: {}",
|
|
|
|
token_key
|
|
|
|
)))?;
|
|
|
|
|
|
|
|
// apply the modifications
|
|
|
|
if let Some(description) = data.description {
|
|
|
|
token_config.description = description;
|
|
|
|
}
|
|
|
|
if let Some(acl) = data.acl {
|
|
|
|
token_config.acl = acl;
|
|
|
|
}
|
|
|
|
if let Some(indexes) = data.indexes {
|
|
|
|
token_config.indexes = indexes;
|
|
|
|
}
|
2019-11-21 18:38:21 +08:00
|
|
|
if let Some(expires_at) = data.expires_at {
|
|
|
|
token_config.expires_at = expires_at;
|
|
|
|
}
|
|
|
|
if let Some(revoked) = data.revoked {
|
|
|
|
token_config.revoked = revoked;
|
|
|
|
}
|
|
|
|
|
2019-10-31 22:00:36 +08:00
|
|
|
token_config.updated_at = Utc::now();
|
2020-01-16 23:58:57 +08:00
|
|
|
common_store.put::<_, Str, SerdeBincode<Token>>(&mut writer, &token_key, &token_config)?;
|
|
|
|
writer.commit()?;
|
2019-10-31 22:00:36 +08:00
|
|
|
|
2020-01-16 00:10:33 +08:00
|
|
|
Ok(tide::Response::new(200).body_json(&token_config).unwrap())
|
2019-10-31 22:00:36 +08:00
|
|
|
}
|
|
|
|
|
2020-01-16 00:10:33 +08:00
|
|
|
pub async fn delete(ctx: Request<Data>) -> SResult<Response> {
|
2019-10-31 22:00:36 +08:00
|
|
|
ctx.is_allowed(Admin)?;
|
|
|
|
let request_key = ctx.url_param("key")?;
|
|
|
|
let db = &ctx.state().db;
|
2020-01-16 23:58:57 +08:00
|
|
|
let mut writer = db.main_write_txn()?;
|
2019-10-31 22:00:36 +08:00
|
|
|
let common_store = db.common_store();
|
|
|
|
let token_key = format!("{}{}", TOKEN_PREFIX_KEY, request_key);
|
2020-01-16 23:58:57 +08:00
|
|
|
common_store.delete::<_, Str>(&mut writer, &token_key)?;
|
|
|
|
writer.commit()?;
|
2020-01-16 00:10:33 +08:00
|
|
|
Ok(tide::Response::new(204))
|
2019-10-31 22:00:36 +08:00
|
|
|
}
|