limit size of ID fields at type level

new-idea
Avril 4 years ago
parent 3a2e30486a
commit 4e0f6945bf
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -0,0 +1,5 @@
/// Default anonymous name
pub const ANON_NAME: &'static str = "名無し";
/// Max length of `name` and `email` feilds in posts.
pub const POST_ID_MAX_LEN: usize = 32;

@ -2,6 +2,7 @@ use super::*;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::{fmt,error}; use std::{fmt,error};
use std::ops::Deref; use std::ops::Deref;
use std::borrow::{Borrow, ToOwned};
/// A spec to validate the formatting of a string for. /// A spec to validate the formatting of a string for.
pub trait FormatSpec pub trait FormatSpec
@ -71,7 +72,7 @@ impl<F: FormatSpec + ?Sized> FormattedString<F>
impl<F: FormatSpec + ?Sized> FormattedString<F> impl<F: FormatSpec + ?Sized> FormattedString<F>
{ {
/// As a formatted str /// As a formatted str
#[inline] pub fn as_str<'a>(&'a self) -> &'a FormattedStr<F> #[inline] pub fn as_ref<'a>(&'a self) -> &'a FormattedStr<F>
{ {
unsafe { FormattedStr::new_unchecked(&self.0) } unsafe { FormattedStr::new_unchecked(&self.0) }
} }
@ -84,10 +85,26 @@ impl<F: FormatSpec + ?Sized> AsRef<str> for FormattedStr<F>
self.as_str() self.as_str()
} }
} }
impl<F: FormatSpec + ?Sized> Borrow<FormattedStr<F>> for FormattedString<F>
{
#[inline] fn borrow(&self) -> &FormattedStr<F> {
self.as_ref()
}
}
impl<F: FormatSpec + ?Sized> ToOwned for FormattedStr<F>
{
type Owned = FormattedString<F>;
#[inline] fn to_owned(&self) -> Self::Owned {
FormattedString(String::from(&self.1), PhantomData)
}
}
impl<F: FormatSpec + ?Sized> AsRef<FormattedStr<F>> for FormattedString<F> impl<F: FormatSpec + ?Sized> AsRef<FormattedStr<F>> for FormattedString<F>
{ {
#[inline] fn as_ref(&self) -> &FormattedStr<F> { #[inline] fn as_ref(&self) -> &FormattedStr<F> {
self.as_str() self.as_ref()
} }
} }
@ -142,7 +159,35 @@ pub mod formats
/// A hex string format specifier /// A hex string format specifier
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum HexFormat{} pub enum HexFormat{}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MaxLenFormat<const MAX: usize>{}
impl<const MAX: usize> FormatSpec for MaxLenFormat<MAX>
{
type Error = MaxLenExceededError<MAX>;
#[inline] fn validate(s: &str) -> Result<(), Self::Error> {
if s.len() > MAX {
Err(MaxLenExceededError)
} else {
Ok(())
}
}
}
#[derive(Debug)]
pub struct MaxLenExceededError<const MAX: usize>;
impl<const MAX: usize> error::Error for MaxLenExceededError<MAX>{}
impl<const MAX: usize> fmt::Display for MaxLenExceededError<MAX>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "string length exceeds {}", MAX)
}
}
impl HexFormat impl HexFormat
{ {
const HEX_MAP: &'static [u8] = b"1234567890abcdefABCDEF"; const HEX_MAP: &'static [u8] = b"1234567890abcdefABCDEF";
@ -201,6 +246,9 @@ pub mod formats
} }
} }
pub type MaxLenStr<const MAX: usize> = FormattedStr<MaxLenFormat<MAX>>;
pub type MaxLenString<const MAX: usize> = FormattedString<MaxLenFormat<MAX>>;
pub type HexFormattedStr = FormattedStr<HexFormat>; pub type HexFormattedStr = FormattedStr<HexFormat>;
pub type HexFormattedString = FormattedString<HexFormat>; pub type HexFormattedString = FormattedString<HexFormat>;

@ -28,6 +28,7 @@ mod bytes;
mod delta; //unused now, but tests still use it, so... mod delta; //unused now, but tests still use it, so...
mod hard_format; mod hard_format;
mod tripcode; mod tripcode;
mod defaults;
mod post; mod post;
mod state; mod state;

@ -1,24 +1,70 @@
use super::*; use super::*;
use cryptohelpers::sha256::Sha256Hash; use cryptohelpers::sha256::Sha256Hash;
use hard_format::formats::PEMFormattedString; use hard_format::formats::{
PEMFormattedString,
PEMFormattedStr,
MaxLenString,
};
use tripcode::Tripcode; use tripcode::Tripcode;
id_type!(PostID; "A unique post ID"); id_type!(PostID; "A unique post ID");
/// Max length of `email` or `name` feild
const ID_MAX_LEN: usize = defaults::POST_ID_MAX_LEN;
/// String type that limits its bytes to the ID string max limit.
pub type IDMaxString = MaxLenString<ID_MAX_LEN>;
/// A single completed post /// A single completed post
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Post pub struct Post
{ {
id: PostID, id: PostID,
name: Option<String>, name: Option<IDMaxString>,
tripcode: Option<Tripcode>, tripcode: Option<Tripcode>,
email: Option<String>, email: Option<IDMaxString>,
/// The client-side encrypted body string
body: PEMFormattedString, body: PEMFormattedString,
/// Signature of the body (optional).
signature: Option<PEMFormattedString>, signature: Option<PEMFormattedString>,
/// Hash of the body /// Hash of the body
hash: Sha256Hash, hash: Sha256Hash,
} }
impl Post
{
/// The user-set name for this post if there is one.
#[inline] pub fn own_name(&self) -> Option<&str>
{
self.name.as_ref().map(|x| x.as_str())
}
/// The name for this post.
///
/// If no name is set, returns the default anon name.
pub fn name(&self) -> &str
{
self.own_name().unwrap_or(defaults::ANON_NAME)
}
/// The email set for this post, if there is one.
pub fn email(&self) -> Option<&str>
{
self.email.as_ref().map(|x| x.as_str())
}
/// Get the tripcode of this post, if there is one.
pub fn tripcode(&self) -> Option<&Tripcode>
{
self.tripcode.as_ref()
}
/// The body of this post
pub fn body(&self) -> &PEMFormattedStr
{
self.body.as_ref()
}
}

Loading…
Cancel
Save