Add wpasec module
parent
76469b8f0c
commit
83442d757e
|
@ -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": {
|
||||
"wpasec": {
|
||||
"projectType": "library",
|
||||
"root": "projects/wpasec",
|
||||
"sourceRoot": "projects/wpasec/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||
"options": {
|
||||
"tsConfig": "projects/wpasec/tsconfig.lib.json",
|
||||
"project": "projects/wpasec/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "projects/wpasec/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "projects/wpasec/src/test.ts",
|
||||
"tsConfig": "projects/wpasec/tsconfig.spec.json",
|
||||
"karmaConfig": "projects/wpasec/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"projects/wpasec/tsconfig.lib.json",
|
||||
"projects/wpasec/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}},
|
||||
"defaultProject": "wpasec"
|
||||
}
|
|
@ -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": "wpasec",
|
||||
"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/wpasec",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "wpasec",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^8.2.14",
|
||||
"@angular/core": "^8.2.14"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "ng build --prod"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
This file is a placeholder for module assets that you may like to add.
|
|
@ -0,0 +1,51 @@
|
|||
<mat-card>
|
||||
<mat-card-title>WpaSec Handshake Submitter</mat-card-title>
|
||||
<mat-card-content>
|
||||
<mat-form-field>
|
||||
<mat-label>Your WpaSec Key</mat-label>
|
||||
<input matInput [(ngModel)]="apiKey" />
|
||||
<br />
|
||||
</mat-form-field>
|
||||
<button mat-flat-button color="accent" (click)="saveApiKey();">
|
||||
Save
|
||||
</button>
|
||||
<i>(you can get it from https://wpa-sec.stanev.org/?get_key)</i>
|
||||
<br />
|
||||
<br />
|
||||
<span>Result: {{ apiResponse }}</span>
|
||||
<br />
|
||||
<button mat-flat-button color="accent" (click)="submitWpaHandshakes();">
|
||||
Submit Selected Handshakes
|
||||
</button>
|
||||
<table mat-table class="lessons-table mat-elevation-z8" style="min-width: 100%;" matSort matSortDisableClear
|
||||
matSortDirection="asc" [dataSource]="handshakes" multiTemplateDataRows>
|
||||
<ng-container matColumnDef="select" sticky>
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox [checked]="selection.length > 0 && isAllSelected()"
|
||||
[indeterminate]="selection.length > 0 && !isAllSelected()" (change)="toggleAll()">
|
||||
</mat-checkbox>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let lesson" (click)="$event.stopPropagation()">
|
||||
<mat-checkbox (change)="onLessonToggled(lesson)" [checked]="selection.includes(lesson)">
|
||||
</mat-checkbox>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="mac">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>MAC</th>
|
||||
<td mat-cell *matCellDef="let lesson">{{lesson.mac}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="client">
|
||||
<th mat-header-cell *matHeaderCellDef>Client</th>
|
||||
<td class="duration-cell" mat-cell *matCellDef="let lesson">{{lesson.client}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="timestamp">
|
||||
<th mat-header-cell *matHeaderCellDef>Timestamp</th>
|
||||
<td class="duration-cell" mat-cell *matCellDef="let lesson">{{lesson.timestamp}}</td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky:true">
|
||||
</tr>
|
||||
<tr mat-row (click)="onToggleLesson(lesson)" *matRowDef="let lesson;columns:displayedColumns">
|
||||
</tr>
|
||||
</table>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
|
@ -0,0 +1,97 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Handshake } from '../model/handshake';
|
||||
import { ApiService } from '../services/api.service';
|
||||
|
||||
@Component({
|
||||
selector: 'lib-wpasec',
|
||||
templateUrl: './wpasec.component.html',
|
||||
styleUrls: ['./wpasec.component.css']
|
||||
})
|
||||
export class wpasecComponent implements OnInit {
|
||||
constructor(private API: ApiService) { }
|
||||
|
||||
apiResponse = '';
|
||||
apiKey = '';
|
||||
|
||||
handshakes: Handshake[] = [];
|
||||
submitted_handshakes: Handshake[] = [];
|
||||
|
||||
selection: Handshake[] = [];
|
||||
displayedColumns = ['select', 'mac', 'client', 'timestamp'];
|
||||
expandedLesson: Handshake | null;
|
||||
|
||||
saveApiKey(): void {
|
||||
this.API.request({
|
||||
module: 'wpasec',
|
||||
action: 'save_api_key',
|
||||
api_key: this.apiKey
|
||||
}, (response) => {
|
||||
this.apiResponse = JSON.stringify(response);
|
||||
});
|
||||
}
|
||||
|
||||
toggleArrayItem(array: any[], item: any) {
|
||||
const index = array.indexOf(item);
|
||||
if (index > -1) {
|
||||
array.splice(index, 1);
|
||||
} else {
|
||||
array.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
onLessonToggled(lesson: Handshake) {
|
||||
this.toggleArrayItem(this.selection, lesson);
|
||||
console.log(this.selection);
|
||||
}
|
||||
|
||||
onToggleLesson(lesson: Handshake) {
|
||||
console.log(lesson);
|
||||
}
|
||||
|
||||
isAllSelected() {
|
||||
return this.selection.length == this.handshakes.length;
|
||||
}
|
||||
|
||||
toggleAll() {
|
||||
if (this.isAllSelected()) {
|
||||
this.selection = [];
|
||||
}
|
||||
else {
|
||||
this.selection = this.handshakes.slice();
|
||||
}
|
||||
}
|
||||
|
||||
getWpaHandshakes(): void {
|
||||
this.API.APIGet(
|
||||
'/api/pineap/handshakes',
|
||||
(response) => {
|
||||
this.handshakes = response.handshakes;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
submitWpaHandshakes(): void {
|
||||
this.API.request({
|
||||
module: 'wpasec',
|
||||
action: 'submit_handshakes',
|
||||
handshakes: this.selection
|
||||
}, (response) => {
|
||||
this.apiResponse = JSON.stringify(response);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.API.request({
|
||||
module: 'wpasec',
|
||||
action: 'get_api_key'
|
||||
}, (response) => {
|
||||
if (response.api_key)
|
||||
this.apiKey = response.api_key;
|
||||
});
|
||||
|
||||
this.getWpaHandshakes();
|
||||
//this.getSubmittedHandshakes();
|
||||
// Filter out already submitted handshakes from the table
|
||||
//this.handshakes = this.handshakes.filter(n => !this.submitted_handshakes.includes(n));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
export interface Handshake {
|
||||
mac: string;
|
||||
client: string;
|
||||
location: string;
|
||||
timestamp: 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 wpasecService {
|
||||
constructor() {}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { wpasecComponent } from './components/wpasec.component';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import {MaterialModule} from './modules/material/material.module';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
|
||||
import {FormsModule} from '@angular/forms';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', component: wpasecComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [wpasecComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild(routes),
|
||||
MaterialModule,
|
||||
FlexLayoutModule,
|
||||
FormsModule,
|
||||
],
|
||||
exports: [wpasecComponent]
|
||||
})
|
||||
export class wpasecModule { }
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "wpasec",
|
||||
"title": "WpaSec",
|
||||
"description": "Provides UI to submit WPA handshakes to https://wpa-sec.stanev.org",
|
||||
"version": "1.0",
|
||||
"author": "makcanca",
|
||||
"firmware_required": "1.0.0",
|
||||
"devices": ["wifipineapplemk7"]
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/env python3
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import subprocess
|
||||
from pineapple.modules import Module, Request
|
||||
from pineapple.helpers.network_helpers import check_for_internet
|
||||
from pineapple.helpers.command_helpers import grep_output
|
||||
|
||||
|
||||
module = Module('wpasec', logging.DEBUG)
|
||||
API_KEY = None
|
||||
STATUS_REPORT = None
|
||||
|
||||
_MODULE_PATH = '/pineapple/ui/modules/wpasec'
|
||||
_ASSETS_PATH = f'{_MODULE_PATH}/assets'
|
||||
|
||||
|
||||
def get_api_key_from_file():
|
||||
"""Set the API key from the API_KEY file"""
|
||||
global API_KEY
|
||||
try:
|
||||
with open(os.path.join(_ASSETS_PATH, 'API_KEY')) as f:
|
||||
API_KEY = f.read().strip()
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
|
||||
def get_report():
|
||||
"""Get json report file that contains submitted handshake paths. If it doesnt exist, create it"""
|
||||
global STATUS_REPORT
|
||||
try:
|
||||
with open(os.path.join(_ASSETS_PATH, 'report.json')) as f:
|
||||
STATUS_REPORT = json.load(f)
|
||||
except Exception:
|
||||
STATUS_REPORT = {"reported": []}
|
||||
with open(os.path.join(_ASSETS_PATH, 'report.json'), 'w') as f:
|
||||
json.dump(STATUS_REPORT, f)
|
||||
|
||||
def submit_handshake(path: str) -> bool:
|
||||
"""Submit handshake to https://wpa-sec.stanev.org with API_KEY as cookie"""
|
||||
try:
|
||||
# Run command 'curl -X POST -F "webfile=xxx" --cookie "key=${wpasec_key}" https://wpa-sec.stanev.org/\?submit;'
|
||||
cmd = f'curl -X POST -F webfile=@{path} --cookie key={API_KEY} https://wpa-sec.stanev.org/?submit'
|
||||
result = subprocess.check_output(cmd.split(' '), encoding='UTF-8')
|
||||
module.logger.debug("Result of submitting handshake: %s", result)
|
||||
return True
|
||||
except Exception as e:
|
||||
module.logger.error('Error submitting handshake: %s', e)
|
||||
return False
|
||||
|
||||
def add_handshake_to_report(path):
|
||||
"""Add handshake to report so we dont submit it twice"""
|
||||
get_report()
|
||||
if path not in STATUS_REPORT["reported"]:
|
||||
STATUS_REPORT["reported"].append(path)
|
||||
with open(os.path.join(_ASSETS_PATH, 'report.json'), 'w') as f:
|
||||
json.dump(STATUS_REPORT, f)
|
||||
|
||||
@module.handles_action('submit_handshakes')
|
||||
def submit_handshakes(request: Request):
|
||||
"""Submit all handshakes to https://wpa-sec.stanev.org with API_KEY as cookie"""
|
||||
if not check_for_internet():
|
||||
return {'status': 'error', 'message': 'No internet connection'}
|
||||
if not API_KEY:
|
||||
return {'status': 'error', 'message': 'No API key set'}
|
||||
get_report()
|
||||
handshake_paths = [handshake['location'] for handshake in request.handshakes]
|
||||
if not handshake_paths:
|
||||
return {'status': 'error', 'message': 'No handshakes found'}
|
||||
for path in handshake_paths:
|
||||
if path not in STATUS_REPORT["reported"]:
|
||||
if submit_handshake(path):
|
||||
add_handshake_to_report(path)
|
||||
return {'status': 'success', 'message': 'Submitted all handshakes'}
|
||||
|
||||
@module.handles_action('save_api_key')
|
||||
def save_api_key(request: Request):
|
||||
"""Save the API key to the API_KEY file"""
|
||||
global API_KEY
|
||||
API_KEY = request.api_key
|
||||
with open(os.path.join(_ASSETS_PATH, 'API_KEY'), 'w') as f:
|
||||
f.write(API_KEY)
|
||||
return {'success': True}
|
||||
|
||||
@module.handles_action('get_api_key')
|
||||
def get_api_key(request: Request):
|
||||
"""Get the API key"""
|
||||
get_api_key_from_file()
|
||||
return {'api_key': API_KEY}
|
||||
|
||||
@module.on_start()
|
||||
def on_start():
|
||||
"""Get the API key on start"""
|
||||
get_api_key_from_file()
|
||||
get_report()
|
||||
|
||||
|
||||
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="M36.7,16.47V11.66c0-3.48-3.13-4.59-5.81-4.67V1.85c7.3,0,11.62,2.49,11.62,9.24v5.35c0,3.42,2.71,5,5.49,5v5.2c-2.78,0-5.49,1.54-5.49,5v5.35c0,6.75-4.32,9.24-11.62,9.24V41c2.68-.08,5.81-1.19,5.81-4.67V31.53c0-4.11,1.75-6.45,4.22-7.53C38.45,22.92,36.7,20.58,36.7,16.47Zm-25.4,0V11.66c0-3.48,3.13-4.59,5.81-4.67V1.85c-7.3,0-11.62,2.49-11.62,9.24v5.35c0,3.42-2.72,5-5.49,5v5.2c2.77,0,5.49,1.54,5.49,5v5.35c0,6.75,4.32,9.24,11.62,9.24V41c-2.68-.08-5.81-1.19-5.81-4.67V31.53c0-4.11-1.75-6.45-4.22-7.53C9.55,22.92,11.3,20.58,11.3,16.47ZM27.38,26.1H20.57v6.48h2.79a4.69,4.69,0,0,1-2.71,4.14l.68,1.46a7.61,7.61,0,0,0,6.05-7.73Zm0-14H20.57v6.81h6.81Z"/></svg>
|
After Width: | Height: | Size: 726 B |
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Public API Surface of wpasec
|
||||
*/
|
||||
|
||||
export * from './lib/services/wpasec.service';
|
||||
export * from './lib/components/wpasec.component';
|
||||
export * from './lib/wpasec.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": {
|
||||
"wpasec": [
|
||||
"dist/wpasec"
|
||||
],
|
||||
"wpasec/*": [
|
||||
"dist/wpasec/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"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