Initial commit
This commit is contained in:
commit
3358daee48
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
22
Cargo.toml
Normal file
22
Cargo.toml
Normal file
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
name = "actix-webfinger"
|
||||
description = "Types and helpers to create and fetch Webfinger resources"
|
||||
version = "0.1.0"
|
||||
license = "GPL-3.0"
|
||||
authors = ["asonix <asonix@asonix.dog>"]
|
||||
repository = "https://git.asonix.dog/asonix/actix-webfinger"
|
||||
readme = "README.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
actix = "0.7"
|
||||
actix-web = "0.7"
|
||||
failure = "0.1"
|
||||
futures = "0.1"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
actix-web = { version = "0.7", features = ["ssl"] }
|
||||
openssl = "0.10"
|
||||
serde_json = "1.0"
|
26
examples/sir_boops.rs
Normal file
26
examples/sir_boops.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use actix::{Actor, System};
|
||||
use actix_web::client::ClientConnector;
|
||||
use actix_webfinger::Webfinger;
|
||||
use futures::Future;
|
||||
use openssl::ssl::{SslConnector, SslMethod};
|
||||
|
||||
fn main() {
|
||||
let sys = System::new("sir-boops");
|
||||
|
||||
let ssl_conn = SslConnector::builder(SslMethod::tls()).unwrap().build();
|
||||
let conn = ClientConnector::with_connector(ssl_conn).start();
|
||||
|
||||
let fut = Webfinger::fetch(conn, "Sir_Boops@sergal.org", "mastodon.sergal.org")
|
||||
.map(move |w: Webfinger| {
|
||||
if let Some(ref link) = w.activitypub() {
|
||||
println!("Sir Boop's activitypub: {:#?}", link);
|
||||
}
|
||||
|
||||
System::current().stop();
|
||||
})
|
||||
.map_err(|e| eprintln!("Error: {}", e));
|
||||
|
||||
actix::spawn(fut);
|
||||
|
||||
let _ = sys.run();
|
||||
}
|
120
src/lib.rs
Normal file
120
src/lib.rs
Normal file
|
@ -0,0 +1,120 @@
|
|||
use actix::Addr;
|
||||
use actix_web::{
|
||||
client::{self, ClientConnector},
|
||||
HttpMessage,
|
||||
};
|
||||
use futures::{future::IntoFuture, Future};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Link {
|
||||
pub rel: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub href: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub template: Option<String>,
|
||||
|
||||
#[serde(rename = "type")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Webfinger {
|
||||
pub aliases: Vec<String>,
|
||||
pub links: Vec<Link>,
|
||||
pub subject: String,
|
||||
}
|
||||
|
||||
impl Webfinger {
|
||||
pub fn aliases(&self) -> &[String] {
|
||||
&self.aliases
|
||||
}
|
||||
|
||||
pub fn links(&self) -> &[Link] {
|
||||
&self.links
|
||||
}
|
||||
|
||||
pub fn activitypub(&self) -> Option<&Link> {
|
||||
self.links.iter().find(|l| {
|
||||
l.rel == "self"
|
||||
&& l.kind
|
||||
.as_ref()
|
||||
.map(|k| k == "application/activity+json")
|
||||
.unwrap_or(false)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn profile(&self) -> Option<&Link> {
|
||||
self.links
|
||||
.iter()
|
||||
.find(|l| l.rel == "http://webfinger.net/rel/profile-page")
|
||||
}
|
||||
|
||||
pub fn atom(&self) -> Option<&Link> {
|
||||
self.links
|
||||
.iter()
|
||||
.find(|l| l.rel == "http://schemas.google.com/g/2010#updates-from")
|
||||
}
|
||||
|
||||
pub fn salmon(&self) -> Option<&Link> {
|
||||
self.links.iter().find(|l| l.rel == "salmon")
|
||||
}
|
||||
|
||||
pub fn magic_public_key(&self) -> Option<&Link> {
|
||||
self.links.iter().find(|l| l.rel == "magic-public-key")
|
||||
}
|
||||
|
||||
pub fn ostatus(&self) -> Option<&Link> {
|
||||
self.links
|
||||
.iter()
|
||||
.find(|l| l.rel == "http://ostatus.org/schema/1.0/subscribe")
|
||||
}
|
||||
|
||||
pub fn fetch(
|
||||
conn: Addr<ClientConnector>,
|
||||
user: &str,
|
||||
domain: &str,
|
||||
) -> Box<Future<Item = Self, Error = actix_web::Error>> {
|
||||
let url = format!(
|
||||
"https://{}/.well-known/webfinger?resource=acct:{}",
|
||||
domain, user
|
||||
);
|
||||
|
||||
let fut = client::get(url)
|
||||
.with_connector(conn)
|
||||
.header("Accept", "application/json")
|
||||
.finish()
|
||||
.into_future()
|
||||
.and_then(|r| {
|
||||
r.send()
|
||||
.from_err()
|
||||
.and_then(|res| res.json::<Webfinger>().from_err())
|
||||
});
|
||||
|
||||
Box::new(fut)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Webfinger;
|
||||
|
||||
const SIR_BOOPS: &'static str = r#"{"subject":"acct:Sir_Boops@sergal.org","aliases":["https://mastodon.sergal.org/@Sir_Boops","https://mastodon.sergal.org/users/Sir_Boops"],"links":[{"rel":"http://webfinger.net/rel/profile-page","type":"text/html","href":"https://mastodon.sergal.org/@Sir_Boops"},{"rel":"http://schemas.google.com/g/2010#updates-from","type":"application/atom+xml","href":"https://mastodon.sergal.org/users/Sir_Boops.atom"},{"rel":"self","type":"application/activity+json","href":"https://mastodon.sergal.org/users/Sir_Boops"},{"rel":"salmon","href":"https://mastodon.sergal.org/api/salmon/1"},{"rel":"magic-public-key","href":"data:application/magic-public-key,RSA.vwDujxmxoYHs64MyVB3LG5ZyBxV3ufaMRBFu42bkcTpISq1WwZ-3Zb6CI8zOO-nM-Q2llrVRYjZa4ZFnOLvMTq_Kf-Zf5wy2aCRer88gX-MsJOAtItSi412y0a_rKOuFaDYLOLeTkRvmGLgZWbsrZJOp-YWb3zQ5qsIOInkc5BwI172tMsGeFtsnbNApPV4lrmtTGaJ8RiM8MR7XANBOfOHggSt1-eAIKGIsCmINEMzs1mG9D75xKtC_sM8GfbvBclQcBstGkHAEj1VHPW0ch6Bok5_QQppicyb8UA1PAA9bznSFtKlYE4xCH8rlCDSDTBRtdnBWHKcj619Ujz4Qaw==.AQAB"},{"rel":"http://ostatus.org/schema/1.0/subscribe","template":"https://mastodon.sergal.org/authorize_interaction?uri={uri}"}]}"#;
|
||||
|
||||
#[test]
|
||||
fn can_deserialize_sir_boops() {
|
||||
let webfinger: Result<Webfinger, _> = serde_json::from_str(SIR_BOOPS);
|
||||
|
||||
assert!(webfinger.is_ok());
|
||||
|
||||
let webfinger = webfinger.unwrap();
|
||||
|
||||
assert!(webfinger.salmon().is_some());
|
||||
assert!(webfinger.ostatus().is_some());
|
||||
assert!(webfinger.activitypub().is_some());
|
||||
assert!(webfinger.atom().is_some());
|
||||
assert!(webfinger.magic_public_key().is_some());
|
||||
assert!(webfinger.profile().is_some());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue