mirror of
https://github.com/aljazceru/pubky-core.git
synced 2026-01-27 01:44:30 +01:00
feat(pubky): add TLS support for homeserver
This commit is contained in:
73
Cargo.lock
generated
73
Cargo.lock
generated
@@ -91,6 +91,12 @@ version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
version = "0.5.3"
|
||||
@@ -153,6 +159,7 @@ dependencies = [
|
||||
"reqwest",
|
||||
"rpassword",
|
||||
"tokio",
|
||||
"tracing-subscriber",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -191,7 +198,7 @@ dependencies = [
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower 0.5.1",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -237,7 +244,7 @@ dependencies = [
|
||||
"serde",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower 0.5.1",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -254,6 +261,30 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-server"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56bac90848f6a9393ac03c63c640925c4b7c8ca21654de40d53f55964667c7d8"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower 0.4.13",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.74"
|
||||
@@ -1735,6 +1766,26 @@ dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.15"
|
||||
@@ -1750,7 +1801,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
[[package]]
|
||||
name = "pkarr"
|
||||
version = "3.0.0"
|
||||
source = "git+https://github.com/Pubky/pkarr?branch=v3#3eda7808eafd6641049f30cd7b32fee8fe9550ea"
|
||||
source = "git+https://github.com/Pubky/pkarr?branch=v3#45e905d273982697e2be19ed738b390fc98a2195"
|
||||
dependencies = [
|
||||
"base32",
|
||||
"byteorder",
|
||||
@@ -1903,6 +1954,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
"axum-extra",
|
||||
"axum-server",
|
||||
"base32",
|
||||
"bytes",
|
||||
"clap",
|
||||
@@ -2844,6 +2896,21 @@ dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"pin-project",
|
||||
"pin-project-lite",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.1"
|
||||
|
||||
@@ -24,4 +24,5 @@ pubky-common = { version = "0.1.0", path = "../pubky-common" }
|
||||
reqwest = "0.12.8"
|
||||
rpassword = "7.3.1"
|
||||
tokio = { version = "1.40.0", features = ["macros", "rt-multi-thread"] }
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
url = "2.5.2"
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::env;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use reqwest::Method;
|
||||
@@ -16,23 +18,31 @@ struct Cli {
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
let args = Cli::parse();
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(env::var("TRACING").unwrap_or("info".to_string()))
|
||||
.init();
|
||||
|
||||
let client = Client::new()?;
|
||||
|
||||
match cli.url.scheme() {
|
||||
"https" => {
|
||||
unimplemented!();
|
||||
}
|
||||
"pubky" => {
|
||||
let response = client.get(cli.url).send().await?.bytes().await?;
|
||||
// Build the request
|
||||
let response = client.get(args.url).send().await?;
|
||||
|
||||
println!("Got a response: \n {:?}", response);
|
||||
}
|
||||
_ => {
|
||||
panic!("Only https:// and pubky:// URL schemes are supported")
|
||||
println!("< Response:");
|
||||
println!("< {:?} {}", response.version(), response.status());
|
||||
for (name, value) in response.headers() {
|
||||
if let Ok(v) = value.to_str() {
|
||||
println!("< {name}: {v}");
|
||||
}
|
||||
}
|
||||
|
||||
let bytes = response.bytes().await?;
|
||||
|
||||
match String::from_utf8(bytes.to_vec()) {
|
||||
Ok(string) => println!("<\n{}", string),
|
||||
Err(_) => println!("<\n{:?}", bytes),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ tower-http = { version = "0.5.2", features = ["cors", "trace"] }
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
url = "2.5.2"
|
||||
axum-server = { version = "0.7.1", features = ["tls-rustls-no-provider"] }
|
||||
|
||||
[dev-dependencies]
|
||||
reqwest = "0.12.8"
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
use std::{future::IntoFuture, net::SocketAddr};
|
||||
use std::{
|
||||
net::{SocketAddr, TcpListener},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
use axum_server::tls_rustls::{RustlsAcceptor, RustlsConfig};
|
||||
use pubky_common::auth::AuthVerifier;
|
||||
use tokio::{net::TcpListener, signal, task::JoinSet};
|
||||
use tokio::task::JoinSet;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use pkarr::{mainline::Testnet, PublicKey};
|
||||
@@ -45,7 +49,7 @@ impl Homeserver {
|
||||
|
||||
let mut tasks = JoinSet::new();
|
||||
|
||||
let listener = TcpListener::bind(SocketAddr::from(([0, 0, 0, 0], config.port()))).await?;
|
||||
let listener = TcpListener::bind(SocketAddr::from(([0, 0, 0, 0], config.port())))?;
|
||||
|
||||
let port = listener.local_addr()?.port();
|
||||
|
||||
@@ -57,24 +61,24 @@ impl Homeserver {
|
||||
port,
|
||||
};
|
||||
|
||||
let acceptor = RustlsAcceptor::new(RustlsConfig::from_config(Arc::new(
|
||||
config.keypair().to_rpk_rustls_server_config(),
|
||||
)));
|
||||
let server = axum_server::from_tcp(listener).acceptor(acceptor);
|
||||
|
||||
let app = crate::routes::create_app(state.clone());
|
||||
|
||||
// Spawn http server task
|
||||
tasks.spawn(
|
||||
axum::serve(
|
||||
listener,
|
||||
app.into_make_service_with_connect_info::<SocketAddr>(),
|
||||
)
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
.into_future(),
|
||||
);
|
||||
tasks.spawn(server.serve(app.into_make_service_with_connect_info::<SocketAddr>()));
|
||||
|
||||
info!("Homeserver listening on http://localhost:{port}");
|
||||
|
||||
info!("Publishing Pkarr packet..");
|
||||
|
||||
publish_server_packet(&pkarr_client, &config, port).await?;
|
||||
|
||||
info!(
|
||||
"Homeserver listening on http://{}",
|
||||
"Homeserver listening on https://{}",
|
||||
config.keypair().public_key()
|
||||
);
|
||||
|
||||
@@ -134,31 +138,3 @@ impl Homeserver {
|
||||
final_res
|
||||
}
|
||||
}
|
||||
|
||||
async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
fn graceful_shutdown() {
|
||||
info!("Gracefully Shutting down..");
|
||||
}
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => graceful_shutdown(),
|
||||
_ = terminate => graceful_shutdown(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ mod wasm;
|
||||
|
||||
use std::{fmt::Debug, sync::Arc};
|
||||
|
||||
use native::CookieJar;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub use error::Error;
|
||||
@@ -25,7 +24,7 @@ pub use crate::shared::list_builder::ListBuilder;
|
||||
#[wasm_bindgen]
|
||||
pub struct Client {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) cookie_store: Arc<CookieJar>,
|
||||
pub(crate) cookie_store: Arc<native::CookieJar>,
|
||||
http: reqwest::Client,
|
||||
pub(crate) pkarr: pkarr::Client,
|
||||
}
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, RwLock},
|
||||
time::Duration,
|
||||
};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use pkarr::{mainline::Testnet, PublicKey};
|
||||
use reqwest::{cookie::CookieStore, header::HeaderValue, Response};
|
||||
use pkarr::mainline::Testnet;
|
||||
|
||||
use crate::Client;
|
||||
|
||||
mod api;
|
||||
mod cookies;
|
||||
mod http;
|
||||
mod internals;
|
||||
|
||||
pub(crate) use cookies::CookieJar;
|
||||
|
||||
static DEFAULT_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@@ -54,10 +52,10 @@ impl Settings {
|
||||
|
||||
let cookie_store = Arc::new(CookieJar::default());
|
||||
|
||||
let http = reqwest::Client::builder()
|
||||
.cookie_provider(cookie_store.clone())
|
||||
let http = reqwest::ClientBuilder::from(pkarr.clone())
|
||||
// TODO: use persistent cookie jar
|
||||
.dns_resolver(Arc::new(pkarr.clone()))
|
||||
.cookie_provider(cookie_store.clone())
|
||||
// TODO: allow custom user agent, but force a Pubky user agent information
|
||||
.user_agent(DEFAULT_USER_AGENT)
|
||||
.build()
|
||||
.expect("config expected to not error");
|
||||
@@ -98,75 +96,3 @@ impl Client {
|
||||
Client::builder().testnet(testnet).build().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CookieJar {
|
||||
pubky_sessions: RwLock<HashMap<String, String>>,
|
||||
normal_jar: RwLock<cookie_store::CookieStore>,
|
||||
}
|
||||
|
||||
impl CookieJar {
|
||||
pub(crate) fn store_session_after_signup(&self, response: &Response, pubky: PublicKey) {
|
||||
for (header_name, header_value) in response.headers() {
|
||||
if header_name == "set-cookie" && header_value.as_ref().starts_with(b"session_id=") {
|
||||
if let Ok(Ok(cookie)) =
|
||||
std::str::from_utf8(header_value.as_bytes()).map(cookie::Cookie::parse)
|
||||
{
|
||||
if cookie.name() == "session_id" {
|
||||
let domain = format!("_pubky.{pubky}");
|
||||
tracing::debug!(?cookie, "Storing coookie after signup");
|
||||
|
||||
self.pubky_sessions
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(domain, cookie.value().to_string());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn delete_session_after_signout(&self, pubky: &PublicKey) {
|
||||
self.pubky_sessions
|
||||
.write()
|
||||
.unwrap()
|
||||
.remove(&format!("_pubky.{pubky}"));
|
||||
}
|
||||
}
|
||||
|
||||
impl CookieStore for CookieJar {
|
||||
fn set_cookies(&self, cookie_headers: &mut dyn Iterator<Item = &HeaderValue>, url: &url::Url) {
|
||||
let iter = cookie_headers.filter_map(|val| {
|
||||
val.to_str()
|
||||
.ok()
|
||||
.and_then(|s| cookie::Cookie::parse(s.to_owned()).ok())
|
||||
});
|
||||
|
||||
self.normal_jar
|
||||
.write()
|
||||
.unwrap()
|
||||
.store_response_cookies(iter, url);
|
||||
}
|
||||
|
||||
fn cookies(&self, url: &url::Url) -> Option<HeaderValue> {
|
||||
let s = self
|
||||
.normal_jar
|
||||
.read()
|
||||
.unwrap()
|
||||
.get_request_values(url)
|
||||
.map(|(name, value)| format!("{name}={value}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("; ");
|
||||
|
||||
if s.is_empty() {
|
||||
return self
|
||||
.pubky_sessions
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(url.host_str().unwrap())
|
||||
.map(|secret| HeaderValue::try_from(format!("session_id={secret}")).unwrap());
|
||||
}
|
||||
|
||||
HeaderValue::from_maybe_shared(bytes::Bytes::from(s)).ok()
|
||||
}
|
||||
}
|
||||
|
||||
76
pubky/src/native/cookies.rs
Normal file
76
pubky/src/native/cookies.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
use std::{collections::HashMap, sync::RwLock};
|
||||
|
||||
use pkarr::PublicKey;
|
||||
use reqwest::{cookie::CookieStore, header::HeaderValue, Response};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CookieJar {
|
||||
pubky_sessions: RwLock<HashMap<String, String>>,
|
||||
normal_jar: RwLock<cookie_store::CookieStore>,
|
||||
}
|
||||
|
||||
impl CookieJar {
|
||||
pub(crate) fn store_session_after_signup(&self, response: &Response, pubky: &PublicKey) {
|
||||
for (header_name, header_value) in response.headers() {
|
||||
if header_name == "set-cookie" && header_value.as_ref().starts_with(b"session_id=") {
|
||||
if let Ok(Ok(cookie)) =
|
||||
std::str::from_utf8(header_value.as_bytes()).map(cookie::Cookie::parse)
|
||||
{
|
||||
if cookie.name() == "session_id" {
|
||||
let domain = format!("_pubky.{pubky}");
|
||||
tracing::debug!(?cookie, "Storing coookie after signup");
|
||||
|
||||
self.pubky_sessions
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(domain, cookie.value().to_string());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn delete_session_after_signout(&self, pubky: &PublicKey) {
|
||||
self.pubky_sessions
|
||||
.write()
|
||||
.unwrap()
|
||||
.remove(&format!("_pubky.{pubky}"));
|
||||
}
|
||||
}
|
||||
|
||||
impl CookieStore for CookieJar {
|
||||
fn set_cookies(&self, cookie_headers: &mut dyn Iterator<Item = &HeaderValue>, url: &url::Url) {
|
||||
let iter = cookie_headers.filter_map(|val| {
|
||||
val.to_str()
|
||||
.ok()
|
||||
.and_then(|s| cookie::Cookie::parse(s.to_owned()).ok())
|
||||
});
|
||||
|
||||
self.normal_jar
|
||||
.write()
|
||||
.unwrap()
|
||||
.store_response_cookies(iter, url);
|
||||
}
|
||||
|
||||
fn cookies(&self, url: &url::Url) -> Option<HeaderValue> {
|
||||
let s = self
|
||||
.normal_jar
|
||||
.read()
|
||||
.unwrap()
|
||||
.get_request_values(url)
|
||||
.map(|(name, value)| format!("{name}={value}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("; ");
|
||||
|
||||
if s.is_empty() {
|
||||
return self
|
||||
.pubky_sessions
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(url.host_str().unwrap())
|
||||
.map(|secret| HeaderValue::try_from(format!("session_id={secret}")).unwrap());
|
||||
}
|
||||
|
||||
HeaderValue::from_maybe_shared(bytes::Bytes::from(s)).ok()
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ impl Client {
|
||||
/// the request body before sending.
|
||||
///
|
||||
/// Differs from [reqwest::Client::request], in that it can make requests to:
|
||||
/// 1. HTTP(s) URLs with with a [pkarr::PublicKey] as Top Level Domain, by resolving
|
||||
/// 1. HTTPs URLs with with a [pkarr::PublicKey] as Top Level Domain, by resolving
|
||||
/// corresponding endpoints, and verifying TLS certificates accordingly.
|
||||
/// (example: `https://o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy`)
|
||||
/// 2. Pubky URLs like `pubky://o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy`
|
||||
@@ -137,10 +137,8 @@ mod tests {
|
||||
|
||||
let client = Client::test(&testnet);
|
||||
|
||||
let url = format!("http://{}/", homeserver.public_key());
|
||||
|
||||
let response = client
|
||||
.request(Default::default(), url)
|
||||
.get(format!("https://{}/", homeserver.public_key()))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use base64::{alphabet::URL_SAFE, engine::general_purpose::NO_PAD, Engine};
|
||||
use reqwest::{Method, StatusCode};
|
||||
use reqwest::StatusCode;
|
||||
use url::Url;
|
||||
|
||||
use pkarr::{Keypair, PublicKey};
|
||||
@@ -17,8 +17,6 @@ use crate::{
|
||||
Client,
|
||||
};
|
||||
|
||||
use super::pkarr::Endpoint;
|
||||
|
||||
impl Client {
|
||||
/// Signup to a homeserver and update Pkarr accordingly.
|
||||
///
|
||||
@@ -29,27 +27,19 @@ impl Client {
|
||||
keypair: &Keypair,
|
||||
homeserver: &PublicKey,
|
||||
) -> Result<Session> {
|
||||
let homeserver = homeserver.to_string();
|
||||
|
||||
let Endpoint { mut url, .. } = self.resolve_endpoint(&homeserver).await?;
|
||||
|
||||
url.set_path("/signup");
|
||||
|
||||
let body = AuthToken::sign(keypair, vec![Capability::root()]).serialize();
|
||||
|
||||
let response = self
|
||||
.http
|
||||
.request(Method::POST, url.clone())
|
||||
.body(body)
|
||||
.post(format!("https://{}", homeserver))
|
||||
.body(AuthToken::sign(keypair, vec![Capability::root()]).serialize())
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?;
|
||||
|
||||
self.publish_pubky_homeserver(keypair, &homeserver).await?;
|
||||
self.publish_pubky_homeserver(keypair, &homeserver.to_string())
|
||||
.await?;
|
||||
|
||||
// Store the cookie to the correct URL.
|
||||
self.cookie_store
|
||||
.store_session_after_signup(&response, keypair.public_key());
|
||||
.store_session_after_signup(&response, &keypair.public_key());
|
||||
|
||||
let bytes = response.bytes().await?;
|
||||
|
||||
@@ -62,7 +52,7 @@ impl Client {
|
||||
/// if the response has any other `>=404` status code.
|
||||
pub(crate) async fn inner_session(&self, pubky: &PublicKey) -> Result<Option<Session>> {
|
||||
let res = self
|
||||
.request(Method::GET, format!("pubky://{}/session", pubky))
|
||||
.get(format!("pubky://{}/session", pubky))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
@@ -81,7 +71,7 @@ impl Client {
|
||||
|
||||
/// Signout from a homeserver.
|
||||
pub(crate) async fn inner_signout(&self, pubky: &PublicKey) -> Result<()> {
|
||||
self.request(Method::DELETE, format!("pubky://{}/session", pubky))
|
||||
self.delete(format!("pubky://{}/session", pubky))
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?;
|
||||
@@ -145,8 +135,7 @@ impl Client {
|
||||
path_segments.push(&channel_id);
|
||||
drop(path_segments);
|
||||
|
||||
self.inner_request(Method::POST, callback)
|
||||
.await
|
||||
self.post(callback)
|
||||
.body(encrypted_token)
|
||||
.send()
|
||||
.await?
|
||||
@@ -157,7 +146,7 @@ impl Client {
|
||||
|
||||
pub(crate) async fn signin_with_authtoken(&self, token: &AuthToken) -> Result<Session> {
|
||||
let response = self
|
||||
.request(Method::POST, format!("pubky://{}/session", token.pubky()))
|
||||
.post(format!("pubky://{}/session", token.pubky()))
|
||||
.body(token.serialize())
|
||||
.send()
|
||||
.await?
|
||||
|
||||
Reference in New Issue
Block a user