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

Extend SigningCallback form to allow returning an object #783

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

## Unreleased

### Added
* Within `authorizeEntry`, the `SigningCallback` callback function should now return an object containing both the signature and the identity of the signer. In multi-signature situations, it isn't necessarily the case that the address within the authorization entry is the one that actually signs that entry. Thus, the callback now takes the following form, where the original `Promise<BufferLike>` option is preserved for backwards compatibility and should be considered deprecated ([]()):
```typescript
export type SigningCallback = (
preimage: xdr.HashIdPreimage
) => Promise<
BufferLike |
{ signature: BufferLike, publicKey: string }
>;
```


## [`v13.0.0`](https://github.com/stellar/js-stellar-base/compare/v12.1.1...v13.0.0)

Expand Down
39 changes: 28 additions & 11 deletions src/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ import { nativeToScVal } from './scval';
* whose hash you should sign, so that you can inspect the entire structure
* if necessary (rather than blindly signing a hash)
*
* @returns {Promise<Uint8Array>} the signature of the raw payload (which is
* the sha256 hash of the preimage bytes, so `hash(preimage.toXDR())`) signed
* @returns {
* Promise<Uint8Array> |
* Promise<{signature: Uint8Array, publicKey: string}
* } the signature of the raw payload (which is the sha256 hash of the preimage
* bytes, so `hash(preimage.toXDR())`) either naked, implying it is signed
* by the key corresponding to the public key in the entry you pass to
* {@link authorizeEntry} (decipherable from its
* `credentials().address().address()`)
* `credentials().address().address()`), or alongside an explicit `publicKey`.
*/

/**
Expand All @@ -43,10 +46,17 @@ import { nativeToScVal } from './scval';
*
* @param {xdr.SorobanAuthorizationEntry} entry an unsigned authorization entr
* @param {Keypair | SigningCallback} signer either a {@link Keypair} instance
* or a function which takes a payload (a
* {@link xdr.HashIdPreimageSorobanAuthorization} instance) input and returns
* the signature of the hash of the raw payload bytes (where the signing key
* should correspond to the address in the `entry`)
* or a function which takes a {@link xdr.HashIdPreimageSorobanAuthorization}
* input payload and returns EITHER
*
* (a) an object containing a `signature` of the hash of the raw payload bytes
* as a Buffer-like and a `publicKey` string representing who just
* created this signature, or
* (b) just the naked signature of the hash of the raw payload bytes (where
* the signing key is implied to be the address in the `entry`).
*
* The latter option (b) is JUST for backwards compatibility and will be
* removed in the future.
* @param {number} validUntilLedgerSeq the (exclusive) future ledger sequence
* number until which this authorization entry should be valid (if
* `currentLedgerSeq==validUntil`, this is expired))
Expand All @@ -58,8 +68,8 @@ import { nativeToScVal } from './scval';
* {@link Operation.invokeHostFunction}
*
* @note If using the `SigningCallback` variation, the signer is assumed to be
* the entry's credential address. If you need a different key to sign the
* entry, you will need to use different method (e.g., fork this code).
* the entry's credential address unless you use the variant that returns
* the object.
*
* @see authorizeInvocation
* @example
Expand Down Expand Up @@ -137,8 +147,15 @@ export async function authorizeEntry(
let signature;
let publicKey;
if (typeof signer === 'function') {
signature = Buffer.from(await signer(preimage));
publicKey = Address.fromScAddress(addrAuth.address()).toString();
const sigResult = await signer(preimage);
if (sigResult?.signature) {
signature = Buffer.from(sigResult.signature);
publicKey = sigResult.publicKey;
} else {
// if using the deprecated form, assume it's for the entry
signature = Buffer.from(sigResult);
publicKey = Address.fromScAddress(addrAuth.address()).toString();
}
} else {
signature = Buffer.from(signer.sign(payload));
publicKey = signer.publicKey();
Expand Down
15 changes: 11 additions & 4 deletions test/unit/auth_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,16 @@ describe('building authorization entries', function () {

[
[kp, 'Keypair'],
[(preimage) => kp.sign(StellarBase.hash(preimage.toXDR())), 'callback']
[(preimage) => kp.sign(StellarBase.hash(preimage.toXDR())), 'callback'],
[
(preimage) => {
return {
signature: kp.sign(StellarBase.hash(preimage.toXDR())),
publicKey: kp.publicKey()
};
},
'callback w/ obj'
]
].forEach(([signer, methodName]) => {
it(`signs the entry correctly (${methodName})`, function (done) {
StellarBase.authorizeEntry(authEntry, signer, 10)
Expand Down Expand Up @@ -87,9 +96,7 @@ describe('building authorization entries', function () {

it('can build from scratch', function (done) {
StellarBase.authorizeInvocation(kp, 10, authEntry.rootInvocation())
.then((signedEntry) => {
done();
})
.then((signedEntry) => done())
.catch((err) => done(err));
});
});
6 changes: 5 additions & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1214,9 +1214,13 @@ export class SorobanDataBuilder {
build(): xdr.SorobanTransactionData;
}

type BufferLike = Buffer | Uint8Array | ArrayBuffer;
export type SigningCallback = (
preimage: xdr.HashIdPreimage
) => Promise<Buffer | Uint8Array | ArrayBuffer /* Buffer-like */>;
) => Promise<
BufferLike |
{ signature: BufferLike, publicKey: string }
>;

export function authorizeInvocation(
signer: Keypair | SigningCallback,
Expand Down
Loading