Skip to content

Commit

Permalink
remove invitation functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
petersalomonsen committed Dec 25, 2023
1 parent e1394e1 commit 10804df
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 240 deletions.
245 changes: 6 additions & 239 deletions nearcontract/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use ed25519_dalek::PublicKey as DalekPK;
use ed25519_dalek::Signature as DalekSig;
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::collections::LookupMap;
use near_sdk::PublicKey;
use near_sdk::{base64, env, near_bindgen, PanicOnDefault};
use near_sdk::{env, near_bindgen, PanicOnDefault};
use std::collections::HashMap;

pub type Permission = u32;
Expand All @@ -13,24 +9,8 @@ const PERMISSION_CONTRIBUTOR: Permission = 0x02;
const PERMISSION_READER: Permission = 0x04;
const PERMISSION_FREE: Permission = 0x08;
static EVERYONE: &str = "EVERYONE";
pub type InvitationId = u64;

const INVITATIONS_KEY: &[u8] = b"INVITATIONS";
const INVITATION_ID_KEY: &[u8] = b"INVITATION_ID";
const REPOSITORY_PERMISSION_KEY: &[u8] = b"rp";

#[derive(BorshDeserialize, BorshSerialize)]
pub struct Invitation {
path: String,
permission: Permission,
signingkey: PublicKey,
}

#[derive(PanicOnDefault, BorshDeserialize, BorshSerialize)]
pub struct Invitations {
invitations: HashMap<InvitationId, Invitation>,
}

#[near_bindgen]
#[derive(PanicOnDefault, BorshDeserialize, BorshSerialize)]
pub struct RepositoryPermission {
Expand All @@ -40,7 +20,7 @@ pub struct RepositoryPermission {
#[near_bindgen]
#[derive(PanicOnDefault, BorshDeserialize, BorshSerialize)]
pub struct Contract {
permission: LookupMap<String, HashMap<String, Permission>>,
permission: LookupMap<String, HashMap<String, Permission>>
}

#[near_bindgen]
Expand All @@ -59,6 +39,7 @@ impl Contract {
contract.permission.insert(&key, &value);
}
}

contract
}

Expand Down Expand Up @@ -112,82 +93,6 @@ impl Contract {
return PERMISSION_FREE;
}
}

fn load_invitations(&self) -> Invitations {
return env::storage_read(INVITATIONS_KEY)
.map(|data| {
Invitations::try_from_slice(&data).expect("Cannot deserialize the invitations.")
})
.unwrap_or_default();
}

fn save_invitations(&self, invitations: Invitations) {
env::storage_write(
INVITATIONS_KEY,
&invitations
.try_to_vec()
.expect("Cannot serialize invitations."),
);
}

pub fn invite(&mut self, path: String, permission: Permission) -> u64 {
let mut invitations = self.load_invitations();

let invitationidbuf = env::storage_read(INVITATION_ID_KEY);
let invitationid = if invitationidbuf.is_some() {
invitationidbuf
.unwrap()
.as_slice()
.read_u64::<BigEndian>()
.unwrap()
} else {
1
};

let caller_account_id = env::signer_account_id();
if self.get_permission(caller_account_id.to_string(), path.to_string()) == PERMISSION_OWNER
{
invitations.invitations.insert(
invitationid,
Invitation {
permission: permission,
path: path,
signingkey: env::signer_account_pk(),
},
);
self.save_invitations(invitations);
let mut wtr = vec![];
wtr.write_u64::<BigEndian>(invitationid + 1).unwrap();
env::storage_write(INVITATION_ID_KEY, wtr.as_slice());
return invitationid;
} else {
panic!("You are not the owner of the path");
}
}

pub fn redeem_invitation(&mut self, invitationid: InvitationId, signature: String) -> bool {
let caller_account_id = env::signer_account_id();
let mut invitations = self.load_invitations();
let invitation = invitations.invitations.get(&invitationid).unwrap();

let pk = DalekPK::from_bytes(&invitation.signingkey.as_bytes()[1..].to_vec()).unwrap();
let sig = DalekSig::from_bytes(base64::decode(&signature).unwrap().as_slice()).unwrap();

let signedmessage = format!("invitation{}", invitationid);

if !pk.verify_strict(signedmessage.as_bytes(), &sig).is_ok() {
panic!("Invalid signature");
}

let mut path_users = self.permission.get(&invitation.path).unwrap().clone();
path_users.insert(caller_account_id.to_string(), invitation.permission);
self.permission
.insert(&invitation.path.to_string(), &path_users);

invitations.invitations.remove(&invitationid);
self.save_invitations(invitations);
return true;
}
}

/*
Expand All @@ -206,14 +111,11 @@ mod tests {
use near_sdk::{test_utils::VMContextBuilder, testing_env, VMContext};

const REQUIRED_ATTACHED_DEPOSIT: u128 = 100000000000000000000000;
const INVITATION_SIGNATURE: &str =
"LtXiPcOxOC8n5/qiICscp3P5Ku8ymC3gj1eYJuq8GFR9co2pZYwbWLBiu5CrtVFtvmeWwMzOIkp4tJaosJ40Dg==";

// part of writing unit tests is setting up a mock context
// in this example, this is only needed for env::log in the contract
fn get_context(
signer_account_id: String,
input: Vec<u8>,
is_view: bool,
attached_deposit: u128,
) -> VMContext {
Expand All @@ -238,7 +140,6 @@ mod tests {
fn set_get_permission() {
let context = get_context(
"peter".to_string(),
vec![],
false,
REQUIRED_ATTACHED_DEPOSIT,
);
Expand Down Expand Up @@ -266,7 +167,6 @@ mod tests {
fn set_get_permission_different_context() {
let context = get_context(
"johan".to_string(),
vec![],
false,
REQUIRED_ATTACHED_DEPOSIT,
);
Expand All @@ -293,15 +193,15 @@ mod tests {
)
);

let context2 = get_context("peter".to_string(), vec![], false, 0);
let context2 = get_context("peter".to_string(), false, 0);
testing_env!(context2);

assert_eq!(
PERMISSION_CONTRIBUTOR,
contract.get_permission("peter".to_string(), "testrepo".to_string())
);

let context3 = get_context("johan".to_string(), vec![], false, 0);
let context3 = get_context("johan".to_string(), false, 0);
testing_env!(context3);

assert_eq!(
Expand All @@ -314,7 +214,6 @@ mod tests {
fn deny_set_permission() {
let context = get_context(
"johan".to_string(),
vec![],
false,
REQUIRED_ATTACHED_DEPOSIT,
);
Expand All @@ -335,7 +234,6 @@ mod tests {

testing_env!(get_context(
"someotheruser".to_string(),
vec![],
false,
REQUIRED_ATTACHED_DEPOSIT,
));
Expand All @@ -355,7 +253,6 @@ mod tests {
fn read_permission_for_everyone() {
let context = get_context(
"peter".to_string(),
vec![],
false,
REQUIRED_ATTACHED_DEPOSIT,
);
Expand Down Expand Up @@ -400,7 +297,6 @@ mod tests {
fn write_permission_for_everyone_read_for_anonymous() {
let context = get_context(
"peter".to_string(),
vec![],
false,
REQUIRED_ATTACHED_DEPOSIT,
);
Expand Down Expand Up @@ -456,7 +352,7 @@ mod tests {

#[test]
fn require_attached_deposits() {
let context = get_context("peter".to_string(), vec![], false, 2);
let context = get_context("peter".to_string(), false, 2);
testing_env!(context);
let mut contract = Contract::init();

Expand All @@ -469,133 +365,4 @@ mod tests {
}));
assert!(result.is_err());
}

#[test]
fn invite_and_redeem_invitation() {
testing_env!(get_context(
"peter".to_string(),
vec![],
false,
REQUIRED_ATTACHED_DEPOSIT
));
let mut contract = Contract::init();
let path = "lalala";
contract.set_permission(path.to_string(), "peter".to_string(), PERMISSION_OWNER);
let invitationid = contract.invite(path.to_string(), PERMISSION_READER);
contract.redeem_invitation(invitationid, INVITATION_SIGNATURE.to_string());
assert_eq!(
PERMISSION_READER,
contract.get_permission("peter".to_string(), path.to_string())
);
}

#[test]
fn invite_without_ownership() {
let context = get_context(
"peter".to_string(),
vec![],
false,
REQUIRED_ATTACHED_DEPOSIT,
);
testing_env!(context);
let mut contract = Contract::init();
let path = "lalala";
contract.set_permission(
path.to_string(),
"peter".to_string(),
PERMISSION_CONTRIBUTOR,
);

let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
return contract.invite(path.to_string(), PERMISSION_READER);
}));
assert!(result.is_err());
}

#[test]
fn invite_invalid_signature() {
let context = get_context(
"peter".to_string(),
vec![],
false,
REQUIRED_ATTACHED_DEPOSIT,
);
testing_env!(context);
let mut contract = Contract::init();
let path = "lalala";
contract.set_permission(path.to_string(), "peter".to_string(), PERMISSION_OWNER);
let invitationid = contract.invite(path.to_string(), PERMISSION_READER);

let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
return contract.redeem_invitation(
invitationid,
"903zZRlh45/KFMoFbpljVffajuNPeEB7J0PLJ7XylcvxdAJ+imQn0vGv9Tp4H/moqr5xJk+jItCv4JAIc/vQBA==".to_string()
);
}));
assert!(result.is_err());
}

#[test]
fn invite_and_redeem_invitation_twice() {
let context = get_context(
"peter".to_string(),
vec![],
false,
REQUIRED_ATTACHED_DEPOSIT,
);
testing_env!(context);
let mut contract = Contract::init();
let path = "lalala";
contract.set_permission(path.to_string(), "peter".to_string(), PERMISSION_OWNER);
let invitationid = contract.invite(path.to_string(), PERMISSION_READER);

contract.redeem_invitation(invitationid, INVITATION_SIGNATURE.to_string());
assert_eq!(
PERMISSION_READER,
contract.get_permission("peter".to_string(), path.to_string())
);

let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
contract.redeem_invitation(invitationid, INVITATION_SIGNATURE.to_string());
}));
assert!(result.is_err());
}
#[test]
fn invite_and_redeem_invitation_old_signature() {
let context = get_context(
"peter".to_string(),
vec![],
false,
REQUIRED_ATTACHED_DEPOSIT,
);
testing_env!(context);
let mut contract = Contract::init();
let mut path = "lalala";
contract.set_permission(path.to_string(), "peter".to_string(), PERMISSION_OWNER);
let mut invitationid = contract.invite(path.to_string(), PERMISSION_READER);

contract.redeem_invitation(invitationid, INVITATION_SIGNATURE.to_string());
assert_eq!(
PERMISSION_READER,
contract.get_permission("peter".to_string(), path.to_string())
);

path = "abc";
contract.set_permission(path.to_string(), "peter".to_string(), PERMISSION_OWNER);
invitationid = contract.invite(path.to_string(), PERMISSION_READER);
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
contract.redeem_invitation(invitationid, INVITATION_SIGNATURE.to_string());
}));
assert!(result.is_err());

contract.redeem_invitation(
invitationid,
"903zZRlh45/KFMoFbpljVffajuNPeEB7J0PLJ7XylcvxdAJ+imQn0vGv9Tp4H/moqr5xJk+jItCv4JAIc/vQBA==".to_string()
);

assert_eq!(
PERMISSION_READER,
contract.get_permission("peter".to_string(), path.to_string())
);
}
}
2 changes: 1 addition & 1 deletion nearcontract/tests/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod test_env;
use {crate::test_env::*, serde_json::json};

#[tokio::test]
async fn test_deploy_contract_self_upgrade() -> anyhow::Result<()> {
async fn test_migration() -> anyhow::Result<()> {
let contract = init_contracts().await?;
let set_permission_result = contract
.call("set_permission")
Expand Down

0 comments on commit 10804df

Please sign in to comment.