make keys shorter by encoding bytes as base64
This commit is contained in:
parent
b3870cd48a
commit
c9912ff332
4 changed files with 49 additions and 6 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use deadpool_diesel::postgres::Connection;
|
use deadpool_diesel::postgres::Connection;
|
||||||
use diesel::{
|
use diesel::{
|
||||||
|
@ -53,3 +55,28 @@ impl ApiKey {
|
||||||
api_keys::team_id.eq(team_id)
|
api_keys::team_id.eq(team_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode big-endian bytes of a UUID as URL-safe base64.
|
||||||
|
*/
|
||||||
|
pub fn compact_uuid(id: &Uuid) -> String {
|
||||||
|
URL_SAFE_NO_PAD.encode(id.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to parse a string as either a standard formatted UUID or a big-endian
|
||||||
|
* base64 encoding of one.
|
||||||
|
*/
|
||||||
|
pub fn try_parse_as_uuid(value: &str) -> Result<Uuid> {
|
||||||
|
if value.len() < 32 {
|
||||||
|
let bytes: Vec<u8> = URL_SAFE_NO_PAD
|
||||||
|
.decode(value)
|
||||||
|
.or(Err(anyhow::anyhow!("failed to parse")))?;
|
||||||
|
let bytes: [u8; 16] = bytes
|
||||||
|
.try_into()
|
||||||
|
.or(Err(anyhow::anyhow!("failed to parse")))?;
|
||||||
|
Ok(Uuid::from_bytes(bytes))
|
||||||
|
} else {
|
||||||
|
Uuid::try_parse(value).or(Err(anyhow::anyhow!("failed to parse")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -248,6 +248,20 @@ async fn projects_page(
|
||||||
.await
|
.await
|
||||||
.unwrap()?;
|
.unwrap()?;
|
||||||
|
|
||||||
|
mod filters {
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
pub fn compact_uuid(id: &Uuid) -> askama::Result<String> {
|
||||||
|
Ok(crate::api_keys::compact_uuid(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn redact(value: &str) -> askama::Result<String> {
|
||||||
|
Ok(format!(
|
||||||
|
"********{}",
|
||||||
|
value[value.char_indices().nth_back(3).unwrap().0..].to_string()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "projects.html")]
|
#[template(path = "projects.html")]
|
||||||
struct ResponseTemplate {
|
struct ResponseTemplate {
|
||||||
|
|
|
@ -16,7 +16,7 @@ use uuid::Uuid;
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api_keys::ApiKey,
|
api_keys::{try_parse_as_uuid, ApiKey},
|
||||||
app_error::AppError,
|
app_error::AppError,
|
||||||
app_state::{AppState, DbConn},
|
app_state::{AppState, DbConn},
|
||||||
channels::Channel,
|
channels::Channel,
|
||||||
|
@ -38,7 +38,7 @@ pub fn new_router(state: AppState) -> Router<AppState> {
|
||||||
#[derive(Deserialize, Validate)]
|
#[derive(Deserialize, Validate)]
|
||||||
struct SayQuery {
|
struct SayQuery {
|
||||||
#[serde(alias = "k")]
|
#[serde(alias = "k")]
|
||||||
key: Uuid,
|
key: String,
|
||||||
#[serde(alias = "p")]
|
#[serde(alias = "p")]
|
||||||
#[serde(default = "default_project")]
|
#[serde(default = "default_project")]
|
||||||
#[validate(regex(
|
#[validate(regex(
|
||||||
|
@ -67,7 +67,9 @@ async fn say_get(
|
||||||
query.validate().map_err(AppError::from_validation_errors)?;
|
query.validate().map_err(AppError::from_validation_errors)?;
|
||||||
|
|
||||||
let api_key = {
|
let api_key = {
|
||||||
let query_key = query.key.clone();
|
let query_key = try_parse_as_uuid(&query.key).or(Err(AppError::ForbiddenError(
|
||||||
|
"key not accepted".to_string(),
|
||||||
|
)))?;
|
||||||
db_conn
|
db_conn
|
||||||
.interact::<_, Result<ApiKey, AppError>>(move |conn| {
|
.interact::<_, Result<ApiKey, AppError>>(move |conn| {
|
||||||
update(api_keys::table.filter(ApiKey::with_id(query_key)))
|
update(api_keys::table.filter(ApiKey::with_id(query_key)))
|
||||||
|
@ -76,7 +78,7 @@ async fn say_get(
|
||||||
.get_result(conn)
|
.get_result(conn)
|
||||||
.optional()
|
.optional()
|
||||||
.context("failed to get API key")?
|
.context("failed to get API key")?
|
||||||
.ok_or(AppError::ForbiddenError("Key not accepted.".to_string()))
|
.ok_or(AppError::ForbiddenError("key not accepted.".to_string()))
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap()?
|
.unwrap()?
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<code>
|
<code>
|
||||||
********{{ key.id.simple().to_string()[key.id.simple().to_string().char_indices().nth_back(3).unwrap().0..] }}
|
{{ key.id|compact_uuid|redact }}
|
||||||
</code>
|
</code>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -94,7 +94,7 @@
|
||||||
class="btn btn-outline-light"
|
class="btn btn-outline-light"
|
||||||
type="button"
|
type="button"
|
||||||
name="api-key-copy-button"
|
name="api-key-copy-button"
|
||||||
data-copy="{{ key.id.simple() }}"
|
data-copy="{{ key.id|compact_uuid }}"
|
||||||
>
|
>
|
||||||
Copy
|
Copy
|
||||||
</button>
|
</button>
|
||||||
|
|
Loading…
Add table
Reference in a new issue