diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2024-09-03 01:25:20 -0400 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2024-09-03 02:09:25 -0400 |
| commit | b404344a7c4ab5cb6c7d7b445fab796be79b848f (patch) | |
| tree | c476b125316b9d4aa7bdece7c9bb8e2f65d2961e /src/id.rs | |
| parent | 92a7518975c6bc4b2f9b9c6c12c458b24e8cfaf5 (diff) | |
Allow login creation and authentication.
This is a beefy change, as it adds a TON of smaller pieces needed to make this all function:
* A database migration.
* A ton of new crates for things like password validation, timekeeping, and HTML generation.
* A first cut at a module structure for routes, templates, repositories.
* A family of ID types, for identifying various kinds of domain thing.
* AppError, which _doesn't_ implement Error but can be sent to clients.
Diffstat (limited to 'src/id.rs')
| -rw-r--r-- | src/id.rs | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/src/id.rs b/src/id.rs new file mode 100644 index 0000000..f630107 --- /dev/null +++ b/src/id.rs @@ -0,0 +1,49 @@ +use rand::{seq::SliceRandom, thread_rng}; + +// Make IDs that: +// +// * Do not require escaping in URLs +// * Do not require escaping in hostnames +// * Are unique up to case conversion +// * Are relatively unlikely to contain cursewords +// * Are relatively unlikely to contain visually similar characters in most typefaces +// * Are not sequential +// +// This leaves 23 ASCII characters, or about 4.52 bits of entropy per character +// if generated with uniform probability. +pub const ALPHABET: [char; 23] = [ + '1', '2', '3', '4', '6', '7', '8', '9', 'b', 'c', 'd', 'f', 'h', 'j', 'k', 'n', 'p', 'r', 's', + 't', 'w', 'x', 'y', +]; + +// Pick enough characters per ID to make accidental collisions "acceptably" unlikely +// without also making them _too_ unwieldy. This gives a fraction under 68 bits per ID. +pub const ID_SIZE: usize = 15; + +// Intended to be wrapped in a newtype that provides both type-based separation +// from other identifier types, and a unique prefix to allow the intended type +// of an ID to be determined by eyeball when debugging. +// +// By convention, the prefix should be UPPERCASE - note that the alphabet for this +// is entirely lowercase. +#[derive(Debug, Hash, PartialEq, Eq, sqlx::Type)] +#[sqlx(transparent)] +pub struct Id(String); + +impl Id { + pub fn generate<T>(prefix: &str) -> T + where + T: From<Self>, + { + let mut rng = thread_rng(); + let id = prefix + .chars() + .chain( + (0..ID_SIZE) + .flat_map(|_| ALPHABET.choose(&mut rng)) /* usize -> &char */ + .cloned(), /* &char -> char */ + ) + .collect::<String>(); + T::from(Self(id)) + } +} |
