Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signatures #124

Closed
wants to merge 3 commits into from
Closed
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
20 changes: 10 additions & 10 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
GIT
remote: [email protected]:stellar/xdrgen.git
revision: 6c8d27a3b2314be1fc352f53fcb22e418ba296b5
revision: c683684abb3cb2c8b8c3dc12dc7c6cc9bf1e3b60
specs:
xdrgen (0.0.1)
activesupport (~> 4)
activesupport (~> 5)
memoist (~> 0.11.0)
slop (~> 3.4)
treetop (~> 1.5.3)

GEM
remote: https://rubygems.org/
specs:
activesupport (4.2.4)
activesupport (5.1.5)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.3.8)
coderay (1.1.0)
concurrent-ruby (1.0.5)
faraday (0.9.1)
multipart-post (>= 1.2, < 3)
i18n (0.7.0)
json (1.8.3)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
memoist (0.11.0)
method_source (0.8.2)
minitest (5.8.0)
minitest (5.11.3)
multipart-post (2.0.0)
netrc (0.10.3)
octokit (4.1.0)
Expand All @@ -39,10 +39,10 @@ GEM
addressable (~> 2.3.5)
faraday (~> 0.8, < 0.10)
slop (3.6.0)
thread_safe (0.3.5)
thread_safe (0.3.6)
treetop (1.5.3)
polyglot (~> 0.3)
tzinfo (1.2.2)
tzinfo (1.2.5)
thread_safe (~> 0.1)

PLATFORMS
Expand Down
144 changes: 144 additions & 0 deletions src/federation_response.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import {default as xdr} from "./generated/stellar-xdr_generated";
import clone from "lodash/clone";
import isString from 'lodash/isString';
import {hash} from "./hashing";
import {StrKey} from "./strkey";
import {Memo} from "./memo";

/**
* `FederationResponse` represents response from a federation server.
*
* @param {string} stellarAddress address in the form of `user*domain`
* @param {string} accountId ID of the account (ex. `GB3KJPLFUYN5VL6R3GU3EGCGVCKFDSD7BEDX42HWG5BWFKB3KQGJJRMA`)
* @param {Memo} memo memo to be used for the stellar address
* @see [Federation concept](https://www.stellar.org/developers/guides/concepts/federation.html)
* @class FederationResponse
*/
export class FederationResponse {
constructor(stellarAddress, accountId, memo) {
if (!StrKey.isValidEd25519PublicKey(accountId)) {
throw new Error('accountId is invalid');
}
if (memo === undefined) {
memo = Memo.none();
}
else {
let memo2 = new Memo(memo.type, memo.value);
}
FederationResponse._validateStellarAddressValue(stellarAddress);
this._stellarAddress = stellarAddress;
this._accountId = accountId;
this._memo = memo;
}

/**
* Contains the stellar address in the form `user*domain`
*/
get stellarAddress() {
return clone(this._stellarAddress);
}

set stellarAddress(stellarAddress) {
throw new Error("FederationResponse is immutable");
}

/**
* Contains the account ID (ex. `GB3KJPLFUYN5VL6R3GU3EGCGVCKFDSD7BEDX42HWG5BWFKB3KQGJJRMA`)
*/
get accountId() {
return clone(this._accountId);
}

set accountId(accountId) {
throw new Error("FederationResponse is immutable");
}

/**
* Contains the memo to be used for this stellar address
*/
get memo() {
return clone(this._memo);
}

set memo(memo) {
throw new Error("FederationResponse is immutable");
}

static _validateStellarAddressValue(value) {
let error = new Error("Expects a stellar address like user*domain. Got " + value);

if (!isString(value)) {
throw error;
}

if (Buffer.byteLength(value, "utf8") > 64) {
throw new Error("Stellar Address should be <= 64 bytes. Got " + Buffer.byteLength(value, "utf8"));
}

let parts = value.split("*");
if (parts.length != 2) {
throw error;
}

if (Buffer.byteLength(parts[1], "utf8") > 32) {
throw new Error("`domain` part of address should be <= 32 bytes. Got " + Buffer.byteLength(parts[1], "utf8"));
}
}

/**
* Returns XDR federation response object.
* @returns {xdr.FederationResponse}
*/
toXDRObject() {
let rawKey = StrKey.decodeEd25519PublicKey(this._accountId);
return new xdr.FederationResponse({
stellarAddress: this._stellarAddress,
accountId: xdr.AccountId.publicKeyTypeEd25519(rawKey),
memo: this._memo.toXDRObject(),
ext: new xdr.FederationResponseExt(0)
});
}

/**
* Returns {@link FederationResponse} from XDR federation response object.
* @param {xdr.FederationResponse}
* @returns {FederationResponse}
*/
static fromXDRObject(object) {
let memo = Memo.fromXDRObject(object.memo());
let rawKey = object.accountId().ed25519();
return new FederationResponse(
object.stellarAddress(),
StrKey.encodeEd25519PublicKey(rawKey),
memo
);
}

/**
* Returns a hash for this federation response, suitable for signing.
* @returns {Buffer}
*/
hash() {
return hash(this.toXDRObject().toXDR());
}

/**
* Signs the federation response with the given {@link Keypair}.
* @param {Keypair} keypair Keypair of signer
* @returns {Buffer}
*/
sign(keypair) {
let txHash = this.hash();
return keypair.sign(txHash);
}

/**
* Verifies the federation response with the given {@link Keypair}.
* @param {Keypair} keypair Keypair (public key is enough) to verify
* @param {Buffer} signature signature to compare with
* @returns {boolean}
*/
verify(keypair, signature) {
return keypair.verify(this.hash(), signature);
}
}
Loading