Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
/node_modules/

*.tgz
/coverage/
/tmp/

/dist/
Expand Down
9 changes: 9 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,12 @@ cache:
yarn: true
directories:
- node_modules
before_install:
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- chmod +x ./cc-test-reporter
before_script:
- ./cc-test-reporter before-build
script:
- yarn test:coverage
after_script:
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[![npm version](https://badge.fury.io/js/%40mobius-network%2Fmobius-client-js.svg)](https://badge.fury.io/js/%40mobius-network%2Fmobius-client-js)
[![Build Status](https://travis-ci.org/mobius-network/mobius-client-js.svg?branch=master)](https://travis-ci.org/mobius-network/mobius-client-js)
[![Maintainability](https://api.codeclimate.com/v1/badges/cf6f78eade10ed549155/maintainability)](https://codeclimate.com/github/mobius-network/mobius-client-js/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/cf6f78eade10ed549155/test_coverage)](https://codeclimate.com/github/mobius-network/mobius-client-js/test_coverage)

# mobius-client-js

Expand Down
10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"lint": "eslint --quiet . --ext .js",
"precommit": "lint-staged",
"prepack": "yarn run build",
"test": "jest --config test/jest.config.js"
"test": "jest",
"test:coverage": "jest --coverage"
},
"dependencies": {
"babel-runtime": "^6.26.0",
Expand Down Expand Up @@ -60,6 +61,7 @@
"husky": "^0.14.3",
"jest": "^22.4.3",
"lint-staged": "^7.0.4",
"ms": "^2.1.1",
"prettier": "^1.12.1",
"timekeeper": "^2.1.1",
"uglifyjs-webpack-plugin": "^1.2.4",
Expand All @@ -74,5 +76,11 @@
"prettier --write",
"git add"
]
},
"jest": {
"transform": {
"^.+\\.js": "babel-jest"
},
"verbose": true
}
}
73 changes: 36 additions & 37 deletions src/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default class App {
this._appAccount = appAccount;
this._clientInstance = new Client().horizonClient;
this._userAccount = userAccount;
this._validateUserAccount();
}

/**
Expand Down Expand Up @@ -59,8 +60,6 @@ export default class App {
* @returns {number} user balance
*/
get userBalance() {
this._validateUserBalance();

return this._userAccount.balance();
}

Expand All @@ -79,15 +78,15 @@ export default class App {
* @returns {Promise}
*/
async charge(amount, destination = null) {
if (this.userBalance < Number(amount)) {
throw new Error("Insufficient Funds");
}
this._ensureSufficientFunds(this.userAccount, amount);

return this._submitTx(tx => {
tx.addOperation(this._userPaymentOp(amount, this.appKeypair.publicKey()));
tx.addOperation(
this._paymentOp(this.userAccount, amount, this.appAccount.address)
);

if (destination) {
tx.addOperation(this._appPaymentOp(amount, destination));
tx.addOperation(this._paymentOp(this.appAccount, amount, destination));
}
});
}
Expand All @@ -109,14 +108,8 @@ export default class App {
* @param {string} [destination] - third party receiver address
* @returns {Promise}
*/
async payout(amount, destination = this.userKeypair.publicKey()) {
if (this.appBalance < Number(amount)) {
throw new Error("Insufficient Funds");
}

return this._submitTx(tx => {
tx.addOperation(this._appPaymentOp(amount, destination));
});
async payout(amount, destination = this.userAccount.address) {
return this._sendPayment(this.appAccount, amount, destination);
}

/**
Expand All @@ -126,12 +119,21 @@ export default class App {
* @returns {Promise}
*/
async transfer(amount, destination) {
if (this.userBalance < Number(amount)) {
throw new Error("Insufficient Funds");
}
return this._sendPayment(this.userAccount, amount, destination);
}

/**
* @private
* @param {Account} account - Source account
* @param {number} amount - Payment amount
* @param {string} destination - Payment destination address
* @returns {Promise}
*/
async _sendPayment(account, amount, destination) {
this._ensureSufficientFunds(account, amount);

return this._submitTx(tx => {
tx.addOperation(this._userPaymentOp(amount, destination));
tx.addOperation(this._paymentOp(account, amount, destination));
});
}

Expand Down Expand Up @@ -163,30 +165,16 @@ export default class App {

/**
* @private
* @param {Account} account - account to send payment from
* @param {number} amount - payment amount
* @param {string} destination - receiver address
* @returns {Operation} payment operation
*/
_userPaymentOp(amount, destination) {
_paymentOp(account, amount, destination) {
return Operation.payment({
asset: Client.stellarAsset,
amount: amount.toString(),
source: this.userKeypair.publicKey(),
destination
});
}

/**
* @private
* @param {number} amount - payment amount
* @param {string} destination - receiver address
* @returns {Operation} payment operation
*/
_appPaymentOp(amount, destination) {
return Operation.payment({
asset: Client.stellarAsset,
amount: amount.toString(),
source: this.appKeypair.publicKey(),
source: account.address,
destination
});
}
Expand All @@ -195,7 +183,7 @@ export default class App {
* @private
* @returns {boolean} true if developer is authorized to use an application and trustline exists
*/
_validateUserBalance() {
_validateUserAccount() {
if (!this.authorized) {
throw new Error("Authorisation missing");
}
Expand All @@ -206,4 +194,15 @@ export default class App {

return true;
}

/**
* @private
* @param {Account} account
* @param {number|string} amount
*/
_ensureSufficientFunds(account, amount) {
if (account.balance() < Number(amount)) {
throw new Error("Insufficient Funds");
}
}
}
57 changes: 16 additions & 41 deletions src/auth/challenge.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ const Challenge = {
/**
* Generates challenge transaction signed by developers private key.
* @param {string} developerSecret - Developers private key
* @param {number} expireIn - Session expiration time in seconds from now. Default is Client.challengeExpiresIn.
* @returns {string} base64-encoded transaction envelope
* @param {number} [expireIn=Client.challengeExpiresIn] - Session expiration time in seconds from now.
* @returns {string|Buffer} base64-encoded transaction envelope
*/
call(developerSecret, expireIn = null) {
const keypair = this._keypair(developerSecret);
const account = new Account(keypair.publicKey(), this._randomSequence());
const tx = new TransactionBuilder(account, {
memo: this._memo(),
timebounds: this._buildTimeBounds(expireIn)
call(developerSecret, expireIn = Client.challengeExpiresIn) {
const keypair = Keypair.fromSecret(developerSecret);
const now = Math.floor(new Date().getTime() / 1000);

const tx = new TransactionBuilder(this._randomAccount(), {
memo: Memo.text("Mobius authentication"),
timebounds: { minTime: now, maxTime: now + expireIn }
})
.addOperation(
Operation.payment({
account: Keypair.random(),
account: keypair,
destination: keypair.publicKey(),
sequence: this._randomSequence(),
amount: "0.000001",
amount: "1",
asset: Asset.native()
})
)
Expand All @@ -41,44 +41,19 @@ const Challenge = {

/**
* @private
* @param {string} developerSecret - Developers private key
* @returns {StellarSdk.Keypair} StellarSdk.Keypair
* @returns {Account} Random account with random sequence
*/
_keypair(developerSecret) {
return Keypair.fromSecret(developerSecret);
_randomAccount() {
const keypair = Keypair.random();
return new Account(keypair.publicKey(), this._randomSequence());
},

/**
* @private
* @returns {number} Random sequence number
* @returns {string} Random sequence number
*/
_randomSequence() {
return (99999999 - Math.floor(Math.random() * 65536)).toString();
},

/**
* @private
* @param {number} expireIn - session expiration time in seconds from now
* @returns {object} Time bounds (`minTime` and `maxTime`)
*/
_buildTimeBounds(expireIn) {
const minTime = Math.floor(new Date().getTime() / 1000).toString();
const maxTime = Math.floor(
new Date().getTime() / 1000 + (expireIn || Client.challengeExpiresIn)
).toString();

return {
minTime,
maxTime
};
},

/**
* @private
* @returns {StellarSdk.Memo} Auth transaction memo
*/
_memo() {
return Memo.text("Mobius authentication");
}
};

Expand Down
Loading