summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtkay123 <dev@kanjala.com>2025-07-30 08:52:05 +0200
committerrtkay123 <dev@kanjala.com>2025-07-30 08:52:05 +0200
commit259cad06f8d88db9ddfa85c2c188b5b0130cb393 (patch)
tree2211866223d17d7a36c89e3eb39da39ea9863153
parent92620ba85d729d27ffe4d141149ba9b82e543d74 (diff)
downloadsellershut-259cad06f8d88db9ddfa85c2c188b5b0130cb393.tar.bz2
sellershut-259cad06f8d88db9ddfa85c2c188b5b0130cb393.zip
feat(auth): create keypair
-rw-r--r--Cargo.lock2
-rw-r--r--contrib/bruno/users/followers.bru4
-rw-r--r--contrib/docker-compose/init-db/init.sql2
-rw-r--r--crates/auth-service/Cargo.toml2
-rw-r--r--crates/auth-service/migrations/20250723100947_user.sql1
-rw-r--r--crates/auth-service/src/server.rs1
-rw-r--r--crates/auth-service/src/server/keys.rs38
-rw-r--r--crates/auth-service/src/server/routes/authorised.rs12
-rw-r--r--crates/users-service/src/server/manager.rs2
-rw-r--r--lib/sellershut-core/proto/users/users.proto6
10 files changed, 59 insertions, 11 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ec78576..695602b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2614,7 +2614,9 @@ dependencies = [
"jsonwebtoken",
"nanoid",
"oauth2",
+ "rand 0.8.5",
"reqwest",
+ "rsa",
"sellershut-core",
"serde",
"serde_json",
diff --git a/contrib/bruno/users/followers.bru b/contrib/bruno/users/followers.bru
index 794e286..32523f1 100644
--- a/contrib/bruno/users/followers.bru
+++ b/contrib/bruno/users/followers.bru
@@ -5,13 +5,13 @@ meta {
}
get {
- url: http://localhost:2210/users/sellershut/followers?cursor=aHR0cDovL2xvY2FsaG9zdDoyMjEwL2FjdGl2aXR5L2ZvbGxvdy9ESmdfZE9oT2h4QUtsOVdESXhXSmp8MjAyNS0wNy0yMFQxMDo1OTozOC41MTgxMTla
+ url: http://localhost:2210/users/sellershut/followers
body: none
auth: inherit
}
params:query {
- cursor: aHR0cDovL2xvY2FsaG9zdDoyMjEwL2FjdGl2aXR5L2ZvbGxvdy9ESmdfZE9oT2h4QUtsOVdESXhXSmp8MjAyNS0wNy0yMFQxMDo1OTozOC41MTgxMTla
+ ~cursor: aHR0cDovL2xvY2FsaG9zdDoyMjEwL2FjdGl2aXR5L2ZvbGxvdy9ESmdfZE9oT2h4QUtsOVdESXhXSmp8MjAyNS0wNy0yMFQxMDo1OTozOC41MTgxMTla
}
assert {
diff --git a/contrib/docker-compose/init-db/init.sql b/contrib/docker-compose/init-db/init.sql
index a8b648d..8403f83 100644
--- a/contrib/docker-compose/init-db/init.sql
+++ b/contrib/docker-compose/init-db/init.sql
@@ -1,3 +1,3 @@
create database sellershut;
create database auth;
-create database profiles;
+create database users;
diff --git a/crates/auth-service/Cargo.toml b/crates/auth-service/Cargo.toml
index 837fc8b..1cd77fd 100644
--- a/crates/auth-service/Cargo.toml
+++ b/crates/auth-service/Cargo.toml
@@ -18,7 +18,9 @@ futures-util.workspace = true
jsonwebtoken = "9.3.1"
nanoid.workspace = true
oauth2 = "5.0.0"
+rand = "0.8.5"
reqwest = { workspace = true, features = ["json", "rustls-tls"] }
+rsa = "0.9.8"
sellershut-core = { workspace = true, features = ["auth", "serde", "users"] }
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
diff --git a/crates/auth-service/migrations/20250723100947_user.sql b/crates/auth-service/migrations/20250723100947_user.sql
index b5566fe..8da2ed2 100644
--- a/crates/auth-service/migrations/20250723100947_user.sql
+++ b/crates/auth-service/migrations/20250723100947_user.sql
@@ -2,6 +2,7 @@
create table auth_user (
id uuid primary key,
email text unique not null,
+ private_key text not null,
updated_at timestamptz not null default now(),
created_at timestamptz not null default now()
);
diff --git a/crates/auth-service/src/server.rs b/crates/auth-service/src/server.rs
index 7b66c42..3433cd2 100644
--- a/crates/auth-service/src/server.rs
+++ b/crates/auth-service/src/server.rs
@@ -7,6 +7,7 @@ use crate::{
};
pub mod csrf_token_validation;
+pub mod keys;
pub mod grpc;
pub mod routes;
diff --git a/crates/auth-service/src/server/keys.rs b/crates/auth-service/src/server/keys.rs
new file mode 100644
index 0000000..5c9ee43
--- /dev/null
+++ b/crates/auth-service/src/server/keys.rs
@@ -0,0 +1,38 @@
+use rsa::{
+ pkcs8::{EncodePrivateKey, EncodePublicKey, LineEnding},
+ RsaPrivateKey,
+ RsaPublicKey,
+};
+
+use crate::error::AppError;
+
+/// A private/public key pair used for HTTP signatures
+#[derive(Debug, Clone)]
+pub struct Keypair {
+ /// Private key in PEM format
+ pub private_key: String,
+ /// Public key in PEM format
+ pub public_key: String,
+}
+
+impl Keypair {
+ /// Helper method to turn this into an openssl private key
+ #[cfg(test)]
+ pub(crate) fn private_key(&self) -> Result<RsaPrivateKey, anyhow::Error> {
+ use rsa::pkcs8::DecodePrivateKey;
+
+ Ok(RsaPrivateKey::from_pkcs8_pem(&self.private_key)?)
+ }
+}
+
+pub fn generate_actor_keypair() -> Result<Keypair, AppError> {
+ let mut rng = rand::thread_rng();
+ let rsa = RsaPrivateKey::new(&mut rng, 2048)?;
+ let pkey = RsaPublicKey::from(&rsa);
+ let public_key = pkey.to_public_key_pem(LineEnding::default())?;
+ let private_key = rsa.to_pkcs8_pem(LineEnding::default())?.to_string();
+ Ok(Keypair {
+ private_key,
+ public_key,
+ })
+}
diff --git a/crates/auth-service/src/server/routes/authorised.rs b/crates/auth-service/src/server/routes/authorised.rs
index 2538cdc..b4c2e00 100644
--- a/crates/auth-service/src/server/routes/authorised.rs
+++ b/crates/auth-service/src/server/routes/authorised.rs
@@ -23,7 +23,7 @@ use crate::{
auth::Claims,
error::AppError,
server::{
- OAUTH_CSRF_COOKIE, csrf_token_validation::csrf_token_validation_workflow, routes::Provider,
+ csrf_token_validation::csrf_token_validation_workflow, keys::generate_actor_keypair, routes::Provider, OAUTH_CSRF_COOKIE
},
state::AppHandle,
};
@@ -49,6 +49,7 @@ struct User {
struct DbUser {
id: Uuid,
email: String,
+ private_key: String,
created_at: OffsetDateTime,
updated_at: OffsetDateTime,
}
@@ -92,8 +93,6 @@ pub async fn login_authorised(
.await
.context("failed to deserialise response as JSON")?;
- dbg!(&user_data);
-
let user_data: User = serde_json::from_value(user_data)?;
if !user_data.verified {
@@ -124,19 +123,22 @@ pub async fn login_authorised(
.fetch_optional(&mut *transaction)
.await?;
+ let keys = generate_actor_keypair()?;
+
let user = if let Some(user) = user {
user
} else {
let uuid = uuid::Uuid::now_v7();
let user = sqlx::query_as!(
DbUser,
- "insert into auth_user (id, email) values ($1, $2)
+ "insert into auth_user (id, email, private_key) values ($1, $2, $3)
on conflict (email) do update
set email = excluded.email
returning *;
",
uuid,
user_data.email,
+ keys.private_key,
)
.fetch_one(&mut *transaction)
.await?;
@@ -180,6 +182,7 @@ pub async fn login_authorised(
),
)?;
+
let user_request = CreateUserRequest {
email: user_data.email.to_owned(),
avatar: user_data.avatar.as_ref().map(|value| {
@@ -188,6 +191,7 @@ pub async fn login_authorised(
user_data.id
)
}),
+ public_key: keys.public_key,
};
store
diff --git a/crates/users-service/src/server/manager.rs b/crates/users-service/src/server/manager.rs
index 6738123..05ee4fe 100644
--- a/crates/users-service/src/server/manager.rs
+++ b/crates/users-service/src/server/manager.rs
@@ -121,7 +121,7 @@ impl UsersService for AppHandle {
request.avatar.or(create_user.avatar),
request.description,
request.user_type.to_string(),
- request.public_key,
+ create_user.public_key,
create_user.email,
)
.fetch_one(&self.services.postgres)
diff --git a/lib/sellershut-core/proto/users/users.proto b/lib/sellershut-core/proto/users/users.proto
index 8c7b41d..bbc8188 100644
--- a/lib/sellershut-core/proto/users/users.proto
+++ b/lib/sellershut-core/proto/users/users.proto
@@ -46,6 +46,8 @@ message CreateUserRequest {
string email = 1;
// Avatar for the new user
optional string avatar = 2;
+ // Public key
+ string public_key = 3;
}
// Response message for CreateUser RPC
@@ -70,10 +72,8 @@ message CompleteUserRequest {
string outbox = 6;
// Is this user local or remote
bool local = 7;
- // Public key for this user
- string public_key = 8;
// User type
- UserType user_type = 9;
+ UserType user_type = 8;
}
// Users gRPC service