Skip to content

Commit

Permalink
feat: register as external ID attester (#120)
Browse files Browse the repository at this point in the history
* feat: register as external ID attestor

* chore: rename tag -> provider_name
  • Loading branch information
8e8b2c committed Sep 17, 2024
1 parent 4c41a1b commit bcf0286
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::str;
use hdk::prelude::*;
use holoom_types::{
ConfirmExternalIdRequestPayload, ExternalIdAttestation, GetAttestationForExternalIdPayload,
Expand Down Expand Up @@ -226,3 +227,39 @@ pub fn delete_external_id_attestation(
) -> ExternResult<ActionHash> {
delete_entry(original_attestation_hash)
}

/// Add your agent to the global external ID attestors list. The `provider_name` is used to
/// indicate the identity provider for which you attest identities.
#[hdk_extern]
pub fn register_as_external_id_attestor(provider_name: String) -> ExternResult<ActionHash> {
create_link(
hash_identifier("all_external_id_attestors".into())?,
agent_info()?.agent_initial_pubkey,
LinkTypes::ExternalIdAttestor,
provider_name,
)
}

/// Gets a list of `(agent, provider_name)` pairs representing all globally listed external ID
/// attestors.
///
/// The `agent` is the attestor, and the `provider_name` is a `String` that names the identity
/// provider for which they are attesting identities.
#[hdk_extern]
pub fn get_all_external_id_attestors(_: ()) -> ExternResult<Vec<(AgentPubKey, String)>> {
let pairs = get_links(
GetLinksInputBuilder::try_new(
hash_identifier("all_external_id_attestors".into())?,
LinkTypes::ExternalIdAttestor,
)?
.build(),
)?
.into_iter()
.filter_map(|link| {
let agent = AgentPubKey::try_from(link.target).ok()?;
let provider_name = str::from_utf8(&link.tag.into_inner()).ok()?.to_string();
Some((agent, provider_name))
})
.collect();
Ok(pairs)
}
3 changes: 3 additions & 0 deletions crates/username_registry_integrity/src/link_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub enum LinkTypes {
AgentMetadata,
AgentToWalletAttestations,
AgentToExternalIdAttestation,
ExternalIdAttestor,
ExternalIdToAttestation,
Publisher,
NameToOracleDocument,
Expand Down Expand Up @@ -36,6 +37,7 @@ impl LinkTypes {
LinkTypes::AgentToExternalIdAttestation => {
validate_create_link_agent_to_external_id_attestations
}
LinkTypes::ExternalIdAttestor => validate_create_link_external_id_attestor,
LinkTypes::ExternalIdToAttestation => validate_create_link_external_id_to_attestation,
LinkTypes::Publisher => validate_create_link_publisher,
LinkTypes::NameToOracleDocument => validate_create_link_name_to_oracle_document,
Expand Down Expand Up @@ -65,6 +67,7 @@ impl LinkTypes {
LinkTypes::AgentToWalletAttestations => {
validate_delete_link_agent_to_wallet_attestations
}
LinkTypes::ExternalIdAttestor => validate_delete_link_external_id_attestor,
LinkTypes::AgentToExternalIdAttestation => {
validate_delete_link_agent_to_external_id_attestations
}
Expand Down
35 changes: 35 additions & 0 deletions crates/username_registry_validation/src/external_id_attestor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use core::str;

use hdi::prelude::*;

pub fn validate_create_link_external_id_attestor(
action: CreateLink,
_base_address: AnyLinkableHash,
target_address: AnyLinkableHash,
tag: LinkTag,
) -> ExternResult<ValidateCallbackResult> {
if AnyLinkableHash::from(action.author) != target_address {
return Ok(ValidateCallbackResult::Invalid(
"Target of attestor link must author".to_string(),
));
}

if str::from_utf8(&tag.into_inner()).is_err() {
return Ok(ValidateCallbackResult::Invalid(
"Tag must be a valid utf-8 string".to_string(),
));
}

Ok(ValidateCallbackResult::Valid)
}
pub fn validate_delete_link_external_id_attestor(
_action: DeleteLink,
_original_action: CreateLink,
_base: AnyLinkableHash,
_target: AnyLinkableHash,
_tag: LinkTag,
) -> ExternResult<ValidateCallbackResult> {
Ok(ValidateCallbackResult::Invalid(String::from(
"Attestor links cannot be deleted",
)))
}
2 changes: 2 additions & 0 deletions crates/username_registry_validation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ pub mod evm_address_to_signing_offer;
pub use evm_address_to_signing_offer::*;
pub mod publisher;
pub use publisher::*;
pub mod external_id_attestor;
pub use external_id_attestor::*;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { expect, test } from "vitest";
import { dhtSync, runScenario } from "@holochain/tryorama";

import { setupPlayer } from "../utils/setup-happ.js";

test("Agents can list as external id attestors", async () => {
await runScenario(async (scenario) => {
const [alice, aliceCoordinators] = await setupPlayer(scenario);
const [bob, bobCoordinators] = await setupPlayer(scenario);
await scenario.shareAllAgents();

await expect(
aliceCoordinators.usernameRegistry.registerAsExternalIdAttestor(
"some-identity-provider"
)
).resolves.not.toThrow();

await dhtSync([alice, bob], alice.cells[0].cell_id[0]);

await expect(
bobCoordinators.usernameRegistry.getAllExternalIdAttestors()
).resolves.toEqual([[alice.agentPubKey, "some-identity-provider"]]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ test("Agents can list as publishers", async () => {
const [bob, bobCoordinators] = await setupPlayer(scenario);
await scenario.shareAllAgents();

// Authority creates a external_id Attestation
await expect(
aliceCoordinators.usernameRegistry.registerAsPublisher("some-topic")
).resolves.not.toThrow();

await dhtSync([alice, bob], alice.cells[0].cell_id[0]);

// Authority gets the external_id Attestation
await expect(
bobCoordinators.usernameRegistry.getAllPublishers()
).resolves.toEqual([[alice.agentPubKey, "some-topic"]]);
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./types";
export * from "./zome-functions";
export * from "./utils";
export * from "./integrity-enums";
15 changes: 8 additions & 7 deletions packages/types/src/integrity-enums/UsernameRegistryIntegrity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ export enum UsernameRegistryIntegrityLinkTypeIndex {
AgentMetadata = 1,
AgentToWalletAttestations = 2,
AgentToExternalIdAttestation = 3,
ExternalIdToAttestation = 4,
Publisher = 5,
NameToOracleDocument = 6,
RelateOracleDocumentName = 7,
NameToRecipe = 8,
NameToSigningOffer = 9,
EvmAddressToSigningOffer = 10,
ExternalIdAttestor = 4,
ExternalIdToAttestation = 5,
Publisher = 6,
NameToOracleDocument = 7,
RelateOracleDocumentName = 8,
NameToRecipe = 9,
NameToSigningOffer = 10,
EvmAddressToSigningOffer = 11,
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ export class UsernameRegistryCoordinator {
return this.callZomeFn("get_all_authored_username_attestations");
}

async getAllExternalIdAttestors(): Promise<[AgentPubKey, string][]> {
return this.callZomeFn("get_all_external_id_attestors");
}

async getAllPublishers(): Promise<[AgentPubKey, string][]> {
return this.callZomeFn("get_all_publishers");
}
Expand Down Expand Up @@ -245,6 +249,10 @@ export class UsernameRegistryCoordinator {
return this.callZomeFn("ingest_signed_username", signedUsername);
}

async registerAsExternalIdAttestor(tag: string): Promise<ActionHash> {
return this.callZomeFn("register_as_external_id_attestor", tag);
}

async registerAsPublisher(tag: string): Promise<ActionHash> {
return this.callZomeFn("register_as_publisher", tag);
}
Expand Down

0 comments on commit bcf0286

Please sign in to comment.