Skip to content
This repository was archived by the owner on Feb 28, 2025. It is now read-only.

Revoke Installation #38

Merged
merged 23 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,921 changes: 2,689 additions & 232 deletions Cargo.lock

Large diffs are not rendered by default.

27 changes: 23 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
[workspace]

members = [
"xps-gateway",
"messaging",
"inbox",
"registry",
"xps-gateway",
"messaging",
"inbox",
"registry",
"gateway-types",
]

exclude = [ ]

# Make the feature resolver explicit.
# See https://doc.rust-lang.org/edition-guide/rust-2021/default-cargo-resolver.html#details
resolver = "2"

[workspace.dependencies]
log = "0.4"
tracing = "0.1"
tracing-subscriber = { version = "0.3.18", features = ["fmt", "env-filter"] }
serde = "1.0"
serde_json = "1.0"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
async-trait = "0.1"
jsonrpsee = { version = "0.21", features = ["macros", "server", "client-core"] }
anyhow = "1.0"
thiserror = "1.0"
ethers = { version = "2", features = ["abigen"] }
ctor = "0.2"
lib-didethresolver = { git = "https://github.com/xmtp/didethresolver", branch = "insipx/revoke-installation", package = "lib-didethresolver" }
gateway-types = { path = "./gateway-types" }
rustc-hex = "2.1"
hex = "0.4"
10 changes: 10 additions & 0 deletions gateway-types/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "gateway-types"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde.workspace = true
lib-didethresolver.workspace = true
42 changes: 42 additions & 0 deletions gateway-types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use lib_didethresolver::types::{
Attribute, KeyEncoding, KeyMetadata, KeyPurpose, KeyType, PublicKey,
};
use serde::{Deserialize, Serialize};

/// Address of the did:ethr Registry on Sepolia
pub const DID_ETH_REGISTRY: &str = "0xd1D374DDE031075157fDb64536eF5cC13Ae75000";

/// A message sent to a conversation
#[derive(Serialize, Deserialize)]
pub struct Message {
// Unique identifier for a conversation
#[serde(rename = "conversationId")]
pub conversation_id: Vec<u8>,
/// message content in bytes
pub payload: Vec<u8>,
/// Signature of V
pub v: Vec<u8>,
/// Signature of R
pub r: Vec<u8>,
/// Signature of S
pub s: Vec<u8>,
}

/// The XMTP-specific attribute type
#[derive(Serialize, Deserialize)]
pub enum XmtpAttributeType {
InstallationKey,
}

impl From<XmtpAttributeType> for Attribute {
fn from(attribute: XmtpAttributeType) -> Self {
match attribute {
XmtpAttributeType::InstallationKey => Attribute::PublicKey(PublicKey {
key_type: KeyType::Ed25519VerificationKey2020,
purpose: KeyPurpose::Xmtp,
encoding: KeyEncoding::Hex,
metadata: Some(KeyMetadata::Installation),
}),
}
}
}
13 changes: 0 additions & 13 deletions inbox/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
9 changes: 9 additions & 0 deletions registry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,12 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
log.workspace = true
tracing.workspace = true
tokio.workspace = true
async-trait.workspace = true
ethers = { workspace = true, features = ["ws"] }
gateway-types.workspace = true
lib-didethresolver.workspace = true
rustc-hex.workspace = true
thiserror.workspace = true
49 changes: 49 additions & 0 deletions registry/src/contact_operations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Contact Operations

use std::str::FromStr;

use ethers::{core::types::Signature, providers::Middleware, types::Address};
use gateway_types::XmtpAttributeType;
use lib_didethresolver::{did_registry::DIDRegistry, types::Attribute};

use crate::error::ContactOperationError;

pub struct ContactOperations<Middleware> {
registry: DIDRegistry<Middleware>,
}

impl<M> ContactOperations<M>
where
M: Middleware + 'static,
{
/// Creates a new ContactOperations instance
pub fn new(registry: DIDRegistry<M>) -> Self {
Self { registry }
}

pub async fn revoke_installation(
&self,
did: String,
name: XmtpAttributeType,
value: Vec<u8>,
signature: Signature,
) -> Result<(), ContactOperationError<M>> {
// for now, we will just assume the DID is a valid ethereum wallet address
// TODO: Parse or resolve the actual DID
// TODO: Remove unwraps
let address = Address::from_str(&did)?;
self.registry
.revoke_attribute_signed(
address,
signature.v.try_into().unwrap(),
signature.r.try_into().unwrap(),
signature.s.try_into().unwrap(),
Attribute::from(name).into(),
value.into(),
)
.send()
.await?
.await?;
Ok(())
}
}
15 changes: 15 additions & 0 deletions registry/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use ethers::{
contract::ContractError,
providers::{Middleware, ProviderError},
};
use thiserror::Error;

#[derive(Error, Debug)]
pub enum ContactOperationError<M: Middleware> {
#[error("Invalid address {0}")]
BadAddress(#[from] rustc_hex::FromHexError),
#[error(transparent)]
ContractError(#[from] ContractError<M>),
#[error(transparent)]
ProviderError(#[from] ProviderError),
}
13 changes: 4 additions & 9 deletions registry/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}
mod contact_operations;
pub mod error;

pub use contact_operations::*;

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
32 changes: 20 additions & 12 deletions xps-gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,27 @@ resolver = "2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
log = "0.4"
tracing = "0.1"
tracing-subscriber = { version = "0.3.18", features = ["fmt", "env-filter"] }
serde = "1"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
log.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
serde.workspace = true
tokio.workspace = true
async-trait.workspace = true
jsonrpsee.workspace = true
anyhow.workspace = true
thiserror.workspace = true
ethers = { workspace = true, features = ["ws"] }
ctor.workspace = true
lib-didethresolver.workspace = true
gateway-types.workspace = true
rand = "0.8"
tokio-stream = { version = "0.1", features = ["net"] }
async-trait = "0.1"
jsonrpsee = { version = "0.21", features = ["macros", "server", "client-core"] }
anyhow = "1"
thiserror = "1"
ctor = "0.2"
registry = { path = "../registry" }
hex.workspace = true

[dev-dependencies]
jsonrpsee = { version = "0.21", features = ["macros", "server", "client"] }
jsonrpsee = { workspace = true, features = ["macros", "server", "client"]}
tokio = { workspace = true, features = ["macros", "rt", "time"]}
futures = "0.3"
tokio = { version = "1.34", features = ["macros", "rt", "time"] }
serde_json.workspace = true

6 changes: 5 additions & 1 deletion xps-gateway/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use anyhow::Result;
use jsonrpsee::server::Server;

pub use crate::rpc::{XpsMethods, XpsServer};
use crate::types::GatewayContext;

pub const SERVER_HOST: &str = "127.0.0.1:0";

Expand All @@ -16,7 +17,10 @@ pub async fn run() -> Result<()> {
// a port of 0 allows the OS to choose an open port
let server = Server::builder().build(SERVER_HOST).await?;
let addr = server.local_addr()?;
let handle = server.start(rpc::XpsMethods.into_rpc());

let context = GatewayContext::new("wss://ethereum-sepolia.publicnode.com").await?;
let xps_methods = rpc::XpsMethods::new(&context);
let handle = server.start(xps_methods.into_rpc());

log::info!("Server Started at {addr}");
handle.stopped().await;
Expand Down
20 changes: 19 additions & 1 deletion xps-gateway/src/rpc/api.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! Trait Interface Definitions for XPS JSON-RPC

use ethers::core::types::Signature;
use jsonrpsee::{proc_macros::rpc, types::ErrorObjectOwned};

use crate::types::Message;
use gateway_types::{Message, XmtpAttributeType};

/// XPS JSON-RPC Interface Methods
#[rpc(server, client, namespace = "xps")]
Expand All @@ -11,6 +12,23 @@ pub trait Xps {
#[method(name = "sendMessage")]
async fn send_message(&self, _message: Message) -> Result<(), ErrorObjectOwned>;

/// removes the contact bundle for the XMTP device installation. Request must be made to a
/// valid DID with an XMTP profile.
///
/// # Arguments
///
/// * `did` - the DID of the XMTP device installation
/// * `name` - the name of the contact bundle
/// * `value` - the value of the contact bundle
/// * `signature` - the signature of the contact bundle
#[method(name = "revokeInstallation")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

async fn revoke_installation(
&self,
did: String,
name: XmtpAttributeType,
value: Vec<u8>,
signature: Signature,
) -> Result<(), ErrorObjectOwned>;
/// # Documentation for JSON RPC Endpoint: `status`

/// ## Overview
Expand Down
58 changes: 47 additions & 11 deletions xps-gateway/src/rpc/methods.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
//! Interface Implementations for XPS JSON-RPC

use crate::types::{GatewayContext, GatewaySigner};

use super::api::*;
use jsonrpsee::types::error::ErrorCode;

use async_trait::async_trait;
use ethers::{core::types::Signature, providers::Middleware};
use jsonrpsee::types::ErrorObjectOwned;
use thiserror::Error;

use crate::types::Message;
use gateway_types::{Message, XmtpAttributeType};
use registry::{error::ContactOperationError, ContactOperations};

/// Gateway Methods for XPS
pub struct XpsMethods;

impl XpsMethods {
/// Create a new instance of the XpsMethods struct
pub fn new() -> Self {
Self {}
}
pub struct XpsMethods {
contact_operations: ContactOperations<GatewaySigner>,
}

impl Default for XpsMethods {
fn default() -> Self {
Self::new()
impl XpsMethods {
pub fn new(context: &GatewayContext) -> Self {
Self {
contact_operations: ContactOperations::new(context.registry.clone()),
}
}
}

Expand All @@ -36,4 +38,38 @@ impl XpsServer for XpsMethods {
log::debug!("xps_status called");
Ok("OK".to_string())
}

async fn revoke_installation(
&self,
did: String,
name: XmtpAttributeType,
value: Vec<u8>,
signature: Signature,
) -> Result<(), ErrorObjectOwned> {
log::debug!("xps_revokeInstallation called");
self.contact_operations
.revoke_installation(did, name, value, signature)
.await
.map_err(RpcError::from)?;

Ok(())
}
}

/// Error types for DID Registry JSON-RPC
#[derive(Debug, Error)]
enum RpcError<M: Middleware> {
/// A public key parameter was invalid
#[error(transparent)]
ContactOperation(#[from] ContactOperationError<M>),
}

impl<M: Middleware> From<RpcError<M>> for ErrorObjectOwned {
fn from(error: RpcError<M>) -> Self {
match error {
RpcError::ContactOperation(c) => {
ErrorObjectOwned::owned(-31999, c.to_string(), None::<()>)
}
}
}
}
Loading