Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
Remove delegate names from identity doc
Alexis Sellier committed 3 years ago
commit 207d2133f97241894a156d7913592d1dd91663bb
parent c33aa8758989e7d96fd35146697224cf72b803a7
10 files changed +68 -89
modified radicle-cli/examples/rad-init.md
@@ -3,19 +3,19 @@ To create your first radicle project, navigate to a git repository, and run
the `init` command:

```
-
$ rad init --name acme --description "Acme's repository" --no-confirm
+
$ rad init --name heartwood --description "Radicle Heartwood Protocol & Stack" --no-confirm

Initializing local 🌱 project in .

-
ok Project acme created
+
ok Project heartwood created
{
-
  "name": "acme",
-
  "description": "Acme's repository",
+
  "name": "heartwood",
+
  "description": "Radicle Heartwood Protocol & Stack",
  "default-branch": "master"
}


-
Your project id is rad:z4EXAgDJk11uFThfVir5FivKhiAeK. You can show it any time by running:
+
Your project id is rad:zb2rNRYmmz7SLZ7xMjM7dddswC3K. You can show it any time by running:
   rad .

To publish your project to the network, run:
@@ -27,5 +27,5 @@ Projects can be listed with the `ls` command:

```
$ rad ls
-
acme rad:z4EXAgDJk11uFThfVir5FivKhiAeK cdf76ce Acme's repository
+
heartwood rad:zb2rNRYmmz7SLZ7xMjM7dddswC3K cdf76ce Radicle Heartwood Protocol & Stack
```
modified radicle-cli/src/commands/checkout.rs
@@ -110,8 +110,8 @@ pub fn execute(options: Options, profile: &Profile) -> anyhow::Result<PathBuf> {
    spinner.finish();

    let remotes = delegates
-
        .iter()
-
        .map(|d| *d.id)
+
        .into_iter()
+
        .map(|did| *did)
        .filter(|id| id != profile.id())
        .collect::<Vec<_>>();

modified radicle-cli/src/commands/clone.rs
@@ -101,7 +101,7 @@ pub fn clone(id: Id, _interactive: Interactive, ctx: impl term::Context) -> anyh
    let delegates = doc
        .delegates
        .iter()
-
        .map(|d| *d.id)
+
        .map(|d| **d)
        .filter(|id| id != profile.id())
        .collect::<Vec<_>>();
    let default_branch = doc.payload.default_branch.clone();
modified radicle-crypto/src/test/signer.rs
@@ -8,12 +8,16 @@ pub struct MockSigner {

impl MockSigner {
    pub fn new(rng: &mut fastrand::Rng) -> Self {
-
        let mut bytes: [u8; 32] = [0; 32];
+
        let mut seed: [u8; 32] = [0; 32];

-
        for byte in &mut bytes {
+
        for byte in &mut seed {
            *byte = rng.u8(..);
        }
-
        let seed = Seed::new(bytes);
+
        Self::from_seed(seed)
+
    }
+

+
    pub fn from_seed(seed: [u8; 32]) -> Self {
+
        let seed = Seed::new(seed);
        let keypair = KeyPair::from_seed(seed);

        Self::from(SecretKey::from(keypair.sk))
modified radicle-httpd/src/api/v1/delegates.rs
@@ -40,7 +40,7 @@ async fn delegates_projects_handler(
            let Ok((_, head)) = repo.head() else { return None };
            let Ok(Doc { payload, delegates, .. }) = repo.project_of(ctx.profile.id()) else { return None };

-
            if !delegates.iter().any(|d| d.id == delegate) {
+
            if !delegates.iter().any(|d| *d == delegate) {
                return None;
            }

modified radicle/src/identity.rs
@@ -9,7 +9,7 @@ use thiserror::Error;
use crate::crypto;

pub use crypto::PublicKey;
-
pub use project::{Delegate, Doc, Id, IdError};
+
pub use project::{Doc, Id, IdError};

#[derive(Error, Debug)]
pub enum DidError {
modified radicle/src/identity/project.rs
@@ -68,24 +68,6 @@ impl DocError {
    }
}

-
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-
pub struct Delegate {
-
    pub name: String,
-
    pub id: Did,
-
}
-

-
impl Delegate {
-
    fn matches(&self, key: &PublicKey) -> bool {
-
        &self.id.0 == key
-
    }
-
}
-

-
impl From<Delegate> for PublicKey {
-
    fn from(delegate: Delegate) -> Self {
-
        delegate.id.0
-
    }
-
}
-

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Payload {
@@ -105,7 +87,7 @@ pub struct Doc<V> {
    pub payload: Payload,
    #[serde(flatten)]
    pub extensions: BTreeMap<Namespace, serde_json::Value>,
-
    pub delegates: NonEmpty<Delegate>,
+
    pub delegates: NonEmpty<Did>,
    pub threshold: usize,

    #[serde(skip)]
@@ -125,13 +107,9 @@ impl Doc<Verified> {
    }

    /// Attempt to add a new delegate to the document. Returns `true` if it wasn't there before.
-
    pub fn delegate(&mut self, name: String, key: crypto::PublicKey) -> bool {
-
        let delegate = Delegate {
-
            name,
-
            id: Did::from(key),
-
        };
-

-
        if self.delegates.iter().all(|d| d.id != delegate.id) {
+
    pub fn delegate(&mut self, key: crypto::PublicKey) -> bool {
+
        let delegate = Did::from(key);
+
        if self.delegates.iter().all(|id| id != &delegate) {
            self.delegates.push(delegate);
            return true;
        }
@@ -233,7 +211,7 @@ impl Doc<Unverified> {
        name: String,
        description: String,
        default_branch: BranchName,
-
        delegate: Delegate,
+
        delegate: Did,
    ) -> Self {
        Self {
            payload: Payload {
@@ -252,7 +230,7 @@ impl Doc<Unverified> {
        name: String,
        description: String,
        default_branch: BranchName,
-
        delegates: NonEmpty<Delegate>,
+
        delegates: NonEmpty<Did>,
        threshold: usize,
    ) -> Self {
        Self {
@@ -289,15 +267,6 @@ impl Doc<Unverified> {
                "number of delegates cannot exceed 255",
            ));
        }
-
        if self
-
            .delegates
-
            .iter()
-
            .any(|d| d.name.is_empty() || d.name.len() > MAX_STRING_LENGTH)
-
        {
-
            return Err(VerificationError::Delegates(
-
                "delegate name must not be empty and must not exceed 255 bytes",
-
            ));
-
        }
        if self.delegates.is_empty() {
            return Err(VerificationError::Delegates(
                "delegate list cannot be empty",
@@ -471,7 +440,7 @@ impl Identity<Untrusted> {
            // Check that enough delegates signed this next version.
            let quorum = signatures
                .iter()
-
                .filter(|(key, _)| trusted.delegates.iter().any(|d| d.matches(key)))
+
                .filter(|(key, _)| trusted.delegates.iter().any(|d| &**d == key))
                .count();
            if quorum < trusted.threshold {
                return Err(IdentityError::QuorumNotReached(quorum, trusted.threshold));
@@ -498,6 +467,7 @@ mod test {
    use radicle_crypto::Signer as _;

    use crate::rad;
+
    use crate::storage::git::transport;
    use crate::storage::git::Storage;
    use crate::storage::{ReadStorage, WriteStorage};
    use crate::test::arbitrary;
@@ -507,6 +477,35 @@ mod test {
    use qcheck_macros::quickcheck;

    #[test]
+
    fn test_canonical_example() {
+
        let tempdir = tempfile::tempdir().unwrap();
+
        let storage = Storage::open(tempdir.path().join("storage")).unwrap();
+

+
        transport::local::register(storage.clone());
+

+
        let delegate = MockSigner::from_seed([0xff; 32]);
+
        let (repo, _) = fixtures::repository(tempdir.path().join("working"));
+
        let (id, _, _) = rad::init(
+
            &repo,
+
            "heartwood",
+
            "Radicle Heartwood Protocol & Stack",
+
            git::refname!("master"),
+
            &delegate,
+
            &storage,
+
        )
+
        .unwrap();
+

+
        assert_eq!(
+
            delegate.public_key().to_human(),
+
            String::from("z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi")
+
        );
+
        assert_eq!(
+
            id.to_human(),
+
            String::from("rad:zb2rNRYmmz7SLZ7xMjM7dddswC3K")
+
        );
+
    }
+

+
    #[test]
    fn test_not_found() {
        let tempdir = tempfile::tempdir().unwrap();
        let storage = Storage::open(tempdir.path().join("storage")).unwrap();
@@ -559,7 +558,7 @@ mod test {
            .unwrap();

        // Add Bob as a delegate, and sign it.
-
        proj.delegate("bob".to_owned(), *bob.public_key());
+
        proj.delegate(*bob.public_key());
        proj.threshold = 2;
        proj.sign(&alice)
            .and_then(|(_, sig)| {
@@ -573,7 +572,7 @@ mod test {
            .unwrap();

        // Add Eve as a delegate, and sign it.
-
        proj.delegate("eve".to_owned(), *eve.public_key());
+
        proj.delegate(*eve.public_key());
        proj.sign(&alice)
            .and_then(|(_, alice_sig)| {
                proj.sign(&bob).and_then(|(_, bob_sig)| {
modified radicle/src/rad.rs
@@ -59,11 +59,7 @@ pub fn init<G: Signer>(
) -> Result<(Id, identity::Doc<Verified>, SignedRefs<Verified>), InitError> {
    // TODO: Better error when project id already exists in storage, but remote doesn't.
    let pk = signer.public_key();
-
    let delegate = identity::Delegate {
-
        // TODO: Use actual user name.
-
        name: String::from("anonymous"),
-
        id: identity::Did::from(*pk),
-
    };
+
    let delegate = identity::Did::from(*pk);
    let doc = identity::Doc::initial(
        name.to_owned(),
        description.to_owned(),
@@ -348,7 +344,7 @@ mod tests {
    use radicle_crypto::test::signer::MockSigner;

    use crate::git::{name::component, qualified, Qualified};
-
    use crate::identity::{Delegate, Did};
+
    use crate::identity::Did;
    use crate::storage::git::transport;
    use crate::storage::git::Storage;
    use crate::storage::{ReadStorage, WriteStorage};
@@ -403,13 +399,7 @@ mod tests {
        assert_eq!(project.name, "acme");
        assert_eq!(project.description, "Acme's repo");
        assert_eq!(project.default_branch, git::refname!("master"));
-
        assert_eq!(
-
            project.delegates.first(),
-
            &Delegate {
-
                name: String::from("anonymous"),
-
                id: Did::from(public_key),
-
            }
-
        );
+
        assert_eq!(project.delegates.first(), &Did::from(public_key));
    }

    #[test]
modified radicle/src/storage/git.rs
@@ -500,7 +500,7 @@ impl ReadRepository for Repository {

        let mut heads = Vec::new();
        for delegate in project.delegates.iter() {
-
            let r = self.reference_oid(&delegate.id, &branch_ref)?.into();
+
            let r = self.reference_oid(delegate, &branch_ref)?.into();

            heads.push(r);
        }
modified radicle/src/test/arbitrary.rs
@@ -10,7 +10,7 @@ use qcheck::Arbitrary;

use crate::collections::HashMap;
use crate::git;
-
use crate::identity::{project::Delegate, project::Doc, Did, Id};
+
use crate::identity::{project::Doc, Did, Id};
use crate::storage;
use crate::storage::refs::{Refs, SignedRefs};
use crate::test::storage::MockStorage;
@@ -57,21 +57,12 @@ impl Arbitrary for Did {
    }
}

-
impl Arbitrary for Delegate {
-
    fn arbitrary(g: &mut qcheck::Gen) -> Self {
-
        Self {
-
            name: String::arbitrary(g),
-
            id: Did::arbitrary(g),
-
        }
-
    }
-
}
-

impl Arbitrary for Doc<Unverified> {
    fn arbitrary(g: &mut qcheck::Gen) -> Self {
        let name = String::arbitrary(g);
        let description = String::arbitrary(g);
        let default_branch = git::RefString::try_from(String::arbitrary(g)).unwrap();
-
        let delegate = Delegate::arbitrary(g);
+
        let delegate = Did::arbitrary(g);

        Self::initial(name, description, default_branch, delegate)
    }
@@ -91,16 +82,11 @@ impl Arbitrary for Doc<Verified> {
            .collect::<String>()
            .try_into()
            .unwrap();
-
        let delegates: NonEmpty<_> = iter::repeat_with(|| Delegate {
-
            name: iter::repeat_with(|| rng.alphanumeric())
-
                .take(rng.usize(1..16))
-
                .collect(),
-
            id: Did::arbitrary(g),
-
        })
-
        .take(rng.usize(1..6))
-
        .collect::<Vec<_>>()
-
        .try_into()
-
        .unwrap();
+
        let delegates: NonEmpty<_> = iter::repeat_with(|| Did::arbitrary(g))
+
            .take(rng.usize(1..6))
+
            .collect::<Vec<_>>()
+
            .try_into()
+
            .unwrap();
        let threshold = delegates.len() / 2 + 1;
        let doc: Doc<Unverified> =
            Doc::new(name, description, default_branch, delegates, threshold);