Skip to content

Commit

Permalink
Merge pull request #36 from Holo-Host/feat/jurisdiction
Browse files Browse the repository at this point in the history
feat/jurisdiction
  • Loading branch information
zeeshan595 authored Mar 21, 2024
2 parents fb13f6a + c154415 commit 6b2c680
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 29 deletions.
16 changes: 16 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,19 @@ This project uses [`cargo-husky`] to provide Git hooks for running these command
If you need to skip running Git hooks, use `git push --no-verify`.

[`cargo-husky`]: https://github.com/rhysd/cargo-husky

# Installing and Uninstalling hApps
holo auto installer does 2 main things.
- Install a happs that are supposed to be installed on the holoport but are not installed
`install_holo_hosted_happs`
- Uninstall happs that are not supposed to be installed on the holoport but are installed
`uninstall_ineligible_happs`

Generally if you want to restrict something so it is not installed on the holoport you can use the function inside
`uninstall_apps.rs` called `should_be_installed` If this returns a `false` the happ will be uninstalled form the holoport.

### HBS
There is a connection made to HBS at the start of the script. Please look at `hbs.rs` if you need to communicate with HBS. Please make any HBS requests in this file and then expose it to the app.

### Zome
If you are making a zome call. Look at `host_zome_calls.rs`. Currently there are 2 cell ids setup, `core_happ` and `holofuel`. If you want to expand the functionality and add additional cell ids then please look at `connect` function. All zome calls should be made here and exposed to the other functions
2 changes: 1 addition & 1 deletion flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/entries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ pub struct PresentedHappBundle {
pub uid: Option<String>,
pub bundle_url: String,
pub name: String,
pub categories: Vec<String>,
pub jurisdictions: Vec<String>,
pub exclude_jurisdictions: bool,
pub special_installed_app_id: Option<String>,
pub host_settings: HostSettings,
}
Expand Down
23 changes: 13 additions & 10 deletions src/hbs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ use hpos_hc_connect::{hpos_agent::get_hpos_config, CoreAppAgent};
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize)]
struct HostingCriteria {
pub struct HostingCriteria {
#[allow(dead_code)]
id: String,
#[allow(dead_code)]
jurisdiction: String,
kyc: KycLevel,
pub id: Option<String>,
pub jurisdiction: Option<String>,
pub kyc: KycLevel,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub enum KycLevel {
Expand All @@ -28,14 +27,18 @@ impl HbsClient {
let client = reqwest::Client::builder().build()?;
Ok(Self { client })
}
// return kyc level and assumes default as level 1
pub async fn get_kyc_level(&self) -> KycLevel {
pub async fn get_hosting_criteria(&self) -> HostingCriteria {
match self.get_access_token().await {
Ok(v) => v.kyc,
Ok(v) => v,
Err(e) => {
tracing::warn!("Unable to get kyc: {:?}", e);
tracing::warn!("Unable to get kyc & jurisdiction: {:?}", e);
tracing::warn!("returning default kyc level 1");
KycLevel::Level1
tracing::warn!("returning default jurisdiction of None");
HostingCriteria {
id: None,
jurisdiction: None,
kyc: KycLevel::Level1,
}
}
}
}
Expand Down
40 changes: 32 additions & 8 deletions src/host_zome_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,22 @@ pub struct HappBundle {
pub is_paused: bool,
pub is_host_disabled: bool,
pub special_installed_app_id: Option<String>,
pub jurisdictions: Vec<String>,
pub exclude_jurisdictions: bool,
}

#[derive(Clone)]
pub struct CoreAppClient {
pub app_ws: AppWebsocket,
pub cell: ProvisionedCell,
pub core_happ_cell: ProvisionedCell,
pub holofuel_cell: ProvisionedCell,
pub keystore: MetaLairClient,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct HappAndHost {
pub happ_id: ActionHashB64,
pub holoport_id: ActionHashB64,
pub holoport_id: String,
pub is_automated: Option<bool>,
}

Expand Down Expand Up @@ -61,15 +65,22 @@ impl CoreAppClient {
}) => {
trace!("got app info");

let cell: holochain_conductor_api::ProvisionedCell =
let core_happ_cell: holochain_conductor_api::ProvisionedCell =
match &cell_info.get("core-app").unwrap()[0] {
CellInfo::Provisioned(c) => c.clone(),
_ => return Err(anyhow!("core-app cell not found")),
};
trace!("got cell {:?}", cell);
trace!("got core happ cell {:?}", core_happ_cell);
let holofuel_cell: holochain_conductor_api::ProvisionedCell =
match &cell_info.get("holofuel").unwrap()[0] {
CellInfo::Provisioned(c) => c.clone(),
_ => return Err(anyhow!("holofuel cell not found")),
};
trace!("got holofuel cell {:?}", holofuel_cell);
Ok(CoreAppClient {
app_ws,
cell,
core_happ_cell,
holofuel_cell,
keystore,
})
}
Expand All @@ -79,6 +90,7 @@ impl CoreAppClient {

pub async fn zome_call<T, R>(
&mut self,
cell: ProvisionedCell,
zome_name: ZomeName,
fn_name: FunctionName,
payload: T,
Expand All @@ -89,12 +101,12 @@ impl CoreAppClient {
{
let (nonce, expires_at) = fresh_nonce()?;
let zome_call_unsigned = ZomeCallUnsigned {
cell_id: self.cell.cell_id.clone(),
cell_id: cell.cell_id.clone(),
zome_name,
fn_name,
payload: ExternIO::encode(payload)?,
cap_secret: None,
provenance: self.cell.cell_id.agent_pubkey().clone(),
provenance: cell.cell_id.agent_pubkey().clone(),
nonce,
expires_at,
};
Expand Down Expand Up @@ -131,8 +143,14 @@ pub async fn get_all_published_hosted_happs(
) -> Result<Vec<HappBundle>> {
trace!("get_all_published_hosted_happs");

let core_happ_cell = core_app_client.clone().core_happ_cell;
let happ_bundles: Vec<entries::PresentedHappBundle> = core_app_client
.zome_call(ZomeName::from("hha"), FunctionName::from("get_happs"), ())
.zome_call(
core_happ_cell,
ZomeName::from("hha"),
FunctionName::from("get_happs"),
(),
)
.await?;

let happ_bundle_ids = happ_bundles
Expand All @@ -151,6 +169,8 @@ pub async fn get_all_published_hosted_happs(
is_paused: happ.is_paused,
is_host_disabled: happ.host_settings.is_host_disabled,
special_installed_app_id: happ.special_installed_app_id,
jurisdictions: happ.jurisdictions,
exclude_jurisdictions: happ.exclude_jurisdictions,
}
})
.collect();
Expand All @@ -162,8 +182,10 @@ pub async fn get_all_published_hosted_happs(
pub async fn get_pending_transactions(
core_app_client: &mut CoreAppClient,
) -> Result<PendingTransaction> {
let holofuel_cell = core_app_client.clone().holofuel_cell;
let pending_transactions: PendingTransaction = core_app_client
.zome_call(
holofuel_cell,
ZomeName::from("transactor"),
FunctionName::from("get_pending_transactions"),
(),
Expand All @@ -175,8 +197,10 @@ pub async fn get_pending_transactions(
}

pub async fn disable_happ(core_app_client: &mut CoreAppClient, payload: HappAndHost) -> Result<()> {
let core_happ_cell = core_app_client.clone().core_happ_cell;
core_app_client
.zome_call(
core_happ_cell,
ZomeName::from("hha"),
FunctionName::from("disable_happ"),
payload,
Expand Down
2 changes: 2 additions & 0 deletions src/install_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ pub async fn install_holo_hosted_happs(
is_paused,
is_host_disabled,
special_installed_app_id,
exclude_jurisdictions: _,
jurisdictions: _,
} in happs
{
// Check if special happ is installed and do nothing if it is installed
Expand Down
15 changes: 13 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@ use crate::host_zome_calls::{get_pending_transactions, CoreAppClient};
pub async fn run(core_happ: &config::Happ, config: &config::Config) -> Result<()> {
info!("Activating holo hosted apps");
let hbs_connect = HbsClient::connect()?;
let kyc_level = hbs_connect.get_kyc_level().await;
let hosting_criteria = hbs_connect.get_hosting_criteria().await;
let kyc_level = hosting_criteria.kyc;
debug!("Got kyc level {:?}", &kyc_level);
let jurisdiction = hosting_criteria.jurisdiction;
debug!("Got jurisdiction from hbs {:?}", jurisdiction);

let is_kyc_level_2 = kyc_level == KycLevel::Level2;

let mut core_app_client = CoreAppClient::connect(core_happ, config).await?;
Expand All @@ -38,6 +42,13 @@ pub async fn run(core_happ: &config::Happ, config: &config::Config) -> Result<()

let list_of_happs = get_all_published_hosted_happs(&mut core_app_client).await?;
install_holo_hosted_happs(config, &list_of_happs, is_kyc_level_2).await?;
uninstall_ineligible_happs(config, &list_of_happs, is_kyc_level_2, suspended_happs).await?;
uninstall_ineligible_happs(
config,
&list_of_happs,
is_kyc_level_2,
suspended_happs,
jurisdiction,
)
.await?;
Ok(())
}
13 changes: 6 additions & 7 deletions src/suspend_happs.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
pub use crate::config;
pub use crate::host_zome_calls::HappBundle;
use crate::host_zome_calls::{
disable_happ, CoreAppClient, HappAndHost, InvoiceNote, PendingTransaction, POS,
};
pub use crate::websocket::AdminWebsocket;
use anyhow::Result;
use chrono::Utc;
use holochain_types::dna::HoloHashB64;
use std::env;
use std::process::Command;
use tracing::debug;

pub async fn suspend_unpaid_happs(
core_app_client: &mut CoreAppClient,
Expand All @@ -18,15 +15,16 @@ pub async fn suspend_unpaid_happs(

let password =
env::var("DEVICE_SEED_DEFAULT_PASSWORD").expect("DEVICE_SEED_DEFAULT_PASSWORD is not set");
let hpos_config_path = env::var("HPOS_CONFIG_PATH")
.expect("HPOS_CONFIG_PATH not found. please add the path to the environment variable");
let holoport_id_output = Command::new("hpos-config-into-base36-id")
.arg("--config-path")
.arg("/run/hpos-init/hp-*.json")
.arg(hpos_config_path)
.arg("--password")
.arg(password)
.output()
.expect("Failed to execute command");
let holoport_id = String::from_utf8_lossy(&holoport_id_output.stdout);
let holoport_id_holo_hash = HoloHashB64::from_b64_str(&holoport_id)?;

for invoice in &pending_transactions.invoice_pending {
if let Some(POS::Hosting(_)) = &invoice.proof_of_service {
Expand All @@ -42,7 +40,7 @@ pub async fn suspend_unpaid_happs(
core_app_client,
HappAndHost {
happ_id: hha_id.clone(),
holoport_id: holoport_id_holo_hash.clone(),
holoport_id: holoport_id.to_string(),
is_automated: Some(true),
},
)
Expand All @@ -58,5 +56,6 @@ pub async fn suspend_unpaid_happs(
}
}

debug!("suspend happs completed: {:?}", suspended_happs);
Ok(suspended_happs)
}
34 changes: 33 additions & 1 deletion src/uninstall_apps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub use crate::host_zome_calls::HappBundle;
pub use crate::websocket::AdminWebsocket;
use anyhow::{Context, Result};
use itertools::Itertools;
use tracing::{info, trace};
use tracing::{debug, info, trace};

Check failure on line 6 in src/uninstall_apps.rs

View workflow job for this annotation

GitHub Actions / Lints

unused import: `debug`

Check warning on line 6 in src/uninstall_apps.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused import: `debug`

/// Ineligible Happs = old holo-hosted happs, holo-disabled happs, or happs with invalid pricing for kyc level
/// Handles ineligible happs for 2 cases - identified and anonymous hosted agents:
Expand All @@ -14,6 +14,7 @@ pub async fn uninstall_ineligible_happs(
published_happs: &[HappBundle],
is_kyc_level_2: bool,
suspended_happs: Vec<String>,
jurisdiction: Option<String>,
) -> Result<()> {
info!("Checking to uninstall happs that were removed from the hosted list....");

Expand All @@ -36,6 +37,7 @@ pub async fn uninstall_ineligible_happs(
published_happs,
is_kyc_level_2,
suspended_happs.clone(),
jurisdiction.clone(),
)
.await
{
Expand Down Expand Up @@ -83,12 +85,42 @@ pub async fn should_be_installed(
published_happs: &[HappBundle],
is_kyc_level_2: bool,
suspended_happs: Vec<String>,
jurisdiction: Option<String>,
) -> bool {
if suspended_happs.contains(running_happ_id) {
trace!("Disabling suspended happ {}", running_happ_id);
return false;
}

match jurisdiction {
Some(jurisdiction) => {
if let Some(happ) = published_happs
.iter()
.find(|&happ| happ.happ_id.to_string() == *running_happ_id)
{
let mut is_jurisdiction_in_list = false;
if let Some(_happ_jurisdiction) = happ
.jurisdictions
.iter()
.find(|&happ_jurisdiction| *happ_jurisdiction == jurisdiction)
{
is_jurisdiction_in_list = true;
}
if happ.exclude_jurisdictions && is_jurisdiction_in_list {
return false;
}
if !happ.exclude_jurisdictions && !is_jurisdiction_in_list {
return false;
}
}
}
None => {
warn!("jurisdiction not available for holoport");

Check failure on line 118 in src/uninstall_apps.rs

View workflow job for this annotation

GitHub Actions / Lints

cannot find macro `warn` in this scope

Check failure on line 118 in src/uninstall_apps.rs

View workflow job for this annotation

GitHub Actions / Test Suite

cannot find macro `warn` in this scope
warn!("happ {} won't be installed", running_happ_id);

Check failure on line 119 in src/uninstall_apps.rs

View workflow job for this annotation

GitHub Actions / Lints

cannot find macro `warn` in this scope

Check failure on line 119 in src/uninstall_apps.rs

View workflow job for this annotation

GitHub Actions / Test Suite

cannot find macro `warn` in this scope
return false;
}
}

trace!("`should_be_installed check` for {}", running_happ_id);

if !is_hosted_happ(running_happ_id) {
Expand Down

0 comments on commit 6b2c680

Please sign in to comment.