cob: Parametrize `Change` with single signature
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
parent
2230c8ddc4
commit
1a5b68c2b3
|
|
@ -64,6 +64,10 @@ pub mod error {
|
||||||
NoChange(Oid),
|
NoChange(Oid),
|
||||||
#[error("the 'change' found at '{0}' was not a blob")]
|
#[error("the 'change' found at '{0}' was not a blob")]
|
||||||
ChangeNotBlob(Oid),
|
ChangeNotBlob(Oid),
|
||||||
|
#[error("the 'change' found at '{0}' was not signed")]
|
||||||
|
ChangeNotSigned(Oid),
|
||||||
|
#[error("the 'change' found at '{0}' has more than one signature")]
|
||||||
|
TooManySignatures(Oid),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
AuthorTrailer(#[from] trailers::error::InvalidAuthorTrailer),
|
AuthorTrailer(#[from] trailers::error::InvalidAuthorTrailer),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|
@ -82,7 +86,7 @@ impl change::Storage for git2::Repository {
|
||||||
type ObjectId = Oid;
|
type ObjectId = Oid;
|
||||||
type Author = Oid;
|
type Author = Oid;
|
||||||
type Resource = Oid;
|
type Resource = Oid;
|
||||||
type Signatures = Signatures;
|
type Signatures = Signature;
|
||||||
|
|
||||||
fn create<Signer>(
|
fn create<Signer>(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -127,7 +131,7 @@ impl change::Storage for git2::Repository {
|
||||||
Ok(Change {
|
Ok(Change {
|
||||||
id,
|
id,
|
||||||
revision: revision.into(),
|
revision: revision.into(),
|
||||||
signatures: signature.into(),
|
signature,
|
||||||
author,
|
author,
|
||||||
resource,
|
resource,
|
||||||
manifest,
|
manifest,
|
||||||
|
|
@ -138,7 +142,15 @@ impl change::Storage for git2::Repository {
|
||||||
fn load(&self, id: Self::ObjectId) -> Result<Change, Self::LoadError> {
|
fn load(&self, id: Self::ObjectId) -> Result<Change, Self::LoadError> {
|
||||||
let commit = Commit::read(self, id.into())?;
|
let commit = Commit::read(self, id.into())?;
|
||||||
let (author, resource) = parse_trailers(commit.trailers())?;
|
let (author, resource) = parse_trailers(commit.trailers())?;
|
||||||
let signatures = Signatures::try_from(&commit)?;
|
let mut signatures = Signatures::try_from(&commit)?
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let Some(signature) = signatures.pop() else {
|
||||||
|
return Err(error::Load::ChangeNotSigned(id));
|
||||||
|
};
|
||||||
|
if !signatures.is_empty() {
|
||||||
|
return Err(error::Load::TooManySignatures(id));
|
||||||
|
}
|
||||||
|
|
||||||
let tree = self.find_tree(commit.tree())?;
|
let tree = self.find_tree(commit.tree())?;
|
||||||
let manifest = load_manifest(self, &tree)?;
|
let manifest = load_manifest(self, &tree)?;
|
||||||
|
|
@ -147,7 +159,7 @@ impl change::Storage for git2::Repository {
|
||||||
Ok(Change {
|
Ok(Change {
|
||||||
id,
|
id,
|
||||||
revision: tree.id().into(),
|
revision: tree.id().into(),
|
||||||
signatures,
|
signature: signature.into(),
|
||||||
author,
|
author,
|
||||||
resource,
|
resource,
|
||||||
manifest,
|
manifest,
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ use git_ext::Oid;
|
||||||
pub mod store;
|
pub mod store;
|
||||||
pub use store::{Create, Storage};
|
pub use store::{Create, Storage};
|
||||||
|
|
||||||
use crate::signatures::Signatures;
|
use crate::signatures::Signature;
|
||||||
|
|
||||||
/// A single change in the change graph. The layout of changes in the repository
|
/// A single change in the change graph. The layout of changes in the repository
|
||||||
/// is specified in the RFC (docs/rfc/0662-collaborative-objects.adoc)
|
/// is specified in the RFC (docs/rfc/0662-collaborative-objects.adoc)
|
||||||
/// under "Change Commits".
|
/// under "Change Commits".
|
||||||
pub type Change = store::Change<Oid, Oid, Oid, Signatures>;
|
pub type Change = store::Change<Oid, Oid, Oid, Signature>;
|
||||||
|
|
|
||||||
|
|
@ -54,14 +54,14 @@ pub struct Create<Id> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Change<Author, Resource, Id, Signatures> {
|
pub struct Change<Author, Resource, Id, Signature> {
|
||||||
/// The content address of the `Change` itself.
|
/// The content address of the `Change` itself.
|
||||||
pub id: Id,
|
pub id: Id,
|
||||||
/// The content address of the tree of the `Change`.
|
/// The content address of the tree of the `Change`.
|
||||||
pub revision: Id,
|
pub revision: Id,
|
||||||
/// The cryptographic signatures and their public keys of the
|
/// The cryptographic signature(s) and their public keys of the
|
||||||
/// authors.
|
/// authors.
|
||||||
pub signatures: Signatures,
|
pub signature: Signature,
|
||||||
/// The author of this change. The `Author` is expected to be a
|
/// The author of this change. The `Author` is expected to be a
|
||||||
/// content address to look up the identity of the author.
|
/// content address to look up the identity of the author.
|
||||||
pub author: Option<Author>,
|
pub author: Option<Author>,
|
||||||
|
|
@ -111,12 +111,21 @@ where
|
||||||
Id: AsRef<[u8]>,
|
Id: AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
pub fn valid_signatures(&self) -> bool {
|
pub fn valid_signatures(&self) -> bool {
|
||||||
self.signatures
|
self.signature
|
||||||
.iter()
|
.iter()
|
||||||
.all(|(key, sig)| key.verify(self.revision.as_ref(), sig).is_ok())
|
.all(|(key, sig)| key.verify(self.revision.as_ref(), sig).is_ok())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<A, R, Id> Change<A, R, Id, signatures::Signature>
|
||||||
|
where
|
||||||
|
Id: AsRef<[u8]>,
|
||||||
|
{
|
||||||
|
pub fn valid_signatures(&self) -> bool {
|
||||||
|
self.signature.verify(self.revision.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Manifest {
|
pub struct Manifest {
|
||||||
/// The name given to the type of collaborative object.
|
/// The name given to the type of collaborative object.
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use petgraph::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
change, object, signatures::Signatures, Change, CollaborativeObject, ObjectId, TypeName,
|
change, object, signatures::Signature, Change, CollaborativeObject, ObjectId, TypeName,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod evaluation;
|
mod evaluation;
|
||||||
|
|
@ -37,7 +37,7 @@ impl ChangeGraph {
|
||||||
oid: &ObjectId,
|
oid: &ObjectId,
|
||||||
) -> Option<ChangeGraph>
|
) -> Option<ChangeGraph>
|
||||||
where
|
where
|
||||||
S: change::Storage<ObjectId = Oid, Author = Oid, Resource = Oid, Signatures = Signatures>,
|
S: change::Storage<ObjectId = Oid, Author = Oid, Resource = Oid, Signatures = Signature>,
|
||||||
{
|
{
|
||||||
log::info!("loading object '{}' '{}'", typename, oid);
|
log::info!("loading object '{}' '{}'", typename, oid);
|
||||||
let mut builder = GraphBuilder::default();
|
let mut builder = GraphBuilder::default();
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ pub use history::{Contents, Entry, History, HistoryType};
|
||||||
mod pruning_fold;
|
mod pruning_fold;
|
||||||
|
|
||||||
pub mod signatures;
|
pub mod signatures;
|
||||||
use signatures::Signatures;
|
use signatures::Signature;
|
||||||
|
|
||||||
pub mod type_name;
|
pub mod type_name;
|
||||||
pub use type_name::TypeName;
|
pub use type_name::TypeName;
|
||||||
|
|
@ -134,7 +134,7 @@ where
|
||||||
ObjectId = git_ext::Oid,
|
ObjectId = git_ext::Oid,
|
||||||
Author = git_ext::Oid,
|
Author = git_ext::Oid,
|
||||||
Resource = git_ext::Oid,
|
Resource = git_ext::Oid,
|
||||||
Signatures = Signatures,
|
Signatures = Signature,
|
||||||
>,
|
>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,12 @@ pub struct Signature {
|
||||||
sig: crypto::Signature,
|
sig: crypto::Signature,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Signature {
|
||||||
|
pub fn verify(&self, payload: &[u8]) -> bool {
|
||||||
|
self.key.verify(payload, &self.sig).is_ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Signature> for ExtendedSignature {
|
impl From<Signature> for ExtendedSignature {
|
||||||
fn from(sig: Signature) -> Self {
|
fn from(sig: Signature) -> Self {
|
||||||
Self::new(sig.key, sig.sig)
|
Self::new(sig.key, sig.sig)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue