Skip to content
79 changes: 79 additions & 0 deletions tests/enclave/accounting/AccountingEnclave/AccountSVD.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/* The concept of a modeled account allows for the depositing of funds into the account,
the withdrawal of money from the account, as well as the structuring of loans between accounts with a fixed daily interest rate.
However, it is set up in such a way that withdrawals are not possible as long as the account has outstanding debts. */
module.exports = {
ctor: function(usedID){
this.usedID = usedID;
this.balance = 0;
this.loans = [];

},
actions:{
deposit: function(amount){
this.balance += amount;
},
withdraw: function(amount){
if(this.balance - this.loanedAmount >= amount){
this.balance -= amount;
} else {
throw new Error("Assert failed: balance should be greater than or equal to amount");
}
},
loan: function(amount, dailyInterestRate, loanerId){
if(this.balance >= amount){
let loaner = this.session.lookup(loanerId);
if(loaner.loanedAmount == undefined) {
loaner.loanedAmount = amount;
loaner.dailyInterestRate = dailyInterestRate;
loaner.lenderId = this.usedID;
loaner.lendedTimestamp = this.session.now();
this.loans.push(loanerId);
this.balance -= amount;
loaner.balance += amount;
} else {
throw new Error("Assert failed: loaner should not have an outstanding loan");
}
} else {
throw new Error("Assert failed: balance should be greater than or equal to amount");
}
},
payLoan: function(amount){
let lender = this.session.lookup(this.lenderId);
/* compute interest using the number of days and then add interest for each passed day for the amount that is returned*/
let now = this.session.now();
let days = Math.floor((now - this.lendedTimestamp) / (1000 * 60 * 60 * 24));
let interest = days * this.dailyInterestRate * this.loanedAmount;

if(lender != undefined){
if(amount < this.balance){
this.balance -= amount;
lender.balance += amount;
this.loanedAmount -= amount;
this.loanedAmount += interest;
}
if(this.loanedAmount < 0){
lender.balance += this.loanedAmount; /* get back money that were wrongfully returned in the previous step*/
this.balance -= this.loanedAmount;
this.loanedAmount = 0;
}
/* if the loaner has no more money to give, it gets removed from the list of loans of the lender*/
if(this.loanedAmount == 0){
this.lenderId = undefined;
this.dailyInterestRate = undefined;
this.lendedTimestamp = undefined;
let index = lender.loans.indexOf(this.usedID);
if(index > -1){
lender.loans.splice(index, 1);
}
}
}
}
},
getTotalDebt: function(){
let interest = 0;
let now = this.session.now();
let days = Math.floor((now - this.lendedTimestamp) / (1000 * 60 * 60 * 24));
interest = days * this.dailyInterestRate * this.loanedAmount;
return this.loanedAmount + interest;
}
}
62 changes: 62 additions & 0 deletions tests/enclave/accounting/AccountingEnclave/UserProfileSVD.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
module.exports = {
ctor: function (userId, name, email, phone, publicDescription, secretToken, userDID, isPrivate) {
this.userId = userId;
this.name = name;
this.email = email;
this.phone = phone;
this.publicDescription=publicDescription;
this.isPrivate = isPrivate;
this.availableInvitesCounter = 0;
this.acceptedInvites = [];
this.followedBrands= [];
this.secretToken=secretToken;
this.userDID = userDID;
/* the email and phone are private by default */
this.isPrivate = true;
//this.secretToken=secretToken;
this.friends = [];
},
actions: {
update: function (userId, name, email, phone, publicDescription, secretToken, userDID, isPrivate) {
this.name = name;
this.email = email;
this.userId = userId;
this.phone = phone;
this.publicDescription=publicDescription;
this.secretToken=secretToken;
this.userDID = userDID;
this.isPrivate = isPrivate;
},
setTemporarySecretToken(temporarySecretToken){
this.temporarySecretToken=temporarySecretToken;
},
registeredAsValidatedUser: function () {
this.availableInvitesCounter += 10;
},
addInvites: function (invites) {
this.availableInvitesCounter += invites;
},
inviteAccepted: function (inviteId) {
this.availableInvitesCounter--;
this.acceptedInvites.push(inviteId);
this.friends.push(inviteId);
},
addFriend: function (friendId) {
this.friends.push(friendId);
},
addBrandToFollowed(brandId)
{
this.followedBrands.push(brandId);
},
removeBrandFromFollowed(brandId){
const index = this.followedBrands.indexOf(brandId);
if(index>-1)
{
this.followedBrands.splice(index, 1);
}
else {
console.error(`Error: not found; Failed to remove brandId ${brandId} from user's followedBrands`);
}
}
}
}
140 changes: 140 additions & 0 deletions tests/enclave/accounting/AccountingEnclave/lambdas/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
const UserProfileSVD = require("../UserProfileSVD");
const {userId} = require("../UserProfileSVD");
let fsSVDStorage;
function initSVD(remoteEnclaveServer) {
const fastSVD = require("opendsu").loadApi("svd");
fsSVDStorage = fastSVD.createFsSVDStorage("./SVDS");
fsSVDStorage.registerType("user", UserProfileSVD);
}
function helloWorld (...args) {
const callback = args.pop();
callback(undefined, args);
}

function helloWorldWithAudit (...args) {
const callback = args.pop();
this.audit(...args);
callback(undefined, args);
}
function updateUser(userId, name, email, phone, publicDescription, secretToken, userDID, isPrivate, callback){

fsSVDStorage.createTransaction(function (err, transaction){
transaction.lookup(userId, (err, userSVD) => {
if(err){
return callback(err);
}
userSVD.update(email, name, email, phone, publicDescription, secretToken, userDID, isPrivate);
transaction.commit((commitError) => {
if(commitError){
return callback(commitError);
}
callback({userId:userId, secretToken:secretToken});
});

});
});
}
function addNewUser(name, email, phone, publicDescription, secretToken, userDID, isPrivate, callback){
const self = this;
const crypto = require("opendsu").loadApi("crypto");
const userSvdUid = "svd:user:" + crypto.getRandomSecret(32);
fsSVDStorage.createTransaction(function (err, transaction){
let user = transaction.create(userSvdUid, userSvdUid, name, email, phone, publicDescription, secretToken, userDID, isPrivate);
self.insertRecord("", "users", userSvdUid, { email: email }, (err) => {
if (err) {
return callback(err);
}
transaction.commit((commitError) => {
if(commitError){
return callback(commitError);
}
callback({userId:userSvdUid, secretToken:secretToken});
})
});
});
}
function getUserSVD(userId,callback){

fsSVDStorage.createTransaction(function (err, transaction){
transaction.lookup(userId, (err, userSVD) => {
if(err){
return callback(err);
}
transaction.commit((commitError) => {
if(commitError){
return callback(commitError);
}


});
callback(userSVD.getState());
});

});
}
function getUserIdByEmail(email, callback){
const self = this;
self.getAllRecords("", "users", (err, users)=>{
if(err){
return callback(err);
}
users.forEach((user)=>{
if(user.email===email){
return callback({userId:user.pk});
}

});
return callback(`No userId found for email: ${email}`);
});
}
function addBrandToFollowed(brandId, userId, callback) {

fsSVDStorage.createTransaction(function (err, transaction){
transaction.lookup(userId, (err, userSVD) => {
if(err){
return callback(err);
}
userSVD.addBrandToFollowed(brandId);
transaction.commit((commitError) => {
if(commitError){
return callback(commitError);
}
callback({brandId:brandId});
});

});
});
}

function removeBrandFromFollowed(brandId, userId, callback){

fsSVDStorage.createTransaction(function (err, transaction){
transaction.lookup(userId, (err, userSVD) => {
if(err){
return callback(err);
}
userSVD.removeBrandFromFollowed(brandId);
transaction.commit((commitError) => {
if(commitError){
return callback(commitError);
}
callback({brandId:brandId});
});

});
});
}

module.exports = {
registerLambdas: async (remoteEnclaveServer) => {
initSVD(remoteEnclaveServer);
remoteEnclaveServer.addEnclaveMethod("helloWorld", helloWorld, "read");
remoteEnclaveServer.addEnclaveMethod("helloWorldWithAudit", helloWorldWithAudit, "read");
remoteEnclaveServer.addEnclaveMethod("addNewUser", addNewUser, "write");
remoteEnclaveServer.addEnclaveMethod("updateUser", updateUser, "write");
remoteEnclaveServer.addEnclaveMethod("getUserIdByEmail", getUserIdByEmail, "read");
remoteEnclaveServer.addEnclaveMethod("addBrandToFollowed", addBrandToFollowed, "write");
remoteEnclaveServer.addEnclaveMethod("removeBrandFromFollowed", removeBrandFromFollowed, "write");
remoteEnclaveServer.addEnclaveMethod("getUserSVD", getUserSVD, "read");
}
}
79 changes: 79 additions & 0 deletions tests/enclave/accounting/RemoteEnclaveTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
require("../../../../../builds/output/testsRuntime");
const tir = require("../../../../../psknode/tests/util/tir");

const dc = require("double-check");
const assert = dc.assert;
const openDSU = require('../../../index');
$$.__registerModule("opendsu", openDSU);
const enclaveAPI = openDSU.loadAPI("enclave");
const scAPI = openDSU.loadAPI("sc");
const w3cDID = openDSU.loadAPI("w3cdid");
const keySSI = openDSU.loadAPI("keyssi");

assert.callback('Remote enclave test', (testFinished) => {
dc.createTestFolder('createDSU', async (err, folder) => {
const vaultDomainConfig = {
"anchoring": {
"type": "FS",
"option": {}
},
"enable": ["enclave", "mq"]
}

const domain = "mqtestdomain";
process.env.CLOUD_ENCLAVE_SECRET = "some secret";
await tir.launchConfigurableApiHubTestNodeAsync({domains: [{name: domain, config: vaultDomainConfig}], rootFolder: folder});
const serverDID = await tir.launchConfigurableCloudEnclaveTestNodeAsync({
rootFolder: folder,
domain,
secret: process.env.CLOUD_ENCLAVE_SECRET,
lambdas: "./AccountingEnclave/lambdas",
name: "cloud-enclave"
});

const runAssertions = async () => {
try {
const clientDIDDocument = await $$.promisify(w3cDID.createIdentity)("ssi:name", domain, "client");
const cloudEnclave = enclaveAPI.initialiseRemoteEnclave(clientDIDDocument.getIdentifier(), serverDID);
const TABLE = "users";
cloudEnclave.on("initialised", async () => {
try {
const userId = await $$.promisify(cloudEnclave.callLambda)("addNewUser", "", "", "", "", "", "", "");
const user = await $$.promisify(cloudEnclave.getRecord)("", TABLE, userId.userId);
assert.equal(userId.userId,user.pk,"user input values differ from user output values");

const password = "12345678";
const crypto = require("opendsu").loadApi("crypto");
const randomNr = crypto.generateRandom(32);
const secretToken = crypto.encrypt(randomNr,crypto.deriveEncryptionKey(password));

const didDocument = await $$.promisify(w3cDID.createIdentity)("key", undefined, randomNr);
const dataToSign = "someData";
const signature = await $$.promisify(didDocument.sign)(dataToSign);
const verificationResult = await $$.promisify(didDocument.verify)(dataToSign, signature);
assert.true(verificationResult, "Failed to verify signature");



const userId2 = await $$.promisify(cloudEnclave.callLambda)("updateUser", userId.userId, "name1", "email1", "phone1", "publicDescription1", secretToken, "userDID", "");
const user2 = await $$.promisify(cloudEnclave.getRecord)("", TABLE, userId2.userId);
assert.equal(userId2.userId,user2.pk,"user input values differ from user output values");
console.log(user2);
testFinished();
} catch (e) {
return console.log(e);
}

});

} catch (e) {
return console.log(e);
}
}
const sc = scAPI.getSecurityContext();
if (sc.isInitialised()) {
return runAssertions();
}
sc.on("initialised", runAssertions);
});
}, 200000);