diff --git a/src/app/elements/iframe/iframe.component.ts b/src/app/elements/iframe/iframe.component.ts index 84db00ab..97d8244e 100644 --- a/src/app/elements/iframe/iframe.component.ts +++ b/src/app/elements/iframe/iframe.component.ts @@ -5,6 +5,8 @@ import {MatDialog} from '@angular/material'; import {Subject} from 'rxjs'; import {debounceTime} from 'rxjs/operators'; import {environment} from '@src/environments/environment'; +import {SafeResourceUrl} from '@angular/platform-browser'; +import {DomSanitizer} from '@angular/platform-browser'; @Component({ selector: 'elements-iframe', @@ -25,6 +27,8 @@ export class ElementIframeComponent implements OnInit, AfterViewInit, OnDestroy showValue: boolean = !window['debugIframe']; ping: number; debug = false; + trustedUrl: SafeResourceUrl; + termComp: any = {}; constructor( private _i18n: I18nService, @@ -33,9 +37,9 @@ export class ElementIframeComponent implements OnInit, AfterViewInit, OnDestroy private _http: HttpService, private _dialog: MatDialog, public viewSrv: ViewService, + private sanitizer: DomSanitizer ) { } - ngOnInit() { this._logger.info(`IFrame URL: ${this.src}`); @@ -65,7 +69,9 @@ export class ElementIframeComponent implements OnInit, AfterViewInit, OnDestroy setTimeout(() => { this.showIframe = this.showValue; }); - this.view.termComp = this; + if (this.view) { + this.view.termComp = this; + } clearInterval(this.ping); break; case 'CLOSE': @@ -89,6 +95,10 @@ export class ElementIframeComponent implements OnInit, AfterViewInit, OnDestroy break; } }.bind(this); + + this.trustedUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.src); + + window.addEventListener('message', this.messageHandler); } ngAfterViewInit() { @@ -106,6 +116,7 @@ export class ElementIframeComponent implements OnInit, AfterViewInit, OnDestroy ngOnDestroy() { window.removeEventListener('message', this.eventHandler); + window.removeEventListener('message', this.messageHandler); } setActive() { @@ -132,6 +143,12 @@ export class ElementIframeComponent implements OnInit, AfterViewInit, OnDestroy this.iframeWindow.postMessage({name: 'CMD', data: data.data}, '*'); } + messageHandler = (event: MessageEvent) => { + if (event.data && typeof event.data === 'object') { + this.termComp = event.data; + } + }; + async reconnect() { const oldConnectToken = this.view.connectToken; const newConnectToken = await this._connectTokenSvc.exchange(oldConnectToken); diff --git a/src/app/pages/pam/pam.component.scss b/src/app/pages/pam/pam.component.scss index f3d145bd..bf76655a 100644 --- a/src/app/pages/pam/pam.component.scss +++ b/src/app/pages/pam/pam.component.scss @@ -1,7 +1,7 @@ @mixin time-container { position: fixed; - bottom: 40px; - right: 40px; + bottom: 55px; + right: 45px; z-index: 999999; .timer { diff --git a/src/app/pages/pam/pam.component.ts b/src/app/pages/pam/pam.component.ts index 5c367f20..68183fc2 100644 --- a/src/app/pages/pam/pam.component.ts +++ b/src/app/pages/pam/pam.component.ts @@ -57,86 +57,40 @@ export class PagePamComponent implements OnInit, OnDestroy { this.assetName = params["assetName"]; this.protocol = params["protocol"]; - this._http.directiveConnect(this.assetId).subscribe((res) => { - if (res) { - let method: string = ""; - - const currentUserInfo = res.accounts.find( - (item: Account) => item.id === this.userId - ); - - switch (this.protocol) { - case "ssh": - case "telnet": - method = "web_cli"; - break; - case "rdp": - method = "web_gui"; - break; - case "sftp": - method = "web_sftp"; - break; - case "vnc": - method = "web_gui"; - break; - default: - method = "web_cli"; - } - - const assetMessage = { - id: this.assetId, - name: this.assetName, - address: res.address, - comment: res.comment, - type: res.type, - category: res.category, - permed_protocols: res.protocols, - permed_accounts: res.accounts, - spec_info: res.spec_info, - }; - const connectData = { - method, - protocol: this.protocol, - asset: assetMessage, - account: currentUserInfo, - input_username: this.username, - }; - - this._http - .adminConnectToken(assetMessage, connectData) - .subscribe((res) => { - if (res) { - const url = this.getUrl(); - - switch (this.protocol) { - case "ssh": { - this.iframeTerminalURL = `${url}/koko/connect?token=${res.id}`; - break; - } - case "sftp": { - this.iframeSFTPURL = `${url}/koko/elfinder/sftp/`; - break; - } - case "rdp": { - this.iframeRDPURL = `${url}/lion/connect?token=${res.id}`; - break; - } - case "vnc": { - this.iframeVNCURL = `${url}/lion/connect?token=${res.id}`; - break; - } - case "telnet": { - this.iframeTerminalURL = `${url}/koko/connect?token=${res.id}`; - break; - } - default: { - break; - } - } - } - }); - } - }); + try { + const res = await this._http.directiveConnect(this.assetId).toPromise(); + if (!res) return; + + const currentUserInfo = res.accounts.find( + (item: Account) => item.id === this.userId + ); + + const method = this.getMethodByProtocol(this.protocol); + + const assetMessage = { + id: this.assetId, + name: this.assetName, + address: res.address, + comment: res.comment, + type: res.type, + category: res.category, + permed_protocols: res.protocols, + permed_accounts: res.accounts, + spec_info: res.spec_info, + }; + + const connectData = { + method, + protocol: this.protocol, + asset: assetMessage, + account: currentUserInfo, + input_username: this.username, + }; + + await this.getConnectToken(assetMessage, connectData); + } catch (error) { + this._logger.error("Failed to connect:", error); + } }); this.startTimer(); @@ -207,6 +161,7 @@ export class PagePamComponent implements OnInit, OnDestroy { switch (this.protocol) { case "ssh": + case "k8s": case "sftp": case "telnet": port = "9530"; @@ -272,4 +227,69 @@ export class PagePamComponent implements OnInit, OnDestroy { private closeDrawer(): void { this.sidenav.close(); } + + /** + * 获取连接令牌 + * @param assetMessage + * @param connectData + */ + private async getConnectToken(assetMessage: any, connectData: any) { + try { + const firstRes = await this._http + .adminConnectToken(assetMessage, connectData) + .toPromise(); + if (!firstRes) return; + + const url = this.getUrl(); + + // 只有 SSH 协议需要第二个 token 用于 SFTP + if (this.protocol === "ssh") { + const secondRes = await this._http + .adminConnectToken(assetMessage, connectData) + .toPromise(); + this.iframeTerminalURL = `${url}/koko/connect?token=${firstRes.id}&sftp=${secondRes.id}`; + return; + } + + switch (this.protocol) { + case "k8s": + this.iframeTerminalURL = `${url}/koko/k8s/?token=${firstRes.id}`; + break; + case "sftp": + this.iframeSFTPURL = `${url}/koko/elfinder/sftp/`; + break; + case "rdp": + this.iframeRDPURL = `${url}/lion/connect?token=${firstRes.id}`; + break; + case "vnc": + this.iframeVNCURL = `${url}/lion/connect?token=${firstRes.id}`; + break; + case "telnet": + this.iframeTerminalURL = `${url}/koko/connect?token=${firstRes.id}`; + break; + } + } catch (error) { + this._logger.error("Failed to get connect token:", error); + } + } + + /** + * 根据协议确定连接方法 + * @param protocol + * @returns + */ + private getMethodByProtocol(protocol: string): string { + switch (protocol) { + case "ssh": + case "telnet": + return "web_cli"; + case "rdp": + case "vnc": + return "web_gui"; + case "sftp": + return "web_sftp"; + default: + return "web_cli"; + } + } }