#![allow(unused_imports)]
use error_chain::bail;
use qrcode::render::unicode;
use qrcode::QrCode;
use regex::Regex;
use std::io::stdout;
use std::io::Write;
use std::ops::Deref;
use std::sync::Arc;
use tracing::{debug, error, info, instrument, span, trace, warn, Level};
use url::Url;
use ate::error::LoadError;
use ate::error::TransformError;
use ate::prelude::*;
use ate::session::AteRolePurpose;
use ate::utils::chain_key_4hex;
use crate::error::*;
use crate::helper::*;
use crate::model::*;
use crate::prelude::*;
use crate::request::*;
use crate::service::AuthService;
impl AuthService {
pub async fn process_create_group(
self: Arc<Self>,
request: CreateGroupRequest,
) -> Result<CreateGroupResponse, CreateGroupFailed> {
info!("create group: {}", request.group);
let web_key = {
let web_key_entropy = format!("web-read:{}", request.group);
let web_key_entropy = AteHash::from_bytes(web_key_entropy.as_bytes());
self.compute_web_key_from_hash(&web_key_entropy)
};
let edge_key = {
let edge_key_entropy = format!("edge-read:{}", request.group);
let edge_key_entropy = AteHash::from_bytes(edge_key_entropy.as_bytes());
self.compute_edge_key_from_hash(&edge_key_entropy)
};
let advert = match Arc::clone(&self)
.process_query(QueryRequest {
identity: request.identity.clone(),
})
.await
{
Ok(a) => Ok(a),
Err(QueryFailed::Banned) => Err(CreateGroupFailed::OperatorBanned),
Err(QueryFailed::NotFound) => Err(CreateGroupFailed::OperatorNotFound),
Err(QueryFailed::Suspended) => Err(CreateGroupFailed::AccountSuspended),
Err(QueryFailed::InternalError(code)) => Err(CreateGroupFailed::InternalError(code)),
}?
.advert;
let request_nominal_read_key = advert.nominal_encrypt;
let request_sudo_read_key = advert.sudo_encrypt;
let regex = Regex::new("^/{0,1}([a-zA-Z0-9_\\.\\-]{1,})$").unwrap();
if let Some(_captures) = regex.captures(request.group.as_str()) {
if request.group.len() <= 0 {
return Err(CreateGroupFailed::InvalidGroupName(
"the group name you specified is not long enough".to_string(),
));
}
} else {
return Err(CreateGroupFailed::InvalidGroupName(
"the group name you specified is invalid".to_string(),
));
}
let master_write_key = match self.master_session.user.write_keys().next() {
Some(a) => a.clone(),
None => {
return Err(CreateGroupFailed::NoMasterKey);
}
};
let key_size = request_nominal_read_key.size();
let master_key = match self.master_key() {
Some(a) => a,
None => {
return Err(CreateGroupFailed::NoMasterKey);
}
};
let group_chain_key = chain_key_4hex(&request.group, Some("redo"));
let chain = self.registry.open(&self.auth_url, &group_chain_key).await?;
let dio = chain.dio_mut(&self.master_session).await;
let gid_offset = u32::MAX as u64;
let mut gid = None;
for n in 0u32..50u32 {
let mut gid_test = estimate_group_name_as_gid(request.group.clone());
if gid_test < 1000 {
gid_test = gid_test + 1000;
}
gid_test = gid_test + n;
if dio.exists(&PrimaryKey::from(gid_test as u64)).await {
continue;
}
if dio
.exists(&PrimaryKey::from(gid_test as u64 + gid_offset))
.await
{
continue;
}
gid = Some(gid_test);
break;
}
let gid = match gid {
Some(a) => a,
None => {
return Err(CreateGroupFailed::NoMoreRoom);
}
};
let group_key = PrimaryKey::from(request.group.clone());
if dio.exists(&group_key).await {
return Err(CreateGroupFailed::AlreadyExists(
"the group with this name already exists".to_string(),
));
}
let owner_read = EncryptKey::generate(key_size);
let owner_private_read = PrivateEncryptKey::generate(key_size);
let owner_write = PrivateSignKey::generate(key_size);
let delegate_read = EncryptKey::generate(key_size);
let delegate_private_read = PrivateEncryptKey::generate(key_size);
let delegate_write = PrivateSignKey::generate(key_size);
let contributor_read = EncryptKey::generate(key_size);
let contributor_private_read = PrivateEncryptKey::generate(key_size);
let contributor_write = PrivateSignKey::generate(key_size);
let observer_read = EncryptKey::generate(key_size);
let observer_private_read = PrivateEncryptKey::generate(key_size);
let observer_write = PrivateSignKey::generate(key_size);
let web_server_read = EncryptKey::generate(key_size);
let web_server_private_read = PrivateEncryptKey::generate(key_size);
let web_server_write = PrivateSignKey::generate(key_size);
let contract_read_key = {
let contract_read_key_entropy = format!("contract-read:{}", request.group);
let contract_read_key_entropy =
AteHash::from_bytes(contract_read_key_entropy.as_bytes());
self.compute_contract_key_from_hash(&contract_read_key_entropy)
};
let finance_read = contract_read_key;
let finance_private_read = PrivateEncryptKey::generate(key_size);
let finance_write = PrivateSignKey::generate(key_size);
let edge_compute_read = EncryptKey::generate(key_size);
let edge_compute_private_read = PrivateEncryptKey::generate(key_size);
let edge_compute_write = PrivateSignKey::generate(key_size);
let broker_read = PrivateEncryptKey::generate(key_size);
let broker_write = PrivateSignKey::generate(key_size);
let mut super_session = self.master_session.clone();
super_session.user.add_read_key(&owner_read);
super_session.user.add_read_key(&delegate_read);
super_session.user.add_private_read_key(&owner_private_read);
super_session
.user
.add_private_read_key(&delegate_private_read);
super_session.user.add_write_key(&owner_write);
super_session.user.add_write_key(&delegate_write);
let dio = chain.dio_full(&super_session).await;
let group = Group {
name: request.group.clone(),
foreign: DaoForeign::default(),
gid,
roles: Vec::new(),
broker_read: broker_read.clone(),
broker_write: broker_write.clone(),
};
let mut group = dio.store_with_key(group, group_key.clone())?;
{
let mut group_mut = group.as_mut();
for purpose in vec![
AteRolePurpose::Owner,
AteRolePurpose::Delegate,
AteRolePurpose::Contributor,
AteRolePurpose::Finance,
AteRolePurpose::WebServer,
AteRolePurpose::EdgeCompute,
AteRolePurpose::Observer,
]
.iter()
{
let role_read;
let role_private_read;
let role_write;
match purpose {
AteRolePurpose::Owner => {
role_read = owner_read.clone();
role_private_read = owner_private_read.clone();
role_write = owner_write.clone();
}
AteRolePurpose::Delegate => {
role_read = delegate_read.clone();
role_private_read = delegate_private_read.clone();
role_write = delegate_write.clone();
}
AteRolePurpose::Contributor => {
role_read = contributor_read.clone();
role_private_read = contributor_private_read.clone();
role_write = contributor_write.clone();
}
AteRolePurpose::Finance => {
role_read = finance_read.clone();
role_private_read = finance_private_read.clone();
role_write = finance_write.clone();
}
AteRolePurpose::Observer => {
role_read = observer_read.clone();
role_private_read = observer_private_read.clone();
role_write = observer_write.clone();
}
AteRolePurpose::WebServer => {
role_read = web_server_read.clone();
role_private_read = web_server_private_read.clone();
role_write = web_server_write.clone();
}
AteRolePurpose::EdgeCompute => {
role_read = edge_compute_read.clone();
role_private_read = edge_compute_private_read.clone();
role_write = edge_compute_write.clone();
}
_ => {
role_read = EncryptKey::generate(key_size);
role_private_read = PrivateEncryptKey::generate(key_size);
role_write = PrivateSignKey::generate(key_size);
}
}
let access_key = match purpose {
AteRolePurpose::WebServer => web_key.clone(),
AteRolePurpose::EdgeCompute => edge_key.clone(),
_ => EncryptKey::generate(owner_private_read.size()),
};
let mut access = MultiEncryptedSecureData::new_ext(
&owner_private_read.as_public_key(),
access_key.clone(),
"owner".to_string(),
Authorization {
read: role_read.clone(),
private_read: role_private_read.clone(),
write: role_write.clone(),
},
)?;
if let AteRolePurpose::Owner = purpose {
access.add(
&request_sudo_read_key,
request.identity.clone(),
&owner_private_read,
)?;
} else if let AteRolePurpose::Finance = purpose {
access.add(
&request_sudo_read_key,
request.identity.clone(),
&owner_private_read,
)?;
} else if let AteRolePurpose::Delegate = purpose {
access.add(
&request_nominal_read_key,
request.identity.clone(),
&owner_private_read,
)?;
} else if let AteRolePurpose::Observer = purpose {
access.add(
&delegate_private_read.as_public_key(),
"delegate".to_string(),
&owner_private_read,
)?;
access.add(
&contributor_private_read.as_public_key(),
"contributor".to_string(),
&owner_private_read,
)?;
} else if let AteRolePurpose::WebServer = purpose {
access.add(
&delegate_private_read.as_public_key(),
"delegate".to_string(),
&owner_private_read,
)?;
access.add(
&contributor_private_read.as_public_key(),
"contributor".to_string(),
&owner_private_read,
)?;
} else if let AteRolePurpose::EdgeCompute = purpose {
access.add(
&delegate_private_read.as_public_key(),
"delegate".to_string(),
&owner_private_read,
)?;
} else {
access.add(
&delegate_private_read.as_public_key(),
"delegate".to_string(),
&owner_private_read,
)?;
}
let role = Role {
purpose: purpose.clone(),
read: role_read.hash(),
private_read: role_private_read.as_public_key().clone(),
write: role_write.as_public_key().clone(),
access,
};
group_mut.roles.push(role);
}
}
group.auth_mut().read = ReadOption::from_key(&master_key);
group.auth_mut().write =
WriteOption::Any(vec![master_write_key.hash(), owner_write.hash()]);
let advert_key_entropy = format!("advert:{}", request.group.clone()).to_string();
let advert_key = PrimaryKey::from(advert_key_entropy);
let advert = Advert {
identity: request.group.clone(),
id: AdvertId::GID(gid),
nominal_encrypt: observer_private_read.as_public_key().clone(),
nominal_auth: contributor_write.as_public_key().clone(),
sudo_encrypt: owner_private_read.as_public_key().clone(),
sudo_auth: owner_write.as_public_key().clone(),
broker_auth: broker_write.as_public_key().clone(),
broker_encrypt: broker_read.as_public_key().clone(),
};
let mut advert = dio.store_with_key(advert, advert_key.clone())?;
advert.auth_mut().read = ReadOption::Everyone(None);
advert.auth_mut().write = WriteOption::Inherit;
dio.commit().await?;
let session = complete_group_auth(group.deref(), AteSessionUser::default().into())?;
Ok(CreateGroupResponse {
key: group.key().clone(),
session,
})
}
}