@honor-claw/yoyo 1.2.1-beta.4 → 1.2.1
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/package.json +1 -1
- package/src/cloud-channel/admin-client-manager.ts +5 -1
- package/src/cloud-channel/client.ts +1 -1
- package/src/gateway-client/protocol-client.ts +1 -0
- package/src/gateway-client/types/client.ts +1 -0
- package/src/modules/configs/config-manager.ts +4 -11
- package/src/modules/configs/identity-persist.ts +5 -0
- package/src/modules/device/gateway-auth.ts +25 -0
- package/src/modules/device/identity.ts +8 -0
- package/src/modules/device/index.ts +1 -0
- package/src/modules/device/registry.ts +35 -1
- package/src/services/connection/impl.ts +11 -3
- package/src/utils/hash.ts +9 -0
package/package.json
CHANGED
|
@@ -29,9 +29,13 @@ export class AdminClientManager {
|
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const
|
|
32
|
+
const gatewayAuthConfig = getConfigManager().getGatewayAuthConfig();
|
|
33
|
+
const token = typeof gatewayAuthConfig?.token === "string" ? gatewayAuthConfig.token : "";
|
|
34
|
+
const password =
|
|
35
|
+
typeof gatewayAuthConfig?.password === "string" ? gatewayAuthConfig.password : "";
|
|
33
36
|
this.client = new AdminGatewayClient({
|
|
34
37
|
token,
|
|
38
|
+
password,
|
|
35
39
|
onAuthenticated: () => {
|
|
36
40
|
useClawLogger().info("[yoyoclaw-channel] admin gateway client authenticated");
|
|
37
41
|
this.ready = true;
|
|
@@ -196,7 +196,7 @@ export class ClawCloudSocketClient {
|
|
|
196
196
|
useClawLogger().debug?.(
|
|
197
197
|
`[yoyoclaw-channel] received cloud message from session ${message.wsOutputEvent?.sourceDeviceId}, deviceId ${
|
|
198
198
|
message.wsOutputEvent?.sourceDeviceInfo?.deviceId || "nil"
|
|
199
|
-
}, ${dataText.slice(0,
|
|
199
|
+
}, ${dataText.slice(0, 3000)}`,
|
|
200
200
|
);
|
|
201
201
|
|
|
202
202
|
if (message.code === "YOYO_CLAW_100000") {
|
|
@@ -101,22 +101,15 @@ export class ConfigManager {
|
|
|
101
101
|
return undefined;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
if (authConfig.token) {
|
|
107
|
-
result.token = authConfig.token;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (authConfig.password) {
|
|
111
|
-
result.password = authConfig.password;
|
|
112
|
-
}
|
|
104
|
+
const token = authConfig.token ?? "";
|
|
105
|
+
const password = authConfig.password ?? "";
|
|
113
106
|
|
|
114
107
|
// 如果没有任何认证信息,返回 undefined
|
|
115
|
-
if (
|
|
108
|
+
if (!token && !password) {
|
|
116
109
|
return undefined;
|
|
117
110
|
}
|
|
118
111
|
|
|
119
|
-
return
|
|
112
|
+
return { token, password };
|
|
120
113
|
} catch (error) {
|
|
121
114
|
console.error(`[claw-configs] Failed to read gateway auth config: ${error}`);
|
|
122
115
|
return undefined;
|
|
@@ -24,6 +24,7 @@ export interface PersistedIdentity {
|
|
|
24
24
|
publicKeyPem?: string;
|
|
25
25
|
privateKeyPem?: string;
|
|
26
26
|
createdAtMs?: number;
|
|
27
|
+
gatewayAuthMd5?: string;
|
|
27
28
|
version: IdentityVersion;
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -130,6 +131,10 @@ export async function updatePersistedIdentity(
|
|
|
130
131
|
updatedConfig.version = identity.version;
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
if ("gatewayAuthMd5" in identity) {
|
|
135
|
+
updatedConfig.gatewayAuthMd5 = identity.gatewayAuthMd5;
|
|
136
|
+
}
|
|
137
|
+
|
|
133
138
|
// 写入配置
|
|
134
139
|
const configPath = getConfigPath();
|
|
135
140
|
await safeWriteFile({
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { md5 } from "../../utils/hash.js";
|
|
2
|
+
import { GatewayAuthConfig } from "../configs/types.js";
|
|
3
|
+
|
|
4
|
+
function normalizeSecretValue(value: unknown): string {
|
|
5
|
+
if (typeof value === "string") {
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
if (value == null) {
|
|
9
|
+
return "";
|
|
10
|
+
}
|
|
11
|
+
return JSON.stringify(value);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function createGatewayAuthMd5(gatewayAuthConfig: GatewayAuthConfig | undefined): string {
|
|
15
|
+
return md5(
|
|
16
|
+
JSON.stringify({
|
|
17
|
+
token: normalizeSecretValue(gatewayAuthConfig?.token),
|
|
18
|
+
password: normalizeSecretValue(gatewayAuthConfig?.password),
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isSameGatewayAuthMd5(persist: string | undefined, right: string): boolean {
|
|
24
|
+
return (persist ?? "") === right;
|
|
25
|
+
}
|
|
@@ -114,6 +114,14 @@ export async function loadOrCreateDeviceIdentity(): Promise<DeviceIdentity> {
|
|
|
114
114
|
return identity;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* 只读取已持久化的 Gateway 认证 MD5
|
|
119
|
+
*/
|
|
120
|
+
export async function loadPersistedGatewayAuthMd5(): Promise<string | undefined> {
|
|
121
|
+
const persisted = await getPersistedIdentity();
|
|
122
|
+
return persisted?.gatewayAuthMd5;
|
|
123
|
+
}
|
|
124
|
+
|
|
117
125
|
/**
|
|
118
126
|
* Sign a payload using device private key
|
|
119
127
|
* @param privateKeyPem - Private key in PEM format
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { createClawCloudClient } from "../../apis/claw-cloud.js";
|
|
2
2
|
import { isOKResponse } from "../../apis/index.js";
|
|
3
3
|
import type { DeviceInfo, HonorUserInfo } from "../../types.js";
|
|
4
|
-
import {
|
|
4
|
+
import { formatHashForLog } from "../../utils/hash.js";
|
|
5
|
+
import { useClawLogger } from "../../utils/logger.js";
|
|
6
|
+
import { getConfigManager, updatePersistedIdentity } from "../configs/index.js";
|
|
7
|
+
import { createGatewayAuthMd5, isSameGatewayAuthMd5 } from "./gateway-auth.js";
|
|
8
|
+
import { loadPersistedGatewayAuthMd5 } from "./identity.js";
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* 注册设备到 Claw Cloud
|
|
@@ -25,3 +29,33 @@ export async function registerDevice(deviceInfo: DeviceInfo, userInfo: HonorUser
|
|
|
25
29
|
throw new Error(`注册失败:${response.data?.cnMessage}`);
|
|
26
30
|
}
|
|
27
31
|
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Gateway 认证信息发生变化时重新注册设备
|
|
35
|
+
*/
|
|
36
|
+
export async function registerDeviceIfGatewayAuthChanged(
|
|
37
|
+
deviceInfo: DeviceInfo,
|
|
38
|
+
userInfo: HonorUserInfo,
|
|
39
|
+
) {
|
|
40
|
+
const configManager = getConfigManager();
|
|
41
|
+
const gatewayAuthConfig = configManager.getGatewayAuthConfig();
|
|
42
|
+
const gatewayAuthMd5 = createGatewayAuthMd5(gatewayAuthConfig);
|
|
43
|
+
const persistedGatewayAuthMd5 = await loadPersistedGatewayAuthMd5();
|
|
44
|
+
const logger = useClawLogger();
|
|
45
|
+
|
|
46
|
+
logger.info(
|
|
47
|
+
`[yoyoclaw-registry] checking gateway auth md5: current=${formatHashForLog(
|
|
48
|
+
gatewayAuthMd5,
|
|
49
|
+
)}, persisted=${formatHashForLog(persistedGatewayAuthMd5)}`,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (isSameGatewayAuthMd5(persistedGatewayAuthMd5, gatewayAuthMd5)) {
|
|
53
|
+
logger.info("[yoyoclaw-registry] gateway auth unchanged, skipping device registration");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
logger.info("[yoyoclaw-registry] gateway auth changed, registering device");
|
|
58
|
+
await registerDevice(deviceInfo, userInfo);
|
|
59
|
+
await updatePersistedIdentity({ gatewayAuthMd5 });
|
|
60
|
+
logger.info("[yoyoclaw-registry] gateway auth md5 persisted after device registration");
|
|
61
|
+
}
|
|
@@ -2,7 +2,11 @@ import { OpenClawPluginApi, OpenClawPluginService } from "openclaw/plugin-sdk";
|
|
|
2
2
|
import { ClawChannel } from "../../cloud-channel/channel.js";
|
|
3
3
|
import { loadToken, clearToken } from "../../honor-auth/token-manager.js";
|
|
4
4
|
import { getConfigManager } from "../../modules/configs/config-manager.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getDeviceInfo,
|
|
7
|
+
registerDevice,
|
|
8
|
+
registerDeviceIfGatewayAuthChanged,
|
|
9
|
+
} from "../../modules/device/index.js";
|
|
6
10
|
import { DeviceInfo, HonorUserInfo } from "../../types.js";
|
|
7
11
|
import { useClawLogger } from "../../utils/logger.js";
|
|
8
12
|
import { StatusTracker, StatusEventType } from "./status-tracker/index.js";
|
|
@@ -79,9 +83,13 @@ export const createClawConnectionService = (api: OpenClawPluginApi) =>
|
|
|
79
83
|
* 创建channel
|
|
80
84
|
*/
|
|
81
85
|
async function createChannel(deviceInfo: DeviceInfo, userInfo: HonorUserInfo): Promise<void> {
|
|
82
|
-
clawConnection.status = "connecting";
|
|
83
86
|
useClawLogger().info(`[yoyoclaw-conn] creating new channel for device: ${deviceInfo.deviceId}`);
|
|
84
87
|
|
|
88
|
+
await registerDeviceIfGatewayAuthChanged(deviceInfo, userInfo);
|
|
89
|
+
|
|
90
|
+
const previousStatus = clawConnection.status;
|
|
91
|
+
clawConnection.status = "connecting";
|
|
92
|
+
|
|
85
93
|
// 通知状态跟踪器:连接状态变更
|
|
86
94
|
if (statusTracker) {
|
|
87
95
|
await statusTracker.handleEvent({
|
|
@@ -89,7 +97,7 @@ async function createChannel(deviceInfo: DeviceInfo, userInfo: HonorUserInfo): P
|
|
|
89
97
|
timestamp: Date.now(),
|
|
90
98
|
data: {
|
|
91
99
|
status: "connecting",
|
|
92
|
-
previousStatus
|
|
100
|
+
previousStatus,
|
|
93
101
|
},
|
|
94
102
|
});
|
|
95
103
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
|
|
3
|
+
export function md5(value: string): string {
|
|
4
|
+
return crypto.createHash("md5").update(value).digest("hex");
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function formatHashForLog(value: string | undefined): string {
|
|
8
|
+
return value ? `${value.slice(0, 8)}...` : "none";
|
|
9
|
+
}
|