@enbox/browser 0.3.39 → 0.3.40
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/dist/browser.mjs +16 -16
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/browser-connect-handler.js +3 -3
- package/dist/esm/browser-connect-handler.js.map +1 -1
- package/dist/esm/dweb-connect-client.js +267 -190
- package/dist/esm/dweb-connect-client.js.map +1 -1
- package/dist/esm/dweb-connect-messages.js +54 -0
- package/dist/esm/dweb-connect-messages.js.map +1 -0
- package/dist/esm/dweb-connect-wallet.js +209 -0
- package/dist/esm/dweb-connect-wallet.js.map +1 -0
- package/dist/esm/index.js +9 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/types/dweb-connect-client.d.ts +123 -59
- package/dist/types/dweb-connect-client.d.ts.map +1 -1
- package/dist/types/dweb-connect-messages.d.ts +64 -0
- package/dist/types/dweb-connect-messages.d.ts.map +1 -0
- package/dist/types/dweb-connect-wallet.d.ts +101 -0
- package/dist/types/dweb-connect-wallet.d.ts.map +1 -0
- package/dist/types/index.d.ts +8 -4
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +9 -6
- package/src/browser-connect-handler.ts +4 -4
- package/src/dweb-connect-client.ts +327 -251
- package/src/dweb-connect-messages.ts +91 -0
- package/src/dweb-connect-wallet.ts +258 -0
- package/src/index.ts +24 -5
- package/dist/esm/dweb-connect-crypto.js +0 -112
- package/dist/esm/dweb-connect-crypto.js.map +0 -1
- package/dist/types/dweb-connect-crypto.d.ts +0 -52
- package/dist/types/dweb-connect-crypto.d.ts.map +0 -1
- package/src/dweb-connect-crypto.ts +0 -156
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DWeb Connect wallet transport — the wallet side of the popup/postMessage
|
|
3
|
+
* connect flow, exported for wallet apps (e.g. the Enbox web wallet).
|
|
4
|
+
*
|
|
5
|
+
* A wallet's `/dweb-connect` page creates one transport per session:
|
|
6
|
+
*
|
|
7
|
+
* 1. `create()` generates a fresh ephemeral X25519 key pair and emits the
|
|
8
|
+
* `loaded` beacon (public key + wallet origin) to the opener window with a
|
|
9
|
+
* pinned `targetOrigin`.
|
|
10
|
+
* 2. `awaitRequest()` receives the sealed request ciphertext and opens it via
|
|
11
|
+
* the `@enbox/connect` kernel (`ConnectProvider.openRequest`), which
|
|
12
|
+
* value-checks the `apv` origin binding against this wallet's origin.
|
|
13
|
+
* 3. After the consent ceremony, the wallet posts the sealed response JWE via
|
|
14
|
+
* `sendResponse()` — or the deny token via `deny()` — back to the opener,
|
|
15
|
+
* again with a pinned `targetOrigin`.
|
|
16
|
+
*
|
|
17
|
+
* The dapp origin is never assumed: it is taken from an explicit option or
|
|
18
|
+
* derived from `document.referrer`, and `create()` fails when neither is
|
|
19
|
+
* available. `'*'` is never used as a `targetOrigin`.
|
|
20
|
+
*
|
|
21
|
+
* @module
|
|
22
|
+
*/
|
|
23
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
24
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
25
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
26
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
27
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
28
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
29
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
import { X25519 } from '@enbox/crypto';
|
|
33
|
+
import { CONNECT_DENIED_TOKEN, ConnectProvider } from '@enbox/connect';
|
|
34
|
+
import { DWEB_CONNECT_LOADED_MESSAGE_TYPE, DWEB_CONNECT_REQUEST_MESSAGE_TYPE, DWEB_CONNECT_RESPONSE_MESSAGE_TYPE, getTrustedMessage, } from './dweb-connect-messages.js';
|
|
35
|
+
/** Default budget for awaiting the dapp's sealed request. */
|
|
36
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 300000;
|
|
37
|
+
/**
|
|
38
|
+
* Wallet-side postMessage transport for the DWeb Connect popup flow.
|
|
39
|
+
*
|
|
40
|
+
* Security properties:
|
|
41
|
+
* - `targetOrigin` of every outbound `postMessage` (beacon and response) is
|
|
42
|
+
* pinned to the dapp origin — never `'*'`.
|
|
43
|
+
* - Inbound messages are dropped unless `event.origin` equals the pinned dapp
|
|
44
|
+
* origin AND `event.source` is the dapp window.
|
|
45
|
+
* - The ephemeral X25519 private key never leaves the transport; the request
|
|
46
|
+
* JWE is opened by the kernel with the `apv` header value-checked against
|
|
47
|
+
* this wallet's own origin.
|
|
48
|
+
*/
|
|
49
|
+
export class WalletPostMessageTransport {
|
|
50
|
+
constructor(params) {
|
|
51
|
+
this._requestReceived = false;
|
|
52
|
+
this._dappOrigin = params.dappOrigin;
|
|
53
|
+
this._dappWindow = params.dappWindow;
|
|
54
|
+
this._recipientPrivateKey = params.recipientPrivateKey;
|
|
55
|
+
this._requestPromise = new Promise((resolve, reject) => {
|
|
56
|
+
this._resolveRequest = resolve;
|
|
57
|
+
this._rejectRequest = reject;
|
|
58
|
+
});
|
|
59
|
+
// Mark early rejections (timeout before `awaitRequest()` is called) as
|
|
60
|
+
// handled until the wallet attaches its own handlers.
|
|
61
|
+
this._requestPromise.catch(() => undefined);
|
|
62
|
+
this._messageListener = (event) => { this.onMessage(event); };
|
|
63
|
+
window.addEventListener('message', this._messageListener);
|
|
64
|
+
this._timeoutId = setTimeout(() => {
|
|
65
|
+
var _a;
|
|
66
|
+
this.close();
|
|
67
|
+
(_a = this._rejectRequest) === null || _a === void 0 ? void 0 : _a.call(this, new Error('[@enbox/browser] Timed out waiting for the connect request from the dapp.'));
|
|
68
|
+
}, params.timeoutMs);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Creates the transport for one connect session: resolves and pins the dapp
|
|
72
|
+
* origin, generates a fresh ephemeral X25519 key pair, starts listening for
|
|
73
|
+
* the sealed request, and emits the `loaded` beacon to the dapp window.
|
|
74
|
+
*
|
|
75
|
+
* @throws If not in a browser, if no dapp window is available, or if the
|
|
76
|
+
* dapp origin can neither be supplied nor derived from the referrer.
|
|
77
|
+
*/
|
|
78
|
+
static create() {
|
|
79
|
+
return __awaiter(this, arguments, void 0, function* (options = {}) {
|
|
80
|
+
var _a, _b;
|
|
81
|
+
if (typeof window === 'undefined') {
|
|
82
|
+
throw new Error('[@enbox/browser] WalletPostMessageTransport is only available in browser environments.');
|
|
83
|
+
}
|
|
84
|
+
const dappWindow = (_a = options.dappWindow) !== null && _a !== void 0 ? _a : window.opener;
|
|
85
|
+
if (!dappWindow) {
|
|
86
|
+
throw new Error('[@enbox/browser] No opener window: the DWeb Connect page must be opened as a popup by the dapp.');
|
|
87
|
+
}
|
|
88
|
+
const dappOrigin = resolveDappOrigin(options.dappOrigin);
|
|
89
|
+
const recipientPrivateKey = yield X25519.generateKey();
|
|
90
|
+
const walletEpk = { kty: 'OKP', crv: 'X25519', x: recipientPrivateKey.x };
|
|
91
|
+
const transport = new WalletPostMessageTransport({
|
|
92
|
+
dappOrigin,
|
|
93
|
+
dappWindow,
|
|
94
|
+
recipientPrivateKey,
|
|
95
|
+
timeoutMs: (_b = options.timeoutMs) !== null && _b !== void 0 ? _b : DEFAULT_REQUEST_TIMEOUT_MS,
|
|
96
|
+
});
|
|
97
|
+
// The listener is registered, so the beacon cannot race the request.
|
|
98
|
+
dappWindow.postMessage({
|
|
99
|
+
type: DWEB_CONNECT_LOADED_MESSAGE_TYPE,
|
|
100
|
+
walletEpk,
|
|
101
|
+
walletOrigin: globalThis.location.origin,
|
|
102
|
+
}, dappOrigin);
|
|
103
|
+
return transport;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/** The pinned origin of the dapp this transport exchanges messages with. */
|
|
107
|
+
get dappOrigin() {
|
|
108
|
+
return this._dappOrigin;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Awaits the dapp's sealed request and opens it via the kernel: ECDH-ES
|
|
112
|
+
* decryption with this session's ephemeral key, `apv` value-checked against
|
|
113
|
+
* this wallet's origin, JWT signature verification, and payload shape
|
|
114
|
+
* assertion. Rejects on timeout, on an unopenable request, or when the
|
|
115
|
+
* request does not use the `post_message` reply mode.
|
|
116
|
+
*/
|
|
117
|
+
awaitRequest() {
|
|
118
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
119
|
+
return yield this._requestPromise;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Posts the sealed response JWE (or the deny token) back to the dapp window
|
|
124
|
+
* with the `targetOrigin` pinned to the dapp origin, then closes the
|
|
125
|
+
* transport.
|
|
126
|
+
*
|
|
127
|
+
* @param idToken - The sealed response JWE, or the literal deny token.
|
|
128
|
+
*/
|
|
129
|
+
sendResponse(idToken) {
|
|
130
|
+
this._dappWindow.postMessage({
|
|
131
|
+
type: DWEB_CONNECT_RESPONSE_MESSAGE_TYPE,
|
|
132
|
+
payload: idToken,
|
|
133
|
+
}, this._dappOrigin);
|
|
134
|
+
this.close();
|
|
135
|
+
}
|
|
136
|
+
/** Posts the deny token back to the dapp — the user rejected the request. */
|
|
137
|
+
deny() {
|
|
138
|
+
this.sendResponse(CONNECT_DENIED_TOKEN);
|
|
139
|
+
}
|
|
140
|
+
/** Stops listening and releases the session's timers. Idempotent. */
|
|
141
|
+
close() {
|
|
142
|
+
clearTimeout(this._timeoutId);
|
|
143
|
+
if (this._messageListener !== undefined) {
|
|
144
|
+
window.removeEventListener('message', this._messageListener);
|
|
145
|
+
this._messageListener = undefined;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
onMessage(event) {
|
|
149
|
+
const message = getTrustedMessage(event, this._dappOrigin, this._dappWindow);
|
|
150
|
+
if (message === undefined) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (message.type !== DWEB_CONNECT_REQUEST_MESSAGE_TYPE || this._requestReceived) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
this._requestReceived = true;
|
|
157
|
+
if (typeof message.jwe !== 'string') {
|
|
158
|
+
this.settleRequest(new Error('[@enbox/browser] Connect request message did not carry a ciphertext payload.'));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
void this.openRequest(message.jwe);
|
|
162
|
+
}
|
|
163
|
+
openRequest(jwe) {
|
|
164
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
165
|
+
try {
|
|
166
|
+
const request = yield ConnectProvider.openRequest({
|
|
167
|
+
jwe,
|
|
168
|
+
decryption: {
|
|
169
|
+
mode: 'ecdh-es',
|
|
170
|
+
recipientPrivateKey: this._recipientPrivateKey,
|
|
171
|
+
walletOrigin: globalThis.location.origin,
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
if (request.reply.mode !== 'post_message') {
|
|
175
|
+
this.settleRequest(new Error('[@enbox/browser] Connect request over the popup channel must use the `post_message` reply mode.'));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
this.settleRequest(request);
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
this.settleRequest(error instanceof Error ? error : new Error(String(error)));
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
settleRequest(outcome) {
|
|
186
|
+
var _a, _b;
|
|
187
|
+
clearTimeout(this._timeoutId);
|
|
188
|
+
if (outcome instanceof Error) {
|
|
189
|
+
this.close();
|
|
190
|
+
(_a = this._rejectRequest) === null || _a === void 0 ? void 0 : _a.call(this, outcome);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
(_b = this._resolveRequest) === null || _b === void 0 ? void 0 : _b.call(this, outcome);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Resolves the dapp origin to pin: the explicit option when provided,
|
|
198
|
+
* otherwise the origin of `document.referrer`. Never falls back to `'*'`.
|
|
199
|
+
*/
|
|
200
|
+
function resolveDappOrigin(explicitOrigin) {
|
|
201
|
+
if (explicitOrigin !== undefined) {
|
|
202
|
+
return new URL(explicitOrigin).origin;
|
|
203
|
+
}
|
|
204
|
+
if (document.referrer) {
|
|
205
|
+
return new URL(document.referrer).origin;
|
|
206
|
+
}
|
|
207
|
+
throw new Error('[@enbox/browser] Unable to determine the dapp origin: no `dappOrigin` option was provided and `document.referrer` is empty.');
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=dweb-connect-wallet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dweb-connect-wallet.js","sourceRoot":"","sources":["../../src/dweb-connect-wallet.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/index.js
CHANGED
|
@@ -31,12 +31,18 @@ export { Enbox, defineProtocol, repository, } from '@enbox/api';
|
|
|
31
31
|
//
|
|
32
32
|
// Authentication lifecycle, session management, connect handlers.
|
|
33
33
|
export { AuthManager, AuthSession, normalizeProtocolRequests, WalletConnect, } from '@enbox/auth/browser';
|
|
34
|
+
// ─── Re-exports from @enbox/connect ─────────────────────────────
|
|
35
|
+
//
|
|
36
|
+
// The connect kernel pieces wallet apps need alongside the popup
|
|
37
|
+
// transports: opening/sealing envelopes and the deny token.
|
|
38
|
+
export { CONNECT_DENIED_TOKEN, ConnectProvider } from '@enbox/connect';
|
|
34
39
|
// ─── Browser-specific exports ───────────────────────────────────
|
|
35
40
|
//
|
|
36
|
-
// DWeb Connect, wallet selector, DRL polyfills.
|
|
41
|
+
// DWeb Connect popup transports, wallet selector, DRL polyfills.
|
|
37
42
|
export * from './web-features.js';
|
|
38
43
|
export { BrowserConnectHandler, DEFAULT_WALLETS } from './browser-connect-handler.js';
|
|
39
|
-
export {
|
|
44
|
+
export { connectViaPopup, PopupClientTransport, PopupWindowClosedError } from './dweb-connect-client.js';
|
|
45
|
+
export { WalletPostMessageTransport } from './dweb-connect-wallet.js';
|
|
46
|
+
export { DWEB_CONNECT_LOADED_MESSAGE_TYPE, DWEB_CONNECT_PATH, DWEB_CONNECT_REQUEST_MESSAGE_TYPE, DWEB_CONNECT_RESPONSE_MESSAGE_TYPE, } from './dweb-connect-messages.js';
|
|
40
47
|
export { showWalletSelector } from './ui/wallet-selector.js';
|
|
41
|
-
export { encryptPostMessagePayload, generateEphemeralKeyPair } from './dweb-connect-crypto.js';
|
|
42
48
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,mEAAmE;AACnE,EAAE;AACF,kEAAkE;AAElE,OAAO,EACL,KAAK,EACL,cAAc,EACd,UAAU,GACX,MAAM,YAAY,CAAC;AAUpB,mEAAmE;AACnE,EAAE;AACF,kEAAkE;AAElE,OAAO,EACL,WAAW,EACX,WAAW,EACX,yBAAyB,EACzB,aAAa,GACd,MAAM,qBAAqB,CAAC;AAuB7B,mEAAmE;AACnE,EAAE;AACF,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,mEAAmE;AACnE,EAAE;AACF,kEAAkE;AAElE,OAAO,EACL,KAAK,EACL,cAAc,EACd,UAAU,GACX,MAAM,YAAY,CAAC;AAUpB,mEAAmE;AACnE,EAAE;AACF,kEAAkE;AAElE,OAAO,EACL,WAAW,EACX,WAAW,EACX,yBAAyB,EACzB,aAAa,GACd,MAAM,qBAAqB,CAAC;AAuB7B,mEAAmE;AACnE,EAAE;AACF,iEAAiE;AACjE,4DAA4D;AAE5D,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGvE,mEAAmE;AACnE,EAAE;AACF,iEAAiE;AAEjE,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEtF,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEzG,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAEtE,OAAO,EACL,gCAAgC,EAChC,iBAAiB,EACjB,iCAAiC,EACjC,kCAAkC,GACnC,MAAM,4BAA4B,CAAC;AAMpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -1,82 +1,146 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* DWeb Connect client —
|
|
2
|
+
* DWeb Connect client — the dapp side of the popup/postMessage connect flow.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* {@link PopupClientTransport} implements the `@enbox/connect` kernel's
|
|
5
|
+
* `ConnectTransport` over a wallet popup:
|
|
6
|
+
*
|
|
7
|
+
* 1. The dapp opens `${walletUrl}/dweb-connect` as a popup window.
|
|
8
|
+
* 2. The wallet emits a `loaded` beacon carrying a fresh ephemeral X25519
|
|
9
|
+
* public key and its origin.
|
|
10
|
+
* 3. The kernel seals the signed connect request to that key (ECDH-ES,
|
|
11
|
+
* `apv` bound to the wallet origin) and the transport posts the
|
|
12
|
+
* ciphertext to the popup.
|
|
13
|
+
* 4. The wallet posts back the sealed response JWE (or the deny token),
|
|
14
|
+
* which the kernel opens and value-checks.
|
|
15
|
+
*
|
|
16
|
+
* Only ciphertext crosses the postMessage channel. Every message is checked
|
|
17
|
+
* against the wallet origin derived from the configured wallet URL (never
|
|
18
|
+
* `'*'`), and against the popup window as `event.source`.
|
|
7
19
|
*
|
|
8
20
|
* @module
|
|
9
21
|
*/
|
|
10
|
-
import type { ConnectPermissionRequest } from '@enbox/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
22
|
+
import type { ConnectPermissionRequest, ConnectRequestProfile, ConnectResult, ConnectTransport } from '@enbox/connect';
|
|
23
|
+
/**
|
|
24
|
+
* Thrown when the user closes the wallet popup before the wallet finished
|
|
25
|
+
* loading (i.e. before its `loaded` beacon arrived). Callers typically treat
|
|
26
|
+
* this the same as a user denial.
|
|
27
|
+
*/
|
|
28
|
+
export declare class PopupWindowClosedError extends Error {
|
|
29
|
+
constructor();
|
|
30
|
+
}
|
|
31
|
+
/** Options for constructing a {@link PopupClientTransport}. */
|
|
32
|
+
export type PopupClientTransportOptions = {
|
|
33
|
+
/** Base URL of the wallet app (e.g. `https://enbox-wallet.pages.dev`). */
|
|
15
34
|
walletUrl: string;
|
|
16
|
-
/** The DID to pre-select in the wallet's identity picker. */
|
|
17
|
-
did?: string;
|
|
18
35
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
36
|
+
* Total budget in milliseconds for the popup handshake. The popup is closed
|
|
37
|
+
* and the handshake rejected when the wallet has not responded in time.
|
|
38
|
+
* @default 300_000 (5 minutes)
|
|
39
|
+
*/
|
|
40
|
+
timeoutMs?: number;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Popup/postMessage {@link ConnectTransport} for browser dapps.
|
|
44
|
+
*
|
|
45
|
+
* Single-use: construct a new transport per handshake. The **constructor**
|
|
46
|
+
* opens the wallet popup synchronously — so `window.open` runs inside the user
|
|
47
|
+
* gesture, ahead of the kernel's awaited key generation, and survives strict
|
|
48
|
+
* popup blockers; `requestProfile()` then awaits the wallet's `loaded` beacon;
|
|
49
|
+
* `deliverRequest()` posts the sealed request ciphertext; `awaitResponse()`
|
|
50
|
+
* resolves with the sealed response JWE, or the deny token when the user denies
|
|
51
|
+
* or closes the popup after the handshake was established.
|
|
52
|
+
*
|
|
53
|
+
* Security properties:
|
|
54
|
+
* - `targetOrigin` of every outbound `postMessage` is pinned to the origin
|
|
55
|
+
* derived from `walletUrl` — never `'*'`.
|
|
56
|
+
* - Inbound messages are dropped unless `event.origin` equals the pinned
|
|
57
|
+
* wallet origin AND `event.source` is the popup window this transport opened.
|
|
58
|
+
* - The beacon's `walletOrigin` field must equal the pinned origin, and its
|
|
59
|
+
* `walletEpk` must be a public-only X25519 JWK; a malformed beacon from the
|
|
60
|
+
* genuine popup fails the handshake closed.
|
|
61
|
+
*/
|
|
62
|
+
export declare class PopupClientTransport implements ConnectTransport {
|
|
63
|
+
/** {@inheritDoc ConnectTransport.requiresPin} */
|
|
64
|
+
readonly requiresPin: boolean;
|
|
65
|
+
private readonly _walletOrigin;
|
|
66
|
+
private readonly _timeoutMs;
|
|
67
|
+
private readonly _popup;
|
|
68
|
+
private _settled;
|
|
69
|
+
private _walletEpkReceived;
|
|
70
|
+
private _timeoutId?;
|
|
71
|
+
private _closedPollId?;
|
|
72
|
+
private _messageListener?;
|
|
73
|
+
private readonly _walletEpkPromise;
|
|
74
|
+
private _resolveWalletEpk?;
|
|
75
|
+
private _rejectWalletEpk?;
|
|
76
|
+
private readonly _responsePromise;
|
|
77
|
+
private _resolveResponse?;
|
|
78
|
+
private _rejectResponse?;
|
|
79
|
+
constructor(options: PopupClientTransportOptions);
|
|
80
|
+
/**
|
|
81
|
+
* Awaits the already-open popup's `loaded` beacon, then returns the popup
|
|
82
|
+
* channel profile: ECDH-ES encryption to the beacon's ephemeral key with the
|
|
83
|
+
* pinned wallet origin as the `apv` binding, a `post_message` reply
|
|
84
|
+
* descriptor, and the client-supplied `state` correlator.
|
|
85
|
+
*
|
|
86
|
+
* The popup was opened synchronously at construction, so this method only
|
|
87
|
+
* awaits the beacon — it never issues the blocker-sensitive `window.open`.
|
|
88
|
+
*
|
|
89
|
+
* @param state - The handshake correlator minted by the {@link ConnectClient}.
|
|
90
|
+
* @throws If the user closes the popup before the beacon arrives
|
|
91
|
+
* ({@link PopupWindowClosedError}), the beacon is malformed, or on
|
|
92
|
+
* timeout.
|
|
93
|
+
*/
|
|
94
|
+
requestProfile(state: string): Promise<ConnectRequestProfile>;
|
|
95
|
+
/**
|
|
96
|
+
* Posts the sealed request ciphertext to the wallet popup with the
|
|
97
|
+
* `targetOrigin` pinned to the wallet origin.
|
|
98
|
+
*/
|
|
99
|
+
deliverRequest(jwe: string): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Awaits the wallet's response ciphertext: the sealed response JWE, or the
|
|
102
|
+
* deny token when the user denies in the wallet or closes the popup.
|
|
103
|
+
* Rejects on timeout.
|
|
21
104
|
*/
|
|
105
|
+
awaitResponse(): Promise<string>;
|
|
106
|
+
private onMessage;
|
|
107
|
+
private onLoadedBeacon;
|
|
108
|
+
private onResponseMessage;
|
|
109
|
+
private onClosedPoll;
|
|
110
|
+
private fail;
|
|
111
|
+
private cleanup;
|
|
112
|
+
}
|
|
113
|
+
/** Options for a one-shot {@link connectViaPopup} flow. */
|
|
114
|
+
export type PopupConnectOptions = {
|
|
115
|
+
/** Base URL of the wallet app (e.g. `https://enbox-wallet.pages.dev`). */
|
|
116
|
+
walletUrl: string;
|
|
117
|
+
/** DWN protocols and permission scopes to request from the wallet. */
|
|
22
118
|
permissionRequests: ConnectPermissionRequest[];
|
|
23
119
|
/**
|
|
24
|
-
* Timeout in milliseconds
|
|
25
|
-
* if the wallet doesn't respond within this time.
|
|
120
|
+
* Timeout in milliseconds for the popup handshake.
|
|
26
121
|
* @default 300_000 (5 minutes)
|
|
27
122
|
*/
|
|
28
123
|
timeout?: number;
|
|
29
124
|
/**
|
|
30
|
-
* Display name of the requesting application
|
|
31
|
-
*
|
|
125
|
+
* Display name of the requesting application, shown in the wallet's
|
|
126
|
+
* consent screen. Defaults to the dapp's host.
|
|
32
127
|
*/
|
|
33
128
|
appName?: string;
|
|
34
129
|
/**
|
|
35
|
-
* Icon URL of the requesting application
|
|
36
|
-
*
|
|
130
|
+
* Icon URL of the requesting application, shown alongside the app name in
|
|
131
|
+
* the wallet's consent screen.
|
|
37
132
|
*/
|
|
38
133
|
appIcon?: string;
|
|
39
|
-
|
|
40
|
-
* A portable identity to transfer to the wallet for import.
|
|
41
|
-
*
|
|
42
|
-
* When provided, the wallet imports this identity and creates
|
|
43
|
-
* delegate grants for the dapp, allowing the dapp to transition
|
|
44
|
-
* from local-DID mode to delegate mode while keeping the same DID.
|
|
45
|
-
*/
|
|
46
|
-
portableIdentity?: PortableIdentity;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Open a wallet popup and run the DWeb Connect postMessage flow.
|
|
50
|
-
*
|
|
51
|
-
* Protocol:
|
|
52
|
-
* 1. Dapp opens `${walletUrl}/dweb-connect` as a popup.
|
|
53
|
-
* 2. Wallet sends `{ type: 'dweb-connect-loaded' }` when ready.
|
|
54
|
-
* 3. Dapp sends `{ type: 'dweb-connect-authorization-request', did, permissions,
|
|
55
|
-
* appName?, appIcon?, portableIdentity? }`.
|
|
56
|
-
* 4. Wallet shows consent UI, then sends back
|
|
57
|
-
* `{ type: 'dweb-connect-authorization-response', delegateDid, grants }`.
|
|
58
|
-
* 5. Popup closes.
|
|
59
|
-
*
|
|
60
|
-
* @returns The delegate credentials, or `undefined` if the user denied.
|
|
61
|
-
* @throws If the popup is blocked, times out, or the wallet returns an error.
|
|
62
|
-
*/
|
|
63
|
-
declare function initClient(options: DWebConnectClientOptions): Promise<ConnectResult | undefined>;
|
|
134
|
+
};
|
|
64
135
|
/**
|
|
65
|
-
*
|
|
136
|
+
* Runs one DWeb Connect popup handshake end-to-end: opens the wallet popup,
|
|
137
|
+
* drives the `@enbox/connect` kernel client over a {@link PopupClientTransport},
|
|
138
|
+
* and returns the delegated credentials.
|
|
66
139
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* @param walletUrl - Base URL of the wallet to probe.
|
|
72
|
-
* @param did - The DID to check.
|
|
73
|
-
* @param timeout - Probe timeout in ms. Default: 5_000 (5 seconds).
|
|
74
|
-
* @returns `true` if the wallet manages the DID, `false` otherwise.
|
|
140
|
+
* @returns The delegate credentials, or `undefined` when the user denied the
|
|
141
|
+
* request or closed the popup.
|
|
142
|
+
* @throws If the popup is blocked, the handshake times out, or the wallet
|
|
143
|
+
* returns an invalid response.
|
|
75
144
|
*/
|
|
76
|
-
declare function
|
|
77
|
-
export declare const DWebConnect: {
|
|
78
|
-
initClient: typeof initClient;
|
|
79
|
-
probeWalletSupport: typeof probeWalletSupport;
|
|
80
|
-
};
|
|
81
|
-
export {};
|
|
145
|
+
export declare function connectViaPopup(options: PopupConnectOptions): Promise<ConnectResult | undefined>;
|
|
82
146
|
//# sourceMappingURL=dweb-connect-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dweb-connect-client.d.ts","sourceRoot":"","sources":["../../src/dweb-connect-client.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"dweb-connect-client.d.ts","sourceRoot":"","sources":["../../src/dweb-connect-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAEV,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AA+BxB;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;;CAKhD;AAED,+DAA+D;AAC/D,MAAM,MAAM,2BAA2B,GAAG;IACxC,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,oBAAqB,YAAW,gBAAgB;IAC3D,iDAAiD;IACjD,SAAgB,WAAW,EAAE,OAAO,CAAS;IAE7C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,UAAU,CAAC,CAAgC;IACnD,OAAO,CAAC,aAAa,CAAC,CAAiC;IACvD,OAAO,CAAC,gBAAgB,CAAC,CAAgC;IAEzD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAe;IACjD,OAAO,CAAC,iBAAiB,CAAC,CAA2B;IACrD,OAAO,CAAC,gBAAgB,CAAC,CAAyB;IAElD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IACnD,OAAO,CAAC,gBAAgB,CAAC,CAA4B;IACrD,OAAO,CAAC,eAAe,CAAC,CAAyB;gBAErC,OAAO,EAAE,2BAA2B;IA8ChD;;;;;;;;;;;;;OAaG;IACU,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAU1E;;;OAGG;IACU,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD;;;;OAIG;IACU,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7C,OAAO,CAAC,SAAS;IAcjB,OAAO,CAAC,cAAc;IAwBtB,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,OAAO;CAQhB;AAED,2DAA2D;AAC3D,MAAM,MAAM,mBAAmB,GAAG;IAChC,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAElB,sEAAsE;IACtE,kBAAkB,EAAE,wBAAwB,EAAE,CAAC;IAE/C;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAmBF;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAqBtG"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire shapes for the DWeb Connect popup/postMessage channel.
|
|
3
|
+
*
|
|
4
|
+
* The dapp and the wallet exchange exactly three message kinds over
|
|
5
|
+
* `window.postMessage`:
|
|
6
|
+
*
|
|
7
|
+
* 1. `loaded` beacon (wallet → dapp): announces the wallet page is ready and
|
|
8
|
+
* carries a fresh ephemeral X25519 public key plus the wallet's origin.
|
|
9
|
+
* 2. `request` (dapp → wallet): the sealed connect request JWE — ciphertext
|
|
10
|
+
* only, encrypted to the beacon key with ECDH-ES and the wallet origin
|
|
11
|
+
* bound into the JWE `apv` header.
|
|
12
|
+
* 3. `response` (wallet → dapp): the sealed connect response JWE, or the
|
|
13
|
+
* literal deny token — again ciphertext only.
|
|
14
|
+
*
|
|
15
|
+
* Plaintext never crosses the channel, and both sides pin `targetOrigin`
|
|
16
|
+
* and verify `event.origin` / `event.source` on every message.
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
import type { Jwk } from '@enbox/crypto';
|
|
21
|
+
/** Path of the wallet's DWeb Connect page, opened as a popup by the dapp. */
|
|
22
|
+
export declare const DWEB_CONNECT_PATH = "/dweb-connect";
|
|
23
|
+
/** Message type of the wallet's `loaded` beacon (wallet → dapp). */
|
|
24
|
+
export declare const DWEB_CONNECT_LOADED_MESSAGE_TYPE = "enbox-connect-loaded";
|
|
25
|
+
/** Message type carrying the sealed connect request JWE (dapp → wallet). */
|
|
26
|
+
export declare const DWEB_CONNECT_REQUEST_MESSAGE_TYPE = "enbox-connect-request";
|
|
27
|
+
/** Message type carrying the sealed connect response JWE or deny token (wallet → dapp). */
|
|
28
|
+
export declare const DWEB_CONNECT_RESPONSE_MESSAGE_TYPE = "enbox-connect-response";
|
|
29
|
+
/**
|
|
30
|
+
* The wallet's readiness beacon. Emitted to `window.opener` once the wallet's
|
|
31
|
+
* DWeb Connect page has generated its per-session ephemeral X25519 key.
|
|
32
|
+
*/
|
|
33
|
+
export type DWebConnectLoadedMessage = {
|
|
34
|
+
type: typeof DWEB_CONNECT_LOADED_MESSAGE_TYPE;
|
|
35
|
+
/** Fresh ephemeral X25519 public JWK the dapp seals the request to. */
|
|
36
|
+
walletEpk: Jwk;
|
|
37
|
+
/** The wallet's own origin; must match the origin the dapp has pinned. */
|
|
38
|
+
walletOrigin: string;
|
|
39
|
+
};
|
|
40
|
+
/** The dapp's sealed connect request, posted to the wallet popup. */
|
|
41
|
+
export type DWebConnectRequestMessage = {
|
|
42
|
+
type: typeof DWEB_CONNECT_REQUEST_MESSAGE_TYPE;
|
|
43
|
+
/** The sealed connect request as a Compact JWE string. */
|
|
44
|
+
jwe: string;
|
|
45
|
+
};
|
|
46
|
+
/** The wallet's sealed connect response, posted back to the opener. */
|
|
47
|
+
export type DWebConnectResponseMessage = {
|
|
48
|
+
type: typeof DWEB_CONNECT_RESPONSE_MESSAGE_TYPE;
|
|
49
|
+
/** The sealed connect response JWE, or the literal `CONNECT_DENIED_TOKEN`. */
|
|
50
|
+
payload: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Applies the shared inbound-message trust filter for the popup channel:
|
|
54
|
+
* pins the message to the expected `event.origin`, pins its `event.source` to
|
|
55
|
+
* the expected window, and requires a non-null object payload.
|
|
56
|
+
*
|
|
57
|
+
* Returns the payload cast to a plain record when every check passes, or
|
|
58
|
+
* `undefined` when the message must be dropped. Both the dapp-side and
|
|
59
|
+
* wallet-side transports early-return on `undefined` before inspecting any
|
|
60
|
+
* message field — this is the security-critical filter that keeps hostile
|
|
61
|
+
* origins and stray windows off the channel.
|
|
62
|
+
*/
|
|
63
|
+
export declare function getTrustedMessage(event: MessageEvent, expectedOrigin: string, expectedSource: Window | undefined): Record<string, unknown> | undefined;
|
|
64
|
+
//# sourceMappingURL=dweb-connect-messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dweb-connect-messages.d.ts","sourceRoot":"","sources":["../../src/dweb-connect-messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEzC,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD,oEAAoE;AACpE,eAAO,MAAM,gCAAgC,yBAAyB,CAAC;AAEvE,4EAA4E;AAC5E,eAAO,MAAM,iCAAiC,0BAA0B,CAAC;AAEzE,2FAA2F;AAC3F,eAAO,MAAM,kCAAkC,2BAA2B,CAAC;AAE3E;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,OAAO,gCAAgC,CAAC;IAE9C,uEAAuE;IACvE,SAAS,EAAE,GAAG,CAAC;IAEf,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,qEAAqE;AACrE,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,OAAO,iCAAiC,CAAC;IAE/C,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,uEAAuE;AACvE,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,OAAO,kCAAkC,CAAC;IAEhD,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,YAAY,EACnB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAWrC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DWeb Connect wallet transport — the wallet side of the popup/postMessage
|
|
3
|
+
* connect flow, exported for wallet apps (e.g. the Enbox web wallet).
|
|
4
|
+
*
|
|
5
|
+
* A wallet's `/dweb-connect` page creates one transport per session:
|
|
6
|
+
*
|
|
7
|
+
* 1. `create()` generates a fresh ephemeral X25519 key pair and emits the
|
|
8
|
+
* `loaded` beacon (public key + wallet origin) to the opener window with a
|
|
9
|
+
* pinned `targetOrigin`.
|
|
10
|
+
* 2. `awaitRequest()` receives the sealed request ciphertext and opens it via
|
|
11
|
+
* the `@enbox/connect` kernel (`ConnectProvider.openRequest`), which
|
|
12
|
+
* value-checks the `apv` origin binding against this wallet's origin.
|
|
13
|
+
* 3. After the consent ceremony, the wallet posts the sealed response JWE via
|
|
14
|
+
* `sendResponse()` — or the deny token via `deny()` — back to the opener,
|
|
15
|
+
* again with a pinned `targetOrigin`.
|
|
16
|
+
*
|
|
17
|
+
* The dapp origin is never assumed: it is taken from an explicit option or
|
|
18
|
+
* derived from `document.referrer`, and `create()` fails when neither is
|
|
19
|
+
* available. `'*'` is never used as a `targetOrigin`.
|
|
20
|
+
*
|
|
21
|
+
* @module
|
|
22
|
+
*/
|
|
23
|
+
import type { ConnectRequest } from '@enbox/connect';
|
|
24
|
+
/** Options for creating a {@link WalletPostMessageTransport}. */
|
|
25
|
+
export type WalletPostMessageTransportOptions = {
|
|
26
|
+
/**
|
|
27
|
+
* Origin of the dapp that opened this wallet popup. When omitted, it is
|
|
28
|
+
* derived from `document.referrer`; creation fails when neither is
|
|
29
|
+
* available — the transport never falls back to `'*'`.
|
|
30
|
+
*/
|
|
31
|
+
dappOrigin?: string;
|
|
32
|
+
/**
|
|
33
|
+
* The dapp window to exchange messages with.
|
|
34
|
+
* @default window.opener
|
|
35
|
+
*/
|
|
36
|
+
dappWindow?: Window;
|
|
37
|
+
/**
|
|
38
|
+
* Budget in milliseconds for awaiting the dapp's sealed request.
|
|
39
|
+
* @default 300_000 (5 minutes)
|
|
40
|
+
*/
|
|
41
|
+
timeoutMs?: number;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Wallet-side postMessage transport for the DWeb Connect popup flow.
|
|
45
|
+
*
|
|
46
|
+
* Security properties:
|
|
47
|
+
* - `targetOrigin` of every outbound `postMessage` (beacon and response) is
|
|
48
|
+
* pinned to the dapp origin — never `'*'`.
|
|
49
|
+
* - Inbound messages are dropped unless `event.origin` equals the pinned dapp
|
|
50
|
+
* origin AND `event.source` is the dapp window.
|
|
51
|
+
* - The ephemeral X25519 private key never leaves the transport; the request
|
|
52
|
+
* JWE is opened by the kernel with the `apv` header value-checked against
|
|
53
|
+
* this wallet's own origin.
|
|
54
|
+
*/
|
|
55
|
+
export declare class WalletPostMessageTransport {
|
|
56
|
+
private readonly _dappOrigin;
|
|
57
|
+
private readonly _dappWindow;
|
|
58
|
+
private readonly _recipientPrivateKey;
|
|
59
|
+
private _requestReceived;
|
|
60
|
+
private _timeoutId?;
|
|
61
|
+
private _messageListener?;
|
|
62
|
+
private readonly _requestPromise;
|
|
63
|
+
private _resolveRequest?;
|
|
64
|
+
private _rejectRequest?;
|
|
65
|
+
private constructor();
|
|
66
|
+
/**
|
|
67
|
+
* Creates the transport for one connect session: resolves and pins the dapp
|
|
68
|
+
* origin, generates a fresh ephemeral X25519 key pair, starts listening for
|
|
69
|
+
* the sealed request, and emits the `loaded` beacon to the dapp window.
|
|
70
|
+
*
|
|
71
|
+
* @throws If not in a browser, if no dapp window is available, or if the
|
|
72
|
+
* dapp origin can neither be supplied nor derived from the referrer.
|
|
73
|
+
*/
|
|
74
|
+
static create(options?: WalletPostMessageTransportOptions): Promise<WalletPostMessageTransport>;
|
|
75
|
+
/** The pinned origin of the dapp this transport exchanges messages with. */
|
|
76
|
+
get dappOrigin(): string;
|
|
77
|
+
/**
|
|
78
|
+
* Awaits the dapp's sealed request and opens it via the kernel: ECDH-ES
|
|
79
|
+
* decryption with this session's ephemeral key, `apv` value-checked against
|
|
80
|
+
* this wallet's origin, JWT signature verification, and payload shape
|
|
81
|
+
* assertion. Rejects on timeout, on an unopenable request, or when the
|
|
82
|
+
* request does not use the `post_message` reply mode.
|
|
83
|
+
*/
|
|
84
|
+
awaitRequest(): Promise<ConnectRequest>;
|
|
85
|
+
/**
|
|
86
|
+
* Posts the sealed response JWE (or the deny token) back to the dapp window
|
|
87
|
+
* with the `targetOrigin` pinned to the dapp origin, then closes the
|
|
88
|
+
* transport.
|
|
89
|
+
*
|
|
90
|
+
* @param idToken - The sealed response JWE, or the literal deny token.
|
|
91
|
+
*/
|
|
92
|
+
sendResponse(idToken: string): void;
|
|
93
|
+
/** Posts the deny token back to the dapp — the user rejected the request. */
|
|
94
|
+
deny(): void;
|
|
95
|
+
/** Stops listening and releases the session's timers. Idempotent. */
|
|
96
|
+
close(): void;
|
|
97
|
+
private onMessage;
|
|
98
|
+
private openRequest;
|
|
99
|
+
private settleRequest;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=dweb-connect-wallet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dweb-connect-wallet.d.ts","sourceRoot":"","sources":["../../src/dweb-connect-wallet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAgBrD,iEAAiE;AACjE,MAAM,MAAM,iCAAiC,GAAG;IAC9C;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,qBAAa,0BAA0B;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAM;IAE3C,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,UAAU,CAAC,CAAgC;IACnD,OAAO,CAAC,gBAAgB,CAAC,CAAgC;IAEzD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0B;IAC1D,OAAO,CAAC,eAAe,CAAC,CAAoC;IAC5D,OAAO,CAAC,cAAc,CAAC,CAAyB;IAEhD,OAAO;IAsBP;;;;;;;OAOG;WACiB,MAAM,CAAC,OAAO,GAAE,iCAAsC,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAgChH,4EAA4E;IAC5E,IAAW,UAAU,IAAI,MAAM,CAE9B;IAED;;;;;;OAMG;IACU,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC;IAIpD;;;;;;OAMG;IACI,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ1C,6EAA6E;IACtE,IAAI,IAAI,IAAI;IAInB,qEAAqE;IAC9D,KAAK,IAAI,IAAI;IAQpB,OAAO,CAAC,SAAS;YAeH,WAAW;IAsBzB,OAAO,CAAC,aAAa;CAStB"}
|