tangled
alpha
login
or
join now
smokesignal.events
/
smokesignal
51
fork
atom
The smokesignal.events web application
51
fork
atom
overview
issues
7
pulls
pipelines
chore: upgrading to atproto-* release candidates
Nick Gerakines
4 months ago
7da344fc
2fffe5fc
+37
-42
12 changed files
expand all
collapse all
unified
split
Cargo.toml
src
bin
smokesignal.rs
http
context.rs
handle_oauth_callback.rs
identity_cache.rs
key_provider.rs
processor.rs
storage
atproto.rs
content.rs
task_identity_refresh.rs
task_search_indexer.rs
task_webhooks.rs
+9
-8
Cargo.toml
···
24
minijinja-embed = {version = "2.7"}
25
26
[dependencies]
27
-
atproto-client = { version = "0.12.0" }
28
-
atproto-identity = { version = "0.12.0", features = ["lru", "zeroize"] }
29
-
atproto-oauth = { version = "0.12.0", features = ["lru", "zeroize"] }
30
-
atproto-oauth-aip = { version = "0.12.0" }
31
-
atproto-oauth-axum = { version = "0.12.0", features = ["zeroize"] }
32
-
atproto-record = { version = "0.12.0" }
33
-
atproto-jetstream = { version = "0.12.0" }
34
-
atproto-xrpcs = { version = "0.12.0" }
0
35
36
anyhow = "1.0"
37
async-trait = "0.1"
···
24
minijinja-embed = {version = "2.7"}
25
26
[dependencies]
27
+
atproto-client = { git = "https://tangled.org/@smokesignal.events/atproto-identity-rs" }
28
+
atproto-attestation = { git = "https://tangled.org/@smokesignal.events/atproto-identity-rs" }
29
+
atproto-identity = { git = "https://tangled.org/@smokesignal.events/atproto-identity-rs", features = ["lru", "zeroize", "hickory-dns"] }
30
+
atproto-jetstream = { git = "https://tangled.org/@smokesignal.events/atproto-identity-rs" }
31
+
atproto-oauth = { git = "https://tangled.org/@smokesignal.events/atproto-identity-rs", features = ["lru", "zeroize"] }
32
+
atproto-oauth-aip = { git = "https://tangled.org/@smokesignal.events/atproto-identity-rs" }
33
+
atproto-oauth-axum = { git = "https://tangled.org/@smokesignal.events/atproto-identity-rs", features = ["zeroize"] }
34
+
atproto-record = { git = "https://tangled.org/@smokesignal.events/atproto-identity-rs" }
35
+
atproto-xrpcs = { git = "https://tangled.org/@smokesignal.events/atproto-identity-rs" }
36
37
anyhow = "1.0"
38
async-trait = "0.1"
+3
-3
src/bin/smokesignal.rs
···
189
}
190
#[cfg(not(feature = "s3"))]
191
{
192
-
return Err(blahg::errors::BlahgError::ConfigFeatureNotEnabled {
193
-
feature: "S3 storage requested but s3 feature is not enabled".to_string(),
194
-
});
195
}
196
} else {
197
let filesystem_storage = Arc::new(FilesystemStorage::new(&config.content_storage).await?);
···
189
}
190
#[cfg(not(feature = "s3"))]
191
{
192
+
return Err(anyhow::anyhow!(
193
+
"S3 storage requested but s3 feature is not enabled. Rebuild with --features s3"
194
+
));
195
}
196
} else {
197
let filesystem_storage = Arc::new(FilesystemStorage::new(&config.content_storage).await?);
+4
-5
src/http/context.rs
···
1
-
use atproto_identity::key::KeyProvider;
2
use atproto_identity::resolve::IdentityResolver;
3
-
use atproto_identity::storage::DidDocumentStorage;
4
use atproto_oauth::storage::OAuthRequestStorage;
5
use atproto_oauth_axum::state::OAuthClientConfig;
6
use axum::extract::FromRef;
···
56
pub(crate) i18n_context: I18nContext,
57
pub(crate) oauth_client_config: atproto_oauth_axum::state::OAuthClientConfig,
58
pub(crate) identity_resolver: Arc<dyn IdentityResolver>,
59
-
pub(crate) key_provider: Arc<dyn KeyProvider>,
60
pub(crate) oauth_storage: Arc<dyn OAuthRequestStorage>,
61
pub(crate) document_storage: Arc<dyn DidDocumentStorage>,
62
pub(crate) content_storage: Arc<dyn ContentStorage>,
···
87
config: Config,
88
oauth_client_config: OAuthClientConfig,
89
identity_resolver: Arc<dyn IdentityResolver>,
90
-
key_provider: Arc<dyn KeyProvider>,
91
oauth_storage: Arc<dyn OAuthRequestStorage>,
92
document_storage: Arc<dyn DidDocumentStorage>,
93
supported_languages: Vec<LanguageIdentifier>,
···
128
}
129
}
130
131
-
impl FromRef<WebContext> for Arc<dyn KeyProvider> {
132
fn from_ref(context: &WebContext) -> Self {
133
context.0.key_provider.clone()
134
}
···
0
1
use atproto_identity::resolve::IdentityResolver;
2
+
use atproto_identity::traits::{DidDocumentStorage, KeyResolver};
3
use atproto_oauth::storage::OAuthRequestStorage;
4
use atproto_oauth_axum::state::OAuthClientConfig;
5
use axum::extract::FromRef;
···
55
pub(crate) i18n_context: I18nContext,
56
pub(crate) oauth_client_config: atproto_oauth_axum::state::OAuthClientConfig,
57
pub(crate) identity_resolver: Arc<dyn IdentityResolver>,
58
+
pub(crate) key_provider: Arc<dyn KeyResolver>,
59
pub(crate) oauth_storage: Arc<dyn OAuthRequestStorage>,
60
pub(crate) document_storage: Arc<dyn DidDocumentStorage>,
61
pub(crate) content_storage: Arc<dyn ContentStorage>,
···
86
config: Config,
87
oauth_client_config: OAuthClientConfig,
88
identity_resolver: Arc<dyn IdentityResolver>,
89
+
key_provider: Arc<dyn KeyResolver>,
90
oauth_storage: Arc<dyn OAuthRequestStorage>,
91
document_storage: Arc<dyn DidDocumentStorage>,
92
supported_languages: Vec<LanguageIdentifier>,
···
127
}
128
}
129
130
+
impl FromRef<WebContext> for Arc<dyn KeyResolver> {
131
fn from_ref(context: &WebContext) -> Self {
132
context.0.key_provider.clone()
133
}
+5
-13
src/http/handle_oauth_callback.rs
···
1
use std::sync::Arc;
2
3
use anyhow::Result;
4
-
use atproto_identity::key::{KeyProvider, identify_key};
0
5
use atproto_oauth::{
6
resources::oauth_authorization_server,
7
workflow::{OAuthClient, oauth_complete},
···
35
36
pub(crate) async fn handle_oauth_callback(
37
State(web_context): State<WebContext>,
38
-
key_provider: State<Arc<dyn KeyProvider>>,
39
Language(language): Language,
40
jar: PrivateCookieJar,
41
Form(callback_form): Form<OAuthCallbackForm>,
···
106
107
let secret_signing_key = key_provider
108
.0
109
-
.get_private_key_by_id(&oauth_request.signing_public_key)
110
.await;
111
112
let secret_key_data = match secret_signing_key {
113
-
Ok(Some(value)) => value,
114
-
Ok(None) => {
115
-
return contextual_error!(
116
-
web_context,
117
-
language,
118
-
error_template,
119
-
default_context,
120
-
LoginError::OAuthCallbackIncomplete
121
-
);
122
-
}
123
Err(err) => {
124
return contextual_error!(web_context, language, error_template, default_context, err);
125
}
···
1
use std::sync::Arc;
2
3
use anyhow::Result;
4
+
use atproto_identity::key::identify_key;
5
+
use atproto_identity::traits::KeyResolver;
6
use atproto_oauth::{
7
resources::oauth_authorization_server,
8
workflow::{OAuthClient, oauth_complete},
···
36
37
pub(crate) async fn handle_oauth_callback(
38
State(web_context): State<WebContext>,
39
+
key_provider: State<Arc<dyn KeyResolver>>,
40
Language(language): Language,
41
jar: PrivateCookieJar,
42
Form(callback_form): Form<OAuthCallbackForm>,
···
107
108
let secret_signing_key = key_provider
109
.0
110
+
.resolve(&oauth_request.signing_public_key)
111
.await;
112
113
let secret_key_data = match secret_signing_key {
114
+
Ok(value) => value,
0
0
0
0
0
0
0
0
0
115
Err(err) => {
116
return contextual_error!(web_context, language, error_template, default_context, err);
117
}
+1
-1
src/identity_cache.rs
···
7
8
use anyhow::Result;
9
use async_trait::async_trait;
10
-
use atproto_identity::{model::Document, resolve::IdentityResolver, storage::DidDocumentStorage};
11
use chrono::{Duration, Utc};
12
13
// TODO: Use a different library because lru uses unsafe.
···
7
8
use anyhow::Result;
9
use async_trait::async_trait;
10
+
use atproto_identity::{model::Document, resolve::IdentityResolver, traits::DidDocumentStorage};
11
use chrono::{Duration, Utc};
12
13
// TODO: Use a different library because lru uses unsafe.
+8
-4
src/key_provider.rs
···
1
use async_trait::async_trait;
2
-
use atproto_identity::key::{KeyData, KeyProvider};
0
3
use std::collections::HashMap;
4
5
#[derive(Clone)]
···
14
}
15
16
#[async_trait]
17
-
impl KeyProvider for SimpleKeyProvider {
18
-
async fn get_private_key_by_id(&self, key_id: &str) -> anyhow::Result<Option<KeyData>> {
19
-
Ok(self.keys.get(key_id).cloned())
0
0
0
20
}
21
}
···
1
use async_trait::async_trait;
2
+
use atproto_identity::key::KeyData;
3
+
use atproto_identity::traits::KeyResolver;
4
use std::collections::HashMap;
5
6
#[derive(Clone)]
···
15
}
16
17
#[async_trait]
18
+
impl KeyResolver for SimpleKeyProvider {
19
+
async fn resolve(&self, key: &str) -> anyhow::Result<KeyData> {
20
+
self.keys
21
+
.get(key)
22
+
.cloned()
23
+
.ok_or_else(|| anyhow::anyhow!("Key not found: {}", key))
24
}
25
}
+1
-1
src/processor.rs
···
2
use atproto_client::com::atproto::repo::get_blob;
3
use atproto_identity::model::Document;
4
use atproto_identity::resolve::IdentityResolver;
5
-
use atproto_identity::storage::DidDocumentStorage;
6
use image::GenericImageView;
7
use image::ImageFormat;
8
use serde_json::Value;
···
2
use atproto_client::com::atproto::repo::get_blob;
3
use atproto_identity::model::Document;
4
use atproto_identity::resolve::IdentityResolver;
5
+
use atproto_identity::traits::DidDocumentStorage;
6
use image::GenericImageView;
7
use image::ImageFormat;
8
use serde_json::Value;
+1
-1
src/storage/atproto.rs
···
1
use async_trait::async_trait;
2
-
use atproto_identity::{model::Document, storage::DidDocumentStorage};
3
use atproto_oauth::{storage::OAuthRequestStorage, workflow::OAuthRequest};
4
use chrono::{DateTime, Utc};
5
use serde_json::Value as JsonValue;
···
1
use async_trait::async_trait;
2
+
use atproto_identity::{model::Document, traits::DidDocumentStorage};
3
use atproto_oauth::{storage::OAuthRequestStorage, workflow::OAuthRequest};
4
use chrono::{DateTime, Utc};
5
use serde_json::Value as JsonValue;
+2
-3
src/storage/content.rs
···
10
#[cfg(feature = "s3")]
11
use minio::s3::{Client as MinioClient, creds::StaticProvider, http::BaseUrl, types::S3Api};
12
0
0
13
/// Trait for storing and retrieving content by CID.
14
#[async_trait]
15
pub trait ContentStorage: Send + Sync {
···
22
/// Read content data for a given CID.
23
async fn read_content(&self, cid: &str) -> Result<Vec<u8>>;
24
}
25
-
26
-
#[cfg(feature = "s3")]
27
-
use crate::storage::errors::ContentError;
28
29
pub use self::FilesystemContentStorage as FilesystemStorage;
30
···
10
#[cfg(feature = "s3")]
11
use minio::s3::{Client as MinioClient, creds::StaticProvider, http::BaseUrl, types::S3Api};
12
13
+
use crate::storage::errors::ContentError;
14
+
15
/// Trait for storing and retrieving content by CID.
16
#[async_trait]
17
pub trait ContentStorage: Send + Sync {
···
24
/// Read content data for a given CID.
25
async fn read_content(&self, cid: &str) -> Result<Vec<u8>>;
26
}
0
0
0
27
28
pub use self::FilesystemContentStorage as FilesystemStorage;
29
+1
-1
src/task_identity_refresh.rs
···
1
use std::sync::Arc;
2
3
use anyhow::Result;
4
-
use atproto_identity::{resolve::IdentityResolver, storage::DidDocumentStorage};
5
use chrono::Duration;
6
use sqlx::FromRow;
7
use tokio::time::{Instant, sleep};
···
1
use std::sync::Arc;
2
3
use anyhow::Result;
4
+
use atproto_identity::{resolve::IdentityResolver, traits::DidDocumentStorage};
5
use chrono::Duration;
6
use sqlx::FromRow;
7
use tokio::time::{Instant, sleep};
+1
-1
src/task_search_indexer.rs
···
1
use anyhow::Result;
2
-
use atproto_identity::{model::Document, resolve::IdentityResolver, storage::DidDocumentStorage};
3
use opensearch::{
4
DeleteParts, IndexParts, OpenSearch,
5
http::transport::Transport,
···
1
use anyhow::Result;
2
+
use atproto_identity::{model::Document, resolve::IdentityResolver, traits::DidDocumentStorage};
3
use opensearch::{
4
DeleteParts, IndexParts, OpenSearch,
5
http::transport::Transport,
+1
-1
src/task_webhooks.rs
···
1
use anyhow::Result;
2
-
use atproto_identity::storage::DidDocumentStorage;
3
use atproto_oauth::jwt::{Claims, Header, mint};
4
use chrono::Utc;
5
use rand::distributions::{Alphanumeric, DistString};
···
1
use anyhow::Result;
2
+
use atproto_identity::traits::DidDocumentStorage;
3
use atproto_oauth::jwt::{Claims, Header, mint};
4
use chrono::Utc;
5
use rand::distributions::{Alphanumeric, DistString};