noosphere_cli/native/commands/sphere/
mod.rs1mod auth;
4mod config;
5mod follow;
6mod history;
7mod render;
8mod save;
9mod status;
10mod sync;
11
12pub use auth::*;
13pub use config::*;
14pub use follow::*;
15pub use history::*;
16pub use render::*;
17pub use save::*;
18pub use status::*;
19pub use sync::*;
20
21use std::{str::FromStr, sync::Arc};
22
23use crate::native::{paths::SpherePaths, workspace::Workspace};
24use anyhow::{anyhow, Result};
25use cid::Cid;
26use noosphere::{
27 key::KeyStorage,
28 sphere::{SphereContextBuilder, SphereContextBuilderArtifacts},
29};
30use noosphere_core::{authority::Authorization, data::Did};
31use noosphere_core::{
32 context::{HasMutableSphereContext, SphereContext, SphereSync},
33 data::Mnemonic,
34};
35
36use tokio::sync::Mutex;
37use ucan::crypto::KeyMaterial;
38use url::Url;
39
40pub async fn sphere_create(owner_key: &str, workspace: &mut Workspace) -> Result<(Did, Mnemonic)> {
43 workspace.ensure_sphere_uninitialized()?;
44
45 let sphere_paths = SpherePaths::initialize(workspace.working_directory()).await?;
46
47 let sphere_context_artifacts = SphereContextBuilder::default()
48 .create_sphere()
49 .at_storage_path(sphere_paths.root())
50 .reading_keys_from(workspace.key_storage().clone())
51 .using_key(owner_key)
52 .build()
53 .await?;
54
55 let mnemonic = sphere_context_artifacts.require_mnemonic()?.to_string();
56 let sphere_context: SphereContext<_> = sphere_context_artifacts.into();
57 let sphere_identity = sphere_context.identity();
58
59 info!(
60 r#"A new sphere has been created in {:?}
61Its identity is {}
62Your key {:?} is considered its owner
63The owner of a sphere can authorize other keys to write to it
64
65IMPORTANT: Write down the following sequence of words...
66
67{}
68
69...and keep it somewhere safe!
70You will be asked to enter them if you ever need to transfer ownership of the sphere to a different key."#,
71 sphere_paths.root(),
72 sphere_identity,
73 owner_key,
74 mnemonic
75 );
76
77 workspace.initialize(sphere_paths)?;
78
79 Ok((sphere_identity.clone(), mnemonic.into()))
80}
81
82pub async fn sphere_join(
84 local_key: &str,
85 authorization: Option<String>,
86 sphere_identity: &Did,
87 gateway_url: &Url,
88 render_depth: Option<u32>,
89 workspace: &mut Workspace,
90) -> Result<()> {
91 workspace.ensure_sphere_uninitialized()?;
92 info!("Joining sphere {sphere_identity}...");
93
94 let did = {
95 let local_key = workspace.key_storage().require_key(local_key).await?;
96 local_key.get_did().await?
97 };
98
99 let cid_string = match authorization {
100 None => {
101 info!(
102 r#"In order to join the sphere, another client must authorize your local key
103This is the local key's ID; share it with an authorized client:
104
105 {did}
106
107Hint: if the authorized client is also using the "orb" CLI, you can use this command from the existing workspace to authorize the new key:
108
109 orb auth add {did}
110
111Once authorized, you will get a code.
112Type or paste the code here and press enter:"#
113 );
114
115 let mut cid_string = String::new();
116
117 std::io::stdin().read_line(&mut cid_string)?;
118
119 cid_string
120 }
121 Some(cid_string) => cid_string,
122 };
123
124 let cid = Cid::from_str(cid_string.trim())
125 .map_err(|_| anyhow!("Could not parse the authorization identity as a CID"))?;
126
127 let sphere_paths = SpherePaths::initialize(workspace.working_directory()).await?;
128
129 {
130 let mut sphere_context = Arc::new(Mutex::new(
131 match SphereContextBuilder::default()
132 .join_sphere(sphere_identity)
133 .at_storage_path(sphere_paths.root())
134 .reading_keys_from(workspace.key_storage().clone())
135 .using_key(local_key)
136 .authorized_by(Some(&Authorization::Cid(cid)))
137 .build()
138 .await?
139 {
140 SphereContextBuilderArtifacts::SphereCreated { context, .. } => context,
141 SphereContextBuilderArtifacts::SphereOpened(context) => context,
142 },
143 ));
144
145 sphere_context
146 .sphere_context_mut()
147 .await?
148 .configure_gateway_url(Some(gateway_url))
149 .await?;
150 sphere_context.sync().await?;
151 }
152
153 workspace.initialize(sphere_paths)?;
154 workspace.render(render_depth, true).await?;
155
156 info!(
159 r#"The authorization has been saved. You should be able to sync:
160
161 orb sphere sync
162
163Happy pondering!"#
164 );
165
166 Ok(())
167}