fix(ohos): 移除硬编码后端凭据,地址规范化默认 https

- Model.ets: defaultConnection 不再内置 url/apiKey,改为空白模板
- 新增 normalizeBaseUrl:补协议(默认 https)、去尾斜杠、去误粘的 /api/v1
  裸域名走 http 会被反代 302 到门户站,客户端只拿到 404,表现为"连接直接失败"
- ConnStore: 增删改与读取存量数据时统一规范化 url
- 去掉 ensureDefaultConnection,首启不再预置连接,未配置时走统一提示
This commit is contained in:
root
2026-08-29 13:49:30 +08:00
parent 46e942f0c2
commit 8510a2f2eb
4 changed files with 47 additions and 20 deletions

View File

@ -1,7 +1,7 @@
import { preferences } from '@kit.ArkData';
import { Context } from '@kit.AbilityKit';
import { deviceInfo } from '@kit.BasicServicesKit';
import { ConnectionConfig, AppSettings, emptySettings, defaultConnection } from '../model/Model';
import { ConnectionConfig, AppSettings, emptySettings, defaultConnection, normalizeBaseUrl } from '../model/Model';
const PREF_NAME: string = 'homeagent_prefs';
const KEY_CONNECTIONS: string = 'connections_json';
@ -31,6 +31,12 @@ export class ConnStore {
} catch (e) {
this.connections = [];
}
// 存量数据可能是旧版本存进去的裸域名或带尾斜杠的地址,读出来时一并规范化,
// 否则老用户升级后仍然会拼出错误的请求地址。
for (let i = 0; i < this.connections.length; i++) {
const c: ConnectionConfig = this.connections[i];
c.url = normalizeBaseUrl(c.url);
}
}
const settingsJson: string = await this.prefs.get(KEY_SETTINGS, '') as string;
if (settingsJson.length > 0) {
@ -42,18 +48,8 @@ export class ConnStore {
}
}
// 首次启动时预置默认连接(用户后端),避免所有页面空白
async ensureDefaultConnection(): Promise<void> {
await this.load();
if (this.connections.length > 0) {
return;
}
const conn: ConnectionConfig = defaultConnection();
conn.id = 'default';
this.connections.push(conn);
this.settings.currentConnId = conn.id;
await this.save();
}
// 不预置任何连接:地址与密钥属于用户私有配置,不能随源码分发。
// 连接列表为空时各页面走"尚未配置后端连接"的统一提示,用户到设置页添加。
getConnections(): ConnectionConfig[] {
return this.connections;
@ -82,7 +78,7 @@ export class ConnStore {
const conn: ConnectionConfig = defaultConnection();
conn.id = Date.now().toString(36) + Math.floor(Math.random() * 10000).toString(36);
conn.name = name;
conn.url = url;
conn.url = normalizeBaseUrl(url);
conn.apiKey = apiKey;
conn.type = 'webui';
this.connections.push(conn);
@ -99,7 +95,7 @@ export class ConnStore {
const c: ConnectionConfig = this.connections[i];
if (c.id === id) {
c.name = name;
c.url = url;
c.url = normalizeBaseUrl(url);
c.apiKey = apiKey;
break;
}

View File

@ -81,7 +81,6 @@ export default class EntryAbility extends UIAbility {
windowStage.getMainWindow((err: BusinessError, win: window.Window) => {
if (err.code !== 0) {
connStore.init(this.context).then(async () => {
await connStore.ensureDefaultConnection();
const cur = connStore.getCurrentConnection();
if (cur !== null) {
apiClient.setConnection(cur);
@ -100,7 +99,6 @@ export default class EntryAbility extends UIAbility {
console.warn('[HomeAgent] setWindowLayoutFullScreen failed: ' + (e as Error).message);
}
connStore.init(this.context).then(async () => {
await connStore.ensureDefaultConnection();
const cur = connStore.getCurrentConnection();
if (cur !== null) {
apiClient.setConnection(cur);

View File

@ -163,12 +163,45 @@ export function emptySettings(): AppSettings {
return s;
}
/**
* 规范化用户填写的后端地址。
*
* 用户习惯直接敲域名homeagent.example.xyz或粘贴带路径的地址。
* 三件事必须在存库前做掉,否则请求会以各种方式失败:
*
* 1) 补协议,且默认 https。
* 很多反代把 http 整站 302 到别的主机(例如门户站 www.xxx
* 重定向后的主机没有 API客户端只会拿到 404 页面而不是 401/200
* 表现为"连接直接失败"且看不出原因。默认 https 可以绕过整类问题。
* 只有明确写了 http:// 的内网地址才走明文。
* 2) 去掉结尾斜杠,避免拼出 //api/v1。
* 3) 去掉用户误粘的 /api/v1 后缀,避免拼成 /api/v1/api/v1。
*/
export function normalizeBaseUrl(raw: string): string {
let u: string = raw.trim();
if (u.length === 0) {
return '';
}
const lower: string = u.toLowerCase();
if (!lower.startsWith('http://') && !lower.startsWith('https://')) {
u = 'https://' + u;
}
u = u.replace(/\/+$/, '');
u = u.replace(/\/api\/v1$/, '');
return u;
}
/**
* 新建连接用的空白模板。
* 这里不能写死任何地址或密钥:源码是公开的,硬编码等于把内网地址和访问凭据一起发布。
* 地址与 API Key 由用户在「设置 - 连接」里填写,未配置时各页面统一提示(见 UserError.MSG_NO_CONN
*/
export function defaultConnection(): ConnectionConfig {
const c: ConnectionConfig = {
id: '',
name: 'HomeAgent',
url: 'http://192.168.2.60:8080',
apiKey: 'jinrui233719',
url: '',
apiKey: '',
type: 'webui',
};
return c;

View File

@ -854,7 +854,7 @@ export struct SettingsPage {
.onChange((v: string) => {
this.editName = v;
})
TextInput({ placeholder: '地址 ( http://192.168.1.100:8080)', text: this.editUrl })
TextInput({ placeholder: '地址 (域名或 http://192.168.1.100:8080)', text: this.editUrl })
.height(36).fontSize(13).fontColor(this.palette().textPrimary)
.placeholderColor(this.palette().textMuted).backgroundColor(this.palette().bgInput)
.borderRadius(RADIUS_SM).border({ width: 1, color: this.palette().border })