@solana-mobile/mobile-wallet-adapter-protocol 2.1.8 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +1 -1
- package/lib/cjs/index.browser.js +0 -26
- package/lib/cjs/index.js +0 -26
- package/lib/esm/index.browser.js +1 -26
- package/lib/esm/index.js +1 -26
- package/lib/types/index.browser.d.ts +1 -5
- package/lib/types/index.d.ts +1 -5
- package/lib/types/index.native.d.ts +1 -5
- package/package.json +1 -1
- package/src/createSIWSMessage.ts +13 -13
- package/src/encryptedMessage.ts +59 -59
- package/src/jsonRpcMessage.ts +38 -38
- package/src/parseHelloRsp.ts +46 -46
- package/src/parseSessionProps.ts +32 -32
- package/src/reflectorId.ts +30 -30
- package/src/transact.ts +0 -23
- package/.DS_Store +0 -0
package/android/build.gradle
CHANGED
|
@@ -8,7 +8,7 @@ buildscript {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
dependencies {
|
|
11
|
-
classpath 'com.android.tools.build:gradle:8.
|
|
11
|
+
classpath 'com.android.tools.build:gradle:8.9.2'
|
|
12
12
|
// noinspection DifferentKotlinGradleVersion
|
|
13
13
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
14
14
|
}
|
package/lib/cjs/index.browser.js
CHANGED
|
@@ -827,31 +827,6 @@ function transact(callback, config) {
|
|
|
827
827
|
});
|
|
828
828
|
});
|
|
829
829
|
}
|
|
830
|
-
function transactRemote(callback, config) {
|
|
831
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
832
|
-
return startRemoteScenario(config).then((scenario) => {
|
|
833
|
-
return {
|
|
834
|
-
associationUrl: scenario.associationUrl,
|
|
835
|
-
result: scenario.wallet.then((wallet) => {
|
|
836
|
-
return callback(new Proxy(wallet, {
|
|
837
|
-
get(target, p) {
|
|
838
|
-
if (p == 'terminateSession') {
|
|
839
|
-
return function () {
|
|
840
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
841
|
-
scenario.close();
|
|
842
|
-
return;
|
|
843
|
-
});
|
|
844
|
-
};
|
|
845
|
-
}
|
|
846
|
-
else
|
|
847
|
-
return target[p];
|
|
848
|
-
},
|
|
849
|
-
}));
|
|
850
|
-
}),
|
|
851
|
-
};
|
|
852
|
-
});
|
|
853
|
-
});
|
|
854
|
-
}
|
|
855
830
|
function startRemoteScenario(config) {
|
|
856
831
|
return __awaiter(this, void 0, void 0, function* () {
|
|
857
832
|
assertSecureContext();
|
|
@@ -1098,4 +1073,3 @@ exports.SolanaSignInWithSolana = SolanaSignInWithSolana;
|
|
|
1098
1073
|
exports.SolanaSignTransactions = SolanaSignTransactions;
|
|
1099
1074
|
exports.startRemoteScenario = startRemoteScenario;
|
|
1100
1075
|
exports.transact = transact;
|
|
1101
|
-
exports.transactRemote = transactRemote;
|
package/lib/cjs/index.js
CHANGED
|
@@ -827,31 +827,6 @@ function transact(callback, config) {
|
|
|
827
827
|
});
|
|
828
828
|
});
|
|
829
829
|
}
|
|
830
|
-
function transactRemote(callback, config) {
|
|
831
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
832
|
-
return startRemoteScenario(config).then((scenario) => {
|
|
833
|
-
return {
|
|
834
|
-
associationUrl: scenario.associationUrl,
|
|
835
|
-
result: scenario.wallet.then((wallet) => {
|
|
836
|
-
return callback(new Proxy(wallet, {
|
|
837
|
-
get(target, p) {
|
|
838
|
-
if (p == 'terminateSession') {
|
|
839
|
-
return function () {
|
|
840
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
841
|
-
scenario.close();
|
|
842
|
-
return;
|
|
843
|
-
});
|
|
844
|
-
};
|
|
845
|
-
}
|
|
846
|
-
else
|
|
847
|
-
return target[p];
|
|
848
|
-
},
|
|
849
|
-
}));
|
|
850
|
-
}),
|
|
851
|
-
};
|
|
852
|
-
});
|
|
853
|
-
});
|
|
854
|
-
}
|
|
855
830
|
function startRemoteScenario(config) {
|
|
856
831
|
return __awaiter(this, void 0, void 0, function* () {
|
|
857
832
|
assertSecureContext();
|
|
@@ -1098,4 +1073,3 @@ exports.SolanaSignInWithSolana = SolanaSignInWithSolana;
|
|
|
1098
1073
|
exports.SolanaSignTransactions = SolanaSignTransactions;
|
|
1099
1074
|
exports.startRemoteScenario = startRemoteScenario;
|
|
1100
1075
|
exports.transact = transact;
|
|
1101
|
-
exports.transactRemote = transactRemote;
|
package/lib/esm/index.browser.js
CHANGED
|
@@ -823,31 +823,6 @@ function transact(callback, config) {
|
|
|
823
823
|
});
|
|
824
824
|
});
|
|
825
825
|
}
|
|
826
|
-
function transactRemote(callback, config) {
|
|
827
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
828
|
-
return startRemoteScenario(config).then((scenario) => {
|
|
829
|
-
return {
|
|
830
|
-
associationUrl: scenario.associationUrl,
|
|
831
|
-
result: scenario.wallet.then((wallet) => {
|
|
832
|
-
return callback(new Proxy(wallet, {
|
|
833
|
-
get(target, p) {
|
|
834
|
-
if (p == 'terminateSession') {
|
|
835
|
-
return function () {
|
|
836
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
837
|
-
scenario.close();
|
|
838
|
-
return;
|
|
839
|
-
});
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
else
|
|
843
|
-
return target[p];
|
|
844
|
-
},
|
|
845
|
-
}));
|
|
846
|
-
}),
|
|
847
|
-
};
|
|
848
|
-
});
|
|
849
|
-
});
|
|
850
|
-
}
|
|
851
826
|
function startRemoteScenario(config) {
|
|
852
827
|
return __awaiter(this, void 0, void 0, function* () {
|
|
853
828
|
assertSecureContext();
|
|
@@ -1085,4 +1060,4 @@ function startRemoteScenario(config) {
|
|
|
1085
1060
|
});
|
|
1086
1061
|
}
|
|
1087
1062
|
|
|
1088
|
-
export { SolanaCloneAuthorization, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterProtocolError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaSignInWithSolana, SolanaSignTransactions, startRemoteScenario, transact
|
|
1063
|
+
export { SolanaCloneAuthorization, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterProtocolError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaSignInWithSolana, SolanaSignTransactions, startRemoteScenario, transact };
|
package/lib/esm/index.js
CHANGED
|
@@ -823,31 +823,6 @@ function transact(callback, config) {
|
|
|
823
823
|
});
|
|
824
824
|
});
|
|
825
825
|
}
|
|
826
|
-
function transactRemote(callback, config) {
|
|
827
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
828
|
-
return startRemoteScenario(config).then((scenario) => {
|
|
829
|
-
return {
|
|
830
|
-
associationUrl: scenario.associationUrl,
|
|
831
|
-
result: scenario.wallet.then((wallet) => {
|
|
832
|
-
return callback(new Proxy(wallet, {
|
|
833
|
-
get(target, p) {
|
|
834
|
-
if (p == 'terminateSession') {
|
|
835
|
-
return function () {
|
|
836
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
837
|
-
scenario.close();
|
|
838
|
-
return;
|
|
839
|
-
});
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
else
|
|
843
|
-
return target[p];
|
|
844
|
-
},
|
|
845
|
-
}));
|
|
846
|
-
}),
|
|
847
|
-
};
|
|
848
|
-
});
|
|
849
|
-
});
|
|
850
|
-
}
|
|
851
826
|
function startRemoteScenario(config) {
|
|
852
827
|
return __awaiter(this, void 0, void 0, function* () {
|
|
853
828
|
assertSecureContext();
|
|
@@ -1085,4 +1060,4 @@ function startRemoteScenario(config) {
|
|
|
1085
1060
|
});
|
|
1086
1061
|
}
|
|
1087
1062
|
|
|
1088
|
-
export { SolanaCloneAuthorization, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterProtocolError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaSignInWithSolana, SolanaSignTransactions, startRemoteScenario, transact
|
|
1063
|
+
export { SolanaCloneAuthorization, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterProtocolError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaSignInWithSolana, SolanaSignTransactions, startRemoteScenario, transact };
|
|
@@ -258,10 +258,6 @@ type RemoteScenario = Scenario & Readonly<{
|
|
|
258
258
|
associationUrl: URL;
|
|
259
259
|
}>;
|
|
260
260
|
declare function transact<TReturn>(callback: (wallet: MobileWallet) => TReturn, config?: WalletAssociationConfig): Promise<TReturn>;
|
|
261
|
-
declare function transactRemote<TReturn>(callback: (wallet: RemoteMobileWallet) => TReturn, config: RemoteWalletAssociationConfig): Promise<{
|
|
262
|
-
associationUrl: URL;
|
|
263
|
-
result: Promise<TReturn>;
|
|
264
|
-
}>;
|
|
265
261
|
declare function startRemoteScenario(config: RemoteWalletAssociationConfig): Promise<RemoteScenario>;
|
|
266
|
-
export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact,
|
|
262
|
+
export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact, startRemoteScenario, Account, AppIdentity, AssociationKeypair, ProtocolVersion, SessionProperties, AuthorizationResult, AuthToken, Base64EncodedAddress, Base64EncodedTransaction, Cluster, Chain, Finality, WalletAssociationConfig, RemoteWalletAssociationConfig, AuthorizeAPI, CloneAuthorizationAPI, DeauthorizeAPI, GetCapabilitiesAPI, ReauthorizeAPI, SignMessagesAPI, SignTransactionsAPI, SignAndSendTransactionsAPI, MobileWallet, TerminateSessionAPI, RemoteMobileWallet, SolanaSignTransactions, SolanaCloneAuthorization, SolanaSignInWithSolana, SignInPayload, SignInPayloadWithRequiredFields, SignInResult, Scenario, RemoteScenario };
|
|
267
263
|
//# sourceMappingURL=index.browser.d.ts.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -258,10 +258,6 @@ type RemoteScenario = Scenario & Readonly<{
|
|
|
258
258
|
associationUrl: URL;
|
|
259
259
|
}>;
|
|
260
260
|
declare function transact<TReturn>(callback: (wallet: MobileWallet) => TReturn, config?: WalletAssociationConfig): Promise<TReturn>;
|
|
261
|
-
declare function transactRemote<TReturn>(callback: (wallet: RemoteMobileWallet) => TReturn, config: RemoteWalletAssociationConfig): Promise<{
|
|
262
|
-
associationUrl: URL;
|
|
263
|
-
result: Promise<TReturn>;
|
|
264
|
-
}>;
|
|
265
261
|
declare function startRemoteScenario(config: RemoteWalletAssociationConfig): Promise<RemoteScenario>;
|
|
266
|
-
export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact,
|
|
262
|
+
export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact, startRemoteScenario, Account, AppIdentity, AssociationKeypair, ProtocolVersion, SessionProperties, AuthorizationResult, AuthToken, Base64EncodedAddress, Base64EncodedTransaction, Cluster, Chain, Finality, WalletAssociationConfig, RemoteWalletAssociationConfig, AuthorizeAPI, CloneAuthorizationAPI, DeauthorizeAPI, GetCapabilitiesAPI, ReauthorizeAPI, SignMessagesAPI, SignTransactionsAPI, SignAndSendTransactionsAPI, MobileWallet, TerminateSessionAPI, RemoteMobileWallet, SolanaSignTransactions, SolanaCloneAuthorization, SolanaSignInWithSolana, SignInPayload, SignInPayloadWithRequiredFields, SignInResult, Scenario, RemoteScenario };
|
|
267
263
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -258,10 +258,6 @@ type RemoteScenario = Scenario & Readonly<{
|
|
|
258
258
|
associationUrl: URL;
|
|
259
259
|
}>;
|
|
260
260
|
declare function transact<TReturn>(callback: (wallet: MobileWallet) => TReturn, config?: WalletAssociationConfig): Promise<TReturn>;
|
|
261
|
-
declare function transactRemote<TReturn>(callback: (wallet: RemoteMobileWallet) => TReturn, config: RemoteWalletAssociationConfig): Promise<{
|
|
262
|
-
associationUrl: URL;
|
|
263
|
-
result: Promise<TReturn>;
|
|
264
|
-
}>;
|
|
265
261
|
declare function startRemoteScenario(config: RemoteWalletAssociationConfig): Promise<RemoteScenario>;
|
|
266
|
-
export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact,
|
|
262
|
+
export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact, startRemoteScenario, Account, AppIdentity, AssociationKeypair, ProtocolVersion, SessionProperties, AuthorizationResult, AuthToken, Base64EncodedAddress, Base64EncodedTransaction, Cluster, Chain, Finality, WalletAssociationConfig, RemoteWalletAssociationConfig, AuthorizeAPI, CloneAuthorizationAPI, DeauthorizeAPI, GetCapabilitiesAPI, ReauthorizeAPI, SignMessagesAPI, SignTransactionsAPI, SignAndSendTransactionsAPI, MobileWallet, TerminateSessionAPI, RemoteMobileWallet, SolanaSignTransactions, SolanaCloneAuthorization, SolanaSignInWithSolana, SignInPayload, SignInPayloadWithRequiredFields, SignInResult, Scenario, RemoteScenario };
|
|
267
263
|
//# sourceMappingURL=index.native.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solana-mobile/mobile-wallet-adapter-protocol",
|
|
3
3
|
"description": "An implementation of the Solana Mobile Mobile Wallet Adapter protocol. Use this to open a session with a mobile wallet app, and to issue API calls to it.",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.2.0",
|
|
5
5
|
"author": "Steven Luscher <steven.luscher@solanamobile.com>",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
package/src/createSIWSMessage.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SolanaSignInInputWithRequiredFields,
|
|
3
|
-
createSignInMessageText,
|
|
4
|
-
} from '@solana/wallet-standard-util';
|
|
5
|
-
import { SignInPayload } from './types';
|
|
6
|
-
import { encode } from './base64Utils';
|
|
7
|
-
|
|
8
|
-
export function createSIWSMessage(payload: SolanaSignInInputWithRequiredFields & SignInPayload): string {
|
|
9
|
-
return createSignInMessageText(payload);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function createSIWSMessageBase64(payload: SolanaSignInInputWithRequiredFields & SignInPayload): string {
|
|
13
|
-
return encode(createSIWSMessage(payload));
|
|
1
|
+
import {
|
|
2
|
+
SolanaSignInInputWithRequiredFields,
|
|
3
|
+
createSignInMessageText,
|
|
4
|
+
} from '@solana/wallet-standard-util';
|
|
5
|
+
import { SignInPayload } from './types';
|
|
6
|
+
import { encode } from './base64Utils';
|
|
7
|
+
|
|
8
|
+
export function createSIWSMessage(payload: SolanaSignInInputWithRequiredFields & SignInPayload): string {
|
|
9
|
+
return createSignInMessageText(payload);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function createSIWSMessageBase64(payload: SolanaSignInInputWithRequiredFields & SignInPayload): string {
|
|
13
|
+
return encode(createSIWSMessage(payload));
|
|
14
14
|
}
|
package/src/encryptedMessage.ts
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import createSequenceNumberVector, { SEQUENCE_NUMBER_BYTES } from './createSequenceNumberVector.js';
|
|
2
|
-
import { SharedSecret } from './parseHelloRsp.js';
|
|
3
|
-
|
|
4
|
-
const INITIALIZATION_VECTOR_BYTES = 12;
|
|
5
|
-
export const ENCODED_PUBLIC_KEY_LENGTH_BYTES = 65;
|
|
6
|
-
|
|
7
|
-
export async function encryptMessage(
|
|
8
|
-
plaintext: string,
|
|
9
|
-
sequenceNumber: number,
|
|
10
|
-
sharedSecret: SharedSecret,
|
|
11
|
-
) {
|
|
12
|
-
const sequenceNumberVector = createSequenceNumberVector(sequenceNumber);
|
|
13
|
-
const initializationVector = new Uint8Array(INITIALIZATION_VECTOR_BYTES);
|
|
14
|
-
crypto.getRandomValues(initializationVector);
|
|
15
|
-
const ciphertext = await crypto.subtle.encrypt(
|
|
16
|
-
getAlgorithmParams(sequenceNumberVector, initializationVector),
|
|
17
|
-
sharedSecret,
|
|
18
|
-
new TextEncoder().encode(plaintext),
|
|
19
|
-
);
|
|
20
|
-
const response = new Uint8Array(
|
|
21
|
-
sequenceNumberVector.byteLength + initializationVector.byteLength + ciphertext.byteLength,
|
|
22
|
-
);
|
|
23
|
-
response.set(new Uint8Array(sequenceNumberVector), 0);
|
|
24
|
-
response.set(new Uint8Array(initializationVector), sequenceNumberVector.byteLength);
|
|
25
|
-
response.set(new Uint8Array(ciphertext), sequenceNumberVector.byteLength + initializationVector.byteLength);
|
|
26
|
-
return response;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export async function decryptMessage(message: ArrayBuffer, sharedSecret: SharedSecret) {
|
|
30
|
-
const sequenceNumberVector = message.slice(0, SEQUENCE_NUMBER_BYTES);
|
|
31
|
-
const initializationVector = message.slice(
|
|
32
|
-
SEQUENCE_NUMBER_BYTES,
|
|
33
|
-
SEQUENCE_NUMBER_BYTES + INITIALIZATION_VECTOR_BYTES,
|
|
34
|
-
);
|
|
35
|
-
const ciphertext = message.slice(SEQUENCE_NUMBER_BYTES + INITIALIZATION_VECTOR_BYTES);
|
|
36
|
-
const plaintextBuffer = await crypto.subtle.decrypt(
|
|
37
|
-
getAlgorithmParams(sequenceNumberVector, initializationVector),
|
|
38
|
-
sharedSecret,
|
|
39
|
-
ciphertext,
|
|
40
|
-
);
|
|
41
|
-
const plaintext = getUtf8Decoder().decode(plaintextBuffer);
|
|
42
|
-
return plaintext
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function getAlgorithmParams(sequenceNumber: ArrayBuffer, initializationVector: ArrayBuffer) {
|
|
46
|
-
return {
|
|
47
|
-
additionalData: sequenceNumber,
|
|
48
|
-
iv: initializationVector,
|
|
49
|
-
name: 'AES-GCM',
|
|
50
|
-
tagLength: 128, // 16 byte tag => 128 bits
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let _utf8Decoder: TextDecoder | undefined;
|
|
55
|
-
function getUtf8Decoder() {
|
|
56
|
-
if (_utf8Decoder === undefined) {
|
|
57
|
-
_utf8Decoder = new TextDecoder('utf-8');
|
|
58
|
-
}
|
|
59
|
-
return _utf8Decoder;
|
|
1
|
+
import createSequenceNumberVector, { SEQUENCE_NUMBER_BYTES } from './createSequenceNumberVector.js';
|
|
2
|
+
import { SharedSecret } from './parseHelloRsp.js';
|
|
3
|
+
|
|
4
|
+
const INITIALIZATION_VECTOR_BYTES = 12;
|
|
5
|
+
export const ENCODED_PUBLIC_KEY_LENGTH_BYTES = 65;
|
|
6
|
+
|
|
7
|
+
export async function encryptMessage(
|
|
8
|
+
plaintext: string,
|
|
9
|
+
sequenceNumber: number,
|
|
10
|
+
sharedSecret: SharedSecret,
|
|
11
|
+
) {
|
|
12
|
+
const sequenceNumberVector = createSequenceNumberVector(sequenceNumber);
|
|
13
|
+
const initializationVector = new Uint8Array(INITIALIZATION_VECTOR_BYTES);
|
|
14
|
+
crypto.getRandomValues(initializationVector);
|
|
15
|
+
const ciphertext = await crypto.subtle.encrypt(
|
|
16
|
+
getAlgorithmParams(sequenceNumberVector, initializationVector),
|
|
17
|
+
sharedSecret,
|
|
18
|
+
new TextEncoder().encode(plaintext),
|
|
19
|
+
);
|
|
20
|
+
const response = new Uint8Array(
|
|
21
|
+
sequenceNumberVector.byteLength + initializationVector.byteLength + ciphertext.byteLength,
|
|
22
|
+
);
|
|
23
|
+
response.set(new Uint8Array(sequenceNumberVector), 0);
|
|
24
|
+
response.set(new Uint8Array(initializationVector), sequenceNumberVector.byteLength);
|
|
25
|
+
response.set(new Uint8Array(ciphertext), sequenceNumberVector.byteLength + initializationVector.byteLength);
|
|
26
|
+
return response;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function decryptMessage(message: ArrayBuffer, sharedSecret: SharedSecret) {
|
|
30
|
+
const sequenceNumberVector = message.slice(0, SEQUENCE_NUMBER_BYTES);
|
|
31
|
+
const initializationVector = message.slice(
|
|
32
|
+
SEQUENCE_NUMBER_BYTES,
|
|
33
|
+
SEQUENCE_NUMBER_BYTES + INITIALIZATION_VECTOR_BYTES,
|
|
34
|
+
);
|
|
35
|
+
const ciphertext = message.slice(SEQUENCE_NUMBER_BYTES + INITIALIZATION_VECTOR_BYTES);
|
|
36
|
+
const plaintextBuffer = await crypto.subtle.decrypt(
|
|
37
|
+
getAlgorithmParams(sequenceNumberVector, initializationVector),
|
|
38
|
+
sharedSecret,
|
|
39
|
+
ciphertext,
|
|
40
|
+
);
|
|
41
|
+
const plaintext = getUtf8Decoder().decode(plaintextBuffer);
|
|
42
|
+
return plaintext
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getAlgorithmParams(sequenceNumber: ArrayBuffer, initializationVector: ArrayBuffer) {
|
|
46
|
+
return {
|
|
47
|
+
additionalData: sequenceNumber,
|
|
48
|
+
iv: initializationVector,
|
|
49
|
+
name: 'AES-GCM',
|
|
50
|
+
tagLength: 128, // 16 byte tag => 128 bits
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let _utf8Decoder: TextDecoder | undefined;
|
|
55
|
+
function getUtf8Decoder() {
|
|
56
|
+
if (_utf8Decoder === undefined) {
|
|
57
|
+
_utf8Decoder = new TextDecoder('utf-8');
|
|
58
|
+
}
|
|
59
|
+
return _utf8Decoder;
|
|
60
60
|
}
|
package/src/jsonRpcMessage.ts
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import { decryptMessage, encryptMessage } from './encryptedMessage.js';
|
|
2
|
-
import { SolanaMobileWalletAdapterProtocolError } from './errors.js';
|
|
3
|
-
import { SharedSecret } from './parseHelloRsp.js';
|
|
4
|
-
|
|
5
|
-
interface JSONRPCRequest<TParams> {
|
|
6
|
-
id: number;
|
|
7
|
-
jsonrpc: '2.0';
|
|
8
|
-
method: string;
|
|
9
|
-
params: TParams;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
type JSONRPCResponse<TMessage> = {
|
|
13
|
-
id: number;
|
|
14
|
-
jsonrpc: '2.0';
|
|
15
|
-
result: TMessage;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export async function encryptJsonRpcMessage<TParams>(
|
|
19
|
-
jsonRpcMessage: JSONRPCRequest<TParams>,
|
|
20
|
-
sharedSecret: SharedSecret,
|
|
21
|
-
) {
|
|
22
|
-
const plaintext = JSON.stringify(jsonRpcMessage);
|
|
23
|
-
const sequenceNumber = jsonRpcMessage.id;
|
|
24
|
-
return encryptMessage(plaintext, sequenceNumber, sharedSecret);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export async function decryptJsonRpcMessage<TMessage>(message: ArrayBuffer, sharedSecret: SharedSecret) {
|
|
28
|
-
const plaintext = await decryptMessage(message, sharedSecret);
|
|
29
|
-
const jsonRpcMessage = JSON.parse(plaintext);
|
|
30
|
-
if (Object.hasOwnProperty.call(jsonRpcMessage, 'error')) {
|
|
31
|
-
throw new SolanaMobileWalletAdapterProtocolError<typeof jsonRpcMessage.error.code>(
|
|
32
|
-
jsonRpcMessage.id,
|
|
33
|
-
jsonRpcMessage.error.code,
|
|
34
|
-
jsonRpcMessage.error.message,
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
return jsonRpcMessage as JSONRPCResponse<TMessage>;
|
|
38
|
-
}
|
|
1
|
+
import { decryptMessage, encryptMessage } from './encryptedMessage.js';
|
|
2
|
+
import { SolanaMobileWalletAdapterProtocolError } from './errors.js';
|
|
3
|
+
import { SharedSecret } from './parseHelloRsp.js';
|
|
4
|
+
|
|
5
|
+
interface JSONRPCRequest<TParams> {
|
|
6
|
+
id: number;
|
|
7
|
+
jsonrpc: '2.0';
|
|
8
|
+
method: string;
|
|
9
|
+
params: TParams;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type JSONRPCResponse<TMessage> = {
|
|
13
|
+
id: number;
|
|
14
|
+
jsonrpc: '2.0';
|
|
15
|
+
result: TMessage;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export async function encryptJsonRpcMessage<TParams>(
|
|
19
|
+
jsonRpcMessage: JSONRPCRequest<TParams>,
|
|
20
|
+
sharedSecret: SharedSecret,
|
|
21
|
+
) {
|
|
22
|
+
const plaintext = JSON.stringify(jsonRpcMessage);
|
|
23
|
+
const sequenceNumber = jsonRpcMessage.id;
|
|
24
|
+
return encryptMessage(plaintext, sequenceNumber, sharedSecret);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function decryptJsonRpcMessage<TMessage>(message: ArrayBuffer, sharedSecret: SharedSecret) {
|
|
28
|
+
const plaintext = await decryptMessage(message, sharedSecret);
|
|
29
|
+
const jsonRpcMessage = JSON.parse(plaintext);
|
|
30
|
+
if (Object.hasOwnProperty.call(jsonRpcMessage, 'error')) {
|
|
31
|
+
throw new SolanaMobileWalletAdapterProtocolError<typeof jsonRpcMessage.error.code>(
|
|
32
|
+
jsonRpcMessage.id,
|
|
33
|
+
jsonRpcMessage.error.code,
|
|
34
|
+
jsonRpcMessage.error.message,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return jsonRpcMessage as JSONRPCResponse<TMessage>;
|
|
38
|
+
}
|
package/src/parseHelloRsp.ts
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import { ENCODED_PUBLIC_KEY_LENGTH_BYTES } from "./encryptedMessage";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* A secret agreed upon by the app and the wallet. Used as
|
|
5
|
-
* a symmetric key to encrypt and decrypt messages over an
|
|
6
|
-
* unsecured channel.
|
|
7
|
-
*/
|
|
8
|
-
export type SharedSecret = CryptoKey;
|
|
9
|
-
|
|
10
|
-
export default async function parseHelloRsp(
|
|
11
|
-
payloadBuffer: ArrayBuffer, // The X9.62-encoded wallet endpoint ephemeral ECDH public keypoint.
|
|
12
|
-
associationPublicKey: CryptoKey,
|
|
13
|
-
ecdhPrivateKey: CryptoKey,
|
|
14
|
-
): Promise<SharedSecret> {
|
|
15
|
-
const [associationPublicKeyBuffer, walletPublicKey] = await Promise.all([
|
|
16
|
-
crypto.subtle.exportKey('raw', associationPublicKey),
|
|
17
|
-
crypto.subtle.importKey(
|
|
18
|
-
'raw',
|
|
19
|
-
payloadBuffer.slice(0, ENCODED_PUBLIC_KEY_LENGTH_BYTES),
|
|
20
|
-
{ name: 'ECDH', namedCurve: 'P-256' },
|
|
21
|
-
false /* extractable */,
|
|
22
|
-
[] /* keyUsages */,
|
|
23
|
-
),
|
|
24
|
-
]);
|
|
25
|
-
const sharedSecret = await crypto.subtle.deriveBits({ name: 'ECDH', public: walletPublicKey }, ecdhPrivateKey, 256);
|
|
26
|
-
const ecdhSecretKey = await crypto.subtle.importKey(
|
|
27
|
-
'raw',
|
|
28
|
-
sharedSecret,
|
|
29
|
-
'HKDF',
|
|
30
|
-
false /* extractable */,
|
|
31
|
-
['deriveKey'] /* keyUsages */,
|
|
32
|
-
);
|
|
33
|
-
const aesKeyMaterialVal = await crypto.subtle.deriveKey(
|
|
34
|
-
{
|
|
35
|
-
name: 'HKDF',
|
|
36
|
-
hash: 'SHA-256',
|
|
37
|
-
salt: new Uint8Array(associationPublicKeyBuffer),
|
|
38
|
-
info: new Uint8Array(),
|
|
39
|
-
},
|
|
40
|
-
ecdhSecretKey,
|
|
41
|
-
{ name: 'AES-GCM', length: 128 },
|
|
42
|
-
false /* extractable */,
|
|
43
|
-
['encrypt', 'decrypt'],
|
|
44
|
-
);
|
|
45
|
-
return aesKeyMaterialVal as SharedSecret;
|
|
46
|
-
}
|
|
1
|
+
import { ENCODED_PUBLIC_KEY_LENGTH_BYTES } from "./encryptedMessage";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A secret agreed upon by the app and the wallet. Used as
|
|
5
|
+
* a symmetric key to encrypt and decrypt messages over an
|
|
6
|
+
* unsecured channel.
|
|
7
|
+
*/
|
|
8
|
+
export type SharedSecret = CryptoKey;
|
|
9
|
+
|
|
10
|
+
export default async function parseHelloRsp(
|
|
11
|
+
payloadBuffer: ArrayBuffer, // The X9.62-encoded wallet endpoint ephemeral ECDH public keypoint.
|
|
12
|
+
associationPublicKey: CryptoKey,
|
|
13
|
+
ecdhPrivateKey: CryptoKey,
|
|
14
|
+
): Promise<SharedSecret> {
|
|
15
|
+
const [associationPublicKeyBuffer, walletPublicKey] = await Promise.all([
|
|
16
|
+
crypto.subtle.exportKey('raw', associationPublicKey),
|
|
17
|
+
crypto.subtle.importKey(
|
|
18
|
+
'raw',
|
|
19
|
+
payloadBuffer.slice(0, ENCODED_PUBLIC_KEY_LENGTH_BYTES),
|
|
20
|
+
{ name: 'ECDH', namedCurve: 'P-256' },
|
|
21
|
+
false /* extractable */,
|
|
22
|
+
[] /* keyUsages */,
|
|
23
|
+
),
|
|
24
|
+
]);
|
|
25
|
+
const sharedSecret = await crypto.subtle.deriveBits({ name: 'ECDH', public: walletPublicKey }, ecdhPrivateKey, 256);
|
|
26
|
+
const ecdhSecretKey = await crypto.subtle.importKey(
|
|
27
|
+
'raw',
|
|
28
|
+
sharedSecret,
|
|
29
|
+
'HKDF',
|
|
30
|
+
false /* extractable */,
|
|
31
|
+
['deriveKey'] /* keyUsages */,
|
|
32
|
+
);
|
|
33
|
+
const aesKeyMaterialVal = await crypto.subtle.deriveKey(
|
|
34
|
+
{
|
|
35
|
+
name: 'HKDF',
|
|
36
|
+
hash: 'SHA-256',
|
|
37
|
+
salt: new Uint8Array(associationPublicKeyBuffer),
|
|
38
|
+
info: new Uint8Array(),
|
|
39
|
+
},
|
|
40
|
+
ecdhSecretKey,
|
|
41
|
+
{ name: 'AES-GCM', length: 128 },
|
|
42
|
+
false /* extractable */,
|
|
43
|
+
['encrypt', 'decrypt'],
|
|
44
|
+
);
|
|
45
|
+
return aesKeyMaterialVal as SharedSecret;
|
|
46
|
+
}
|
package/src/parseSessionProps.ts
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import { decryptMessage } from "./encryptedMessage";
|
|
2
|
-
import { SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode } from "./errors";
|
|
3
|
-
import { SharedSecret } from "./parseHelloRsp";
|
|
4
|
-
import { ProtocolVersion, SessionProperties } from "./types";
|
|
5
|
-
|
|
6
|
-
export default async function parseSessionProps(
|
|
7
|
-
message: ArrayBuffer,
|
|
8
|
-
sharedSecret: SharedSecret
|
|
9
|
-
): Promise<SessionProperties> {
|
|
10
|
-
const plaintext = await decryptMessage(message, sharedSecret);
|
|
11
|
-
const jsonProperties = JSON.parse(plaintext);
|
|
12
|
-
let protocolVersion: ProtocolVersion = 'legacy';
|
|
13
|
-
if (Object.hasOwnProperty.call(jsonProperties, 'v')) {
|
|
14
|
-
switch (jsonProperties.v) {
|
|
15
|
-
case 1:
|
|
16
|
-
case '1':
|
|
17
|
-
case 'v1':
|
|
18
|
-
protocolVersion = 'v1'
|
|
19
|
-
break;
|
|
20
|
-
case 'legacy':
|
|
21
|
-
protocolVersion = 'legacy'
|
|
22
|
-
break;
|
|
23
|
-
default:
|
|
24
|
-
throw new SolanaMobileWalletAdapterError(
|
|
25
|
-
SolanaMobileWalletAdapterErrorCode.ERROR_INVALID_PROTOCOL_VERSION,
|
|
26
|
-
`Unknown/unsupported protocol version: ${jsonProperties.v}`
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return <SessionProperties>({
|
|
31
|
-
protocol_version: protocolVersion
|
|
32
|
-
})
|
|
1
|
+
import { decryptMessage } from "./encryptedMessage";
|
|
2
|
+
import { SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode } from "./errors";
|
|
3
|
+
import { SharedSecret } from "./parseHelloRsp";
|
|
4
|
+
import { ProtocolVersion, SessionProperties } from "./types";
|
|
5
|
+
|
|
6
|
+
export default async function parseSessionProps(
|
|
7
|
+
message: ArrayBuffer,
|
|
8
|
+
sharedSecret: SharedSecret
|
|
9
|
+
): Promise<SessionProperties> {
|
|
10
|
+
const plaintext = await decryptMessage(message, sharedSecret);
|
|
11
|
+
const jsonProperties = JSON.parse(plaintext);
|
|
12
|
+
let protocolVersion: ProtocolVersion = 'legacy';
|
|
13
|
+
if (Object.hasOwnProperty.call(jsonProperties, 'v')) {
|
|
14
|
+
switch (jsonProperties.v) {
|
|
15
|
+
case 1:
|
|
16
|
+
case '1':
|
|
17
|
+
case 'v1':
|
|
18
|
+
protocolVersion = 'v1'
|
|
19
|
+
break;
|
|
20
|
+
case 'legacy':
|
|
21
|
+
protocolVersion = 'legacy'
|
|
22
|
+
break;
|
|
23
|
+
default:
|
|
24
|
+
throw new SolanaMobileWalletAdapterError(
|
|
25
|
+
SolanaMobileWalletAdapterErrorCode.ERROR_INVALID_PROTOCOL_VERSION,
|
|
26
|
+
`Unknown/unsupported protocol version: ${jsonProperties.v}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return <SessionProperties>({
|
|
31
|
+
protocol_version: protocolVersion
|
|
32
|
+
})
|
|
33
33
|
}
|
package/src/reflectorId.ts
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import { SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode } from './errors.js';
|
|
2
|
-
|
|
3
|
-
declare const tag: unique symbol;
|
|
4
|
-
export type ReflectorId = number & { readonly [tag]: 'ReflectorId' };
|
|
5
|
-
|
|
6
|
-
export function getRandomReflectorId(): ReflectorId {
|
|
7
|
-
return assertReflectorId(getRandomInt(0, 9007199254740991)); // 0 < id < 2^53 - 1
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function getRandomInt(min: number, max: number) {
|
|
11
|
-
const randomBuffer = new Uint32Array(1);
|
|
12
|
-
|
|
13
|
-
window.crypto.getRandomValues(randomBuffer);
|
|
14
|
-
|
|
15
|
-
let randomNumber = randomBuffer[0] / (0xffffffff + 1);
|
|
16
|
-
|
|
17
|
-
min = Math.ceil(min);
|
|
18
|
-
max = Math.floor(max);
|
|
19
|
-
return Math.floor(randomNumber * (max - min + 1)) + min;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function assertReflectorId(id: number): ReflectorId {
|
|
23
|
-
if (id < 0 || id > 9007199254740991) { // 0 < id < 2^53 - 1
|
|
24
|
-
throw new SolanaMobileWalletAdapterError(
|
|
25
|
-
SolanaMobileWalletAdapterErrorCode.ERROR_REFLECTOR_ID_OUT_OF_RANGE,
|
|
26
|
-
`Association port number must be between 49152 and 65535. ${id} given.`,
|
|
27
|
-
{ id },
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
return id as ReflectorId;
|
|
1
|
+
import { SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode } from './errors.js';
|
|
2
|
+
|
|
3
|
+
declare const tag: unique symbol;
|
|
4
|
+
export type ReflectorId = number & { readonly [tag]: 'ReflectorId' };
|
|
5
|
+
|
|
6
|
+
export function getRandomReflectorId(): ReflectorId {
|
|
7
|
+
return assertReflectorId(getRandomInt(0, 9007199254740991)); // 0 < id < 2^53 - 1
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function getRandomInt(min: number, max: number) {
|
|
11
|
+
const randomBuffer = new Uint32Array(1);
|
|
12
|
+
|
|
13
|
+
window.crypto.getRandomValues(randomBuffer);
|
|
14
|
+
|
|
15
|
+
let randomNumber = randomBuffer[0] / (0xffffffff + 1);
|
|
16
|
+
|
|
17
|
+
min = Math.ceil(min);
|
|
18
|
+
max = Math.floor(max);
|
|
19
|
+
return Math.floor(randomNumber * (max - min + 1)) + min;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function assertReflectorId(id: number): ReflectorId {
|
|
23
|
+
if (id < 0 || id > 9007199254740991) { // 0 < id < 2^53 - 1
|
|
24
|
+
throw new SolanaMobileWalletAdapterError(
|
|
25
|
+
SolanaMobileWalletAdapterErrorCode.ERROR_REFLECTOR_ID_OUT_OF_RANGE,
|
|
26
|
+
`Association port number must be between 49152 and 65535. ${id} given.`,
|
|
27
|
+
{ id },
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return id as ReflectorId;
|
|
31
31
|
}
|
package/src/transact.ts
CHANGED
|
@@ -330,29 +330,6 @@ export async function transact<TReturn>(
|
|
|
330
330
|
});
|
|
331
331
|
}
|
|
332
332
|
|
|
333
|
-
export async function transactRemote<TReturn>(
|
|
334
|
-
callback: (wallet: RemoteMobileWallet) => TReturn,
|
|
335
|
-
config: RemoteWalletAssociationConfig,
|
|
336
|
-
): Promise<{associationUrl: URL, result: Promise<TReturn>}> {
|
|
337
|
-
return startRemoteScenario(config).then((scenario) => {
|
|
338
|
-
return {
|
|
339
|
-
associationUrl: scenario.associationUrl,
|
|
340
|
-
result: scenario.wallet.then((wallet) =>{
|
|
341
|
-
return callback(new Proxy(wallet as RemoteMobileWallet, {
|
|
342
|
-
get<TMethodName extends keyof RemoteMobileWallet>(target: RemoteMobileWallet, p: TMethodName) {
|
|
343
|
-
if (p == 'terminateSession') {
|
|
344
|
-
return async function () {
|
|
345
|
-
scenario.close();
|
|
346
|
-
return;
|
|
347
|
-
};
|
|
348
|
-
} else return target[p];
|
|
349
|
-
},
|
|
350
|
-
}));
|
|
351
|
-
}),
|
|
352
|
-
};
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
|
|
356
333
|
export async function startRemoteScenario(
|
|
357
334
|
config: RemoteWalletAssociationConfig,
|
|
358
335
|
): Promise<RemoteScenario> {
|
package/.DS_Store
DELETED
|
Binary file
|