1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use crate::{
    utils,
    key_registration::{
        CreateKeyInput,
        AppBindingInput,
        DerivationDetailsInput,
    },
};
use crate::hdi_extensions::{
    guest_error,
    ScopedTypeConnector,
};
use crate::hdk_extensions::{
    agent_id,
    must_get,
};

use deepkey::*;
use hdk::prelude::*;


pub fn create_keyset_root() -> ExternResult<ActionHash> {
    let fda: AgentPubKey = agent_info()?.agent_latest_pubkey;
    let fda_bytes = fda.clone().into_inner();

    let esigs = sign_ephemeral_raw(vec![ fda_bytes ])?;
    let [signed_fda, ..] = esigs.signatures.as_slice() else {
        return Err(guest_error!("sign_ephemeral returned wrong number of signatures".to_string()))
    };

    let keyset_root = KeysetRoot::new(
        fda.clone(),
        esigs.key.get_raw_32().try_into()
            .map_err( |e| guest_error!(format!("Failed AgentPubKey to [u8;32] conversion: {:?}", e)) )?,
        signed_fda.to_owned()
    );
    let create_hash = create_entry( keyset_root.to_input() )?;

    init_change_rule( 1, vec![
        fda.get_raw_32().try_into()
            .map_err(|e| guest_error!(format!(
                "FDA.get_raw_32() did not have 32 elements; this should be unreachable -> {}", e
            )))?,
    ])?;

    let dna_hash = dna_info()?.hash;

    // Register the FDA as a key under this KSR
    crate::key_registration::create_key(CreateKeyInput {
        key_generation: KeyGeneration {
            new_key: fda.clone(),
            new_key_signing_of_author: sign_raw( fda, agent_id()?.into_inner() )?,
        },
        app_binding: AppBindingInput {
            app_name: "deepkey".to_string(),
            installed_app_id: "deepkey".to_string(),
            dna_hashes: vec![ dna_hash ],
            metadata: Default::default(),
        },
        derivation_details: Some(DerivationDetailsInput {
            app_index: 0,
            key_index: 0,
            derivation_seed: vec![],
            derivation_bytes: vec![],
        }),
        create_only: false,
    })?;

    Ok( create_hash )
}


pub fn init_change_rule(
    sigs_required: u8,
    revocation_keys: Vec<KeyBytes>
) -> ExternResult<ActionHash> {
    let ksr_addr = utils::query_keyset_root_addr()?;
    let new_authority_spec = AuthoritySpec::new(
        sigs_required,
        revocation_keys,
    );
    let auth_spec_bytes = utils::serialize( &new_authority_spec )?;
    let signed_bytes = sign( agent_id()?, auth_spec_bytes )?;

    let spec_change = AuthorizedSpecChange::new(
        new_authority_spec, vec![(0, signed_bytes)]
    );

    let change_rule = ChangeRule::new(
        ksr_addr.clone(),
        spec_change,
    );

    Ok( crate::change_rule::create_change_rule( change_rule )? )
}


#[hdk_extern]
pub fn get_keyset_root(ksr_addr: ActionHash) -> ExternResult<KeysetRoot> {
    must_get( &ksr_addr )?.try_into()
}


// Get all of the keys registered on the keyset, across all the deepkey agents
#[hdk_extern]
pub fn query_apps_with_keys(_:()) -> ExternResult<Vec<(AppBinding, Vec<KeyMeta>)>> {
    let key_metas : Vec<(ActionHash, KeyMeta)> = utils::query_entry_type( EntryTypesUnit::KeyMeta )?
        .into_iter()
        .filter_map( |record| Some((
            record.action_address().to_owned(),
            KeyMeta::try_from(record).ok()?,
        )))
        .collect();

    Ok(
        utils::query_entry_type( EntryTypesUnit::AppBinding )?
            .into_iter()
            .filter( |record| record.action().action_type() == ActionType::Create )
            .filter_map( |record| Some((
                record.action_address().to_owned(),
                AppBinding::try_from(record).ok()?,
            )))
            .map( |(addr, app_binding)| {
                (
                    app_binding,
                    key_metas.iter()
                        .filter( |(_, key_meta)| key_meta.app_binding_addr == addr )
                        .map( |(_, key_meta)| key_meta )
                        .cloned()
                        .collect(),
                )
            })
            .collect()
    )
}


// #[hdk_extern]
// pub fn query_key_registrations(_:()) -> ExternResult<Vec<(ActionHash, Vec<KeyRegistration>)>> {
// }