fix(external-gateway): derive gateway client identity from the dcrouter token and make the settings UI read-only
This commit is contained in:
@@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-05-09 - 1.26.1 - fix(external-gateway)
|
||||||
|
derive gateway client identity from the dcrouter token and make the settings UI read-only
|
||||||
|
|
||||||
|
- Resolves external gateway ownership and domain sync to use the gateway client context returned by dcrouter instead of a locally entered client ID.
|
||||||
|
- Falls back to stored gateway client settings only when token context is unavailable.
|
||||||
|
- Removes editable Gateway Client ID fields from settings and shows them as diagnostic read-only values for managed and external modes.
|
||||||
|
- Updates external gateway tests to validate token-derived gateway client IDs and admin-token behavior.
|
||||||
|
|
||||||
## 2026-05-09 - 1.26.0 - feat(dcrouter)
|
## 2026-05-09 - 1.26.0 - feat(dcrouter)
|
||||||
add managed local dcrouter mode with status controls and gateway integration
|
add managed local dcrouter mode with status controls and gateway integration
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,6 @@ class FakeDatabase {
|
|||||||
const makeOneboxRef = () => {
|
const makeOneboxRef = () => {
|
||||||
const database = new FakeDatabase();
|
const database = new FakeDatabase();
|
||||||
database.settings.set('dcrouterGatewayUrl', 'https://edge.example.com');
|
database.settings.set('dcrouterGatewayUrl', 'https://edge.example.com');
|
||||||
database.settings.set('dcrouterGatewayClientId', 'onebox-1');
|
|
||||||
database.settings.set('dcrouterWorkHosterId', 'onebox-1');
|
|
||||||
database.secretSettings.set('dcrouterGatewayApiToken', 'dcr-token');
|
database.secretSettings.set('dcrouterGatewayApiToken', 'dcr-token');
|
||||||
|
|
||||||
let reloadCount = 0;
|
let reloadCount = 0;
|
||||||
@@ -94,8 +92,11 @@ Deno.test('ExternalGatewayManager syncs dcrouter domains into Onebox domains', a
|
|||||||
|
|
||||||
const manager = new ExternalGatewayManager(oneboxRef as any);
|
const manager = new ExternalGatewayManager(oneboxRef as any);
|
||||||
(manager as any).fireDcRouterRequest = async (method: string, requestData: Record<string, unknown>) => {
|
(manager as any).fireDcRouterRequest = async (method: string, requestData: Record<string, unknown>) => {
|
||||||
|
if (method === 'getGatewayClientContext') {
|
||||||
|
return { context: { role: 'gatewayClient', gatewayClient: { type: 'onebox', id: 'onebox-token' } } };
|
||||||
|
}
|
||||||
assertEquals(method, 'getGatewayClientDomains');
|
assertEquals(method, 'getGatewayClientDomains');
|
||||||
assertEquals(requestData.gatewayClientId, 'onebox-1');
|
assertEquals(requestData.gatewayClientId, 'onebox-token');
|
||||||
return {
|
return {
|
||||||
domains: [
|
domains: [
|
||||||
{
|
{
|
||||||
@@ -139,6 +140,9 @@ Deno.test('ExternalGatewayManager syncs service routes to dcrouter gatewayClient
|
|||||||
const requests: Array<{ method: string; requestData: Record<string, unknown> }> = [];
|
const requests: Array<{ method: string; requestData: Record<string, unknown> }> = [];
|
||||||
const manager = new ExternalGatewayManager(oneboxRef as any);
|
const manager = new ExternalGatewayManager(oneboxRef as any);
|
||||||
(manager as any).fireDcRouterRequest = async (method: string, requestData: Record<string, unknown>) => {
|
(manager as any).fireDcRouterRequest = async (method: string, requestData: Record<string, unknown>) => {
|
||||||
|
if (method === 'getGatewayClientContext') {
|
||||||
|
return { context: { role: 'gatewayClient', gatewayClient: { type: 'onebox', id: 'onebox-token' } } };
|
||||||
|
}
|
||||||
requests.push({ method, requestData });
|
requests.push({ method, requestData });
|
||||||
if (method === 'exportCertificate') {
|
if (method === 'exportCertificate') {
|
||||||
return { success: false };
|
return { success: false };
|
||||||
@@ -154,7 +158,7 @@ Deno.test('ExternalGatewayManager syncs service routes to dcrouter gatewayClient
|
|||||||
|
|
||||||
assertEquals(ownership, {
|
assertEquals(ownership, {
|
||||||
gatewayClientType: 'onebox',
|
gatewayClientType: 'onebox',
|
||||||
gatewayClientId: 'onebox-1',
|
gatewayClientId: 'onebox-token',
|
||||||
appId: 'hello',
|
appId: 'hello',
|
||||||
hostname: 'hello.example.com',
|
hostname: 'hello.example.com',
|
||||||
});
|
});
|
||||||
@@ -189,6 +193,9 @@ Deno.test('ExternalGatewayManager uses managed dcrouter local target in managed
|
|||||||
let syncRequest: Record<string, unknown> | null = null;
|
let syncRequest: Record<string, unknown> | null = null;
|
||||||
const manager = new ExternalGatewayManager(oneboxRef as any);
|
const manager = new ExternalGatewayManager(oneboxRef as any);
|
||||||
(manager as any).fireDcRouterRequest = async (method: string, requestData: Record<string, unknown>, config: any) => {
|
(manager as any).fireDcRouterRequest = async (method: string, requestData: Record<string, unknown>, config: any) => {
|
||||||
|
if (method === 'getGatewayClientContext') {
|
||||||
|
return { context: { role: 'admin' } };
|
||||||
|
}
|
||||||
if (method === 'exportCertificate') {
|
if (method === 'exportCertificate') {
|
||||||
return { success: false };
|
return { success: false };
|
||||||
}
|
}
|
||||||
@@ -213,6 +220,9 @@ Deno.test('ExternalGatewayManager deletes service routes through dcrouter gatewa
|
|||||||
let deleteRequest: Record<string, unknown> | null = null;
|
let deleteRequest: Record<string, unknown> | null = null;
|
||||||
|
|
||||||
(manager as any).fireDcRouterRequest = async (method: string, requestData: Record<string, unknown>) => {
|
(manager as any).fireDcRouterRequest = async (method: string, requestData: Record<string, unknown>) => {
|
||||||
|
if (method === 'getGatewayClientContext') {
|
||||||
|
return { context: { role: 'gatewayClient', gatewayClient: { type: 'onebox', id: 'onebox-token' } } };
|
||||||
|
}
|
||||||
assertEquals(method, 'syncGatewayClientRoute');
|
assertEquals(method, 'syncGatewayClientRoute');
|
||||||
deleteRequest = requestData;
|
deleteRequest = requestData;
|
||||||
return { success: true, action: 'deleted', routeId: 'route-1' };
|
return { success: true, action: 'deleted', routeId: 'route-1' };
|
||||||
@@ -227,7 +237,7 @@ Deno.test('ExternalGatewayManager deletes service routes through dcrouter gatewa
|
|||||||
assert(deleteRequest);
|
assert(deleteRequest);
|
||||||
const capturedDeleteRequest = deleteRequest as Record<string, unknown>;
|
const capturedDeleteRequest = deleteRequest as Record<string, unknown>;
|
||||||
assertEquals(capturedDeleteRequest.delete, true);
|
assertEquals(capturedDeleteRequest.delete, true);
|
||||||
assertEquals((capturedDeleteRequest.ownership as any).gatewayClientId, 'onebox-1');
|
assertEquals((capturedDeleteRequest.ownership as any).gatewayClientId, 'onebox-token');
|
||||||
assertEquals((capturedDeleteRequest.ownership as any).hostname, 'hello.example.com');
|
assertEquals((capturedDeleteRequest.ownership as any).hostname, 'hello.example.com');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -235,6 +245,9 @@ Deno.test('ExternalGatewayManager imports exported dcrouter certificates into On
|
|||||||
const oneboxRef = makeOneboxRef();
|
const oneboxRef = makeOneboxRef();
|
||||||
const manager = new ExternalGatewayManager(oneboxRef as any);
|
const manager = new ExternalGatewayManager(oneboxRef as any);
|
||||||
(manager as any).fireDcRouterRequest = async (method: string, requestData: Record<string, unknown>) => {
|
(manager as any).fireDcRouterRequest = async (method: string, requestData: Record<string, unknown>) => {
|
||||||
|
if (method === 'getGatewayClientContext') {
|
||||||
|
return { context: { role: 'gatewayClient', gatewayClient: { type: 'onebox', id: 'onebox-token' } } };
|
||||||
|
}
|
||||||
assertEquals(method, 'exportCertificate');
|
assertEquals(method, 'exportCertificate');
|
||||||
assertEquals(requestData.domain, 'hello.example.com');
|
assertEquals(requestData.domain, 'hello.example.com');
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/onebox',
|
name: '@serve.zone/onebox',
|
||||||
version: '1.26.0',
|
version: '1.26.1',
|
||||||
description: 'Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers'
|
description: 'Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,24 @@ type TWorkHosterType = 'onebox';
|
|||||||
interface IExternalGatewayConfig {
|
interface IExternalGatewayConfig {
|
||||||
url: string;
|
url: string;
|
||||||
apiToken: string;
|
apiToken: string;
|
||||||
gatewayClientId: string;
|
gatewayClientType?: TWorkHosterType;
|
||||||
|
gatewayClientId?: string;
|
||||||
/** @deprecated Use gatewayClientId. */
|
/** @deprecated Use gatewayClientId. */
|
||||||
workHosterId: string;
|
workHosterId?: string;
|
||||||
targetHost?: string;
|
targetHost?: string;
|
||||||
targetPort?: number;
|
targetPort?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IGatewayClientContextResponse {
|
||||||
|
context: {
|
||||||
|
role: 'admin' | 'gatewayClient' | 'operator';
|
||||||
|
gatewayClient?: {
|
||||||
|
type: 'onebox' | 'cloudly' | 'custom';
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface IWorkHosterDomain {
|
interface IWorkHosterDomain {
|
||||||
id?: string;
|
id?: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -62,8 +73,8 @@ interface IWorkAppRouteOwnership {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface IGatewayClientOwnership {
|
interface IGatewayClientOwnership {
|
||||||
gatewayClientType: TWorkHosterType;
|
gatewayClientType?: TWorkHosterType;
|
||||||
gatewayClientId: string;
|
gatewayClientId?: string;
|
||||||
appId: string;
|
appId: string;
|
||||||
hostname: string;
|
hostname: string;
|
||||||
}
|
}
|
||||||
@@ -128,8 +139,14 @@ export class ExternalGatewayManager {
|
|||||||
if (this.getMode() === 'disabled') {
|
if (this.getMode() === 'disabled') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const config = await this.getConfig({ requireTarget: false });
|
const mode = this.getMode();
|
||||||
return Boolean(config);
|
const url = mode === 'managed'
|
||||||
|
? this.oneboxRef.managedDcRouter.getGatewayUrl()
|
||||||
|
: this.normalizeUrl(this.database.getSetting('dcrouterGatewayUrl') || '');
|
||||||
|
const apiToken = mode === 'managed'
|
||||||
|
? await this.oneboxRef.managedDcRouter.getAdminToken()
|
||||||
|
: await this.database.getSecretSetting('dcrouterGatewayApiToken');
|
||||||
|
return Boolean(url && apiToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async syncDomains(): Promise<IDomain[]> {
|
public async syncDomains(): Promise<IDomain[]> {
|
||||||
@@ -188,7 +205,7 @@ export class ExternalGatewayManager {
|
|||||||
try {
|
try {
|
||||||
const response = await this.fireDcRouterRequest<{ domains: IWorkHosterDomain[] }>(
|
const response = await this.fireDcRouterRequest<{ domains: IWorkHosterDomain[] }>(
|
||||||
'getGatewayClientDomains',
|
'getGatewayClientDomains',
|
||||||
{ gatewayClientId: config.gatewayClientId },
|
config.gatewayClientId ? { gatewayClientId: config.gatewayClientId } : {},
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
return response.domains.map((domain) => ({
|
return response.domains.map((domain) => ({
|
||||||
@@ -216,7 +233,7 @@ export class ExternalGatewayManager {
|
|||||||
try {
|
try {
|
||||||
const response = await this.fireDcRouterRequest<{ records: IGatewayDnsRecord[] }>(
|
const response = await this.fireDcRouterRequest<{ records: IGatewayDnsRecord[] }>(
|
||||||
'getGatewayClientDnsRecords',
|
'getGatewayClientDnsRecords',
|
||||||
{ gatewayClientId: config.gatewayClientId },
|
config.gatewayClientId ? { gatewayClientId: config.gatewayClientId } : {},
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
return response.records.map((record) => ({
|
return response.records.map((record) => ({
|
||||||
@@ -355,16 +372,27 @@ export class ExternalGatewayManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gatewayClientId = mode === 'managed'
|
|
||||||
? this.oneboxRef.managedDcRouter.ensureGatewayClientId()
|
|
||||||
: this.ensureGatewayClientId();
|
|
||||||
const config: IExternalGatewayConfig = {
|
const config: IExternalGatewayConfig = {
|
||||||
url,
|
url,
|
||||||
apiToken,
|
apiToken,
|
||||||
gatewayClientId,
|
|
||||||
workHosterId: gatewayClientId,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const contextClient = await this.getGatewayClientFromToken(config);
|
||||||
|
if (contextClient) {
|
||||||
|
config.gatewayClientType = contextClient.type;
|
||||||
|
config.gatewayClientId = contextClient.id;
|
||||||
|
config.workHosterId = contextClient.id;
|
||||||
|
} else {
|
||||||
|
const fallbackGatewayClientId = mode === 'managed'
|
||||||
|
? this.oneboxRef.managedDcRouter.ensureGatewayClientId()
|
||||||
|
: this.getStoredGatewayClientId();
|
||||||
|
if (fallbackGatewayClientId) {
|
||||||
|
config.gatewayClientType = 'onebox';
|
||||||
|
config.gatewayClientId = fallbackGatewayClientId;
|
||||||
|
config.workHosterId = fallbackGatewayClientId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (options.requireTarget !== false) {
|
if (options.requireTarget !== false) {
|
||||||
if (mode === 'managed') {
|
if (mode === 'managed') {
|
||||||
const target = this.oneboxRef.managedDcRouter.getRouteTarget();
|
const target = this.oneboxRef.managedDcRouter.getRouteTarget();
|
||||||
@@ -417,13 +445,27 @@ export class ExternalGatewayManager {
|
|||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ensureGatewayClientId(): string {
|
private getStoredGatewayClientId(): string {
|
||||||
let gatewayClientId = this.database.getSetting('dcrouterGatewayClientId') || this.database.getSetting('dcrouterWorkHosterId');
|
return this.database.getSetting('dcrouterGatewayClientId') || this.database.getSetting('dcrouterWorkHosterId') || '';
|
||||||
if (!gatewayClientId) {
|
}
|
||||||
gatewayClientId = crypto.randomUUID();
|
|
||||||
this.database.setSetting('dcrouterGatewayClientId', gatewayClientId);
|
private async getGatewayClientFromToken(config: IExternalGatewayConfig): Promise<{ type: TWorkHosterType; id: string } | null> {
|
||||||
|
try {
|
||||||
|
const response = await this.fireDcRouterRequest<IGatewayClientContextResponse>(
|
||||||
|
'getGatewayClientContext',
|
||||||
|
{},
|
||||||
|
config,
|
||||||
|
);
|
||||||
|
const gatewayClient = response.context.gatewayClient;
|
||||||
|
if (!gatewayClient) return null;
|
||||||
|
if (gatewayClient.type !== 'onebox') {
|
||||||
|
throw new Error(`dcrouter token is bound to unsupported gateway client type: ${gatewayClient.type}`);
|
||||||
|
}
|
||||||
|
return { type: gatewayClient.type, id: gatewayClient.id };
|
||||||
|
} catch (error) {
|
||||||
|
logger.debug(`dcrouter gateway client context unavailable: ${getErrorMessage(error)}`);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return gatewayClientId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildOwnership(
|
private buildOwnership(
|
||||||
@@ -433,7 +475,7 @@ export class ExternalGatewayManager {
|
|||||||
): IWorkAppRouteOwnership {
|
): IWorkAppRouteOwnership {
|
||||||
return {
|
return {
|
||||||
workHosterType: 'onebox',
|
workHosterType: 'onebox',
|
||||||
workHosterId: config.gatewayClientId,
|
workHosterId: config.gatewayClientId || '',
|
||||||
workAppId: service.name || `service-${service.id}`,
|
workAppId: service.name || `service-${service.id}`,
|
||||||
hostname,
|
hostname,
|
||||||
};
|
};
|
||||||
@@ -444,12 +486,15 @@ export class ExternalGatewayManager {
|
|||||||
hostname: string,
|
hostname: string,
|
||||||
config: IExternalGatewayConfig,
|
config: IExternalGatewayConfig,
|
||||||
): IGatewayClientOwnership {
|
): IGatewayClientOwnership {
|
||||||
return {
|
const ownership: IGatewayClientOwnership = {
|
||||||
gatewayClientType: 'onebox',
|
gatewayClientType: config.gatewayClientType || 'onebox',
|
||||||
gatewayClientId: config.gatewayClientId,
|
|
||||||
appId: service.name || `service-${service.id}`,
|
appId: service.name || `service-${service.id}`,
|
||||||
hostname,
|
hostname,
|
||||||
};
|
};
|
||||||
|
if (config.gatewayClientId) {
|
||||||
|
ownership.gatewayClientId = config.gatewayClientId;
|
||||||
|
}
|
||||||
|
return ownership;
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildRoute(service: IService, config: IExternalGatewayConfig): IDcRouterRouteConfig {
|
private buildRoute(service: IService, config: IExternalGatewayConfig): IDcRouterRouteConfig {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/onebox',
|
name: '@serve.zone/onebox',
|
||||||
version: '1.26.0',
|
version: '1.26.1',
|
||||||
description: 'Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers'
|
description: 'Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,6 +144,32 @@ export class ObViewSettings extends DeesElement {
|
|||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gateway-readonly {
|
||||||
|
padding: 10px 12px;
|
||||||
|
border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')};
|
||||||
|
border-radius: 8px;
|
||||||
|
background: ${cssManager.bdTheme('#fafafa', '#18181b')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.gateway-readonly-label {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: ${cssManager.bdTheme('#52525b', '#d4d4d8')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.gateway-readonly-value {
|
||||||
|
margin-top: 4px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: ${cssManager.bdTheme('#18181b', '#fafafa')};
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gateway-readonly-hint {
|
||||||
|
margin-top: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||||
|
}
|
||||||
|
|
||||||
dees-input-text {
|
dees-input-text {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@@ -240,11 +266,11 @@ export class ObViewSettings extends DeesElement {
|
|||||||
${this.renderGatewayInput('dcrouterManagedOpsPort', 'Local Ops Port', String(settings?.dcrouterManagedOpsPort || 3300), 'Bound to 127.0.0.1 for Onebox to call dcrouter APIs.')}
|
${this.renderGatewayInput('dcrouterManagedOpsPort', 'Local Ops Port', String(settings?.dcrouterManagedOpsPort || 3300), 'Bound to 127.0.0.1 for Onebox to call dcrouter APIs.')}
|
||||||
${this.renderGatewayInput('dcrouterManagedHttpPort', 'Public HTTP Port', String(settings?.dcrouterManagedHttpPort || 80), 'Host port owned by dcrouter for HTTP ingress.')}
|
${this.renderGatewayInput('dcrouterManagedHttpPort', 'Public HTTP Port', String(settings?.dcrouterManagedHttpPort || 80), 'Host port owned by dcrouter for HTTP ingress.')}
|
||||||
${this.renderGatewayInput('dcrouterManagedHttpsPort', 'Public HTTPS Port', String(settings?.dcrouterManagedHttpsPort || 443), 'Host port owned by dcrouter for HTTPS ingress.')}
|
${this.renderGatewayInput('dcrouterManagedHttpsPort', 'Public HTTPS Port', String(settings?.dcrouterManagedHttpsPort || 443), 'Host port owned by dcrouter for HTTPS ingress.')}
|
||||||
${this.renderGatewayInput('dcrouterGatewayClientId', 'Gateway Client ID', settings?.dcrouterGatewayClientId || settings?.dcrouterWorkHosterId || '', 'Leave empty to let Onebox create a stable ID.')}
|
${this.renderGatewayReadonly('Gateway Client ID', settings?.dcrouterGatewayClientId || settings?.dcrouterWorkHosterId || 'Created when managed dcrouter starts', 'Diagnostic only. Onebox manages this local client automatically.')}
|
||||||
` : mode === 'external' ? html`
|
` : mode === 'external' ? html`
|
||||||
${this.renderGatewayInput('dcrouterGatewayUrl', 'Gateway URL', settings?.dcrouterGatewayUrl || '', 'Base URL of the dcrouter OpsServer.')}
|
${this.renderGatewayInput('dcrouterGatewayUrl', 'Gateway URL', settings?.dcrouterGatewayUrl || '', 'Base URL of the dcrouter OpsServer.')}
|
||||||
${this.renderGatewayInput('dcrouterGatewayApiToken', 'API Token', settings?.dcrouterGatewayApiToken || '', 'Requires gateway-client access in dcrouter.', true)}
|
${this.renderGatewayInput('dcrouterGatewayApiToken', 'API Token', settings?.dcrouterGatewayApiToken || '', 'Requires gateway-client access in dcrouter.', true)}
|
||||||
${this.renderGatewayInput('dcrouterGatewayClientId', 'Gateway Client ID', settings?.dcrouterGatewayClientId || settings?.dcrouterWorkHosterId || '', 'Leave empty to let Onebox create a stable ID.')}
|
${this.renderGatewayReadonly('Gateway Client ID', settings?.dcrouterGatewayClientId || settings?.dcrouterWorkHosterId || 'Derived from token', 'Configure this in dcrouter Gateway Clients, not in Onebox.')}
|
||||||
${this.renderGatewayInput('dcrouterTargetHost', 'Target Host', settings?.dcrouterTargetHost || '', 'Defaults to the configured server IP when empty.')}
|
${this.renderGatewayInput('dcrouterTargetHost', 'Target Host', settings?.dcrouterTargetHost || '', 'Defaults to the configured server IP when empty.')}
|
||||||
${this.renderGatewayInput('dcrouterTargetPort', 'Target Port', String(settings?.dcrouterTargetPort || 80), 'Internal HTTP port dcrouter forwards to.')}
|
${this.renderGatewayInput('dcrouterTargetPort', 'Target Port', String(settings?.dcrouterTargetPort || 80), 'Internal HTTP port dcrouter forwards to.')}
|
||||||
` : html`
|
` : html`
|
||||||
@@ -316,6 +342,16 @@ export class ObViewSettings extends DeesElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private renderGatewayReadonly(label: string, value: string, hint: string): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="gateway-readonly">
|
||||||
|
<div class="gateway-readonly-label">${label}</div>
|
||||||
|
<div class="gateway-readonly-value">${value}</div>
|
||||||
|
<div class="gateway-readonly-hint">${hint}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
private updateGatewayDraft(
|
private updateGatewayDraft(
|
||||||
key: keyof NonNullable<appstate.ISettingsState['settings']>,
|
key: keyof NonNullable<appstate.ISettingsState['settings']>,
|
||||||
value: string,
|
value: string,
|
||||||
@@ -351,7 +387,6 @@ export class ObViewSettings extends DeesElement {
|
|||||||
dcrouterManagedDataDir: settings.dcrouterManagedDataDir || './.nogit/dcrouter-data',
|
dcrouterManagedDataDir: settings.dcrouterManagedDataDir || './.nogit/dcrouter-data',
|
||||||
dcrouterGatewayUrl: settings.dcrouterGatewayUrl || '',
|
dcrouterGatewayUrl: settings.dcrouterGatewayUrl || '',
|
||||||
dcrouterGatewayApiToken: settings.dcrouterGatewayApiToken || '',
|
dcrouterGatewayApiToken: settings.dcrouterGatewayApiToken || '',
|
||||||
dcrouterGatewayClientId: settings.dcrouterGatewayClientId || settings.dcrouterWorkHosterId || '',
|
|
||||||
dcrouterTargetHost: settings.dcrouterTargetHost || '',
|
dcrouterTargetHost: settings.dcrouterTargetHost || '',
|
||||||
dcrouterTargetPort: Number(settings.dcrouterTargetPort) || 80,
|
dcrouterTargetPort: Number(settings.dcrouterTargetPort) || 80,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user