Skip to content

Commit

Permalink
Merge branch '2.2' into master-3.0
Browse files Browse the repository at this point in the history
# Conflicts:
#	package.json
#	src/app/app.module.ts
#	src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.ts
#	src/app/components/project-map/packet-capturing/start-capture/start-capture.component.spec.ts
#	src/app/components/project-map/project-map.component.ts
#	src/app/services/packet-capture.service.ts
#	yarn.lock
  • Loading branch information
grossmj committed May 15, 2024
2 parents eb82af9 + f94d592 commit 3880d28
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 51 deletions.
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.
import { MATERIAL_IMPORTS } from './material.imports';
import { ControllerResolve } from './resolvers/controller-resolve';
import { ApplianceService } from './services/appliances.service';
import { ProtocolHandlerService } from './services/protocol-handler.service';
import { BuiltInTemplatesConfigurationService } from './services/built-in-templates-configuration.service';
import { BuiltInTemplatesService } from './services/built-in-templates.service';
import { ComputeService } from './services/compute.service';
Expand Down Expand Up @@ -651,6 +652,7 @@ import { DeleteResourceConfirmationDialogComponent } from './components/resource
InfoService,
ComputeService,
PacketCaptureService,
ProtocolHandlerService,
NotificationService,
ThemeService,
GoogleAnalyticsService,
Expand Down
1 change: 1 addition & 0 deletions src/app/cartography/models/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export class Properties {
headless: boolean;
linked_clone: boolean;
on_close: string;
aux: number;
ram: number;
nvram: number;
usage: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,11 @@
<mat-icon>web_asset</mat-icon>
<span>Console</span>
</button>
<button
mat-menu-item
*ngIf="node.node_type === 'docker' || node.node_type === 'dynamips'"
(click)="openConsole(auxiliary=true)"
>
<mat-icon>web_asset</mat-icon>
<span>Auxiliary console</span>
</button>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Node } from '../../../../../cartography/models/node';
import { Controller } from '../../../../../models/controller';
import { NodeService } from '../../../../../services/node.service';
import { ToasterService } from '../../../../../services/toaster.service';
import { ProtocolHandlerService } from '../../../../../services/protocol-handler.service';

import * as ipaddr from 'ipaddr.js';

@Component({
Expand All @@ -17,43 +19,18 @@ export class ConsoleDeviceActionBrowserComponent {
constructor(
private toasterService: ToasterService,
private nodeService: NodeService,
private deviceService: DeviceDetectorService
private deviceService: DeviceDetectorService,
private protocolHandlerService: ProtocolHandlerService
) {}

openConsole() {
openConsole(auxiliary: boolean = false) {
this.nodeService.getNode(this.controller, this.node).subscribe((node: Node) => {
this.node = node;
this.startConsole();
this.startConsole(auxiliary);
});
}

createHiddenIframe(target: Element, uri: string) {
const iframe = document.createElement("iframe");
iframe.src = uri;
iframe.id = "hiddenIframe";
iframe.style.display = "none";
target.appendChild(iframe);
return iframe;
}

openUriUsingFirefox(uri: string) {
var iframe = (document.querySelector("#hiddenIframe") as HTMLIFrameElement);

if (!iframe) {
iframe = this.createHiddenIframe(document.body, "about:blank");
//setTimeout(() => { iframe.parentNode.removeChild(iframe); }, 0);
}

try {
iframe.contentWindow.location.href = uri;
} catch (e) {
if (e.name === "NS_ERROR_UNKNOWN_PROTOCOL") {
this.toasterService.error('Protocol handler does not exist');
}
}
}

startConsole() {
startConsole(auxiliary: boolean) {
if (this.node.status !== 'started') {
this.toasterService.error('This node must be started before a console can be opened');
} else {
Expand All @@ -65,16 +42,25 @@ export class ConsoleDeviceActionBrowserComponent {
this.node.console_host = this.controller.host;
}

const device = this.deviceService.getDeviceInfo();

try {
var uri;
var host = this.node.console_host;
if (ipaddr.IPv6.isValid(host)) {
host = `[${host}]`;
}
if (this.node.console_type === 'telnet') {
uri = `gns3+telnet://${host}:${this.node.console}?name=${this.node.name}&project_id=${this.node.project_id}&node_id=${this.node.node_id}`;

var console_port;
if (auxiliary === true) {
console_port = this.node.properties.aux;
if (console_port === undefined) {
this.toasterService.error('Auxiliary console port is not set.');
return;
}
} else {
console_port = this.node.console;
}
uri = `gns3+telnet://${host}:${console_port}?name=${this.node.name}&project_id=${this.node.project_id}&node_id=${this.node.node_id}`;
} else if (this.node.console_type === 'vnc') {
uri = `gns3+vnc://${host}:${this.node.console}?name=${this.node.name}&project_id=${this.node.project_id}&node_id=${this.node.node_id}`;
} else if (this.node.console_type.startsWith('spice')) {
Expand All @@ -84,16 +70,10 @@ export class ConsoleDeviceActionBrowserComponent {
return window.open(uri); // open an http console directly in a new window/tab
} else {
this.toasterService.error('Supported console types are: telnet, vnc, spice and spice+agent.');
return;
}

console.log("Opening external console using " + device.browser + " browser");
if (device.browser === "Firefox") {
// Use a hidden iframe otherwise Firefox will disconnect
// from the GNS3 controller websocket if we use location.assign()
this.openUriUsingFirefox(uri);
} else {
location.assign(uri);
}
this.protocolHandlerService.open(uri);

} catch (e) {
this.toasterService.error(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { MatMenuModule } from '@angular/material/menu';
import { BrowserModule } from '@angular/platform-browser';
import { RouterTestingModule } from '@angular/router/testing';
import { ToasterService } from '../../../services/toaster.service';
import { ProtocolHandlerService } from '../../../services/protocol-handler.service';
import { of } from 'rxjs';
import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource';
import { ProjectWebServiceHandler, WebServiceMessage } from '../../../handlers/project-web-service-handler';
Expand Down Expand Up @@ -38,6 +39,7 @@ describe('LogConsoleComponent', () => {
let nodeConsoleService: NodeConsoleService;
let mapSettingsService: MapSettingsService;
let toasterService: ToasterService;
let protocolHandlerService: ProtocolHandlerService;

let httpController = new HttpController({} as HttpClient, {} as ControllerErrorHandler);

Expand All @@ -52,13 +54,15 @@ describe('LogConsoleComponent', () => {
{ provide: HttpController, useValue: httpController },
NodeConsoleService,
ToasterService,
ProtocolHandlerService,
MapSettingsService
],
declarations: [LogConsoleComponent],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();

toasterService = TestBed.inject(ToasterService);
protocolHandlerService = TestBed.inject(ProtocolHandlerService);
mapSettingsService = TestBed.inject(MapSettingsService);
nodeConsoleService = TestBed.inject(NodeConsoleService);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import{ Controller } from '../../../models/controller';
import { HttpController } from '../../../services/http-controller.service';
import { NodeService } from '../../../services/node.service';
import { NodeConsoleService } from '../../../services/nodeConsole.service';
import { ProtocolHandlerService } from '../../../services/protocol-handler.service';
import { ThemeService } from '../../../services/theme.service';
import { version } from '../../../version';
import { LogEventsDataSource } from './log-events-datasource';
Expand Down Expand Up @@ -70,6 +71,7 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy {
private projectWebServiceHandler: ProjectWebServiceHandler,
private nodeService: NodeService,
private nodesDataSource: NodesDataSource,
private protocolHandlerService: ProtocolHandlerService,
private logEventsDataSource: LogEventsDataSource,
private httpService: HttpController,
private themeService: ThemeService,
Expand Down Expand Up @@ -230,15 +232,15 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy {
host = `[${host}]`;
}
if (node.console_type === 'telnet') {
location.assign(
this.protocolHandlerService.open(
`gns3+telnet://${host}:${node.console}?name=${node.name}&project_id=${node.project_id}&node_id=${node.node_id}`
);
} else if (node.console_type === 'vnc') {
location.assign(
this.protocolHandlerService.open(
`gns3+vnc://${host}:${node.console}?name=${node.name}&project_id=${node.project_id}&node_id=${node.node_id}`
);
} else if (node.console_type.startsWith('spice')) {
location.assign(
this.protocolHandlerService.open(
`gns3+spice://${host}:${node.console}?name=${node.name}&project_id=${node.project_id}&node_id=${node.node_id}`
);
} else if (node.console_type.startsWith('http')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ToasterService } from '../../../../services/toaster.service';
import { MockedToasterService } from '../../../../services/toaster.service.spec';
import { MockedLinkService, MockedNodesDataSource } from '../../project-map.component.spec';
import { StartCaptureDialogComponent } from './start-capture.component';
import { ProtocolHandlerService } from '../../../../services/protocol-handler.service';

describe('StartCaptureDialogComponent', () => {
let component: StartCaptureDialogComponent;
Expand All @@ -25,6 +26,8 @@ describe('StartCaptureDialogComponent', () => {
let mockedToasterService = new MockedToasterService();
let mockedLinkService = new MockedLinkService();
let mockedNodesDataSource = new MockedNodesDataSource();
let protocolHandlerService: ProtocolHandlerService;

let dialogRef = {
close: jasmine.createSpy('close'),
};
Expand All @@ -49,11 +52,14 @@ describe('StartCaptureDialogComponent', () => {
{ provide: LinkService, useValue: mockedLinkService },
{ provide: NodesDataSource, useValue: mockedNodesDataSource },
{ provide: PacketCaptureService },
ProtocolHandlerService,
],
declarations: [StartCaptureDialogComponent],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});

protocolHandlerService = TestBed.inject(ProtocolHandlerService);
}));

beforeEach(() => {
fixture = TestBed.createComponent(StartCaptureDialogComponent);
Expand Down
15 changes: 9 additions & 6 deletions src/app/services/packet-capture.service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { Injectable } from '@angular/core';
import { Link } from '../models/link';
import { Project } from '../models/project';
import{ Controller } from '../models/controller';
import { Controller } from '../models/controller';
import { ProtocolHandlerService } from './protocol-handler.service';

@Injectable()
export class PacketCaptureService {
constructor() {}

startCapture(controller:Controller , project: Project, link: Link, name: string) {
location.assign(
`gns3+pcap://${controller.host}:${controller.port}?protocol=${controller.protocol.slice(0, -1)}&project_id=${project.project_id}&link_id=${link.link_id}&project=${project.name}&name=${name}`
);
constructor(private protocolHandlerService: ProtocolHandlerService) {}

startCapture(controller: Controller, project: Project, link: Link, name: string) {

const uri = `gns3+pcap://${controller.host}:${controller.port}?protocol=${controller.protocol.slice(0, -1)}&project_id=${project.project_id}&link_id=${link.link_id}&project=${project.name}&name=${name}`;
this.protocolHandlerService.open(uri);

}
}
48 changes: 48 additions & 0 deletions src/app/services/protocol-handler.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Injectable } from '@angular/core';
import { DeviceDetectorService } from 'ngx-device-detector';
import { ToasterService } from './toaster.service';

@Injectable()
export class ProtocolHandlerService {

constructor(private toasterService: ToasterService, private deviceService: DeviceDetectorService) {}

createHiddenIframe(target: Element, uri: string) {
const iframe = document.createElement("iframe");
iframe.src = uri;
iframe.id = "hiddenIframe";
iframe.style.display = "none";
target.appendChild(iframe);
return iframe;
}

openUriUsingFirefox(uri: string) {
var iframe = (document.querySelector("#hiddenIframe") as HTMLIFrameElement);

if (!iframe) {
iframe = this.createHiddenIframe(document.body, "about:blank");
}

try {
iframe.contentWindow.location.href = uri;
} catch (e) {
if (e.name === "NS_ERROR_UNKNOWN_PROTOCOL") {
this.toasterService.error('Protocol handler does not exist');
}
}
}

open(uri: string) {

const device = this.deviceService.getDeviceInfo();

console.log("Launching external protocol handler with " + device.browser + ": " + uri)
if (device.browser === "Firefox") {
// Use a hidden iframe otherwise Firefox will disconnect
// from the GNS3 controller websocket if we use location.assign()
this.openUriUsingFirefox(uri);
} else {
location.assign(uri);
}
}
}

0 comments on commit 3880d28

Please sign in to comment.