mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-04 00:03:59 +00:00
fix(ohos): 移除硬编码后端凭据,地址规范化默认 https
- Model.ets: defaultConnection 不再内置 url/apiKey,改为空白模板 - 新增 normalizeBaseUrl:补协议(默认 https)、去尾斜杠、去误粘的 /api/v1 裸域名走 http 会被反代 302 到门户站,客户端只拿到 404,表现为"连接直接失败" - ConnStore: 增删改与读取存量数据时统一规范化 url - 去掉 ensureDefaultConnection,首启不再预置连接,未配置时走统一提示
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
import { preferences } from '@kit.ArkData';
|
import { preferences } from '@kit.ArkData';
|
||||||
import { Context } from '@kit.AbilityKit';
|
import { Context } from '@kit.AbilityKit';
|
||||||
import { deviceInfo } from '@kit.BasicServicesKit';
|
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 PREF_NAME: string = 'homeagent_prefs';
|
||||||
const KEY_CONNECTIONS: string = 'connections_json';
|
const KEY_CONNECTIONS: string = 'connections_json';
|
||||||
@ -31,6 +31,12 @@ export class ConnStore {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.connections = [];
|
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;
|
const settingsJson: string = await this.prefs.get(KEY_SETTINGS, '') as string;
|
||||||
if (settingsJson.length > 0) {
|
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[] {
|
getConnections(): ConnectionConfig[] {
|
||||||
return this.connections;
|
return this.connections;
|
||||||
@ -82,7 +78,7 @@ export class ConnStore {
|
|||||||
const conn: ConnectionConfig = defaultConnection();
|
const conn: ConnectionConfig = defaultConnection();
|
||||||
conn.id = Date.now().toString(36) + Math.floor(Math.random() * 10000).toString(36);
|
conn.id = Date.now().toString(36) + Math.floor(Math.random() * 10000).toString(36);
|
||||||
conn.name = name;
|
conn.name = name;
|
||||||
conn.url = url;
|
conn.url = normalizeBaseUrl(url);
|
||||||
conn.apiKey = apiKey;
|
conn.apiKey = apiKey;
|
||||||
conn.type = 'webui';
|
conn.type = 'webui';
|
||||||
this.connections.push(conn);
|
this.connections.push(conn);
|
||||||
@ -99,7 +95,7 @@ export class ConnStore {
|
|||||||
const c: ConnectionConfig = this.connections[i];
|
const c: ConnectionConfig = this.connections[i];
|
||||||
if (c.id === id) {
|
if (c.id === id) {
|
||||||
c.name = name;
|
c.name = name;
|
||||||
c.url = url;
|
c.url = normalizeBaseUrl(url);
|
||||||
c.apiKey = apiKey;
|
c.apiKey = apiKey;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,6 @@ export default class EntryAbility extends UIAbility {
|
|||||||
windowStage.getMainWindow((err: BusinessError, win: window.Window) => {
|
windowStage.getMainWindow((err: BusinessError, win: window.Window) => {
|
||||||
if (err.code !== 0) {
|
if (err.code !== 0) {
|
||||||
connStore.init(this.context).then(async () => {
|
connStore.init(this.context).then(async () => {
|
||||||
await connStore.ensureDefaultConnection();
|
|
||||||
const cur = connStore.getCurrentConnection();
|
const cur = connStore.getCurrentConnection();
|
||||||
if (cur !== null) {
|
if (cur !== null) {
|
||||||
apiClient.setConnection(cur);
|
apiClient.setConnection(cur);
|
||||||
@ -100,7 +99,6 @@ export default class EntryAbility extends UIAbility {
|
|||||||
console.warn('[HomeAgent] setWindowLayoutFullScreen failed: ' + (e as Error).message);
|
console.warn('[HomeAgent] setWindowLayoutFullScreen failed: ' + (e as Error).message);
|
||||||
}
|
}
|
||||||
connStore.init(this.context).then(async () => {
|
connStore.init(this.context).then(async () => {
|
||||||
await connStore.ensureDefaultConnection();
|
|
||||||
const cur = connStore.getCurrentConnection();
|
const cur = connStore.getCurrentConnection();
|
||||||
if (cur !== null) {
|
if (cur !== null) {
|
||||||
apiClient.setConnection(cur);
|
apiClient.setConnection(cur);
|
||||||
|
|||||||
@ -163,12 +163,45 @@ export function emptySettings(): AppSettings {
|
|||||||
return s;
|
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 {
|
export function defaultConnection(): ConnectionConfig {
|
||||||
const c: ConnectionConfig = {
|
const c: ConnectionConfig = {
|
||||||
id: '',
|
id: '',
|
||||||
name: 'HomeAgent',
|
name: 'HomeAgent',
|
||||||
url: 'http://192.168.2.60:8080',
|
url: '',
|
||||||
apiKey: 'jinrui233719',
|
apiKey: '',
|
||||||
type: 'webui',
|
type: 'webui',
|
||||||
};
|
};
|
||||||
return c;
|
return c;
|
||||||
|
|||||||
@ -854,7 +854,7 @@ export struct SettingsPage {
|
|||||||
.onChange((v: string) => {
|
.onChange((v: string) => {
|
||||||
this.editName = v;
|
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)
|
.height(36).fontSize(13).fontColor(this.palette().textPrimary)
|
||||||
.placeholderColor(this.palette().textMuted).backgroundColor(this.palette().bgInput)
|
.placeholderColor(this.palette().textMuted).backgroundColor(this.palette().bgInput)
|
||||||
.borderRadius(RADIUS_SM).border({ width: 1, color: this.palette().border })
|
.borderRadius(RADIUS_SM).border({ width: 1, color: this.palette().border })
|
||||||
|
|||||||
Reference in New Issue
Block a user