Merge pull request #59 from MAkcanca/master

Add wpasec module
pull/66/head
hak5glytch 2022-10-26 12:08:59 -07:00 committed by GitHub
commit a0691e82e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 33279 additions and 0 deletions

13
wpasec/.editorconfig Normal file
View File

@ -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

46
wpasec/.gitignore vendored Normal file
View File

@ -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

47
wpasec/angular.json Normal file
View File

@ -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"
}

90
wpasec/build.sh Executable file
View File

@ -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

32223
wpasec/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

52
wpasec/package.json Normal file
View File

@ -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"
}
}

View File

@ -0,0 +1,7 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/wpasec",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

@ -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"
}
}

View File

@ -0,0 +1 @@
This file is a placeholder for module assets that you may like to add.

View File

@ -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>

View File

@ -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));
}
}

View File

@ -0,0 +1,7 @@
export interface Handshake {
mac: string;
client: string;
location: string;
timestamp: string;
}

View File

@ -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 {
}

View File

@ -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();
});
}
}

View File

@ -0,0 +1,8 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class wpasecService {
constructor() {}
}

View File

@ -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 { }

View File

@ -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"]
}

View File

@ -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()

View File

@ -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

View File

@ -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';

View File

@ -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"
]
}

View File

@ -0,0 +1,6 @@
{
"extends": "./tsconfig.lib.json",
"angularCompilerOptions": {
"enableIvy": false
}
}

View File

@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/spec",
"types": [
"jasmine",
"node"
]
},
"files": [
"src/test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@ -0,0 +1,17 @@
{
"extends": "../../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"lib",
"camelCase"
],
"component-selector": [
true,
"element",
"lib",
"kebab-case"
]
}
}

34
wpasec/tsconfig.json Normal file
View File

@ -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
}
}

79
wpasec/tslint.json Normal file
View File

@ -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
}
}