Add WiGLE module
parent
03d0424288
commit
36a9ce8098
|
@ -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": {
|
||||||
|
"wigle": {
|
||||||
|
"projectType": "library",
|
||||||
|
"root": "projects/wigle",
|
||||||
|
"sourceRoot": "projects/wigle/src",
|
||||||
|
"prefix": "lib",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "projects/wigle/tsconfig.lib.json",
|
||||||
|
"project": "projects/wigle/ng-package.json"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"tsConfig": "projects/wigle/tsconfig.lib.prod.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "projects/wigle/src/test.ts",
|
||||||
|
"tsConfig": "projects/wigle/tsconfig.spec.json",
|
||||||
|
"karmaConfig": "projects/wigle/karma.conf.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"projects/wigle/tsconfig.lib.json",
|
||||||
|
"projects/wigle/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
"defaultProject": "wigle"
|
||||||
|
}
|
|
@ -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": "wigle",
|
||||||
|
"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/wigle",
|
||||||
|
"lib": {
|
||||||
|
"entryFile": "src/public-api.ts"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "wigle",
|
||||||
|
"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,93 @@
|
||||||
|
<div style="display: flex; justify-content: center; align-items: center;">
|
||||||
|
<mat-card *ngIf="!hasKey" style="width: 40%;">
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-card-title>Welcome To WiGLE</mat-card-title>
|
||||||
|
<mat-card-subtitle>Lets get started.</mat-card-subtitle>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<br>
|
||||||
|
<p>To request data from the WiGLE.net database on your WiFi Pineapple, you need an API token, which is generated when you create a free account at WiGLE.net
|
||||||
|
</p>
|
||||||
|
<br>
|
||||||
|
<mat-form-field style="width: 100%;">
|
||||||
|
<mat-label>Encoded Token</mat-label>
|
||||||
|
<input class="control-input" matInput [(ngModel)]="userKey"/>
|
||||||
|
</mat-form-field>
|
||||||
|
<br>
|
||||||
|
<div style="display: flex; justify-content: center; align-items: center;">
|
||||||
|
<button style="width: 45%; height: 34px; display: flex; justify-content: center; align-items: center;" mat-flat-button color="accent" (click)="saveKey()">
|
||||||
|
<span *ngIf="!isSubmittingKey">Save</span>
|
||||||
|
<span *ngIf="isSubmittingKey">
|
||||||
|
<mat-spinner [diameter]="20"></mat-spinner>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div style="display: flex; justify-content: center; align-items: center;">
|
||||||
|
<span><small>You can find your encoded API token at <a href="https://wigle.net/account">wigle.net/account</a></small></span>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
|
||||||
|
<mat-card *ngIf="hasKey" style="width: 40%;">
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-card-title>WiGLE Lookup</mat-card-title>
|
||||||
|
<div>
|
||||||
|
<div style="display: flex; justify-content: space-evenly;">
|
||||||
|
<mat-form-field style="word-break: break-word; padding: 1vw; width: 49%">
|
||||||
|
<mat-label>Country Code</mat-label>
|
||||||
|
<input class="control-input" matInput [(ngModel)]="userCC"/>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field style="padding: 1vw; width: 49%;">
|
||||||
|
<mat-label>City</mat-label>
|
||||||
|
<input class="control-input" matInput [(ngModel)]="userCity"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: space-evenly;">
|
||||||
|
<mat-form-field style="word-break: break-word; padding: 1vw; width: 49%">
|
||||||
|
<mat-label>SSID</mat-label>
|
||||||
|
<input class="control-input" matInput [(ngModel)]="userSSID"/>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field style="padding: 1vw; width: 49%;">
|
||||||
|
<mat-label>MAC Address</mat-label>
|
||||||
|
<input class="control-input" matInput [(ngModel)]="userMAC"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div *ngIf="apiResponse" style="display: flex; justify-content: space-evenly;">
|
||||||
|
<div style="word-break: break-word; padding: 1vw; max-width: 300px;">
|
||||||
|
<span><strong>SSID: </strong>{{ ssid }}</span>
|
||||||
|
<br>
|
||||||
|
<span><strong>Channel: </strong>{{ channel }}</span>
|
||||||
|
<br>
|
||||||
|
<span><strong>Encryption: </strong>{{ enc }}</span>
|
||||||
|
<br>
|
||||||
|
<span><strong>MAC Address: </strong>{{ mac }}</span>
|
||||||
|
<br>
|
||||||
|
<span><strong>DHCP: </strong>{{ dhcp }}</span>
|
||||||
|
</div>
|
||||||
|
<div style="padding: 1vw;">
|
||||||
|
<span><strong>CC: </strong>{{ country }}</span>
|
||||||
|
<br>
|
||||||
|
<span><strong>City: </strong>{{ city }}</span>
|
||||||
|
<br>
|
||||||
|
<span><strong>Road: </strong>{{ road }}</span>
|
||||||
|
<br>
|
||||||
|
<span><strong>Latitude: </strong>{{ lat }}</span>
|
||||||
|
<br>
|
||||||
|
<span><strong>Longitude: </strong>{{ long }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span style="display: flex; justify-content: center; align-items: center;"><a href="{{ wiglenet }}"><small>{{ msg }}</small></a></span>
|
||||||
|
<br>
|
||||||
|
<div style="display: flex; justify-content: center; align-items: center;">
|
||||||
|
<button style="width: 45%; height: 34px; display: flex; justify-content: center; align-items: center;" mat-flat-button color="accent" (click)="fetch()">
|
||||||
|
<span *ngIf="!isLoading">Search</span>
|
||||||
|
<span *ngIf="isLoading">
|
||||||
|
<mat-spinner [diameter]="20"></mat-spinner>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
|
@ -0,0 +1,106 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ApiService } from '../services/api.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'lib-wigle',
|
||||||
|
templateUrl: './wigle.component.html',
|
||||||
|
styleUrls: ['./wigle.component.css']
|
||||||
|
})
|
||||||
|
export class wigleComponent implements OnInit {
|
||||||
|
constructor(private API: ApiService) { }
|
||||||
|
|
||||||
|
userSSID = "";
|
||||||
|
userMAC = "";
|
||||||
|
userCC = "";
|
||||||
|
userCity = "";
|
||||||
|
userKey = "";
|
||||||
|
apiResponse: boolean = false;
|
||||||
|
isLoading: boolean = false;
|
||||||
|
isSubmittingKey: boolean = false;
|
||||||
|
hasKey: boolean = true;
|
||||||
|
|
||||||
|
msg = "";
|
||||||
|
wiglenet = "https://wigle.net/";
|
||||||
|
ssid = "";
|
||||||
|
channel = "";
|
||||||
|
enc = "";
|
||||||
|
mac = "";
|
||||||
|
dhcp = "";
|
||||||
|
country = "";
|
||||||
|
city = "";
|
||||||
|
road = "";
|
||||||
|
lat = "";
|
||||||
|
long = "";
|
||||||
|
|
||||||
|
fetch(): void {
|
||||||
|
if ((this.userSSID == "") && (this.userMAC == "") && (this.userCC == "") && (this.userCity == "")) {
|
||||||
|
this.msg = "Please specify at least one option...";
|
||||||
|
this.apiResponse = false;
|
||||||
|
} else {
|
||||||
|
this.isLoading = true;
|
||||||
|
this.API.request({
|
||||||
|
module: "wigle",
|
||||||
|
action: "search",
|
||||||
|
user_ssid: this.userSSID,
|
||||||
|
user_mac: this.userMAC,
|
||||||
|
user_cc: this.userCC,
|
||||||
|
user_city: this.userCity
|
||||||
|
}, (response) => {
|
||||||
|
if (response.total > 0) {
|
||||||
|
this.msg = response.Message;
|
||||||
|
this.wiglenet = response.Link;
|
||||||
|
this.ssid = response.SSID;
|
||||||
|
this.channel = response.Channel;
|
||||||
|
this.enc = response.Encryption;
|
||||||
|
this.mac = response.MAC;
|
||||||
|
this.dhcp = response.DHCP;
|
||||||
|
this.country = response.Country;
|
||||||
|
this.city = response.City;
|
||||||
|
this.road = response.Road;
|
||||||
|
this.lat = response.Latitude;
|
||||||
|
this.long = response.Longitude;
|
||||||
|
this.apiResponse = true;
|
||||||
|
} else {
|
||||||
|
this.msg = response.Message;
|
||||||
|
this.wiglenet = "https://wigle.net/";
|
||||||
|
this.apiResponse = false;
|
||||||
|
}
|
||||||
|
this.isLoading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveKey(): void {
|
||||||
|
this.isSubmittingKey = true;
|
||||||
|
this.API.request({
|
||||||
|
module: 'wigle',
|
||||||
|
action: "save",
|
||||||
|
user_key: this.userKey
|
||||||
|
}, (response) => {
|
||||||
|
if (response == "Key saved") {
|
||||||
|
this.hasKey = true;
|
||||||
|
} else {
|
||||||
|
this.hasKey = false;
|
||||||
|
}
|
||||||
|
this.isSubmittingKey = false;
|
||||||
|
})
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
checkKey(): void {
|
||||||
|
this.API.request({
|
||||||
|
module: 'wigle',
|
||||||
|
action: "check"
|
||||||
|
}, (response) => {
|
||||||
|
if (response == "Key specified") {
|
||||||
|
this.hasKey = true;
|
||||||
|
} else {
|
||||||
|
this.hasKey = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.checkKey();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 WigleService {
|
||||||
|
constructor() {}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
import { wigleComponent } from './components/wigle.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: wigleComponent }
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [wigleComponent],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
RouterModule.forChild(routes),
|
||||||
|
MaterialModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
FormsModule,
|
||||||
|
],
|
||||||
|
exports: [wigleComponent]
|
||||||
|
})
|
||||||
|
export class wigleModule { }
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"name": "wigle",
|
||||||
|
"title": "WiGLE",
|
||||||
|
"description": "Information gathering of APs with the WiGLE.net database",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"author": "90N45",
|
||||||
|
"firmware_required": "1.0.0",
|
||||||
|
"devices": ["wifipineapplemk7"]
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import urllib.request
|
||||||
|
import urllib.parse
|
||||||
|
import logging
|
||||||
|
from pineapple.modules import Module, Request
|
||||||
|
import pineapple.helpers.notification_helpers as notifier
|
||||||
|
|
||||||
|
module = Module('wigle', logging.DEBUG)
|
||||||
|
|
||||||
|
@module.handles_action('search')
|
||||||
|
def search_db(request):
|
||||||
|
try:
|
||||||
|
with open("modules/wigle/wigle.key", "r") as file:
|
||||||
|
auth_token = file.read()
|
||||||
|
|
||||||
|
req = urllib.request.Request("https://api.wigle.net/api/v2/network/search?onlymine=false&freenet=false&paynet=false&resultsPerPage=1&country=" + urllib.parse.quote(request.user_cc.upper()) + "&city=" + urllib.parse.quote(request.user_city.title()) + "&ssid=" + urllib.parse.quote(request.user_ssid) + "&netid=" + urllib.parse.quote(request.user_mac), headers={"authorization": "Basic " + auth_token})
|
||||||
|
with urllib.request.urlopen(req) as resp:
|
||||||
|
data = resp.read()
|
||||||
|
resp_dict = json.loads(data)
|
||||||
|
|
||||||
|
if resp_dict.get("success") == True:
|
||||||
|
result = resp_dict.get("results")[0]
|
||||||
|
return {"SSID":str(result.get("ssid")),"Channel":str(result.get("channel")),"Encryption":str(result.get("encryption")).upper(),"MAC":str(result.get("netid")).upper(),"DHCP":str(result.get("dhcp")),"Country":str(result.get("country")),"City":str(result.get("city")),"Road":str(result.get("road")),"Latitude":str(result.get("trilat")),"Longitude":str(result.get("trilong")),"total":resp_dict.get("totalResults"),"Message":"Total results: " + str(resp_dict.get("totalResults")),"Link":"https://wigle.net/search?country=" + request.user_cc.upper() + "&ssid=" + request.user_ssid + "&netid=" + request.user_mac}
|
||||||
|
else:
|
||||||
|
return {"Message":str(resp_dict.get("message")).upper()}
|
||||||
|
except Exception as e:
|
||||||
|
if str(e) == "list index out of range":
|
||||||
|
return {"Message":"Total results: " + str(resp_dict.get("totalResults"))}
|
||||||
|
else:
|
||||||
|
return {"Message":"Error: " + str(e)}
|
||||||
|
|
||||||
|
@module.handles_action('check')
|
||||||
|
def check_api_token(request):
|
||||||
|
try:
|
||||||
|
if os.path.getsize("modules/wigle/wigle.key") == 0:
|
||||||
|
return "Key not specified"
|
||||||
|
else:
|
||||||
|
return "Key specified"
|
||||||
|
except Exception as e:
|
||||||
|
return "Key not specified: " + str(e)
|
||||||
|
|
||||||
|
@module.handles_action('save')
|
||||||
|
def save_api_token(request):
|
||||||
|
try:
|
||||||
|
with open("modules/wigle/wigle.key", "w") as file:
|
||||||
|
file.write(request.user_key)
|
||||||
|
return "Key saved"
|
||||||
|
except Exception as e:
|
||||||
|
return "Key not saved: " + str(e)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
module.start()
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,7 @@
|
||||||
|
/*
|
||||||
|
* Public API Surface of wigle
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './lib/services/wigle.service';
|
||||||
|
export * from './lib/components/wigle.component';
|
||||||
|
export * from './lib/wigle.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": {
|
||||||
|
"wigle": [
|
||||||
|
"dist/wigle"
|
||||||
|
],
|
||||||
|
"wigle/*": [
|
||||||
|
"dist/wigle/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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