Add caretta-id
This commit is contained in:
parent
f2e79d4cd0
commit
99fdb12712
18 changed files with 241 additions and 30 deletions
|
|
@ -26,7 +26,7 @@ caretta-sync-macros = { path="macros", optional = true}
|
|||
caretta-sync-core = {workspace = true, features = ["test"]}
|
||||
|
||||
[workspace]
|
||||
members = [ ".", "core", "macros", "cli", "mobile", "examples/*" , "bevy"]
|
||||
members = [ ".", "core", "macros", "cli", "mobile", "examples/*" , "bevy", "id"]
|
||||
resolver = "3"
|
||||
|
||||
[workspace.package]
|
||||
|
|
@ -43,6 +43,7 @@ ciborium = "0.2.2"
|
|||
clap = { version = "4.5.38", features = ["derive"] }
|
||||
caretta-sync-core.path = "core"
|
||||
futures = { version = "0.3.31", features = ["executor"] }
|
||||
rand = "0.8.5"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.45.0", features = ["macros", "rt", "rt-multi-thread"] }
|
||||
|
|
@ -56,6 +57,7 @@ prost-types = "0.14.1"
|
|||
tonic-prost-build = "0.14.0"
|
||||
tonic-prost = "0.14.0"
|
||||
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
use clap::Args;
|
||||
use caretta_sync_core::utils::runnable::Runnable;
|
||||
|
||||
use crate::cli::ConfigArgs;
|
||||
|
||||
use crate::cli::PeerArgs;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct DeviceAddCommandArgs {
|
||||
#[command(flatten)]
|
||||
peer: PeerArgs,
|
||||
#[arg(short, long)]
|
||||
passcode: Option<String>,
|
||||
#[command(flatten)]
|
||||
config: ConfigArgs
|
||||
}
|
||||
|
||||
impl Runnable for DeviceAddCommandArgs {
|
||||
fn run(self, app_name: &'static str) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
0
cli/src/cli/device/auth/approve.rs
Normal file
0
cli/src/cli/device/auth/approve.rs
Normal file
0
cli/src/cli/device/auth/list.rs
Normal file
0
cli/src/cli/device/auth/list.rs
Normal file
0
cli/src/cli/device/auth/mod.rs
Normal file
0
cli/src/cli/device/auth/mod.rs
Normal file
0
cli/src/cli/device/auth/request.rs
Normal file
0
cli/src/cli/device/auth/request.rs
Normal file
|
|
@ -36,7 +36,7 @@ tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
|
|||
uuid.workspace = true
|
||||
url.workspace = true
|
||||
whoami = "1.6.1"
|
||||
rand = "0.8.5"
|
||||
rand.workspace = true
|
||||
ed25519-dalek = { version = "2.2.0", features = ["signature"] }
|
||||
tokio-stream.workspace = true
|
||||
|
||||
|
|
|
|||
|
|
@ -10,26 +10,29 @@ use iroh::NodeId;
|
|||
pub use request::*;
|
||||
pub use response::*;
|
||||
use rusqlite::{params, types::FromSqlError, Connection};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::data::local::RusqliteRecord;
|
||||
|
||||
/// On going authorization
|
||||
pub struct Authorization {
|
||||
request_id: Uuid,
|
||||
node_id: NodeId,
|
||||
passcode: String,
|
||||
node_info: Option<String>,
|
||||
passcode: Option<String>,
|
||||
created_at: DateTime<Local>,
|
||||
updated_at: DateTime<Local>,
|
||||
}
|
||||
static TABLE_NAME: &str = "authorization";
|
||||
static DEFAULT_COLUMNS: [&str;4] = [
|
||||
static DEFAULT_COLUMNS: [&str;5] = [
|
||||
"request_id",
|
||||
"node_id",
|
||||
"passcode",
|
||||
"created_at",
|
||||
"updated_at"
|
||||
];
|
||||
|
||||
impl Authorization {
|
||||
pub fn new(node_id: NodeId, passcode: String) -> Self {
|
||||
pub fn new_sent(node_id: NodeId, passcode: String) -> Self {
|
||||
let timestamp = Local::now();
|
||||
Self {
|
||||
node_id: node_id,
|
||||
|
|
@ -38,6 +41,7 @@ impl Authorization {
|
|||
updated_at: timestamp
|
||||
}
|
||||
}
|
||||
pub fn new_received(node_id:)
|
||||
pub fn get_by_node_id(node_id: NodeId, connection: &Connection) -> Result<Self, rusqlite::Error> {
|
||||
connection.query_row(
|
||||
"SELECT node_id, passcode, created_at, updated_at FROM authorizaation WHRE node_id=(?1)",
|
||||
|
|
|
|||
13
id/Cargo.toml
Normal file
13
id/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "caretta-id"
|
||||
edition.workspace = true
|
||||
version = "0.1.0-alpha"
|
||||
description.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[features]
|
||||
|
||||
[dependencies]
|
||||
rand.workspace = true
|
||||
thiserror.workspace = true
|
||||
21
id/README.md
Normal file
21
id/README.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Carreta ID
|
||||
Random user-friendly id for distubuted system for personal data.
|
||||
## Examples
|
||||
|
||||
- `123` : shortest version
|
||||
- `456-789` : default size, still user freindly and sufficient randomness (for personal data)
|
||||
- `abc-def-ghj` : long version. alphabets except i, l and o are also valid
|
||||
## Specs
|
||||
### Characters
|
||||
|
||||
|
||||
|
||||
## Perpose
|
||||
When I considering implementing IDs for users(not for internal system) to specify items, such as GitHub commit hashes or issue numbers, the following issues arose.
|
||||
|
||||
- Sequential numbers like Git issues are difficult to implement in distributes systems because collitions are unavoidable.
|
||||
- Random number like UUID is too long for users
|
||||
- Short random number like 7-digit commit hash seems good but is is not standardized specification.
|
||||
|
||||
So I decided to make my own ID specifications.
|
||||
|
||||
3
id/src/builder.rs
Normal file
3
id/src/builder.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
pub struct IdBuilder {
|
||||
|
||||
}
|
||||
174
id/src/chunk.rs
Normal file
174
id/src/chunk.rs
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
static CHARACTERS: &[u8;33] = b"0123456789abcdefghjkmnpqrstuvwxyz";
|
||||
|
||||
static BASE: u16 = 33;
|
||||
static SQUARED_BASE: u16 = 1089;
|
||||
static CUBED_BASE: u16 = 35937;
|
||||
|
||||
pub static NIL: IdChunk = IdChunk(0);
|
||||
pub static MAX: IdChunk = IdChunk(CUBED_BASE-1);
|
||||
|
||||
fn char_to_u8(c: char) -> Option<u8> {
|
||||
Some(match c {
|
||||
'0' => 0,
|
||||
'1' => 1,
|
||||
'2' => 2,
|
||||
'3' => 3,
|
||||
'4' => 4,
|
||||
'5' => 5,
|
||||
'6' => 6,
|
||||
'7' => 7,
|
||||
'8' => 8,
|
||||
'9' => 9,
|
||||
'a' => 10,
|
||||
'b' => 11,
|
||||
'c' => 12,
|
||||
'd' => 13,
|
||||
'e' => 14,
|
||||
'f' => 15,
|
||||
'g' => 16,
|
||||
'h' => 17,
|
||||
'i' => 1,
|
||||
'j' => 18,
|
||||
'k' => 19,
|
||||
'l' => 1,
|
||||
'm' => 20,
|
||||
'n' => 21,
|
||||
'o' => 0,
|
||||
'p' => 22,
|
||||
'q' => 23,
|
||||
'r' => 24,
|
||||
's' => 25,
|
||||
't' => 26,
|
||||
'u' => 27,
|
||||
'v' => 28,
|
||||
'w' => 29,
|
||||
'x' => 30,
|
||||
'y' => 31,
|
||||
'z' => 32,
|
||||
'A' => 10,
|
||||
'B' => 11,
|
||||
'C' => 12,
|
||||
'D' => 13,
|
||||
'E' => 14,
|
||||
'F' => 15,
|
||||
'G' => 16,
|
||||
'H' => 17,
|
||||
'I' => 1,
|
||||
'J' => 18,
|
||||
'K' => 19,
|
||||
'L' => 1,
|
||||
'M' => 20,
|
||||
'N' => 21,
|
||||
'O' => 0,
|
||||
'P' => 22,
|
||||
'Q' => 23,
|
||||
'R' => 24,
|
||||
'S' => 25,
|
||||
'T' => 26,
|
||||
'U' => 27,
|
||||
'V' => 28,
|
||||
'W' => 29,
|
||||
'X' => 30,
|
||||
'Y' => 31,
|
||||
'Z' => 32,
|
||||
_ => return None
|
||||
})
|
||||
}
|
||||
|
||||
fn str_to_u16(s: &str) -> Result<u16, Error> {
|
||||
if s.len() != 3 {
|
||||
return Err(Error::InvalidChunk(format!("Chunk '{}' is not 3 characters", s)))
|
||||
}
|
||||
let mut buf : [u16;3] = [0;3];
|
||||
for (i, c) in s.chars().enumerate() {
|
||||
buf[i] = BASE.pow((2 - i) as u32) * (char_to_u8(c).ok_or(Error::InvalidChunk(format!("Invalid char: {}", c)))? as u16);
|
||||
}
|
||||
|
||||
Ok(buf.iter().sum())
|
||||
}
|
||||
fn u16_to_string(int: u16) -> Result<String, Error> {
|
||||
if int >= CUBED_BASE {
|
||||
return Err(Error::OutsideOfRange(int))
|
||||
}
|
||||
let first_char = char::from(CHARACTERS[usize::try_from(int / SQUARED_BASE).unwrap()]);
|
||||
let second_char = char::from(CHARACTERS[usize::try_from((int % SQUARED_BASE)/ BASE).unwrap()]);
|
||||
let third_char = char::from(CHARACTERS[usize::try_from(int % BASE).unwrap()]);
|
||||
Ok(format!("{}{}{}", first_char, second_char, third_char))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct IdChunk(u16);
|
||||
|
||||
impl IdChunk {
|
||||
pub fn new<R: Rng + ?Sized>(rng: &mut R) -> Self {
|
||||
Self(rng.gen_range(0..CUBED_BASE))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IdChunk {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for IdChunk {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u16> for IdChunk {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u16) -> Result<Self, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IdChunk> for u16 {
|
||||
fn from(value: IdChunk) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
fn assert_eq_chunk(s: &str, i: u16) {
|
||||
assert_eq!(s, &u16_to_string(i).unwrap());
|
||||
assert_eq!(i, str_to_u16(s).unwrap())
|
||||
|
||||
}
|
||||
#[test]
|
||||
fn test_nil() {
|
||||
assert_eq_chunk("000", 0);
|
||||
}
|
||||
#[test]
|
||||
fn test_max() {
|
||||
assert_eq_chunk("zzz", CUBED_BASE-1);
|
||||
}
|
||||
fn assert_random<R>(rand: &mut R)
|
||||
where
|
||||
R: Rng
|
||||
{
|
||||
let chunk = IdChunk::new(rand);
|
||||
let s = chunk.to_string();
|
||||
assert_eq!(chunk,IdChunk::from_str(&s).unwrap())
|
||||
}
|
||||
fn random_x10() {
|
||||
let mut rng = rand::thread_rng();
|
||||
for _ in 0..10 {
|
||||
assert_random(&mut rng);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
4
id/src/config.rs
Normal file
4
id/src/config.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
pub struct Config {
|
||||
pub enable_nil: bool,
|
||||
pub enable_max: bool,
|
||||
}
|
||||
0
id/src/double.rs
Normal file
0
id/src/double.rs
Normal file
8
id/src/error.rs
Normal file
8
id/src/error.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("Outside of range: {0}")]
|
||||
OutsideOfRange(u16),
|
||||
#[error("Invalid chunk: {0}")]
|
||||
InvalidChunk(String),
|
||||
}
|
||||
|
||||
6
id/src/lib.rs
Normal file
6
id/src/lib.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
mod chunk;
|
||||
mod double;
|
||||
mod error;
|
||||
mod single;
|
||||
mod triple;
|
||||
|
||||
0
id/src/single.rs
Normal file
0
id/src/single.rs
Normal file
0
id/src/triple.rs
Normal file
0
id/src/triple.rs
Normal file
Loading…
Add table
Reference in a new issue