@blocklet/sdk 1.16.54-beta-20251017-133309-7d40faa6 → 1.16.54-beta-20251023-041534-36eec6b9
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/lib/config.js +5 -5
- package/lib/connect/authenticator.d.ts +1 -1
- package/lib/connect/authenticator.js +9 -11
- package/lib/connect/handler.d.ts +1 -1
- package/lib/connect/handler.js +3 -1
- package/lib/connect/shared.d.ts +1 -1
- package/lib/connect/shared.js +17 -6
- package/lib/database/index.d.ts +2 -2
- package/lib/database/index.js +4 -2
- package/lib/did.d.ts +2 -2
- package/lib/did.js +4 -7
- package/lib/env.d.ts +2 -2
- package/lib/env.js +4 -5
- package/lib/index.d.ts +9 -9
- package/lib/index.js +18 -18
- package/lib/middlewares/auth.d.ts +3 -3
- package/lib/middlewares/auth.js +7 -8
- package/lib/middlewares/blocklet.d.ts +2 -2
- package/lib/middlewares/blocklet.js +2 -2
- package/lib/middlewares/csrf.js +2 -4
- package/lib/middlewares/fallback.d.ts +1 -1
- package/lib/middlewares/fallback.js +3 -1
- package/lib/middlewares/index.d.ts +5 -5
- package/lib/middlewares/index.js +15 -15
- package/lib/middlewares/session.d.ts +1 -1
- package/lib/middlewares/session.js +3 -1
- package/lib/middlewares/sitemap.d.ts +1 -1
- package/lib/middlewares/sitemap.js +3 -1
- package/lib/middlewares/user.d.ts +1 -1
- package/lib/middlewares/user.js +3 -1
- package/lib/security/index.d.ts +2 -2
- package/lib/security/index.js +3 -3
- package/lib/service/blocklet.d.ts +5 -2
- package/lib/service/blocklet.js +14 -11
- package/lib/service/eventbus.d.ts +2 -2
- package/lib/service/eventbus.js +5 -8
- package/lib/service/notification.d.ts +7 -6
- package/lib/service/notification.js +33 -29
- package/lib/service/signature.d.ts +27 -0
- package/lib/service/signature.js +112 -0
- package/lib/util/app-info.d.ts +1 -1
- package/lib/util/app-info.js +2 -2
- package/lib/util/check-blocklet-env.d.ts +1 -1
- package/lib/util/check-blocklet-env.js +4 -2
- package/lib/util/component-api.js +8 -4
- package/lib/util/csrf.d.ts +5 -0
- package/lib/util/csrf.js +9 -0
- package/lib/util/jest-setup.js +9 -4
- package/lib/util/jest-teardown.js +2 -2
- package/lib/util/send-notification.d.ts +13 -10
- package/lib/util/send-notification.js +42 -47
- package/lib/util/service-api.js +8 -4
- package/lib/util/verify-session.js +10 -7
- package/lib/util/verify-sign.d.ts +8 -7
- package/lib/util/verify-sign.js +11 -42
- package/lib/wallet-authenticator.d.ts +1 -1
- package/lib/wallet-authenticator.js +9 -10
- package/lib/wallet-handler.d.ts +1 -1
- package/lib/wallet-handler.js +3 -1
- package/lib/wallet.d.ts +35 -7
- package/lib/wallet.js +136 -29
- package/package.json +19 -18
package/lib/security/index.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.verifyResponse = exports.signResponse = exports.decrypt = exports.encryp
|
|
|
7
7
|
const crypto_1 = __importDefault(require("crypto"));
|
|
8
8
|
const aes_legacy_1 = __importDefault(require("@ocap/mcrypto/lib/crypter/aes-legacy"));
|
|
9
9
|
const security_1 = require("@blocklet/meta/lib/security");
|
|
10
|
-
const wallet_1 =
|
|
10
|
+
const wallet_1 = require("../wallet");
|
|
11
11
|
const AES = { default: aes_legacy_1.default }.default;
|
|
12
12
|
const encrypt = (message, password, salt) => {
|
|
13
13
|
const _password = password || process.env.BLOCKLET_APP_EK;
|
|
@@ -27,9 +27,9 @@ const decrypt = (message, password, salt) => {
|
|
|
27
27
|
return AES.decrypt(message, crypto_1.default.pbkdf2Sync(_password, _salt, 256, 32, 'sha512').toString('hex'));
|
|
28
28
|
};
|
|
29
29
|
exports.decrypt = decrypt;
|
|
30
|
-
const signResponse = (data) => (0, security_1.signResponse)(data, (0, wallet_1.
|
|
30
|
+
const signResponse = (data) => (0, security_1.signResponse)(data, (0, wallet_1.getWallet)());
|
|
31
31
|
exports.signResponse = signResponse;
|
|
32
|
-
const verifyResponse = (data) => (0, security_1.verifyResponse)(data, (0, wallet_1.
|
|
32
|
+
const verifyResponse = (data) => (0, security_1.verifyResponse)(data, (0, wallet_1.getWallet)());
|
|
33
33
|
exports.verifyResponse = verifyResponse;
|
|
34
34
|
exports.default = {
|
|
35
35
|
encrypt,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Client from '@blocklet/server-js';
|
|
2
2
|
import { LOGIN_PROVIDER } from '@blocklet/constant';
|
|
3
|
+
import { AxiosHeaders } from 'axios';
|
|
3
4
|
type PartialDeep<T> = {
|
|
4
5
|
[K in keyof T]?: T[K] extends object ? PartialDeep<T[K]> : T[K];
|
|
5
6
|
};
|
|
@@ -14,7 +15,9 @@ declare class BlockletService {
|
|
|
14
15
|
constructor(httpEndpoint?: string);
|
|
15
16
|
}
|
|
16
17
|
interface BlockletService {
|
|
17
|
-
login: (params: object
|
|
18
|
+
login: (params: object, options?: {
|
|
19
|
+
headers: AxiosHeaders;
|
|
20
|
+
}) => Promise<{
|
|
18
21
|
user: Object;
|
|
19
22
|
token: string;
|
|
20
23
|
refreshToken: string;
|
|
@@ -94,4 +97,4 @@ interface BlockletService {
|
|
|
94
97
|
configBlocklet(params: OmitDid<Client.RequestConfigBlockletInput>): Promise<Client.ResponseBlocklet>;
|
|
95
98
|
configNavigations(params: OmitDid<Client.RequestConfigNavigationsInput>): Promise<Client.ResponseBlocklet>;
|
|
96
99
|
}
|
|
97
|
-
export
|
|
100
|
+
export { BlockletService };
|
package/lib/service/blocklet.js
CHANGED
|
@@ -35,6 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.BlockletService = void 0;
|
|
38
40
|
/* eslint-disable prettier/prettier */
|
|
39
41
|
/* eslint-disable max-classes-per-file */
|
|
40
42
|
/* eslint-disable @typescript-eslint/indent */
|
|
@@ -47,9 +49,9 @@ const constant_2 = require("@blocklet/constant");
|
|
|
47
49
|
const util_2 = require("@blocklet/meta/lib/util");
|
|
48
50
|
const security_1 = require("@blocklet/meta/lib/security");
|
|
49
51
|
const error_1 = require("@blocklet/error");
|
|
50
|
-
const check_blocklet_env_1 =
|
|
52
|
+
const check_blocklet_env_1 = require("../util/check-blocklet-env");
|
|
51
53
|
const version_1 = require("../version");
|
|
52
|
-
const wallet_1 =
|
|
54
|
+
const wallet_1 = require("../wallet");
|
|
53
55
|
const service_api_1 = __importDefault(require("../util/service-api"));
|
|
54
56
|
const parse_docker_endpoint_1 = require("../util/parse-docker-endpoint");
|
|
55
57
|
const { WELLKNOWN_SERVICE_PATH_PREFIX, USER_AVATAR_URL_PREFIX, USER_AVATAR_PATH_PREFIX } = constant_1.default;
|
|
@@ -64,18 +66,17 @@ const fixAvatar = (user) => {
|
|
|
64
66
|
};
|
|
65
67
|
class BlockletClient extends server_js_1.default {
|
|
66
68
|
constructor(httpEndpoint) {
|
|
67
|
-
(0, check_blocklet_env_1.
|
|
69
|
+
(0, check_blocklet_env_1.checkBlockletEnvironment)();
|
|
68
70
|
super(httpEndpoint || `http://${(0, parse_docker_endpoint_1.getServerHost)()}:${process.env.ABT_NODE_PORT}/api/gql`.trim(), `BlockletSDK/${VERSION}`);
|
|
69
|
-
const wallet =
|
|
71
|
+
const wallet = wallet_1.getWallet.getAccessWallet();
|
|
70
72
|
this.setAuthAccessKey({
|
|
71
73
|
accessKeyId: wallet.address,
|
|
72
|
-
// for backward compatibility
|
|
73
74
|
accessKeySecret: (0, util_1.toBuffer)(wallet.secretKey),
|
|
74
75
|
type: 'sha256',
|
|
75
76
|
});
|
|
76
77
|
}
|
|
77
|
-
_getAuthHeaders() {
|
|
78
|
-
const headers = super._getAuthHeaders();
|
|
78
|
+
async _getAuthHeaders() {
|
|
79
|
+
const headers = await super._getAuthHeaders();
|
|
79
80
|
// BLOCKLET_DID is always same as BLOCKLET_APP_PID in structV2 application
|
|
80
81
|
headers['x-access-blocklet'] = process.env.BLOCKLET_DID;
|
|
81
82
|
headers['x-access-component'] = process.env.BLOCKLET_COMPONENT_DID;
|
|
@@ -229,9 +230,11 @@ class BlockletService {
|
|
|
229
230
|
const fn = client[api];
|
|
230
231
|
this[api] = apiFnMap[api] ? apiFnMap[api](fn) : apiFallback(fn);
|
|
231
232
|
});
|
|
232
|
-
this.login = async (data) => {
|
|
233
|
+
this.login = async (data, options) => {
|
|
233
234
|
try {
|
|
234
|
-
const { data: resData } = await service_api_1.default.post('/api/user/login', data
|
|
235
|
+
const { data: resData } = await service_api_1.default.post('/api/user/login', data, {
|
|
236
|
+
headers: options?.headers,
|
|
237
|
+
});
|
|
235
238
|
if (resData?.user) {
|
|
236
239
|
fixAvatar(resData.user);
|
|
237
240
|
}
|
|
@@ -281,7 +284,7 @@ class BlockletService {
|
|
|
281
284
|
return (0, util_2.findComponentByIdV2)(blocklet, did);
|
|
282
285
|
};
|
|
283
286
|
this.getVault = async () => {
|
|
284
|
-
const wallet = wallet_1.
|
|
287
|
+
const wallet = wallet_1.getWallet.getPermanentWallet();
|
|
285
288
|
const { blocklet } = await this.getBlocklet();
|
|
286
289
|
return (0, security_1.verifyVault)(blocklet.vaults, wallet.address);
|
|
287
290
|
};
|
|
@@ -353,4 +356,4 @@ class BlockletService {
|
|
|
353
356
|
});
|
|
354
357
|
}
|
|
355
358
|
}
|
|
356
|
-
|
|
359
|
+
exports.BlockletService = BlockletService;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TEvent } from '../types/event';
|
|
2
|
-
export declare const subscribe: (cb: (event: TEvent) => any | Promise<any>) => void
|
|
2
|
+
export declare const subscribe: (cb: (event: TEvent) => any | Promise<any>) => Promise<void>;
|
|
3
3
|
export declare const unsubscribe: (cb: (event: TEvent) => any | Promise<any>) => void;
|
|
4
4
|
export declare const publish: (name: string, event: {
|
|
5
5
|
id?: string;
|
|
@@ -7,7 +7,7 @@ export declare const publish: (name: string, event: {
|
|
|
7
7
|
data: any;
|
|
8
8
|
}) => Promise<any>;
|
|
9
9
|
declare const _default: {
|
|
10
|
-
subscribe: (cb: (event: TEvent) => any | Promise<any>) => void
|
|
10
|
+
subscribe: (cb: (event: TEvent) => any | Promise<any>) => Promise<void>;
|
|
11
11
|
unsubscribe: (cb: (event: TEvent) => any | Promise<any>) => void;
|
|
12
12
|
publish: (name: string, event: {
|
|
13
13
|
id?: string;
|
package/lib/service/eventbus.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.publish = exports.unsubscribe = exports.subscribe = void 0;
|
|
7
4
|
const util_1 = require("@blocklet/meta/lib/util");
|
|
8
5
|
const notification_1 = require("./notification");
|
|
9
|
-
const check_blocklet_env_1 =
|
|
6
|
+
const check_blocklet_env_1 = require("../util/check-blocklet-env");
|
|
10
7
|
const send_notification_1 = require("../util/send-notification");
|
|
11
8
|
const event_1 = require("../validators/event");
|
|
12
|
-
const subscribe = (cb) => {
|
|
13
|
-
(0, notification_1.ensureClient)();
|
|
9
|
+
const subscribe = async (cb) => {
|
|
10
|
+
await (0, notification_1.ensureClient)();
|
|
14
11
|
notification_1._eventBus.on('event', cb);
|
|
15
12
|
};
|
|
16
13
|
exports.subscribe = subscribe;
|
|
@@ -19,8 +16,8 @@ const unsubscribe = (cb) => {
|
|
|
19
16
|
};
|
|
20
17
|
exports.unsubscribe = unsubscribe;
|
|
21
18
|
const publish = async (name, event) => {
|
|
22
|
-
(0, check_blocklet_env_1.
|
|
23
|
-
(0, notification_1.ensureClient)();
|
|
19
|
+
(0, check_blocklet_env_1.checkBlockletEnvironment)();
|
|
20
|
+
await (0, notification_1.ensureClient)();
|
|
24
21
|
const payload = {
|
|
25
22
|
id: event.id || (0, util_1.nanoid)(),
|
|
26
23
|
time: event.time || new Date().toISOString(),
|
|
@@ -3,7 +3,7 @@ import { TNotification, TNotificationInput, TSendOptions } from '../types/notifi
|
|
|
3
3
|
type $TSFixMe = any;
|
|
4
4
|
export declare const getSender: () => {
|
|
5
5
|
appDid: string;
|
|
6
|
-
|
|
6
|
+
wallet: import("@ocap/wallet").WalletObject<string>;
|
|
7
7
|
};
|
|
8
8
|
/**
|
|
9
9
|
*
|
|
@@ -29,11 +29,12 @@ declare const doSendMail: (receiver: string | string[], notification: TNotificat
|
|
|
29
29
|
*/
|
|
30
30
|
export declare const broadcast: (notification: TNotificationInput, options?: TSendOptions) => Promise<any>;
|
|
31
31
|
export declare const _eventBus: EventEmitter<[never]>;
|
|
32
|
-
export declare const
|
|
33
|
-
export declare const
|
|
32
|
+
export declare const _emitter: EventEmitter<[never]>;
|
|
33
|
+
export declare const ensureClient: () => Promise<void>;
|
|
34
|
+
export declare const on: (event: string, cb?: $TSFixMe) => Promise<EventEmitter<[never]>>;
|
|
34
35
|
export declare const off: any;
|
|
35
36
|
export declare const _message: {
|
|
36
|
-
on: (event: string, cb: $TSFixMe) => EventEmitter<[never]
|
|
37
|
+
on: (event: string, cb: $TSFixMe) => Promise<EventEmitter<[never]>>;
|
|
37
38
|
off: any;
|
|
38
39
|
};
|
|
39
40
|
export { doSendToUser as sendToUser };
|
|
@@ -44,10 +45,10 @@ declare const _default: {
|
|
|
44
45
|
sendToRelay: (topic: string, event: string, data: any) => Promise<any>;
|
|
45
46
|
sendToMail: (receiver: string | string[], notification: TNotification, options?: TSendOptions) => Promise<any>;
|
|
46
47
|
broadcast: (notification: TNotificationInput, options?: TSendOptions) => Promise<any>;
|
|
47
|
-
on: (event: string, cb?: $TSFixMe) => EventEmitter<[never]
|
|
48
|
+
on: (event: string, cb?: $TSFixMe) => Promise<EventEmitter<[never]>>;
|
|
48
49
|
off: any;
|
|
49
50
|
_message: {
|
|
50
|
-
on: (event: string, cb: $TSFixMe) => EventEmitter<[never]
|
|
51
|
+
on: (event: string, cb: $TSFixMe) => Promise<EventEmitter<[never]>>;
|
|
51
52
|
off: any;
|
|
52
53
|
};
|
|
53
54
|
};
|
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.sendToRelay = exports.sendToMail = exports.sendToUser = exports._message = exports.off = exports.on = exports.ensureClient = exports._eventBus = exports.broadcast = exports.getSender = void 0;
|
|
39
|
+
exports.sendToRelay = exports.sendToMail = exports.sendToUser = exports._message = exports.off = exports.on = exports.ensureClient = exports._emitter = exports._eventBus = exports.broadcast = exports.getSender = void 0;
|
|
40
40
|
/* eslint-disable @typescript-eslint/naming-convention */
|
|
41
41
|
const Jwt = __importStar(require("@arcblock/jwt"));
|
|
42
42
|
const debug_1 = __importDefault(require("debug"));
|
|
@@ -45,18 +45,21 @@ const ws_1 = require("@arcblock/ws");
|
|
|
45
45
|
const util_1 = require("@blocklet/meta/lib/util");
|
|
46
46
|
const channel_1 = require("@blocklet/meta/lib/channel");
|
|
47
47
|
const constant_1 = require("@blocklet/constant");
|
|
48
|
-
const check_blocklet_env_1 =
|
|
48
|
+
const check_blocklet_env_1 = require("../util/check-blocklet-env");
|
|
49
49
|
const send_notification_1 = require("../util/send-notification");
|
|
50
50
|
const constants_1 = require("../util/constants");
|
|
51
|
-
const wallet_1 =
|
|
51
|
+
const wallet_1 = require("../wallet");
|
|
52
52
|
const notification_1 = require("../validators/notification");
|
|
53
53
|
const parse_docker_endpoint_1 = require("../util/parse-docker-endpoint");
|
|
54
54
|
const debug = (0, debug_1.default)('@blocklet/sdk:notification');
|
|
55
55
|
const getSender = () => {
|
|
56
|
-
const wallet = (0, wallet_1.
|
|
56
|
+
const wallet = (0, wallet_1.getWallet)();
|
|
57
|
+
const accessKeyWallet = (0, wallet_1.getAccessWallet)();
|
|
57
58
|
return {
|
|
59
|
+
// appDid is used by the server to identify the blocklet
|
|
58
60
|
appDid: wallet.address,
|
|
59
|
-
|
|
61
|
+
// wallet is used for signing on the client side and verification on the server side
|
|
62
|
+
wallet: accessKeyWallet,
|
|
60
63
|
};
|
|
61
64
|
};
|
|
62
65
|
exports.getSender = getSender;
|
|
@@ -70,19 +73,19 @@ exports.getSender = getSender;
|
|
|
70
73
|
*/
|
|
71
74
|
// eslint-disable-next-line require-await
|
|
72
75
|
const doSendToUser = async (receiver, notification, options) => {
|
|
73
|
-
(0, check_blocklet_env_1.
|
|
76
|
+
(0, check_blocklet_env_1.checkBlockletEnvironment)();
|
|
74
77
|
return (0, send_notification_1.sendToUser)(receiver, notification, (0, exports.getSender)(), options, 'send-to-user');
|
|
75
78
|
};
|
|
76
79
|
exports.sendToUser = doSendToUser;
|
|
77
80
|
// eslint-disable-next-line require-await
|
|
78
81
|
const doSendToRelay = async (topic, event, data) => {
|
|
79
|
-
(0, check_blocklet_env_1.
|
|
82
|
+
(0, check_blocklet_env_1.checkBlockletEnvironment)();
|
|
80
83
|
return (0, send_notification_1.sendToRelay)(topic, event, data, (0, exports.getSender)());
|
|
81
84
|
};
|
|
82
85
|
exports.sendToRelay = doSendToRelay;
|
|
83
86
|
// eslint-disable-next-line require-await
|
|
84
87
|
const doSendMail = async (receiver, notification, options) => {
|
|
85
|
-
(0, check_blocklet_env_1.
|
|
88
|
+
(0, check_blocklet_env_1.checkBlockletEnvironment)();
|
|
86
89
|
return (0, send_notification_1.sendToUser)(receiver, notification, (0, exports.getSender)(), options, 'send-to-mail');
|
|
87
90
|
};
|
|
88
91
|
exports.sendToMail = doSendMail;
|
|
@@ -99,7 +102,7 @@ exports.sendToMail = doSendMail;
|
|
|
99
102
|
*/
|
|
100
103
|
// eslint-disable-next-line require-await
|
|
101
104
|
const broadcast = async (notification, options = {}) => {
|
|
102
|
-
(0, check_blocklet_env_1.
|
|
105
|
+
(0, check_blocklet_env_1.checkBlockletEnvironment)();
|
|
103
106
|
const sender = (0, exports.getSender)();
|
|
104
107
|
const { channel = (0, channel_1.getAppPublicChannel)(sender.appDid) } = options;
|
|
105
108
|
const { event = 'message' } = options;
|
|
@@ -110,6 +113,7 @@ const noop = () => { };
|
|
|
110
113
|
const emitter = new node_events_1.EventEmitter();
|
|
111
114
|
const messageEmitter = new node_events_1.EventEmitter();
|
|
112
115
|
exports._eventBus = new node_events_1.EventEmitter(); // for event bus
|
|
116
|
+
exports._emitter = emitter; // export internal emitter for testing
|
|
113
117
|
const emitError = (error) => {
|
|
114
118
|
messageEmitter.emit('error', error);
|
|
115
119
|
emitter.emit('error', error);
|
|
@@ -125,30 +129,30 @@ const joinChannelErrorHandler = (name, type, emitters) => (err) => {
|
|
|
125
129
|
(emitters || [emitter]).forEach((x) => x.emit('error', { message: msg }));
|
|
126
130
|
};
|
|
127
131
|
let client = null;
|
|
128
|
-
const initClient = () => {
|
|
132
|
+
const initClient = async () => {
|
|
129
133
|
if (!client) {
|
|
130
134
|
ensureErrorListener();
|
|
131
|
-
const
|
|
135
|
+
const accessWallet = (0, wallet_1.getAccessWallet)();
|
|
132
136
|
const componentDid = process.env.BLOCKLET_COMPONENT_DID;
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
|
|
137
|
+
const appDid = process.env.BLOCKLET_APP_PID;
|
|
138
|
+
const { publicKey: pk } = accessWallet;
|
|
139
|
+
// Generate one token and reuse it for connection and all channels
|
|
140
|
+
const token = await accessWallet.signJWT({});
|
|
141
|
+
// Build URL with query parameters directly
|
|
142
|
+
const baseUrl = `ws://${(0, parse_docker_endpoint_1.getServerHost)()}:${process.env.ABT_NODE_SERVICE_PORT}${constants_1.SERVICE_PREFIX}/websocket`;
|
|
143
|
+
const url = `${baseUrl}?token=${encodeURIComponent(token)}&pk=${encodeURIComponent(pk)}`;
|
|
136
144
|
client = new ws_1.WsClient(url, {
|
|
137
145
|
heartbeatIntervalMs: 10 * 1000,
|
|
138
|
-
params: () => ({
|
|
139
|
-
token: token(),
|
|
140
|
-
pk,
|
|
141
|
-
}),
|
|
142
146
|
});
|
|
143
147
|
client.connect();
|
|
144
|
-
const messageChannel = client.channel(
|
|
145
|
-
const appPublicChannel = client.channel((0, channel_1.getAppPublicChannel)(
|
|
146
|
-
const componentChannel = client.channel((0, channel_1.getComponentChannel)(
|
|
147
|
-
token
|
|
148
|
+
const messageChannel = client.channel(accessWallet.address, () => ({ token, pk }));
|
|
149
|
+
const appPublicChannel = client.channel((0, channel_1.getAppPublicChannel)(appDid), () => ({ token, pk }));
|
|
150
|
+
const componentChannel = client.channel((0, channel_1.getComponentChannel)(appDid, componentDid), () => ({
|
|
151
|
+
token,
|
|
148
152
|
pk,
|
|
149
153
|
apiKey: process.env.BLOCKLET_COMPONENT_API_KEY,
|
|
150
154
|
}));
|
|
151
|
-
const eventBusChannel = client.channel((0, channel_1.getEventBusChannel)(
|
|
155
|
+
const eventBusChannel = client.channel((0, channel_1.getEventBusChannel)(appDid), () => ({ token, pk }));
|
|
152
156
|
messageChannel
|
|
153
157
|
.join()
|
|
154
158
|
.receive('error', joinChannelErrorHandler('message channel', 'error', [messageEmitter, emitter]))
|
|
@@ -237,24 +241,24 @@ const initClient = () => {
|
|
|
237
241
|
});
|
|
238
242
|
}
|
|
239
243
|
};
|
|
240
|
-
const ensureClient = () => {
|
|
244
|
+
const ensureClient = async () => {
|
|
241
245
|
if (process.env.BLOCKLET_MODE === 'test') {
|
|
242
246
|
return;
|
|
243
247
|
}
|
|
244
248
|
if (!client) {
|
|
245
|
-
initClient();
|
|
249
|
+
await initClient();
|
|
246
250
|
}
|
|
247
251
|
};
|
|
248
252
|
exports.ensureClient = ensureClient;
|
|
249
|
-
const on = (event, cb) => {
|
|
250
|
-
(0, exports.ensureClient)();
|
|
253
|
+
const on = async (event, cb) => {
|
|
254
|
+
await (0, exports.ensureClient)();
|
|
251
255
|
return emitter.on(event, cb);
|
|
252
256
|
};
|
|
253
257
|
exports.on = on;
|
|
254
258
|
exports.off = emitter.off.bind(emitter);
|
|
255
259
|
exports._message = {
|
|
256
|
-
on: (event, cb) => {
|
|
257
|
-
(0, exports.ensureClient)();
|
|
260
|
+
on: async (event, cb) => {
|
|
261
|
+
await (0, exports.ensureClient)();
|
|
258
262
|
return messageEmitter.on(event, cb);
|
|
259
263
|
},
|
|
260
264
|
off: messageEmitter.off.bind(messageEmitter),
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { SerializedWallet } from '@ocap/wallet';
|
|
2
|
+
import { DIDTypeArg } from '@arcblock/did';
|
|
3
|
+
import { EncodingType } from '@ocap/util';
|
|
4
|
+
export interface RemoteSignResponse {
|
|
5
|
+
signature: string;
|
|
6
|
+
publicKey?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface RemoteSignJWTResponse {
|
|
9
|
+
token: string;
|
|
10
|
+
publicKey?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RemoteSignETHResponse {
|
|
13
|
+
signature: string;
|
|
14
|
+
publicKey?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface RemoteSignOptions {
|
|
17
|
+
keyType?: 'sk' | 'psk';
|
|
18
|
+
type?: DIDTypeArg;
|
|
19
|
+
doSign?: boolean;
|
|
20
|
+
version?: string;
|
|
21
|
+
encoding?: EncodingType;
|
|
22
|
+
hashBeforeSign?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function remoteSign(payload: unknown, options?: RemoteSignOptions): Promise<RemoteSignResponse>;
|
|
25
|
+
export declare function remoteSignJWT(payload: unknown, options?: any): Promise<RemoteSignJWTResponse>;
|
|
26
|
+
export declare function remoteSignETH(data: string, options?: RemoteSignOptions): Promise<RemoteSignETHResponse>;
|
|
27
|
+
export declare function remoteDeriveWallet(sub: string, type?: any, index?: number, options?: RemoteSignOptions): Promise<SerializedWallet>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.remoteSign = remoteSign;
|
|
7
|
+
exports.remoteSignJWT = remoteSignJWT;
|
|
8
|
+
exports.remoteSignETH = remoteSignETH;
|
|
9
|
+
exports.remoteDeriveWallet = remoteDeriveWallet;
|
|
10
|
+
const axios_1 = __importDefault(require("axios"));
|
|
11
|
+
const env_1 = require("@blocklet/env");
|
|
12
|
+
const debug_1 = __importDefault(require("debug"));
|
|
13
|
+
const omit_1 = __importDefault(require("lodash/omit"));
|
|
14
|
+
const error_1 = require("@blocklet/error");
|
|
15
|
+
const constants_1 = require("../util/constants");
|
|
16
|
+
const parse_docker_endpoint_1 = require("../util/parse-docker-endpoint");
|
|
17
|
+
const debug = (0, debug_1.default)('@blocklet/sdk:remote-sign');
|
|
18
|
+
const { serverVersion } = env_1.blockletEnv;
|
|
19
|
+
const signClient = axios_1.default.create({
|
|
20
|
+
proxy: false,
|
|
21
|
+
baseURL: `http://${(0, parse_docker_endpoint_1.getServerHost)()}:${process.env.ABT_NODE_SERVICE_PORT}${constants_1.SERVICE_PREFIX}`,
|
|
22
|
+
timeout: 30 * 1000,
|
|
23
|
+
headers: {
|
|
24
|
+
'User-Agent': `BlockletSDK/${serverVersion}`,
|
|
25
|
+
'x-blocklet-server-version': serverVersion,
|
|
26
|
+
'x-blocklet-did': process.env.BLOCKLET_DID,
|
|
27
|
+
'x-component-did': process.env.BLOCKLET_COMPONENT_DID,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
const ensureRemoteContext = () => {
|
|
31
|
+
const { BLOCKLET_DID, BLOCKLET_REAL_DID, BLOCKLET_COMPONENT_API_KEY } = process.env;
|
|
32
|
+
if (!BLOCKLET_DID || !BLOCKLET_REAL_DID) {
|
|
33
|
+
throw new Error('Missing blocklet runtime context for remote signing: require BLOCKLET_DID and BLOCKLET_REAL_DID');
|
|
34
|
+
}
|
|
35
|
+
if (!BLOCKLET_COMPONENT_API_KEY) {
|
|
36
|
+
throw new Error('Missing BLOCKLET_COMPONENT_API_KEY for remote signing');
|
|
37
|
+
}
|
|
38
|
+
return { apiKey: BLOCKLET_COMPONENT_API_KEY, did: BLOCKLET_DID, realDid: BLOCKLET_REAL_DID };
|
|
39
|
+
};
|
|
40
|
+
const normalizePayload = (payload) => {
|
|
41
|
+
if (Buffer.isBuffer(payload)) {
|
|
42
|
+
return {
|
|
43
|
+
__type: 'buffer',
|
|
44
|
+
data: payload.toString('hex'),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return payload;
|
|
48
|
+
};
|
|
49
|
+
const getPayloadInfo = (payload) => {
|
|
50
|
+
if (payload !== undefined) {
|
|
51
|
+
if (typeof payload === 'string') {
|
|
52
|
+
return { payloadPreview: payload.substring(0, 100), payloadType: 'string' };
|
|
53
|
+
}
|
|
54
|
+
if (Buffer.isBuffer(payload)) {
|
|
55
|
+
return { payloadPreview: `Buffer(${payload.length} bytes)`, payloadType: 'Buffer' };
|
|
56
|
+
}
|
|
57
|
+
if (typeof payload === 'object') {
|
|
58
|
+
const preview = JSON.stringify(payload).substring(0, 100);
|
|
59
|
+
return { payloadPreview: preview, payloadType: 'object' };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {};
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Generic remote signing API caller
|
|
66
|
+
* @param endpoint - API endpoint (e.g., '/api/sign', '/api/sign/jwt')
|
|
67
|
+
* @param requestBody - Request body to send
|
|
68
|
+
* @returns API response data
|
|
69
|
+
*/
|
|
70
|
+
async function callRemoteSignAPI(endpoint, requestBody) {
|
|
71
|
+
const { apiKey } = ensureRemoteContext();
|
|
72
|
+
const startTime = Date.now();
|
|
73
|
+
// Prepare payload preview for logging (avoid logging sensitive data)
|
|
74
|
+
const payloadInfo = getPayloadInfo(requestBody.payload);
|
|
75
|
+
debug(`Remote Sign API call started: ${endpoint}`, {
|
|
76
|
+
...payloadInfo,
|
|
77
|
+
body: (0, omit_1.default)(requestBody, 'payload'),
|
|
78
|
+
});
|
|
79
|
+
try {
|
|
80
|
+
const { data } = await signClient.post(endpoint, {
|
|
81
|
+
...requestBody,
|
|
82
|
+
apiKey,
|
|
83
|
+
});
|
|
84
|
+
const duration = Date.now() - startTime;
|
|
85
|
+
debug(`Remote Sign API call succeeded: ${endpoint} in ${duration}`, {
|
|
86
|
+
responseKeys: Object.keys(data),
|
|
87
|
+
});
|
|
88
|
+
return data;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
const duration = Date.now() - startTime;
|
|
92
|
+
const message = (0, error_1.formatError)(error);
|
|
93
|
+
debug(`Remote Sign API call failed: ${endpoint} in ${duration}`, {
|
|
94
|
+
message,
|
|
95
|
+
});
|
|
96
|
+
throw new Error(`Remote signing API request failed: ${message}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function remoteSign(payload, options) {
|
|
100
|
+
const normalized = normalizePayload(payload);
|
|
101
|
+
return callRemoteSignAPI('/api/sign', { payload: normalized, options });
|
|
102
|
+
}
|
|
103
|
+
function remoteSignJWT(payload, options) {
|
|
104
|
+
return callRemoteSignAPI('/api/sign/jwt', { payload, options });
|
|
105
|
+
}
|
|
106
|
+
function remoteSignETH(data, options) {
|
|
107
|
+
const { hashBeforeSign, ...restOptions } = options || {};
|
|
108
|
+
return callRemoteSignAPI('/api/sign/eth', { data, hashBeforeSign, options: restOptions });
|
|
109
|
+
}
|
|
110
|
+
function remoteDeriveWallet(sub, type, index, options) {
|
|
111
|
+
return callRemoteSignAPI('/api/sign/derive', { sub, type, index, options });
|
|
112
|
+
}
|
package/lib/util/app-info.d.ts
CHANGED
|
@@ -17,9 +17,9 @@ export declare function getBlockletInfoSimple(getBlocklet?: () => Promise<ABTNod
|
|
|
17
17
|
federated: import("@blocklet/server-js").FederatedConfig;
|
|
18
18
|
appPid: string;
|
|
19
19
|
blocklet: import("@blocklet/server-js").BlockletState;
|
|
20
|
+
version: string;
|
|
20
21
|
description: string;
|
|
21
22
|
name: string;
|
|
22
|
-
version: string;
|
|
23
23
|
} | {
|
|
24
24
|
version: any;
|
|
25
25
|
name: string;
|
package/lib/util/app-info.js
CHANGED
|
@@ -9,7 +9,7 @@ exports.getAppInfo = getAppInfo;
|
|
|
9
9
|
exports.getMemberAppInfo = getMemberAppInfo;
|
|
10
10
|
const ufo_1 = require("ufo");
|
|
11
11
|
const util_1 = require("@blocklet/meta/lib/util");
|
|
12
|
-
const info_1 =
|
|
12
|
+
const info_1 = require("@blocklet/meta/lib/info");
|
|
13
13
|
const constant_1 = require("@abtnode/constant");
|
|
14
14
|
const pick_1 = __importDefault(require("lodash/pick"));
|
|
15
15
|
const login_1 = require("./login");
|
|
@@ -40,7 +40,7 @@ async function getBlockletInfoSimple(getBlocklet) {
|
|
|
40
40
|
// 适用于 service 中获取 blocklet 信息
|
|
41
41
|
if (getBlocklet && getBlocklet instanceof Function) {
|
|
42
42
|
const blocklet = await getBlocklet();
|
|
43
|
-
const blockletInfo = (0, info_1.
|
|
43
|
+
const blockletInfo = (0, info_1.getBlockletInfo)(blocklet, undefined, {
|
|
44
44
|
returnWallet: false,
|
|
45
45
|
});
|
|
46
46
|
return {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
declare const checkBlockletEnvironment: () => void;
|
|
2
|
-
export
|
|
2
|
+
export { checkBlockletEnvironment };
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkBlockletEnvironment = void 0;
|
|
2
4
|
const checkBlockletEnvironment = () => {
|
|
3
5
|
const envNames = [
|
|
4
6
|
'BLOCKLET_APP_ID',
|
|
5
7
|
'BLOCKLET_APP_NAME',
|
|
6
8
|
'BLOCKLET_APP_DESCRIPTION',
|
|
7
|
-
'BLOCKLET_APP_SK',
|
|
8
9
|
'BLOCKLET_DID',
|
|
10
|
+
'BLOCKLET_APP_EK',
|
|
9
11
|
'ABT_NODE_DID',
|
|
10
12
|
'ABT_NODE_PK',
|
|
11
13
|
'ABT_NODE_PORT',
|
|
@@ -17,4 +19,4 @@ const checkBlockletEnvironment = () => {
|
|
|
17
19
|
}
|
|
18
20
|
});
|
|
19
21
|
};
|
|
20
|
-
|
|
22
|
+
exports.checkBlockletEnvironment = checkBlockletEnvironment;
|
|
@@ -7,20 +7,24 @@ const axios_1 = __importDefault(require("axios"));
|
|
|
7
7
|
const env_1 = require("@blocklet/env");
|
|
8
8
|
const qs_1 = __importDefault(require("qs"));
|
|
9
9
|
const verify_sign_1 = require("./verify-sign");
|
|
10
|
+
const { serverVersion } = env_1.blockletEnv;
|
|
10
11
|
const componentApi = axios_1.default.create({
|
|
11
12
|
timeout: 60 * 1000,
|
|
12
13
|
headers: {
|
|
13
|
-
'User-Agent': `BlockletSDK/${
|
|
14
|
-
'x-blocklet-server-version':
|
|
14
|
+
'User-Agent': `BlockletSDK/${serverVersion}`,
|
|
15
|
+
'x-blocklet-server-version': serverVersion,
|
|
15
16
|
},
|
|
16
17
|
paramsSerializer: (params) => qs_1.default.stringify(params),
|
|
17
18
|
});
|
|
18
|
-
componentApi.interceptors.request.use((config) => {
|
|
19
|
-
const { sig, exp, iat, version } = (0, verify_sign_1.getSignData)({
|
|
19
|
+
componentApi.interceptors.request.use(async (config) => {
|
|
20
|
+
const { sig, exp, iat, version } = await (0, verify_sign_1.getSignData)({
|
|
20
21
|
data: config.data,
|
|
21
22
|
method: config.method,
|
|
22
23
|
params: config.params,
|
|
23
24
|
url: config.url,
|
|
25
|
+
}, {
|
|
26
|
+
// Compatible with previous version where APP_ASK does not exist
|
|
27
|
+
appSk: process.env.BLOCKLET_APP_ASK || process.env.BLOCKLET_APP_SK,
|
|
24
28
|
});
|
|
25
29
|
config.headers['x-component-did'] = process.env.BLOCKLET_COMPONENT_DID;
|
|
26
30
|
config.headers['x-component-sig'] = sig;
|
package/lib/util/csrf.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { LiteralUnion } from 'type-fest';
|
|
2
2
|
export declare function hmac(secretKey: string, message: string, algorithm?: LiteralUnion<'md5' | 'sha256', string>): string;
|
|
3
|
+
/**
|
|
4
|
+
* Get CSRF secret key with smart fallback strategy
|
|
5
|
+
* @returns CSRF secret key
|
|
6
|
+
*/
|
|
7
|
+
export declare function getCsrfSecret(): string;
|
|
3
8
|
/**
|
|
4
9
|
* 生成 CSRF Token
|
|
5
10
|
* @param secretKey 服务器密钥(必填,需保密)
|
package/lib/util/csrf.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.hmac = hmac;
|
|
4
|
+
exports.getCsrfSecret = getCsrfSecret;
|
|
4
5
|
exports.sign = sign;
|
|
5
6
|
exports.verify = verify;
|
|
6
7
|
const crypto_1 = require("crypto");
|
|
@@ -8,6 +9,14 @@ function hmac(secretKey, message, algorithm = 'md5') {
|
|
|
8
9
|
const hmacFunc = (0, crypto_1.createHmac)(algorithm, secretKey);
|
|
9
10
|
return hmacFunc.update(message).digest('base64url');
|
|
10
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Get CSRF secret key with smart fallback strategy
|
|
14
|
+
* @returns CSRF secret key
|
|
15
|
+
*/
|
|
16
|
+
function getCsrfSecret() {
|
|
17
|
+
// Compatible with previous version where APP_ASK does not exist
|
|
18
|
+
return process.env.BLOCKLET_APP_ASK || process.env.BLOCKLET_APP_SK;
|
|
19
|
+
}
|
|
11
20
|
/**
|
|
12
21
|
* 生成 CSRF Token
|
|
13
22
|
* @param secretKey 服务器密钥(必填,需保密)
|
package/lib/util/jest-setup.js
CHANGED
|
@@ -8,14 +8,15 @@ exports.default = setupJest;
|
|
|
8
8
|
const os_1 = __importDefault(require("os"));
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const parse_1 =
|
|
11
|
+
const parse_1 = require("@blocklet/meta/lib/parse");
|
|
12
12
|
const mcrypto_1 = require("@ocap/mcrypto");
|
|
13
13
|
const wallet_1 = require("@ocap/wallet");
|
|
14
|
+
const did_ext_1 = require("@arcblock/did-ext");
|
|
14
15
|
function setupJest() {
|
|
15
16
|
try {
|
|
16
17
|
const dir = process.cwd();
|
|
17
18
|
const wallet = (0, wallet_1.fromRandom)({ role: mcrypto_1.types.RoleType.ROLE_APPLICATION });
|
|
18
|
-
const meta = (0, parse_1.
|
|
19
|
+
const meta = (0, parse_1.parse)(dir, { ensureComponentStore: false });
|
|
19
20
|
const tmpDir = path_1.default.join(os_1.default.tmpdir(), meta.did);
|
|
20
21
|
if (fs_1.default.existsSync(tmpDir) === false) {
|
|
21
22
|
fs_1.default.mkdirSync(tmpDir, { recursive: true });
|
|
@@ -29,13 +30,17 @@ function setupJest() {
|
|
|
29
30
|
process.env.BLOCKLET_COMPONENT_DID = meta.did;
|
|
30
31
|
process.env.BLOCKLET_DATA_DIR = path_1.default.join(tmpDir, wallet.address);
|
|
31
32
|
process.env.BLOCKLET_LOG_DIR = path_1.default.join(tmpDir, wallet.address);
|
|
32
|
-
process.env.BLOCKLET_APP_SK = wallet.secretKey;
|
|
33
|
-
process.env.BLOCKLET_APP_PSK = wallet.secretKey;
|
|
33
|
+
// process.env.BLOCKLET_APP_SK = wallet.secretKey;
|
|
34
|
+
// process.env.BLOCKLET_APP_PSK = wallet.secretKey;
|
|
35
|
+
process.env.BLOCKLET_APP_PK = wallet.publicKey;
|
|
36
|
+
process.env.BLOCKLET_APP_PPK = wallet.publicKey;
|
|
34
37
|
process.env.BLOCKLET_APP_ID = wallet.address;
|
|
35
38
|
process.env.BLOCKLET_APP_PID = wallet.address;
|
|
36
39
|
process.env.BLOCKLET_APP_IDS = wallet.address;
|
|
37
40
|
process.env.BLOCKLET_APP_NAME = meta.title;
|
|
38
41
|
process.env.BLOCKLET_APP_DESCRIPTION = meta.description;
|
|
42
|
+
process.env.BLOCKLET_APP_EK = (0, did_ext_1.fromAppDid)(meta.did, process.env.ABT_NODE_PK, undefined, 1).secretKey;
|
|
43
|
+
process.env.BLOCKLET_APP_ASK = (0, did_ext_1.fromAppDid)(meta.did, process.env.ABT_NODE_PK, undefined, 1).secretKey;
|
|
39
44
|
process.env.BLOCKLET_APP_URL = 'http://192.168.0.10:3030';
|
|
40
45
|
process.env.BLOCKLET_MOUNT_POINTS = JSON.stringify([
|
|
41
46
|
{
|