Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: register as external ID attester #120

Merged
merged 2 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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 tag is used to indicate the
/// identity provider for which you attest identities.
#[hdk_extern]
pub fn register_as_external_id_attestor(tag: String) -> ExternResult<ActionHash> {
create_link(
hash_identifier("all_external_id_attestors".into())?,
agent_info()?.agent_initial_pubkey,
LinkTypes::ExternalIdAttestor,
tag,
8e8b2c marked this conversation as resolved.
Show resolved Hide resolved
)
}

/// 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