Merge branch 'hcpx'
commit
eb454857c9
|
@ -0,0 +1,13 @@
|
|||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
|
@ -0,0 +1,46 @@
|
|||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
# Only exists if Bazel was run
|
||||
/bazel-out
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# profiling files
|
||||
chrome-profiler-events*.json
|
||||
speed-measure-plugin*.json
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"hcxdumptool": {
|
||||
"projectType": "library",
|
||||
"root": "projects/hcxdumptool",
|
||||
"sourceRoot": "projects/hcxdumptool/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"options": {
|
||||
"tsConfig": "projects/hcxdumptool/tsconfig.lib.json",
|
||||
"project": "projects/hcxdumptool/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "projects/hcxdumptool/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "projects/hcxdumptool/src/test.ts",
|
||||
"tsConfig": "projects/hcxdumptool/tsconfig.spec.json",
|
||||
"karmaConfig": "projects/hcxdumptool/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"projects/hcxdumptool/tsconfig.lib.json",
|
||||
"projects/hcxdumptool/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}},
|
||||
"defaultProject": "hcxdumptool"
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
#!/bin/bash
|
||||
|
||||
MODULENAME=$(basename $PWD)
|
||||
|
||||
check_workspace() {
|
||||
if [[ ! -d "node_modules" ]]; then
|
||||
while true; do
|
||||
read -p "[!!] The Angular workspace has not been prepared. Would you like to do it now? [Y\n] " yn
|
||||
case $yn in
|
||||
[Yy]* ) prepare_workspace; break;;
|
||||
[Nn]* ) exit 1;;
|
||||
* ) prepare_workspace; break;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_workspace() {
|
||||
echo "[*] Preparing the Angular workspace."
|
||||
|
||||
if ! command -v npm &> /dev/null; then
|
||||
echo "[!] NPM does not appear to be installed on this system. Failed to create workspace."
|
||||
return
|
||||
fi
|
||||
|
||||
if ! npm install &> /dev/null; then
|
||||
echo "[!] Failed to prepare workspace. Run npm install to see why."
|
||||
return
|
||||
fi
|
||||
|
||||
echo "[*] Prepared the Angular workspace successfully."
|
||||
}
|
||||
|
||||
build_module() {
|
||||
ng build --prod > /dev/null 2>&1
|
||||
RET=$?
|
||||
|
||||
if [[ $RET -ne 0 ]]; then
|
||||
echo "[!] Angular Build Failed: Run 'ng build --prod' to figure out why."
|
||||
exit 1
|
||||
else
|
||||
echo "[*] Angular Build Succeeded"
|
||||
fi
|
||||
|
||||
# Step 2: Copy the required files to the build output
|
||||
cp -r projects/$MODULENAME/src/module.svg dist/$MODULENAME/bundles/
|
||||
cp -r projects/$MODULENAME/src/module.json dist/$MODULENAME/bundles/
|
||||
cp -r projects/$MODULENAME/src/module.py dist/$MODULENAME/bundles/ > /dev/null 2>&1
|
||||
cp -r projects/$MODULENAME/src/module.php dist/$MODULENAME/bundles/ > /dev/null 2>&1
|
||||
cp -r projects/$MODULENAME/src/assets/ dist/$MODULENAME/bundles/ > /dev/null 2>&1
|
||||
|
||||
# Step 3: Clean up
|
||||
rm -rf dist/$MODULENAME/bundles/*.map
|
||||
rm -rf dist/$MODULENAME/bundles/*.min*
|
||||
rm -rf bundletmp
|
||||
mv dist/$MODULENAME/bundles/ bundletmp
|
||||
rm -rf dist/$MODULENAME/*
|
||||
mv bundletmp/* dist/$MODULENAME/
|
||||
rm -rf bundletmp
|
||||
}
|
||||
|
||||
package() {
|
||||
VERS=$(cat dist/$MODULENAME/module.json | grep "version" | awk '{split($0, a, ": "); gsub("\"", "", a[2]); gsub(",", "", a[2]); print a[2]}')
|
||||
rm -rf $MODULENAME-$VERS.tar.gz
|
||||
echo "[*] Packaging $MODULENAME (Version $VERS)"
|
||||
cd dist/
|
||||
tar -pczf $MODULENAME-$VERS.tar.gz $MODULENAME
|
||||
mv $MODULENAME-$VERS.tar.gz ../
|
||||
cd ../
|
||||
}
|
||||
|
||||
copy_to_device() {
|
||||
echo "[*] Copying module to WiFi Pineapple via SCP"
|
||||
scp -r dist/$MODULENAME root@172.16.42.1:/pineapple/modules
|
||||
}
|
||||
|
||||
main() {
|
||||
check_workspace
|
||||
build_module
|
||||
|
||||
if [[ $1 == "package" ]]; then
|
||||
package
|
||||
elif [[ $1 == "copy" ]]; then
|
||||
copy_to_device
|
||||
fi
|
||||
|
||||
echo "[*] Success!"
|
||||
}
|
||||
|
||||
main $1
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"name": "hcxdumptool",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~9.1.11",
|
||||
"@angular/cdk": "^9.2.4",
|
||||
"@angular/common": "~9.1.11",
|
||||
"@angular/compiler": "~9.1.11",
|
||||
"@angular/core": "~9.1.11",
|
||||
"@angular/flex-layout": "^9.0.0-beta.31",
|
||||
"@angular/forms": "~9.1.11",
|
||||
"@angular/material": "^9.2.4",
|
||||
"@angular/platform-browser": "~9.1.11",
|
||||
"@angular/platform-browser-dynamic": "~9.1.11",
|
||||
"@angular/router": "~9.1.11",
|
||||
"rxjs": "~6.5.5",
|
||||
"tslib": "^1.10.0",
|
||||
"zone.js": "~0.10.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.901.8",
|
||||
"@angular-devkit/build-ng-packagr": "~0.901.8",
|
||||
"@angular/cli": "~9.1.8",
|
||||
"@angular/compiler-cli": "~9.1.11",
|
||||
"@angular/language-service": "~9.1.11",
|
||||
"@types/jasmine": "~3.5.10",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "^12.11.1",
|
||||
"codelyzer": "^5.1.2",
|
||||
"jasmine-core": "~3.5.0",
|
||||
"jasmine-spec-reporter": "~5.0.2",
|
||||
"karma": "~5.1.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.3",
|
||||
"karma-jasmine": "~3.3.1",
|
||||
"karma-jasmine-html-reporter": "^1.4.0",
|
||||
"ng-packagr": "^9.1.5",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~8.10.2",
|
||||
"tslint": "~6.1.2",
|
||||
"typescript": "^3.6.5"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../dist/hcxdumptool",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "hcxdumptool",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^8.2.14",
|
||||
"@angular/core": "^8.2.14"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "ng build --prod"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<nav mat-tab-nav-bar color="accent">
|
||||
<a mat-tab-link
|
||||
*ngFor="let link of navLinks"
|
||||
[routerLink]="link.link"
|
||||
routerLinkActive #rla="routerLinkActive"
|
||||
[routerLinkActiveOptions]="{exact: true}"
|
||||
[active]="rla.isActive">
|
||||
<mat-icon *ngIf="link.label === 'HCXdumptool'">
|
||||
<svg style="width:24px;height:24px">
|
||||
<path d="M 17 3 C 18.105469 3 19 3.894531 19 5 L 19 15 C 19 16.105469 18.105469 17 17 17 L 13 17 L 13 19 L 14 19 C 14.550781 19 15 19.449219 15 20 L 22 20 L 22 22 L 15 22 C 15 22.550781 14.550781 23 14 23 L 10 23 C 9.449219 23 9 22.550781 9 22 L 2 22 L 2 20 L 9 20 C 9 19.449219 9.449219 19 10 19 L 11 19 L 11 17 L 7 17 C 5.890625 17 5 16.101562 5 15 L 5 5 C 5 3.894531 5.894531 3 7 3 L 17 3 M 12 14.5 L 16.5 10 L 13 10 L 13 6 L 11 6 L 11 10 L 7.5 10 Z M 12 14.5 "></path>
|
||||
</svg>
|
||||
</mat-icon>
|
||||
<mat-icon *ngIf="link.label === 'History'">
|
||||
<svg style="width:24px;height:24px">
|
||||
<path d="M4 14h4v-4H4v4zm0 5h4v-4H4v4zM4 9h4V5H4v4zm5 5h12v-4H9v4zm0 5h12v-4H9v4zM9 5v4h12V5H9z" />
|
||||
</svg>
|
||||
</mat-icon>
|
||||
<div [fxShow.sm]="false" [fxShow.xs]="false">
|
||||
|
||||
{{ link.label }}
|
||||
</div>
|
||||
</a>
|
||||
</nav>
|
||||
<br/>
|
||||
<div>
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
|
@ -0,0 +1,30 @@
|
|||
import {Component, OnInit, ViewChild} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'lib-hcxdumptool',
|
||||
templateUrl: './hcxdumptool.component.html',
|
||||
styleUrls: ['./hcxdumptool.component.css']
|
||||
})
|
||||
export class HcxdumptoolComponent implements OnInit {
|
||||
navLinks: any[];
|
||||
|
||||
@ViewChild('rla') rla;
|
||||
|
||||
constructor() {
|
||||
this.navLinks = [
|
||||
{
|
||||
label: 'Hcxdumptool',
|
||||
link: './',
|
||||
index: 0
|
||||
},
|
||||
{
|
||||
label: 'History',
|
||||
link: './history',
|
||||
index: 1
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
.confirmation-dialog-body-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.confirmation-dialog-buttons {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.confirmation-dialog-button-first {
|
||||
margin-right: 10px;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<div class="right-left-split-container">
|
||||
<h1 mat-dialog-title>{{ title }}</h1>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button (click)="closeDialog();">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
<br/>
|
||||
|
||||
<div class="confirmation-dialog-body-container">
|
||||
<p>{{ message }}</p>
|
||||
<div class="confirmation-dialog-buttons">
|
||||
<span fxFlex></span>
|
||||
<button mat-raised-button class="confirmation-dialog-button-first" (click)="handleResponse(false);">No</button>
|
||||
<button mat-raised-button color="warn" (click)="handleResponse(true);">Yes</button>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,32 @@
|
|||
import {Component, Inject, OnInit} from '@angular/core';
|
||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||
import {ConfirmationDialogDelegate} from "../../../interfaces/confirmationdialogdelegate.interface";
|
||||
|
||||
@Component({
|
||||
selector: 'lib-confirmation-dialog',
|
||||
templateUrl: './confirmation-dialog.component.html',
|
||||
styleUrls: ['./confirmation-dialog.component.css']
|
||||
})
|
||||
export class ConfirmationDialogComponent implements OnInit {
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<ConfirmationDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: ConfirmationDialogDelegate) {
|
||||
this.title = data.title;
|
||||
this.message = data.message;
|
||||
}
|
||||
|
||||
public title: string;
|
||||
public message: string;
|
||||
|
||||
closeDialog(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
handleResponse(affirmative: boolean): void {
|
||||
this.closeDialog();
|
||||
this.data.handleResponse(affirmative);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
.error-dialog-buttons {
|
||||
margin-top: 16px;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<div class="right-left-split-container">
|
||||
<mat-card-title>Error</mat-card-title>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button>
|
||||
<mat-icon (click)="closeDialog();">close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<div>
|
||||
<p>{{ message }}</p>
|
||||
<div class="error-dialog-buttons">
|
||||
<span fxFlex></span>
|
||||
<button mat-raised-button color="accent" class="error-dialog-button-first" (click)="closeDialog();">
|
||||
Okay
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,26 @@
|
|||
import {Component, Inject, OnInit} from '@angular/core';
|
||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||
import {ErrorDialogData} from "../../../interfaces/errordialogdata.interface";
|
||||
|
||||
@Component({
|
||||
selector: 'lib-error-dialog',
|
||||
templateUrl: './error-dialog.component.html',
|
||||
styleUrls: ['./error-dialog.component.css']
|
||||
})
|
||||
export class ErrorDialogComponent implements OnInit {
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<ErrorDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: ErrorDialogData) {
|
||||
this.message = data.message;
|
||||
}
|
||||
|
||||
public message: string;
|
||||
|
||||
closeDialog(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
.legal-textarea {
|
||||
width: 100%;
|
||||
min-height: 480px;
|
||||
resize: none;
|
||||
margin: 0 0 5px;
|
||||
padding: 0;
|
||||
background-color: #efefef;
|
||||
border-radius: 2px;
|
||||
border-color: #cecece;
|
||||
max-lines: 50;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<div class="right-left-split-container">
|
||||
<h1 mat-dialog-title>TCPDump License</h1>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button (click)="closeDialog();">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
<br/>
|
||||
|
||||
<div>
|
||||
<textarea class="legal-textarea" readonly>
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2000-2023 ZeroBeat
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
</textarea>
|
||||
</div>
|
|
@ -0,0 +1,21 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import {MatDialogRef} from "@angular/material/dialog";
|
||||
|
||||
@Component({
|
||||
selector: 'lib-license-dialog',
|
||||
templateUrl: './license-dialog.component.html',
|
||||
styleUrls: ['./license-dialog.component.css']
|
||||
})
|
||||
export class LicenseDialogComponent implements OnInit {
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<LicenseDialogComponent>) {
|
||||
}
|
||||
|
||||
closeDialog(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
.right-left-split-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.dependency-card-centered {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.dependency-card-button {
|
||||
width: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.spinner-padding {
|
||||
margin-top: 6px;
|
||||
margin-bottom: 7px;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<div class="right-left-split-container">
|
||||
<h1 mat-dialog-title>Uninstall Dependencies?</h1>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button (click)="closeDialog();" [disabled]="isBusy">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
<br/>
|
||||
|
||||
<div>
|
||||
<p>You are about to uninstall dependencies for this module. You'll still be able to access your history
|
||||
but will be unable to preform new packet captures.</p>
|
||||
<p>Do you want to continue?</p>
|
||||
|
||||
<br/>
|
||||
<div class="dependency-card-centered">
|
||||
<button mat-raised-button color="warn"
|
||||
class="dependency-card-button"
|
||||
(click)="removeDependencies();"
|
||||
[disabled]="isBusy">
|
||||
<span *ngIf="isBusy">
|
||||
<mat-spinner [diameter]="20" class="spinner-padding" color="accent"></mat-spinner>
|
||||
</span>
|
||||
<span *ngIf="!isBusy">
|
||||
Uninstall Dependencies
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,82 @@
|
|||
import {Component, Inject, OnInit} from '@angular/core';
|
||||
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog";
|
||||
import {ApiService} from "../../../services/api.service";
|
||||
import {ErrorDialogComponent} from "../error-dialog/error-dialog.component";
|
||||
import {JobResultDTO} from "../../../interfaces/jobresult.interface";
|
||||
|
||||
@Component({
|
||||
selector: 'lib-uninstall-dialog',
|
||||
templateUrl: './uninstall-dialog.component.html',
|
||||
styleUrls: ['./uninstall-dialog.component.css']
|
||||
})
|
||||
export class UninstallDialogComponent implements OnInit {
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<UninstallDialogComponent>,
|
||||
private API: ApiService,
|
||||
private dialog: MatDialog,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||
}
|
||||
|
||||
public isBusy: boolean = false;
|
||||
private backgroundJobInterval = null;
|
||||
|
||||
private handleError(msg: string): void {
|
||||
this.closeDialog();
|
||||
this.dialog.open(ErrorDialogComponent, {
|
||||
hasBackdrop: true,
|
||||
width: '900px',
|
||||
data: {
|
||||
message: msg
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private pollBackgroundJob<T>(jobId: string, onComplete: (result: JobResultDTO<T>) => void): void {
|
||||
this.backgroundJobInterval = setInterval(() => {
|
||||
this.API.request({
|
||||
module: 'tcpdump',
|
||||
action: 'check_background_job',
|
||||
job_id: jobId
|
||||
}, (response: JobResultDTO<T>) => {
|
||||
if (response.is_complete) {
|
||||
onComplete(response);
|
||||
clearInterval(this.backgroundJobInterval);
|
||||
}
|
||||
});
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
closeDialog(): void {
|
||||
if (this.isBusy) { return; }
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
removeDependencies(): void {
|
||||
this.API.request({
|
||||
module: 'tcpdump',
|
||||
action: 'manage_dependencies',
|
||||
install: false
|
||||
}, (response) => {
|
||||
if (response.error) {
|
||||
this.handleError(response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.isBusy = true;
|
||||
this.pollBackgroundJob(response.job_id, (result: JobResultDTO<boolean>) => {
|
||||
this.isBusy = false;
|
||||
|
||||
if (result.job_error !== null) {
|
||||
this.handleError(result.job_error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.data.onComplete();
|
||||
this.closeDialog();
|
||||
});
|
||||
});
|
||||
}
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="right-left-split-container">
|
||||
<mat-card-title>History</mat-card-title>
|
||||
<span *ngIf="isBusy"><mat-spinner [diameter]="24" color="accent" style="margin-left: 8px"></mat-spinner></span>
|
||||
<span fxFlex></span>
|
||||
<mat-menu #historyMenu>
|
||||
<button mat-menu-item (click)="loadHistory();">Refresh</button>
|
||||
<button mat-menu-item (click)="showClearHistoryDialog();">Delete History</button>
|
||||
</mat-menu>
|
||||
|
||||
<button mat-icon-button [matMenuTriggerFor]="historyMenu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<mat-divider></mat-divider>
|
||||
<br/>
|
||||
|
||||
<mat-table style="display: none;">
|
||||
<mat-header-row *matHeaderRowDef="[]"></mat-header-row>
|
||||
</mat-table>
|
||||
<table class="mat-table" style="min-width: 100%; overflow-x: auto; justify-content: center;">
|
||||
<tbody>
|
||||
<ng-container *ngFor="let item of scanHistory">
|
||||
<tr class="mat-row">
|
||||
<td class="mat-cell">{{ item }}</td>
|
||||
<td class="mat-cell"><button mat-icon-button (click)="downloadItem(item);"><mat-icon>cloud_download</mat-icon></button></td>
|
||||
<td class="mat-cell"><button mat-icon-button (click)="showDeleteDialog(item);"><mat-icon>delete</mat-icon></button></td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</tbody>
|
||||
</table>
|
||||
<i *ngIf="scanHistory.length == 0;">No capture history to display.</i>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
|
@ -0,0 +1,120 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import {MatDialog} from "@angular/material/dialog";
|
||||
import {ApiService} from "../../../services/api.service";
|
||||
import {ConfirmationDialogComponent} from "../../helpers/confirmation-dialog/confirmation-dialog.component";
|
||||
import {ErrorDialogComponent} from "../../helpers/error-dialog/error-dialog.component";
|
||||
|
||||
@Component({
|
||||
selector: 'lib-hcxdumptool-history',
|
||||
templateUrl: './hcxdumptool-history.component.html',
|
||||
styleUrls: ['./hcxdumptool-history.component.css']
|
||||
})
|
||||
export class HcxdumptoolHistoryComponent implements OnInit {
|
||||
|
||||
constructor(private API: ApiService,
|
||||
private dialog: MatDialog) {
|
||||
}
|
||||
|
||||
public isBusy: boolean = false;
|
||||
public scanHistory: Array<string> = [];
|
||||
|
||||
private handleError(msg: string): void {
|
||||
this.dialog.closeAll();
|
||||
this.dialog.open(ErrorDialogComponent, {
|
||||
hasBackdrop: true,
|
||||
width: '900px',
|
||||
data: {
|
||||
message: msg
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadHistory(): void {
|
||||
this.isBusy = true;
|
||||
this.API.request({
|
||||
module: 'hcxdumptool',
|
||||
action: 'list_capture_history'
|
||||
}, (response) => {
|
||||
this.isBusy = false;
|
||||
if (response.error) {
|
||||
this.handleError(response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.scanHistory = response;
|
||||
});
|
||||
}
|
||||
|
||||
private deleteItem(item: string): void {
|
||||
this.isBusy = true;
|
||||
this.API.request({
|
||||
module: 'hcxdumptool',
|
||||
action: 'delete_capture',
|
||||
output_file: item
|
||||
}, (response) => {
|
||||
this.isBusy = false;
|
||||
if (response.error) {
|
||||
this.handleError(response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadHistory();
|
||||
});
|
||||
}
|
||||
|
||||
private deleteAll(): void {
|
||||
this.isBusy = true;
|
||||
this.API.request({
|
||||
module: 'hcxdumptool',
|
||||
action: 'delete_all'
|
||||
}, (response) => {
|
||||
this.isBusy = false;
|
||||
if (response.error) {
|
||||
this.handleError(response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadHistory();
|
||||
});
|
||||
}
|
||||
|
||||
downloadItem(item: string): void {
|
||||
this.API.APIDownload('/root/.hcxdumptool/' + item, item);
|
||||
}
|
||||
|
||||
showDeleteDialog(item: string): void {
|
||||
this.dialog.open(ConfirmationDialogComponent, {
|
||||
hasBackdrop: true,
|
||||
width: '900px',
|
||||
data: {
|
||||
title: 'Delete?',
|
||||
message: 'You are about to delete ' + item + '? This action can not be undone. Are you sure you want to continue?',
|
||||
handleResponse: (affirmative: boolean) => {
|
||||
if (affirmative) {
|
||||
this.deleteItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
showClearHistoryDialog(): void {
|
||||
this.dialog.open(ConfirmationDialogComponent, {
|
||||
hasBackdrop: true,
|
||||
width: '900px',
|
||||
data: {
|
||||
title: 'Delete All?',
|
||||
message: 'You are about to delete all scan history. This action can not be undone. Are you sure you want to continue?',
|
||||
handleResponse: (affirmative: boolean) => {
|
||||
if (affirmative) {
|
||||
this.deleteAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadHistory();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
.right-left-split-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.dependency-card {
|
||||
max-width: 600px;
|
||||
min-height: 246px;
|
||||
}
|
||||
|
||||
.dependency-card-centered {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.dependency-card-button {
|
||||
width: 75%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.spinner-padding {
|
||||
margin-top: 6px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.controls-container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.control-item {
|
||||
flex: 1;
|
||||
margin-right: 2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.output-container {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.control-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.output-textarea {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
min-height: 200px;
|
||||
max-height: 600px;
|
||||
resize: vertical;
|
||||
margin: 0 0 5px;
|
||||
padding: 0;
|
||||
background-color: #efefef;
|
||||
border-radius: 2px;
|
||||
border-color: #cecece;
|
||||
max-lines: 50;
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
<div class="dependency-card-centered" *ngIf="!hasDependencies">
|
||||
<mat-card class="dependency-card">
|
||||
<mat-card-content>
|
||||
<mat-card-title>Welcome To hcxdumptool</mat-card-title>
|
||||
<mat-card-subtitle>Lets get started.</mat-card-subtitle>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
<br />
|
||||
|
||||
<p>You need to install some dependencies before you can use this module.</p>
|
||||
<p>This will make a request to the internet.</p>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="dependency-card-centered">
|
||||
<button mat-raised-button color="accent"
|
||||
class="dependency-card-button"
|
||||
(click)="installDependencies()"
|
||||
[disabled]="isInstalling">
|
||||
<span *ngIf="isInstalling">
|
||||
<mat-spinner [diameter]="20" class="spinner-padding" color="accent"></mat-spinner>
|
||||
</span>
|
||||
<span *ngIf="!isInstalling">
|
||||
Install Dependencies
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="dependency-card-centered">
|
||||
<button mat-button color="accent" (click)="showLicenseDialog();">View hcxdumptool License</button>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
<div *ngIf="hasDependencies" class="controls-container" fxLayoutGap="20px" fxLayout="row" fxLayout.xs="column" fxLayout.sm="column">
|
||||
<mat-card class="control-item">
|
||||
<mat-card-content>
|
||||
<div class="right-left-split-container">
|
||||
<mat-card-title>HCXdumptool</mat-card-title>
|
||||
<span *ngIf="isCapturing"><mat-spinner [diameter]="24" color="accent" style="margin-left: 8px"></mat-spinner></span>
|
||||
<span fxFlex></span>
|
||||
<mat-menu #hcxdumptoolMenu>
|
||||
<button mat-menu-item (click)="showUninstallDialog();">Uninstall Dependencies</button>
|
||||
<button mat-menu-item (click)="showLicenseDialog();">Show License</button>
|
||||
</mat-menu>
|
||||
|
||||
<button mat-icon-button [matMenuTriggerFor]="hcxdumptoolMenu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<form>
|
||||
<mat-form-field style="width: 100%;">
|
||||
<mat-label>Command</mat-label>
|
||||
<input matInput class="control-input" name="command" [(ngModel)]="hcxDumptoolState.command"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field style="width: 100%;">
|
||||
<mat-label>Interface</mat-label>
|
||||
<mat-select name="interface" [(ngModel)]="hcxDumptoolState.selectedInterface" (ngModelChange)="update();">
|
||||
<mat-option>--</mat-option>
|
||||
<mat-option *ngFor="let iface of interfaces" value="{{ iface }}">{{ iface }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field style="width: 100%;">
|
||||
<mat-label>Band</mat-label>
|
||||
<mat-select name="scanlist" [(ngModel)]="hcxDumptoolState.scanlist" (ngModelChange)="update();">
|
||||
<mat-option>--</mat-option>
|
||||
<mat-option value="-c 1,6,11,3,5,1,6,11,2,4,1,6,11,7,9,1,6,11,8,10,1,6,11,12,13">Optimized 2.4GHz</mat-option>
|
||||
<mat-option value="-c 1,2,3,4,5,6,7,8,9,10,11,12,13">Standard 2.4 GHz</mat-option>
|
||||
<mat-option value="-c 36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140,144,149,153,157,161,165">Standard 5GHz</mat-option>
|
||||
<mat-option value="-c 1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140,144,149,153,157,161,165">Standard 2.4GHz/5GHz</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<button mat-raised-button color="accent" style="width: 100%;" *ngIf="!isCapturing" (click)="startCapture();">Capture</button>
|
||||
<button mat-raised-button color="warn" style="width: 100%;" *ngIf="isCapturing" (click)="stopCapture();">Stop</button>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<mat-card class="control-item">
|
||||
<mat-card-content>
|
||||
<div>
|
||||
<mat-card-title>Options</mat-card-title>
|
||||
</div>
|
||||
<mat-checkbox [(ngModel)]="optionsState.disableClientAttacks.toggled" (ngModelChange)="update();">Do not attack clients</mat-checkbox>
|
||||
<br/>
|
||||
<mat-checkbox [(ngModel)]="optionsState.disableAPAttacks.toggled" (ngModelChange)="update();">Do not attack access points</mat-checkbox>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<mat-card *ngIf="hasDependencies">
|
||||
<mat-card-content>
|
||||
<div class="output-container">
|
||||
<div class="right-left-split-container">
|
||||
<mat-card-title>Output</mat-card-title>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button [disabled]="isFetchingOutput || !isCapturing" (click)="getLogContent();"><mat-icon>refresh</mat-icon></button>
|
||||
<button mat-icon-button [disabled]="captureFileName == null || isCapturing" (click)="downloadPcap();"><mat-icon>cloud_download</mat-icon></button>
|
||||
</div>
|
||||
<textarea class="output-textarea" [(ngModel)]="captureOutput" placeholder="No output to display..." readonly></textarea>
|
||||
<div class="right-left-split-container">
|
||||
<span *ngIf="isCapturing" style="margin-right: 8px;"><i>Refreshes every 5 seconds...</i></span>
|
||||
<span *ngIf="isFetchingOutput"><mat-spinner [diameter]="24" color="accent"></mat-spinner></span>
|
||||
<span fxFlex></span>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {ApiService} from "../../../services/api.service";
|
||||
import {MatDialog} from "@angular/material/dialog";
|
||||
import {StartupDTO, StartupLastJob} from "../../../interfaces/startupdto.interface";
|
||||
import {ErrorDialogComponent} from "../../helpers/error-dialog/error-dialog.component";
|
||||
import {JobResultDTO} from "../../../interfaces/jobresult.interface";
|
||||
import {UninstallDialogComponent} from "../../helpers/uninstall-dialog/uninstall-dialog.component";
|
||||
import {OtherOptions, HCXDumptoolState} from "../../../interfaces/optionstate.interface";
|
||||
import {LicenseDialogComponent} from "../../helpers/license-dialog/license-dialog.component";
|
||||
|
||||
@Component({
|
||||
selector: 'lib-hcxdumptool-main',
|
||||
templateUrl: './hcxdumptool-main.component.html',
|
||||
styleUrls: ['./hcxdumptool-main.component.css']
|
||||
})
|
||||
export class HcxdumptoolMainComponent implements OnInit, OnDestroy {
|
||||
|
||||
public hasDependencies: boolean = true;
|
||||
public isInstalling: boolean = false;
|
||||
public interfaces: Array<string> = [];
|
||||
public isFetchingOutput: boolean = false;
|
||||
public isCapturing: boolean = false;
|
||||
public captureFileName: string = null;
|
||||
public captureOutput: string = null;
|
||||
private backgroundJobInterval = null;
|
||||
|
||||
public hcxDumptoolState: HCXDumptoolState = {
|
||||
command: 'hcxdumptool --enable_status=3 ',
|
||||
selectedInterface: '',
|
||||
scanlist: ''
|
||||
};
|
||||
|
||||
public optionsState: OtherOptions = {
|
||||
disableClientAttacks: { toggled: false, value: '--disable_client_attacks' },
|
||||
disableAPAttacks: { toggled: false, value: '--disable_ap_attacks' },
|
||||
};
|
||||
|
||||
constructor(private API: ApiService,
|
||||
private dialog: MatDialog) {
|
||||
}
|
||||
|
||||
private handleError(msg: string): void {
|
||||
this.dialog.closeAll();
|
||||
this.dialog.open(ErrorDialogComponent, {
|
||||
hasBackdrop: true,
|
||||
width: '500px',
|
||||
data: {
|
||||
message: msg
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pollBackgroundJob<T>(jobId: string, onComplete: (result: JobResultDTO<T>) => void, onInterval?: Function): void {
|
||||
this.backgroundJobInterval = setInterval(() => {
|
||||
this.API.request({
|
||||
module: 'hcxdumptool',
|
||||
action: 'poll_job',
|
||||
job_id: jobId
|
||||
}, (response: JobResultDTO<T>) => {
|
||||
if (response.is_complete) {
|
||||
onComplete(response);
|
||||
clearInterval(this.backgroundJobInterval);
|
||||
} else if (onInterval) {
|
||||
onInterval();
|
||||
}
|
||||
});
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
getLogContent(): void {
|
||||
this.isFetchingOutput = true;
|
||||
this.API.request({
|
||||
module: 'hcxdumptool',
|
||||
action: 'get_log_content',
|
||||
}, (response) => {
|
||||
this.isFetchingOutput = false;
|
||||
if (response.error) {
|
||||
this.handleError(response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.captureOutput = response;
|
||||
});
|
||||
}
|
||||
|
||||
downloadPcap(): void {
|
||||
this.API.APIDownload('/root/.hcxdumptool/' + this.captureFileName, this.captureFileName);
|
||||
}
|
||||
|
||||
private monitorCaptureJob(jobId: string, captureFile: string): void {
|
||||
this.isCapturing = true;
|
||||
this.captureFileName = captureFile;
|
||||
this.pollBackgroundJob(jobId, (result: JobResultDTO<boolean>) => {
|
||||
this.isCapturing = false;
|
||||
this.getLogContent();
|
||||
|
||||
if (result.job_error) {
|
||||
this.handleError(result.job_error);
|
||||
}
|
||||
}, () => {
|
||||
this.getLogContent();
|
||||
})
|
||||
}
|
||||
|
||||
startCapture(): void {
|
||||
this.isCapturing = true;
|
||||
this.API.request({
|
||||
module: 'hcxdumptool',
|
||||
action: 'start_capture',
|
||||
command: this.hcxDumptoolState.command
|
||||
}, (response) => {
|
||||
if (response.error !== undefined) {
|
||||
this.isCapturing = false;
|
||||
this.handleError(response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.monitorCaptureJob(response.job_id, response.output_file);
|
||||
});
|
||||
}
|
||||
|
||||
stopCapture(): void {
|
||||
this.API.request({
|
||||
module: 'hcxdumptool',
|
||||
action: 'stop_capture'
|
||||
}, (response) => {
|
||||
if (response.error !== undefined) {
|
||||
this.handleError(response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.isCapturing = false
|
||||
})
|
||||
}
|
||||
|
||||
checkForDependencies(): void {
|
||||
this.API.request({
|
||||
module: 'hcxdumptool',
|
||||
action: 'check_dependencies'
|
||||
}, (response) => {
|
||||
if (response.error !== undefined) {
|
||||
this.handleError(response.error);
|
||||
return;
|
||||
}
|
||||
this.hasDependencies = response;
|
||||
});
|
||||
}
|
||||
|
||||
private monitorDependencies(jobId: string) {
|
||||
this.isInstalling = true;
|
||||
this.pollBackgroundJob(jobId, (result: JobResultDTO<boolean>) => {
|
||||
this.isInstalling = false;
|
||||
if (result.job_error !== null) {
|
||||
this.handleError(result.job_error);
|
||||
}
|
||||
this.checkForDependencies();
|
||||
});
|
||||
}
|
||||
|
||||
installDependencies(): void {
|
||||
this.API.request({
|
||||
module: 'hcxdumptool',
|
||||
action: 'manage_dependencies',
|
||||
install: true
|
||||
}, (response) => {
|
||||
if (response.error !== undefined && response.error !== null) {
|
||||
this.handleError(response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.monitorDependencies(response.job_id);
|
||||
});
|
||||
}
|
||||
|
||||
showUninstallDialog(): void {
|
||||
this.dialog.open(UninstallDialogComponent, {
|
||||
hasBackdrop: true,
|
||||
width: '700px',
|
||||
disableClose: true,
|
||||
data: {
|
||||
onComplete: () => {
|
||||
this.checkForDependencies();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.hcxDumptoolState.command = 'hcxdumptool --enable_status=3 ' + this.updateInterface() +
|
||||
this.updateScanlist() + this.updateOptions()
|
||||
}
|
||||
|
||||
private updateInterface(): string {
|
||||
const iface = this.hcxDumptoolState.selectedInterface;
|
||||
return (iface !== '' && iface !== undefined) ? '-i ' + iface + ' ' : '';
|
||||
}
|
||||
|
||||
private updateOptions(): string {
|
||||
let returnValue: string = '';
|
||||
|
||||
for (let option of Object.values(this.optionsState)) {
|
||||
if (option.toggled) {
|
||||
returnValue += option.value + ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private updateScanlist(): string {
|
||||
const scanlist = this.hcxDumptoolState.scanlist;
|
||||
return (scanlist !== '' && scanlist !== undefined) ? scanlist + ' ' : '';
|
||||
}
|
||||
|
||||
private rebind(lastJob: StartupLastJob): void {
|
||||
switch (lastJob.job_type) {
|
||||
case 'pcap':
|
||||
this.monitorCaptureJob(lastJob.job_id, lastJob.job_info);
|
||||
this.getLogContent();
|
||||
break;
|
||||
case 'opkg':
|
||||
this.monitorDependencies(lastJob.job_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private startup(): void {
|
||||
this.API.request({
|
||||
module: 'hcxdumptool',
|
||||
action: 'startup'
|
||||
}, (response: StartupDTO) => {
|
||||
if (response.error !== undefined && response.error !== null) {
|
||||
this.handleError(response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.hasDependencies = response.has_dependencies;
|
||||
this.interfaces = response.interfaces;
|
||||
|
||||
if (response.last_job.job_id !== null) {
|
||||
this.rebind(response.last_job);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
showLicenseDialog(): void {
|
||||
this.dialog.open(LicenseDialogComponent, {
|
||||
hasBackdrop: true,
|
||||
width: '900px',
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.startup();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
clearInterval(this.backgroundJobInterval);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { HcxdumptoolComponent } from './components/hcxdumptool.component';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import {MaterialModule} from './modules/material/material.module';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import { HcxdumptoolMainComponent } from './components/subviews/hcxdumptool-main/hcxdumptool-main.component';
|
||||
import { HcxdumptoolHistoryComponent } from './components/subviews/hcxdumptool-history/hcxdumptool-history.component';
|
||||
import { ConfirmationDialogComponent } from './components/helpers/confirmation-dialog/confirmation-dialog.component';
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import { ErrorDialogComponent } from './components/helpers/error-dialog/error-dialog.component';
|
||||
import { UninstallDialogComponent } from './components/helpers/uninstall-dialog/uninstall-dialog.component';
|
||||
import { LicenseDialogComponent } from './components/helpers/license-dialog/license-dialog.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: HcxdumptoolComponent,
|
||||
children: [
|
||||
{ path: '', component: HcxdumptoolMainComponent, pathMatch: 'full' },
|
||||
{ path: 'history', component: HcxdumptoolHistoryComponent }
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
HcxdumptoolComponent,
|
||||
HcxdumptoolMainComponent,
|
||||
HcxdumptoolHistoryComponent,
|
||||
ConfirmationDialogComponent,
|
||||
ErrorDialogComponent,
|
||||
UninstallDialogComponent,
|
||||
LicenseDialogComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild(routes),
|
||||
MaterialModule,
|
||||
FlexLayoutModule,
|
||||
FormsModule
|
||||
],
|
||||
exports: [HcxdumptoolComponent],
|
||||
entryComponents: [
|
||||
ConfirmationDialogComponent,
|
||||
ErrorDialogComponent,
|
||||
UninstallDialogComponent,
|
||||
LicenseDialogComponent
|
||||
]
|
||||
})
|
||||
export class hcxdumptoolModule { }
|
|
@ -0,0 +1,5 @@
|
|||
export interface ConfirmationDialogDelegate {
|
||||
title: string;
|
||||
message: string;
|
||||
handleResponse: (affirmative: boolean) => void;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export interface ErrorDialogData {
|
||||
message: string;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export interface JobResultDTO<T> {
|
||||
is_complete: boolean;
|
||||
job_error: string,
|
||||
result: T
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
export interface HCXDumptoolState {
|
||||
command: string;
|
||||
selectedInterface: string;
|
||||
scanlist: string;
|
||||
}
|
||||
|
||||
export interface OtherOptions {
|
||||
disableClientAttacks: ToggleOption;
|
||||
disableAPAttacks: ToggleOption;
|
||||
}
|
||||
|
||||
export interface ToggleOption {
|
||||
toggled: boolean,
|
||||
value: string
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
export interface StartupDTO {
|
||||
error: string;
|
||||
has_dependencies: boolean;
|
||||
interfaces: Array<string>;
|
||||
last_job: StartupLastJob;
|
||||
}
|
||||
|
||||
export interface StartupLastJob {
|
||||
job_id: string;
|
||||
job_type: string;
|
||||
job_info: string;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Hak5 LLC.
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { A11yModule } from '@angular/cdk/a11y';
|
||||
import { BidiModule } from '@angular/cdk/bidi';
|
||||
import { ObserversModule } from '@angular/cdk/observers';
|
||||
import { OverlayModule } from '@angular/cdk/overlay';
|
||||
import { PlatformModule } from '@angular/cdk/platform';
|
||||
import { PortalModule } from '@angular/cdk/portal';
|
||||
import { CdkStepperModule } from '@angular/cdk/stepper';
|
||||
import { CdkTableModule } from '@angular/cdk/table';
|
||||
import { CdkTreeModule } from '@angular/cdk/tree';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatNativeDateModule, MatRippleModule } from '@angular/material/core';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatExpansionModule } from '@angular/material/expansion';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatGridListModule } from '@angular/material/grid-list';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatSliderModule } from '@angular/material/slider';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatStepperModule } from '@angular/material/stepper';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { MatTreeModule } from '@angular/material/tree';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule],
|
||||
exports: [
|
||||
// CDK
|
||||
A11yModule,
|
||||
BidiModule,
|
||||
ObserversModule,
|
||||
OverlayModule,
|
||||
PlatformModule,
|
||||
PortalModule,
|
||||
CdkStepperModule,
|
||||
CdkTableModule,
|
||||
CdkTreeModule,
|
||||
|
||||
// Material
|
||||
MatAutocompleteModule,
|
||||
MatBadgeModule,
|
||||
MatBottomSheetModule,
|
||||
MatButtonModule,
|
||||
MatButtonToggleModule,
|
||||
MatCardModule,
|
||||
MatCheckboxModule,
|
||||
MatChipsModule,
|
||||
MatDatepickerModule,
|
||||
MatDialogModule,
|
||||
MatDividerModule,
|
||||
MatExpansionModule,
|
||||
MatFormFieldModule,
|
||||
MatGridListModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatListModule,
|
||||
MatMenuModule,
|
||||
MatNativeDateModule,
|
||||
MatPaginatorModule,
|
||||
MatProgressBarModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatRadioModule,
|
||||
MatRippleModule,
|
||||
MatSelectModule,
|
||||
MatSidenavModule,
|
||||
MatSliderModule,
|
||||
MatSlideToggleModule,
|
||||
MatSnackBarModule,
|
||||
MatSortModule,
|
||||
MatStepperModule,
|
||||
MatTableModule,
|
||||
MatTabsModule,
|
||||
MatToolbarModule,
|
||||
MatTooltipModule,
|
||||
MatTreeModule,
|
||||
],
|
||||
declarations: []
|
||||
})
|
||||
export class MaterialModule {
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {Router} from '@angular/router';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ApiService {
|
||||
public static totalRequests = 0;
|
||||
apiModuleBusy = document.getElementById('ApiModuleBusy');
|
||||
|
||||
constructor(private http: HttpClient,
|
||||
private router: Router) {}
|
||||
|
||||
emptyResponse = {error: 'Request returned empty response'};
|
||||
|
||||
unauth(): void {
|
||||
localStorage.removeItem('authToken');
|
||||
|
||||
if (this.router.url !== '/Login' && this.router.url !== '/Setup') {
|
||||
this.router.navigateByUrl('/Login');
|
||||
}
|
||||
}
|
||||
|
||||
setBusy(): void {
|
||||
this.apiModuleBusy.style.display = 'block';
|
||||
}
|
||||
setNotBusy(): void {
|
||||
this.apiModuleBusy.style.display = 'none';
|
||||
}
|
||||
|
||||
static extractBaseHref(): string {
|
||||
// Duplicated from injector because we have to be able to support
|
||||
// a static method here
|
||||
if (window['_app_base']) {
|
||||
if (window['_app_base'].endsWith('/')) {
|
||||
return window['_app_base'].slice(0, -1)
|
||||
}
|
||||
}
|
||||
return window['_app_base'] || '';
|
||||
}
|
||||
|
||||
request(payload: any, callback: (any) => void) {
|
||||
this.setBusy();
|
||||
let resp;
|
||||
|
||||
this.http.post(`${ApiService.extractBaseHref()}/api/module/request`, payload).subscribe((r: any) => {
|
||||
if (r === undefined || r === null) {
|
||||
resp = this.emptyResponse;
|
||||
} else if (r.error) {
|
||||
resp = r;
|
||||
} else {
|
||||
resp = r.payload;
|
||||
}
|
||||
}, (err) => {
|
||||
resp = err.error;
|
||||
if (err.status === 401) {
|
||||
this.unauth();
|
||||
}
|
||||
this.setNotBusy();
|
||||
callback(resp);
|
||||
}, () => {
|
||||
this.setNotBusy();
|
||||
callback(resp);
|
||||
});
|
||||
|
||||
ApiService.totalRequests++;
|
||||
}
|
||||
|
||||
APIGet(path: string, callback: (any) => void): any {
|
||||
ApiService.totalRequests++;
|
||||
|
||||
let resp;
|
||||
|
||||
this.http.get(`${ApiService.extractBaseHref()}${path}`).subscribe((r) => {
|
||||
if (r === undefined || r === null) {
|
||||
r = this.emptyResponse;
|
||||
}
|
||||
resp = r;
|
||||
}, (err) => {
|
||||
resp = err.error;
|
||||
if (err.status === 401) {
|
||||
this.unauth();
|
||||
}
|
||||
callback(resp);
|
||||
}, () => {
|
||||
callback(resp);
|
||||
});
|
||||
}
|
||||
|
||||
async APIGetAsync(path: string): Promise<any> {
|
||||
ApiService.totalRequests++;
|
||||
|
||||
return await this.http.get(`${ApiService.extractBaseHref()}${path}`).toPromise();
|
||||
}
|
||||
|
||||
APIPut(path: string, body: any, callback: (any) => void): any {
|
||||
ApiService.totalRequests++;
|
||||
|
||||
let resp;
|
||||
|
||||
this.http.put(`${ApiService.extractBaseHref()}${path}`, body).subscribe((r) => {
|
||||
if (r === undefined || r === null) {
|
||||
r = this.emptyResponse;
|
||||
}
|
||||
resp = r;
|
||||
}, (err) => {
|
||||
resp = err.error;
|
||||
if (err.status === 401) {
|
||||
this.unauth();
|
||||
}
|
||||
callback(resp);
|
||||
}, () => {
|
||||
callback(resp);
|
||||
});
|
||||
}
|
||||
|
||||
async APIPutAsync(path: string, body: any): Promise<any> {
|
||||
return await this.http.put(`${ApiService.extractBaseHref()}/${path}`, body).toPromise();
|
||||
}
|
||||
|
||||
APIPost(path: string, body: any, callback: (any) => void): any {
|
||||
ApiService.totalRequests++;
|
||||
|
||||
let resp;
|
||||
|
||||
this.http.post(`${ApiService.extractBaseHref()}${path}`, body).subscribe((r) => {
|
||||
if (r === undefined || r === null) {
|
||||
resp = this.emptyResponse;
|
||||
}
|
||||
resp = r;
|
||||
}, (err) => {
|
||||
resp = err.error;
|
||||
if (err.status === 401) {
|
||||
this.unauth();
|
||||
}
|
||||
callback(resp);
|
||||
}, () => {
|
||||
callback(resp);
|
||||
});
|
||||
}
|
||||
|
||||
async APIPostAsync(path: string, body: any): Promise<any> {
|
||||
return await this.http.post(`${ApiService.extractBaseHref()}/${path}`, body).toPromise();
|
||||
}
|
||||
|
||||
APIDelete(path: string, body: any, callback: (any) => void): any {
|
||||
ApiService.totalRequests++;
|
||||
|
||||
const opts = {
|
||||
headers: null,
|
||||
body: body
|
||||
};
|
||||
|
||||
let resp;
|
||||
|
||||
this.http.delete(`${ApiService.extractBaseHref()}/${path}`, opts).subscribe((r) => {
|
||||
if (r === undefined || r === null) {
|
||||
r = this.emptyResponse;
|
||||
}
|
||||
resp = r;
|
||||
}, (err) => {
|
||||
resp = err.error;
|
||||
if (err.status === 401) {
|
||||
this.unauth();
|
||||
}
|
||||
callback(resp);
|
||||
}, () => {
|
||||
callback(resp);
|
||||
});
|
||||
}
|
||||
|
||||
async APIDeleteAsync(path: string, body: any): Promise<any> {
|
||||
return await this.http.delete(`${ApiService.extractBaseHref()}${path}`, body).toPromise();
|
||||
}
|
||||
|
||||
APIDownload(fullpath: string, filename: string): void {
|
||||
ApiService.totalRequests++;
|
||||
|
||||
const body = {
|
||||
filename: fullpath
|
||||
};
|
||||
|
||||
this.http.post(`${ApiService.extractBaseHref()}/api/download`, body, {responseType: 'blob'}).subscribe((r) => {
|
||||
const url = window.URL.createObjectURL(r);
|
||||
const a = document.createElement('a');
|
||||
document.body.appendChild(a);
|
||||
a.setAttribute('style', 'display: none');
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
a.remove();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class hcxdumptoolService {
|
||||
constructor() {}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "hcxdumptool",
|
||||
"title": "Hcxdumptool",
|
||||
"description": "Small tool to capture packets from wlan devices.",
|
||||
"version": "1.0",
|
||||
"author": "lorenzoPrimi",
|
||||
"firmware_required": "1.0.0",
|
||||
"devices": ["wifipineapplemk7", "wifipineappleent1"]
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
from logging import Logger
|
||||
from typing import List, Optional, Union, Tuple
|
||||
|
||||
from pineapple.modules import Module, Request
|
||||
from pineapple.helpers.opkg_helpers import OpkgJob
|
||||
from pineapple.helpers import opkg_helpers as opkg
|
||||
import pineapple.helpers.notification_helpers as notifier
|
||||
from pineapple.helpers import network_helpers as net
|
||||
from pineapple.jobs import JobManager, Job
|
||||
|
||||
|
||||
module = Module('hcxdumptool', logging.DEBUG)
|
||||
job_manager = JobManager(name='hcxdumptool', module=module, log_level=logging.DEBUG)
|
||||
|
||||
PCAP_DIRECTORY_PATH = '/root/.hcxdumptool'
|
||||
PCAP_DIRECTORY = pathlib.Path(PCAP_DIRECTORY_PATH)
|
||||
|
||||
|
||||
class PcapJob(Job[bool]):
|
||||
|
||||
def __init__(self, command: List[str], file_name: str):
|
||||
super().__init__()
|
||||
self.file_name = file_name
|
||||
self.command = command
|
||||
self.pcap_file = f'{PCAP_DIRECTORY_PATH}/{file_name}'
|
||||
self.proc = None
|
||||
|
||||
def do_work(self, logger: Logger) -> bool:
|
||||
logger.debug('hcxdumptool job started.')
|
||||
output_file = open('/tmp/hcxdumptool.log', 'w')
|
||||
stderr_file = open('/tmp/hcxdumptool-err.log', 'w')
|
||||
|
||||
logger.debug(f'Calling hcxdumptool and writing output to {self.pcap_file}')
|
||||
self.command += ['-o', self.pcap_file]
|
||||
subprocess.call(self.command, stdout=output_file, stderr=stderr_file)
|
||||
|
||||
logger.debug('Scan completed.')
|
||||
|
||||
return True
|
||||
|
||||
def stop(self):
|
||||
os.system('killall -9 hcxdumptool')
|
||||
|
||||
|
||||
def _get_last_background_job() -> dict:
|
||||
last_job_id: Optional[str] = None
|
||||
last_job_type: Optional[str] = None
|
||||
last_job_info: Optional[str] = None
|
||||
|
||||
if len(job_manager.jobs) > 0:
|
||||
last_job_id = list(job_manager.jobs.keys())[-1]
|
||||
last_job = job_manager.get_job(last_job_id, remove_if_complete=False)
|
||||
if type(last_job) is PcapJob:
|
||||
last_job_type = 'pcap'
|
||||
last_job_info = last_job.file_name
|
||||
elif type(last_job) is OpkgJob:
|
||||
last_job_type = 'opkg'
|
||||
else:
|
||||
last_job_type = 'unknown'
|
||||
|
||||
return {
|
||||
'job_id': last_job_id,
|
||||
'job_type': last_job_type,
|
||||
'job_info': last_job_info
|
||||
}
|
||||
|
||||
|
||||
def _notify_dependencies_finished(job: OpkgJob):
|
||||
if not job.was_successful:
|
||||
module.send_notification(job.error, notifier.ERROR)
|
||||
elif job.install:
|
||||
module.send_notification('hcxdumptool finished installing.', notifier.INFO)
|
||||
|
||||
|
||||
@module.on_start()
|
||||
def make_history_directory():
|
||||
path = pathlib.Path(PCAP_DIRECTORY_PATH)
|
||||
|
||||
if not path.exists():
|
||||
path.mkdir(parents=True)
|
||||
|
||||
|
||||
@module.on_shutdown()
|
||||
def stop_hcxdumptool(signal: int = None):
|
||||
if len(list(filter(lambda job_runner: job_runner.running is True, job_manager.jobs.values()))) > 0:
|
||||
module.logger.debug('Stopping hcxdumptool.')
|
||||
os.system('killall -9 hcxdumptool')
|
||||
|
||||
|
||||
@module.handles_action('check_dependencies')
|
||||
def check_dependencies(request: Request):
|
||||
return opkg.check_if_installed('hcxdumptool', module.logger)
|
||||
|
||||
|
||||
@module.handles_action('manage_dependencies')
|
||||
def manage_dependencies(request: Request):
|
||||
return {'job_id': job_manager.execute_job(OpkgJob('hcxdumptool', request.install), callbacks=[_notify_dependencies_finished])}
|
||||
|
||||
|
||||
@module.handles_action('start_capture')
|
||||
def start_capture(request: Request):
|
||||
command = request.command.split(' ')
|
||||
|
||||
filename = f"{datetime.now().strftime('%Y-%m-%dT%H-%M-%S')}.pcap"
|
||||
|
||||
job_id = job_manager.execute_job(PcapJob(command, filename))
|
||||
return {'job_id': job_id, 'output_file': filename}
|
||||
|
||||
|
||||
@module.handles_action('stop_capture')
|
||||
def stop_capture(request: Request):
|
||||
stop_hcxdumptool()
|
||||
return True
|
||||
|
||||
|
||||
@module.handles_action('list_capture_history')
|
||||
def list_capture_history(request: Request):
|
||||
return [item.name for item in PCAP_DIRECTORY.iterdir() if item.is_file()]
|
||||
|
||||
|
||||
@module.handles_action('get_capture_output')
|
||||
def get_capture_output(request: Request):
|
||||
output_path = f'{PCAP_DIRECTORY_PATH}/{request.output_file}'
|
||||
if not os.path.exists(output_path):
|
||||
return 'Could not find scan output.', False
|
||||
|
||||
with open(output_path, 'r') as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
@module.handles_action('get_log_content')
|
||||
def get_log_content(request: Request):
|
||||
if not os.path.exists('/tmp/hcxdumptool.log'):
|
||||
return 'Could not find log output: /tmp/hcxdumptool.log', False
|
||||
|
||||
with open('/tmp/hcxdumptool.log', 'r') as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
@module.handles_action('delete_capture')
|
||||
def delete_capture(request: Request):
|
||||
output_path = pathlib.Path(f'{PCAP_DIRECTORY_PATH}/{request.output_file}')
|
||||
if output_path.exists() and output_path.is_file():
|
||||
output_path.unlink()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@module.handles_action('delete_all')
|
||||
def delete_all(request: Request):
|
||||
for item in PCAP_DIRECTORY.iterdir():
|
||||
if item.is_file():
|
||||
item.unlink()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@module.handles_action('startup')
|
||||
def startup(request: Request):
|
||||
return {
|
||||
'has_dependencies': opkg.check_if_installed('hcxdumptool', module.logger),
|
||||
'interfaces': net.get_interfaces(),
|
||||
'last_job': _get_last_background_job()
|
||||
}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
module.start()
|
|
@ -0,0 +1 @@
|
|||
<svg id="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><path d="M0 0h48v48h-48z" fill="none"/><path d="M41 19c.56 0 1.09.08 1.63.16l5.37-7.16c-6.69-5.02-15-8-24-8s-17.31 2.98-24 8l24 32 7-9.33v-5.67c0-5.52 4.48-10 10-10zm5 13v-3c0-2.76-2.24-5-5-5s-5 2.24-5 5v3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-8c0-1.1-.9-2-2-2zm-2 0h-6v-3c0-1.66 1.34-3 3-3s3 1.34 3 3v3z"/></svg>
|
After Width: | Height: | Size: 396 B |
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Public API Surface of hcxdumptool
|
||||
*/
|
||||
|
||||
export * from './lib/services/hcxdumptool.service';
|
||||
export * from './lib/components/hcxdumptool.component';
|
||||
export * from './lib/hcxdumptool.module';
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"inlineSources": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2018"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"fullTemplateTypeCheck": true,
|
||||
"strictInjectionParameters": true,
|
||||
"enableResourceInlining": true
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"lib",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"lib",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2015",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
],
|
||||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
],
|
||||
"paths": {
|
||||
"hcxdumptool": [
|
||||
"dist/hcxdumptool"
|
||||
],
|
||||
"hcxdumptool/*": [
|
||||
"dist/hcxdumptool/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"fullTemplateTypeCheck": true,
|
||||
"strictInjectionParameters": true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
"extends": "tslint:recommended",
|
||||
"rulesDirectory": [
|
||||
"codelyzer"
|
||||
],
|
||||
"rules": {
|
||||
"array-type": false,
|
||||
"arrow-parens": false,
|
||||
"deprecation": {
|
||||
"severity": "warning"
|
||||
},
|
||||
"import-blacklist": [
|
||||
true,
|
||||
"rxjs/Rx"
|
||||
],
|
||||
"interface-name": false,
|
||||
"max-classes-per-file": false,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
],
|
||||
"member-access": false,
|
||||
"member-ordering": [
|
||||
true,
|
||||
{
|
||||
"order": [
|
||||
"static-field",
|
||||
"instance-field",
|
||||
"static-method",
|
||||
"instance-method"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-consecutive-blank-lines": false,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-empty": false,
|
||||
"no-inferrable-types": [
|
||||
true,
|
||||
"ignore-params"
|
||||
],
|
||||
"no-non-null-assertion": true,
|
||||
"no-redundant-jsdoc": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-var-requires": false,
|
||||
"object-literal-key-quotes": [
|
||||
true,
|
||||
"as-needed"
|
||||
],
|
||||
"object-literal-sort-keys": false,
|
||||
"ordered-imports": false,
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"trailing-comma": false,
|
||||
"component-class-suffix": true,
|
||||
"contextual-lifecycle": true,
|
||||
"directive-class-suffix": true,
|
||||
"no-conflicting-lifecycle": true,
|
||||
"no-host-metadata-property": true,
|
||||
"no-input-rename": true,
|
||||
"no-inputs-metadata-property": true,
|
||||
"no-output-native": true,
|
||||
"no-output-on-prefix": true,
|
||||
"no-output-rename": true,
|
||||
"no-outputs-metadata-property": true,
|
||||
"template-banana-in-box": true,
|
||||
"template-no-negated-async": true,
|
||||
"use-lifecycle-interface": true,
|
||||
"use-pipe-transform-interface": true
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue