@waiaas/daemon 2.4.0-rc.2 → 2.4.0-rc.3
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/README.md +1 -0
- package/dist/api/routes/admin.d.ts.map +1 -1
- package/dist/api/routes/admin.js +23 -32
- package/dist/api/routes/admin.js.map +1 -1
- package/dist/api/routes/openapi-schemas.d.ts +57 -0
- package/dist/api/routes/openapi-schemas.d.ts.map +1 -1
- package/dist/api/routes/openapi-schemas.js +14 -1
- package/dist/api/routes/openapi-schemas.js.map +1 -1
- package/dist/api/routes/transactions.d.ts +2 -0
- package/dist/api/routes/transactions.d.ts.map +1 -1
- package/dist/api/routes/transactions.js +1 -0
- package/dist/api/routes/transactions.js.map +1 -1
- package/dist/api/routes/wallets.d.ts.map +1 -1
- package/dist/api/routes/wallets.js +9 -0
- package/dist/api/routes/wallets.js.map +1 -1
- package/dist/api/server.d.ts +2 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +1 -0
- package/dist/api/server.js.map +1 -1
- package/dist/infrastructure/database/compatibility.js +2 -2
- package/dist/infrastructure/database/compatibility.js.map +1 -1
- package/dist/infrastructure/database/migrate.d.ts +1 -1
- package/dist/infrastructure/database/migrate.d.ts.map +1 -1
- package/dist/infrastructure/database/migrate.js +17 -3
- package/dist/infrastructure/database/migrate.js.map +1 -1
- package/dist/infrastructure/database/schema.d.ts +20 -0
- package/dist/infrastructure/database/schema.d.ts.map +1 -1
- package/dist/infrastructure/database/schema.js +2 -0
- package/dist/infrastructure/database/schema.js.map +1 -1
- package/dist/infrastructure/settings/setting-keys.d.ts +2 -2
- package/dist/infrastructure/settings/setting-keys.d.ts.map +1 -1
- package/dist/infrastructure/settings/setting-keys.js +10 -1
- package/dist/infrastructure/settings/setting-keys.js.map +1 -1
- package/dist/infrastructure/telegram/telegram-auth.d.ts +1 -1
- package/dist/infrastructure/telegram/telegram-auth.d.ts.map +1 -1
- package/dist/infrastructure/telegram/telegram-auth.js +1 -1
- package/dist/infrastructure/telegram/telegram-auth.js.map +1 -1
- package/dist/infrastructure/telegram/telegram-bot-service.d.ts +9 -0
- package/dist/infrastructure/telegram/telegram-bot-service.d.ts.map +1 -1
- package/dist/infrastructure/telegram/telegram-bot-service.js +46 -1
- package/dist/infrastructure/telegram/telegram-bot-service.js.map +1 -1
- package/dist/infrastructure/telegram/telegram-types.d.ts +1 -0
- package/dist/infrastructure/telegram/telegram-types.d.ts.map +1 -1
- package/dist/lifecycle/daemon.d.ts +2 -0
- package/dist/lifecycle/daemon.d.ts.map +1 -1
- package/dist/lifecycle/daemon.js +63 -0
- package/dist/lifecycle/daemon.js.map +1 -1
- package/dist/pipeline/stages.d.ts +2 -0
- package/dist/pipeline/stages.d.ts.map +1 -1
- package/dist/pipeline/stages.js +14 -0
- package/dist/pipeline/stages.js.map +1 -1
- package/dist/services/signing-sdk/approval-channel-router.d.ts +65 -0
- package/dist/services/signing-sdk/approval-channel-router.d.ts.map +1 -0
- package/dist/services/signing-sdk/approval-channel-router.js +147 -0
- package/dist/services/signing-sdk/approval-channel-router.js.map +1 -0
- package/dist/services/signing-sdk/channels/index.d.ts +10 -0
- package/dist/services/signing-sdk/channels/index.d.ts.map +1 -0
- package/dist/services/signing-sdk/channels/index.js +8 -0
- package/dist/services/signing-sdk/channels/index.js.map +1 -0
- package/dist/services/signing-sdk/channels/ntfy-signing-channel.d.ts +66 -0
- package/dist/services/signing-sdk/channels/ntfy-signing-channel.d.ts.map +1 -0
- package/dist/services/signing-sdk/channels/ntfy-signing-channel.js +257 -0
- package/dist/services/signing-sdk/channels/ntfy-signing-channel.js.map +1 -0
- package/dist/services/signing-sdk/channels/telegram-signing-channel.d.ts +56 -0
- package/dist/services/signing-sdk/channels/telegram-signing-channel.d.ts.map +1 -0
- package/dist/services/signing-sdk/channels/telegram-signing-channel.js +87 -0
- package/dist/services/signing-sdk/channels/telegram-signing-channel.js.map +1 -0
- package/dist/services/signing-sdk/index.d.ts +34 -0
- package/dist/services/signing-sdk/index.d.ts.map +1 -0
- package/dist/services/signing-sdk/index.js +25 -0
- package/dist/services/signing-sdk/index.js.map +1 -0
- package/dist/services/signing-sdk/sign-request-builder.d.ts +61 -0
- package/dist/services/signing-sdk/sign-request-builder.d.ts.map +1 -0
- package/dist/services/signing-sdk/sign-request-builder.js +157 -0
- package/dist/services/signing-sdk/sign-request-builder.js.map +1 -0
- package/dist/services/signing-sdk/sign-response-handler.d.ts +92 -0
- package/dist/services/signing-sdk/sign-response-handler.d.ts.map +1 -0
- package/dist/services/signing-sdk/sign-response-handler.js +303 -0
- package/dist/services/signing-sdk/sign-response-handler.js.map +1 -0
- package/dist/services/signing-sdk/wallet-link-registry.d.ts +44 -0
- package/dist/services/signing-sdk/wallet-link-registry.d.ts.map +1 -0
- package/dist/services/signing-sdk/wallet-link-registry.js +116 -0
- package/dist/services/signing-sdk/wallet-link-registry.js.map +1 -0
- package/package.json +4 -4
- package/public/admin/assets/index-D7vqMezf.js +1 -0
- package/public/admin/index.html +1 -1
- package/public/admin/assets/index-BEqsuxTi.js +0 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ApprovalChannelRouter -- routes PENDING_APPROVAL transactions to the correct
|
|
3
|
+
* signing channel based on wallet's owner_approval_method.
|
|
4
|
+
*
|
|
5
|
+
* Routing logic:
|
|
6
|
+
* 1. Read wallet's owner_approval_method from DB
|
|
7
|
+
* 2. If set: route to that specific channel
|
|
8
|
+
* - sdk_ntfy -> NtfySigningChannel.sendRequest()
|
|
9
|
+
* - sdk_telegram -> TelegramSigningChannel.sendRequest()
|
|
10
|
+
* - walletconnect / telegram_bot / rest -> return method (no channel call)
|
|
11
|
+
* 3. If SDK method but signing_sdk.enabled=false: fall through to global fallback
|
|
12
|
+
* 4. Global fallback priority (CHAN-06):
|
|
13
|
+
* SDK ntfy > SDK Telegram > WalletConnect > Telegram Bot > REST
|
|
14
|
+
*
|
|
15
|
+
* CHAN-07: When signing_sdk.enabled !== 'true', SDK channels are skipped entirely.
|
|
16
|
+
*
|
|
17
|
+
* @see internal/design/74-wallet-sdk-daemon-components.md
|
|
18
|
+
* @see .planning/phases/203-telegram-channel-routing-rest-admin/203-03-PLAN.md
|
|
19
|
+
*/
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// ApprovalChannelRouter
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
export class ApprovalChannelRouter {
|
|
24
|
+
sqlite;
|
|
25
|
+
settings;
|
|
26
|
+
ntfyChannel;
|
|
27
|
+
telegramChannel;
|
|
28
|
+
constructor(deps) {
|
|
29
|
+
this.sqlite = deps.sqlite;
|
|
30
|
+
this.settings = deps.settingsService;
|
|
31
|
+
this.ntfyChannel = deps.ntfyChannel;
|
|
32
|
+
this.telegramChannel = deps.telegramChannel;
|
|
33
|
+
}
|
|
34
|
+
// -------------------------------------------------------------------------
|
|
35
|
+
// route() -- determine and execute the appropriate signing channel
|
|
36
|
+
// -------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Route a PENDING_APPROVAL transaction to the correct signing channel.
|
|
39
|
+
*
|
|
40
|
+
* @param walletId - The wallet ID to look up approval method for
|
|
41
|
+
* @param params - Transaction parameters for SDK channel sendRequest()
|
|
42
|
+
* @returns RouteResult with selected method and optional channel result
|
|
43
|
+
* @throws Error if wallet not found in DB
|
|
44
|
+
* @throws Error if SDK channel sendRequest() fails (propagated, no silent fallback)
|
|
45
|
+
*/
|
|
46
|
+
async route(walletId, params) {
|
|
47
|
+
// 1. Read wallet's owner_approval_method from DB
|
|
48
|
+
const row = this.sqlite.prepare('SELECT owner_approval_method FROM wallets WHERE id = ?').get(walletId);
|
|
49
|
+
if (!row) {
|
|
50
|
+
throw new Error(`Wallet not found: ${walletId}`);
|
|
51
|
+
}
|
|
52
|
+
const explicitMethod = row.owner_approval_method;
|
|
53
|
+
// 2. If explicit method is set, try to use it
|
|
54
|
+
if (explicitMethod) {
|
|
55
|
+
const sdkEnabled = this.isSdkEnabled();
|
|
56
|
+
// Non-SDK methods: return immediately without channel call
|
|
57
|
+
if (explicitMethod === 'walletconnect') {
|
|
58
|
+
return { method: 'walletconnect', channelResult: null };
|
|
59
|
+
}
|
|
60
|
+
if (explicitMethod === 'telegram_bot') {
|
|
61
|
+
return { method: 'telegram_bot', channelResult: null };
|
|
62
|
+
}
|
|
63
|
+
if (explicitMethod === 'rest') {
|
|
64
|
+
return { method: 'rest', channelResult: null };
|
|
65
|
+
}
|
|
66
|
+
// SDK methods: only use if SDK is enabled, otherwise fall through to global fallback
|
|
67
|
+
if (explicitMethod === 'sdk_ntfy' && sdkEnabled && this.ntfyChannel) {
|
|
68
|
+
const result = await this.ntfyChannel.sendRequest(params);
|
|
69
|
+
return { method: 'sdk_ntfy', channelResult: { requestId: result.requestId } };
|
|
70
|
+
}
|
|
71
|
+
if (explicitMethod === 'sdk_telegram' && sdkEnabled && this.telegramChannel) {
|
|
72
|
+
const result = await this.telegramChannel.sendRequest(params);
|
|
73
|
+
return { method: 'sdk_telegram', channelResult: { requestId: result.requestId } };
|
|
74
|
+
}
|
|
75
|
+
// SDK method set but SDK disabled or channel not available -> fall through to global fallback
|
|
76
|
+
}
|
|
77
|
+
// 3. Global fallback priority (CHAN-06)
|
|
78
|
+
return this.globalFallback(params);
|
|
79
|
+
}
|
|
80
|
+
// -------------------------------------------------------------------------
|
|
81
|
+
// shutdown() -- clean up channels
|
|
82
|
+
// -------------------------------------------------------------------------
|
|
83
|
+
/**
|
|
84
|
+
* Shutdown all managed signing channels.
|
|
85
|
+
*/
|
|
86
|
+
shutdown() {
|
|
87
|
+
this.ntfyChannel?.shutdown();
|
|
88
|
+
this.telegramChannel?.shutdown();
|
|
89
|
+
}
|
|
90
|
+
// -------------------------------------------------------------------------
|
|
91
|
+
// Private: global fallback logic (CHAN-06, CHAN-07)
|
|
92
|
+
// -------------------------------------------------------------------------
|
|
93
|
+
async globalFallback(params) {
|
|
94
|
+
const sdkEnabled = this.isSdkEnabled();
|
|
95
|
+
// Priority 1: SDK ntfy (if SDK enabled and channel available)
|
|
96
|
+
if (sdkEnabled && this.ntfyChannel) {
|
|
97
|
+
const result = await this.ntfyChannel.sendRequest(params);
|
|
98
|
+
return { method: 'sdk_ntfy', channelResult: { requestId: result.requestId } };
|
|
99
|
+
}
|
|
100
|
+
// Priority 2: SDK Telegram (if SDK enabled and channel available)
|
|
101
|
+
if (sdkEnabled && this.telegramChannel) {
|
|
102
|
+
const result = await this.telegramChannel.sendRequest(params);
|
|
103
|
+
return { method: 'sdk_telegram', channelResult: { requestId: result.requestId } };
|
|
104
|
+
}
|
|
105
|
+
// Priority 3: WalletConnect (if project_id configured)
|
|
106
|
+
if (this.isWalletConnectConfigured()) {
|
|
107
|
+
return { method: 'walletconnect', channelResult: null };
|
|
108
|
+
}
|
|
109
|
+
// Priority 4: Telegram Bot (if enabled and bot_token configured)
|
|
110
|
+
if (this.isTelegramBotConfigured()) {
|
|
111
|
+
return { method: 'telegram_bot', channelResult: null };
|
|
112
|
+
}
|
|
113
|
+
// Priority 5: REST (always available as final fallback)
|
|
114
|
+
return { method: 'rest', channelResult: null };
|
|
115
|
+
}
|
|
116
|
+
// -------------------------------------------------------------------------
|
|
117
|
+
// Private: setting checks
|
|
118
|
+
// -------------------------------------------------------------------------
|
|
119
|
+
isSdkEnabled() {
|
|
120
|
+
try {
|
|
121
|
+
return this.settings.get('signing_sdk.enabled') === 'true';
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
isWalletConnectConfigured() {
|
|
128
|
+
try {
|
|
129
|
+
const projectId = this.settings.get('walletconnect.project_id');
|
|
130
|
+
return !!projectId && projectId.trim().length > 0;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
isTelegramBotConfigured() {
|
|
137
|
+
try {
|
|
138
|
+
const enabled = this.settings.get('telegram.enabled');
|
|
139
|
+
const botToken = this.settings.get('telegram.bot_token');
|
|
140
|
+
return enabled === 'true' && !!botToken && botToken.trim().length > 0;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=approval-channel-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-channel-router.js","sourceRoot":"","sources":["../../../src/services/signing-sdk/approval-channel-router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signing SDK channel exports.
|
|
3
|
+
*
|
|
4
|
+
* @see internal/design/73-signing-protocol-v1.md
|
|
5
|
+
*/
|
|
6
|
+
export { NtfySigningChannel } from './ntfy-signing-channel.js';
|
|
7
|
+
export type { NtfySigningChannelOpts, SendRequestParams, SendRequestResult, } from './ntfy-signing-channel.js';
|
|
8
|
+
export { TelegramSigningChannel } from './telegram-signing-channel.js';
|
|
9
|
+
export type { TelegramSigningChannelOpts } from './telegram-signing-channel.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/services/signing-sdk/channels/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,YAAY,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signing SDK channel exports.
|
|
3
|
+
*
|
|
4
|
+
* @see internal/design/73-signing-protocol-v1.md
|
|
5
|
+
*/
|
|
6
|
+
export { NtfySigningChannel } from './ntfy-signing-channel.js';
|
|
7
|
+
export { TelegramSigningChannel } from './telegram-signing-channel.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/services/signing-sdk/channels/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAO/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NtfySigningChannel -- publishes SignRequests to ntfy and subscribes to responses via SSE.
|
|
3
|
+
*
|
|
4
|
+
* When a PENDING_APPROVAL transaction triggers a SignRequest:
|
|
5
|
+
* 1. Publishes the request to the wallet's ntfy request topic (JSON format per doc 73 Section 7.2)
|
|
6
|
+
* 2. Subscribes to the response topic via SSE
|
|
7
|
+
* 3. Parses incoming SignResponse messages (base64url in ntfy message field)
|
|
8
|
+
* 4. Delegates to SignResponseHandler for approval/rejection processing
|
|
9
|
+
*
|
|
10
|
+
* @see internal/design/73-signing-protocol-v1.md (Section 7.2, 7.3)
|
|
11
|
+
* @see internal/design/74-wallet-sdk-daemon-components.md
|
|
12
|
+
*/
|
|
13
|
+
import type { SignRequestBuilder, BuildRequestParams } from '../sign-request-builder.js';
|
|
14
|
+
import type { SignResponseHandler } from '../sign-response-handler.js';
|
|
15
|
+
import type { SettingsService } from '../../../infrastructure/settings/settings-service.js';
|
|
16
|
+
export interface NtfySigningChannelOpts {
|
|
17
|
+
signRequestBuilder: SignRequestBuilder;
|
|
18
|
+
signResponseHandler: SignResponseHandler;
|
|
19
|
+
settingsService: SettingsService;
|
|
20
|
+
}
|
|
21
|
+
export interface SendRequestParams extends BuildRequestParams {
|
|
22
|
+
walletId: string;
|
|
23
|
+
}
|
|
24
|
+
export interface SendRequestResult {
|
|
25
|
+
requestId: string;
|
|
26
|
+
requestTopic: string;
|
|
27
|
+
responseTopic: string;
|
|
28
|
+
}
|
|
29
|
+
export declare class NtfySigningChannel {
|
|
30
|
+
private readonly signRequestBuilder;
|
|
31
|
+
private readonly signResponseHandler;
|
|
32
|
+
private readonly settings;
|
|
33
|
+
/** Active SSE subscriptions: requestId -> AbortController */
|
|
34
|
+
private readonly activeSubscriptions;
|
|
35
|
+
constructor(opts: NtfySigningChannelOpts);
|
|
36
|
+
/**
|
|
37
|
+
* Publish a SignRequest to ntfy request topic and subscribe to response topic.
|
|
38
|
+
*
|
|
39
|
+
* @param params - Transaction metadata + walletId for topic routing
|
|
40
|
+
* @returns requestId, requestTopic, responseTopic
|
|
41
|
+
*/
|
|
42
|
+
sendRequest(params: SendRequestParams): Promise<SendRequestResult>;
|
|
43
|
+
/**
|
|
44
|
+
* Cancel a specific SSE subscription by requestId.
|
|
45
|
+
*/
|
|
46
|
+
cancelSubscription(requestId: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* Shutdown all active SSE subscriptions (daemon shutdown).
|
|
49
|
+
*/
|
|
50
|
+
shutdown(): void;
|
|
51
|
+
private getNtfyServer;
|
|
52
|
+
private publishToNtfy;
|
|
53
|
+
private subscribeToResponseTopic;
|
|
54
|
+
private connectSse;
|
|
55
|
+
/**
|
|
56
|
+
* Parse an SSE stream into NtfyMessage objects.
|
|
57
|
+
*
|
|
58
|
+
* ntfy SSE format:
|
|
59
|
+
* event: message
|
|
60
|
+
* data: {"id":"...","time":...,"event":"message","topic":"...","message":"..."}
|
|
61
|
+
*
|
|
62
|
+
* We only care about `data:` lines containing JSON with a `message` field.
|
|
63
|
+
*/
|
|
64
|
+
private parseSseStream;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=ntfy-signing-channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ntfy-signing-channel.d.ts","sourceRoot":"","sources":["../../../../src/services/signing-sdk/channels/ntfy-signing-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sDAAsD,CAAC;AAc5F,MAAM,WAAW,sBAAsB;IACrC,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,eAAe,EAAE,eAAe,CAAC;CAClC;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAcD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAE3C,6DAA6D;IAC7D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsC;gBAE9D,IAAI,EAAE,sBAAsB;IAUxC;;;;;OAKG;IACG,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAsCxE;;OAEG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAQ3C;;OAEG;IACH,QAAQ,IAAI,IAAI;IAWhB,OAAO,CAAC,aAAa;YAaP,aAAa;IAsC3B,OAAO,CAAC,wBAAwB;YAyBlB,UAAU;IAgFxB;;;;;;;;OAQG;YACY,cAAc;CAuC9B"}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NtfySigningChannel -- publishes SignRequests to ntfy and subscribes to responses via SSE.
|
|
3
|
+
*
|
|
4
|
+
* When a PENDING_APPROVAL transaction triggers a SignRequest:
|
|
5
|
+
* 1. Publishes the request to the wallet's ntfy request topic (JSON format per doc 73 Section 7.2)
|
|
6
|
+
* 2. Subscribes to the response topic via SSE
|
|
7
|
+
* 3. Parses incoming SignResponse messages (base64url in ntfy message field)
|
|
8
|
+
* 4. Delegates to SignResponseHandler for approval/rejection processing
|
|
9
|
+
*
|
|
10
|
+
* @see internal/design/73-signing-protocol-v1.md (Section 7.2, 7.3)
|
|
11
|
+
* @see internal/design/74-wallet-sdk-daemon-components.md
|
|
12
|
+
*/
|
|
13
|
+
import { SignResponseSchema, } from '@waiaas/core';
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Constants
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
const MAX_RECONNECT_ATTEMPTS = 3;
|
|
18
|
+
const RECONNECT_DELAY_MS = 5_000;
|
|
19
|
+
const DEFAULT_NTFY_SERVER = 'https://ntfy.sh';
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// NtfySigningChannel
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
export class NtfySigningChannel {
|
|
24
|
+
signRequestBuilder;
|
|
25
|
+
signResponseHandler;
|
|
26
|
+
settings;
|
|
27
|
+
/** Active SSE subscriptions: requestId -> AbortController */
|
|
28
|
+
activeSubscriptions = new Map();
|
|
29
|
+
constructor(opts) {
|
|
30
|
+
this.signRequestBuilder = opts.signRequestBuilder;
|
|
31
|
+
this.signResponseHandler = opts.signResponseHandler;
|
|
32
|
+
this.settings = opts.settingsService;
|
|
33
|
+
}
|
|
34
|
+
// -------------------------------------------------------------------------
|
|
35
|
+
// sendRequest -- publish to ntfy + subscribe for response
|
|
36
|
+
// -------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Publish a SignRequest to ntfy request topic and subscribe to response topic.
|
|
39
|
+
*
|
|
40
|
+
* @param params - Transaction metadata + walletId for topic routing
|
|
41
|
+
* @returns requestId, requestTopic, responseTopic
|
|
42
|
+
*/
|
|
43
|
+
async sendRequest(params) {
|
|
44
|
+
// 1. Build SignRequest via SignRequestBuilder
|
|
45
|
+
const { request, universalLinkUrl, requestTopic } = this.signRequestBuilder.buildRequest(params);
|
|
46
|
+
// 2. Register request with SignResponseHandler for later matching
|
|
47
|
+
this.signResponseHandler.registerRequest(request);
|
|
48
|
+
// 3. Resolve ntfy server URL
|
|
49
|
+
const ntfyServer = this.getNtfyServer();
|
|
50
|
+
// 4. Publish to ntfy request topic (doc 73 Section 7.2)
|
|
51
|
+
await this.publishToNtfy(ntfyServer, requestTopic, request.displayMessage, universalLinkUrl);
|
|
52
|
+
// 5. Determine response topic
|
|
53
|
+
let responseTopic;
|
|
54
|
+
if (request.responseChannel.type === 'ntfy') {
|
|
55
|
+
responseTopic = request.responseChannel.responseTopic;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Fallback: construct response topic from request
|
|
59
|
+
const prefix = this.settings.get('signing_sdk.ntfy_response_topic_prefix');
|
|
60
|
+
responseTopic = `${prefix}-${request.requestId}`;
|
|
61
|
+
}
|
|
62
|
+
// 6. Subscribe to response topic via SSE (background, non-blocking)
|
|
63
|
+
this.subscribeToResponseTopic(ntfyServer, responseTopic, request.requestId, request.expiresAt);
|
|
64
|
+
return {
|
|
65
|
+
requestId: request.requestId,
|
|
66
|
+
requestTopic,
|
|
67
|
+
responseTopic,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// -------------------------------------------------------------------------
|
|
71
|
+
// Subscription management
|
|
72
|
+
// -------------------------------------------------------------------------
|
|
73
|
+
/**
|
|
74
|
+
* Cancel a specific SSE subscription by requestId.
|
|
75
|
+
*/
|
|
76
|
+
cancelSubscription(requestId) {
|
|
77
|
+
const controller = this.activeSubscriptions.get(requestId);
|
|
78
|
+
if (controller) {
|
|
79
|
+
controller.abort();
|
|
80
|
+
this.activeSubscriptions.delete(requestId);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Shutdown all active SSE subscriptions (daemon shutdown).
|
|
85
|
+
*/
|
|
86
|
+
shutdown() {
|
|
87
|
+
for (const [requestId, controller] of this.activeSubscriptions) {
|
|
88
|
+
controller.abort();
|
|
89
|
+
this.activeSubscriptions.delete(requestId);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// -------------------------------------------------------------------------
|
|
93
|
+
// Private: ntfy server URL
|
|
94
|
+
// -------------------------------------------------------------------------
|
|
95
|
+
getNtfyServer() {
|
|
96
|
+
try {
|
|
97
|
+
const server = this.settings.get('notifications.ntfy_server');
|
|
98
|
+
return server || DEFAULT_NTFY_SERVER;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return DEFAULT_NTFY_SERVER;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// -------------------------------------------------------------------------
|
|
105
|
+
// Private: publish to ntfy (doc 73 Section 7.2)
|
|
106
|
+
// -------------------------------------------------------------------------
|
|
107
|
+
async publishToNtfy(ntfyServer, requestTopic, displayMessage, universalLinkUrl) {
|
|
108
|
+
const url = `${ntfyServer}/${requestTopic}`;
|
|
109
|
+
const body = JSON.stringify({
|
|
110
|
+
topic: requestTopic,
|
|
111
|
+
message: displayMessage,
|
|
112
|
+
title: 'WAIaaS Sign Request',
|
|
113
|
+
priority: 5,
|
|
114
|
+
tags: ['waiaas', 'sign'],
|
|
115
|
+
actions: [
|
|
116
|
+
{
|
|
117
|
+
action: 'view',
|
|
118
|
+
label: 'Sign in wallet',
|
|
119
|
+
url: universalLinkUrl,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
click: universalLinkUrl,
|
|
123
|
+
});
|
|
124
|
+
const res = await fetch(url, {
|
|
125
|
+
method: 'POST',
|
|
126
|
+
headers: { 'Content-Type': 'application/json' },
|
|
127
|
+
body,
|
|
128
|
+
});
|
|
129
|
+
if (!res.ok) {
|
|
130
|
+
throw new Error(`Failed to publish sign request to ntfy: HTTP ${res.status}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// -------------------------------------------------------------------------
|
|
134
|
+
// Private: subscribe to response topic via SSE
|
|
135
|
+
// -------------------------------------------------------------------------
|
|
136
|
+
subscribeToResponseTopic(ntfyServer, responseTopic, requestId, expiresAt) {
|
|
137
|
+
const abortController = new AbortController();
|
|
138
|
+
this.activeSubscriptions.set(requestId, abortController);
|
|
139
|
+
// Set timeout for request expiration
|
|
140
|
+
const expiresAtMs = new Date(expiresAt).getTime();
|
|
141
|
+
const timeoutMs = Math.max(0, expiresAtMs - Date.now());
|
|
142
|
+
const timer = setTimeout(() => {
|
|
143
|
+
this.cancelSubscription(requestId);
|
|
144
|
+
}, timeoutMs);
|
|
145
|
+
// Unref timer so it doesn't prevent process exit
|
|
146
|
+
if (typeof timer === 'object' && 'unref' in timer) {
|
|
147
|
+
timer.unref();
|
|
148
|
+
}
|
|
149
|
+
// Start SSE connection (non-blocking)
|
|
150
|
+
void this.connectSse(ntfyServer, responseTopic, requestId, abortController, timer);
|
|
151
|
+
}
|
|
152
|
+
async connectSse(ntfyServer, responseTopic, requestId, abortController, expirationTimer, reconnectAttempt = 0) {
|
|
153
|
+
if (abortController.signal.aborted) {
|
|
154
|
+
clearTimeout(expirationTimer);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const url = `${ntfyServer}/${responseTopic}/sse`;
|
|
159
|
+
const res = await fetch(url, {
|
|
160
|
+
signal: abortController.signal,
|
|
161
|
+
});
|
|
162
|
+
if (!res.ok || !res.body) {
|
|
163
|
+
throw new Error(`SSE connection failed: HTTP ${res.status}`);
|
|
164
|
+
}
|
|
165
|
+
const reader = res.body.getReader();
|
|
166
|
+
for await (const ntfyMsg of this.parseSseStream(reader, abortController.signal)) {
|
|
167
|
+
if (abortController.signal.aborted)
|
|
168
|
+
break;
|
|
169
|
+
if (!ntfyMsg.message)
|
|
170
|
+
continue;
|
|
171
|
+
// ntfy message field contains base64url-encoded SignResponse
|
|
172
|
+
try {
|
|
173
|
+
const json = Buffer.from(ntfyMsg.message, 'base64url').toString('utf-8');
|
|
174
|
+
const parsed = JSON.parse(json);
|
|
175
|
+
const signResponse = SignResponseSchema.parse(parsed);
|
|
176
|
+
// Only process responses for this requestId
|
|
177
|
+
if (signResponse.requestId !== requestId)
|
|
178
|
+
continue;
|
|
179
|
+
// Delegate to SignResponseHandler
|
|
180
|
+
await this.signResponseHandler.handle(signResponse);
|
|
181
|
+
// Response processed -- close subscription
|
|
182
|
+
this.cancelSubscription(requestId);
|
|
183
|
+
clearTimeout(expirationTimer);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
// Ignore malformed messages or handler errors
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (_err) {
|
|
192
|
+
// Don't reconnect if explicitly aborted
|
|
193
|
+
if (abortController.signal.aborted) {
|
|
194
|
+
clearTimeout(expirationTimer);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
// Reconnect logic: max 3 attempts, 5s delay
|
|
198
|
+
if (reconnectAttempt < MAX_RECONNECT_ATTEMPTS) {
|
|
199
|
+
await new Promise((resolve) => setTimeout(resolve, RECONNECT_DELAY_MS));
|
|
200
|
+
return this.connectSse(ntfyServer, responseTopic, requestId, abortController, expirationTimer, reconnectAttempt + 1);
|
|
201
|
+
}
|
|
202
|
+
// Max reconnects exceeded -- clean up
|
|
203
|
+
this.activeSubscriptions.delete(requestId);
|
|
204
|
+
clearTimeout(expirationTimer);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// -------------------------------------------------------------------------
|
|
208
|
+
// Private: SSE stream parser
|
|
209
|
+
// -------------------------------------------------------------------------
|
|
210
|
+
/**
|
|
211
|
+
* Parse an SSE stream into NtfyMessage objects.
|
|
212
|
+
*
|
|
213
|
+
* ntfy SSE format:
|
|
214
|
+
* event: message
|
|
215
|
+
* data: {"id":"...","time":...,"event":"message","topic":"...","message":"..."}
|
|
216
|
+
*
|
|
217
|
+
* We only care about `data:` lines containing JSON with a `message` field.
|
|
218
|
+
*/
|
|
219
|
+
async *parseSseStream(reader, signal) {
|
|
220
|
+
const decoder = new TextDecoder();
|
|
221
|
+
let buffer = '';
|
|
222
|
+
try {
|
|
223
|
+
while (!signal.aborted) {
|
|
224
|
+
const { done, value } = await reader.read();
|
|
225
|
+
if (done)
|
|
226
|
+
break;
|
|
227
|
+
buffer += decoder.decode(value, { stream: true });
|
|
228
|
+
const lines = buffer.split('\n');
|
|
229
|
+
// Keep the last incomplete line in buffer
|
|
230
|
+
buffer = lines.pop() ?? '';
|
|
231
|
+
for (const line of lines) {
|
|
232
|
+
if (!line.startsWith('data: '))
|
|
233
|
+
continue;
|
|
234
|
+
const dataStr = line.slice(6).trim();
|
|
235
|
+
if (!dataStr)
|
|
236
|
+
continue;
|
|
237
|
+
try {
|
|
238
|
+
const msg = JSON.parse(dataStr);
|
|
239
|
+
yield msg;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// Ignore malformed JSON
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
finally {
|
|
248
|
+
try {
|
|
249
|
+
reader.releaseLock();
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
// Reader may already be released
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=ntfy-signing-channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ntfy-signing-channel.js","sourceRoot":"","sources":["../../../../src/services/signing-sdk/channels/ntfy-signing-channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TelegramSigningChannel -- sends SignRequests via Telegram inline button message.
|
|
3
|
+
*
|
|
4
|
+
* When a PENDING_APPROVAL transaction triggers a SignRequest:
|
|
5
|
+
* 1. Builds the SignRequest via SignRequestBuilder
|
|
6
|
+
* 2. Registers the request with SignResponseHandler for later matching
|
|
7
|
+
* 3. Sends a Telegram message to the admin chat with an inline "Open in Wallet"
|
|
8
|
+
* button containing the universal link URL
|
|
9
|
+
*
|
|
10
|
+
* Unlike NtfySigningChannel, TelegramSigningChannel does NOT subscribe to a response
|
|
11
|
+
* topic. The response arrives via the /sign_response Telegram bot command, which
|
|
12
|
+
* delegates to SignResponseHandler. This is a one-way push channel.
|
|
13
|
+
*
|
|
14
|
+
* Implements ISigningChannel interface for consistent channel abstraction.
|
|
15
|
+
*
|
|
16
|
+
* @see internal/design/73-signing-protocol-v1.md (Section 7.2, 7.3)
|
|
17
|
+
* @see internal/design/74-wallet-sdk-daemon-components.md
|
|
18
|
+
*/
|
|
19
|
+
import type { SignRequestBuilder, BuildRequestParams } from '../sign-request-builder.js';
|
|
20
|
+
import type { SignResponseHandler } from '../sign-response-handler.js';
|
|
21
|
+
import type { SettingsService } from '../../../infrastructure/settings/settings-service.js';
|
|
22
|
+
import type { TelegramApi } from '../../../infrastructure/telegram/telegram-api.js';
|
|
23
|
+
export interface TelegramSigningChannelOpts {
|
|
24
|
+
signRequestBuilder: SignRequestBuilder;
|
|
25
|
+
signResponseHandler: SignResponseHandler;
|
|
26
|
+
settingsService: SettingsService;
|
|
27
|
+
telegramApi: TelegramApi;
|
|
28
|
+
}
|
|
29
|
+
export interface SendRequestParams extends BuildRequestParams {
|
|
30
|
+
walletId: string;
|
|
31
|
+
}
|
|
32
|
+
export interface SendRequestResult {
|
|
33
|
+
requestId: string;
|
|
34
|
+
requestTopic: string;
|
|
35
|
+
responseTopic: string;
|
|
36
|
+
}
|
|
37
|
+
export declare class TelegramSigningChannel {
|
|
38
|
+
private readonly signRequestBuilder;
|
|
39
|
+
private readonly signResponseHandler;
|
|
40
|
+
private readonly settings;
|
|
41
|
+
private readonly telegramApi;
|
|
42
|
+
constructor(opts: TelegramSigningChannelOpts);
|
|
43
|
+
/**
|
|
44
|
+
* Send a SignRequest via Telegram message with an inline "Open in Wallet" button.
|
|
45
|
+
*
|
|
46
|
+
* @param params - Transaction metadata + walletId
|
|
47
|
+
* @returns requestId, requestTopic (empty for Telegram), responseTopic (empty)
|
|
48
|
+
* @throws Error if telegram chat_id is not configured
|
|
49
|
+
*/
|
|
50
|
+
sendRequest(params: SendRequestParams): Promise<SendRequestResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Shutdown the channel. No-op for Telegram (no SSE subscriptions to clean up).
|
|
53
|
+
*/
|
|
54
|
+
shutdown(): void;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=telegram-signing-channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram-signing-channel.d.ts","sourceRoot":"","sources":["../../../../src/services/signing-sdk/channels/telegram-signing-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sDAAsD,CAAC;AAC5F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAC;AAOpF,MAAM,WAAW,0BAA0B;IACzC,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,eAAe,EAAE,eAAe,CAAC;IACjC,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAMD,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;gBAE9B,IAAI,EAAE,0BAA0B;IAW5C;;;;;;OAMG;IACG,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA4CxE;;OAEG;IACH,QAAQ,IAAI,IAAI;CAGjB"}
|