Add BlackIP v1.0.0
parent
64d07e7b20
commit
45ea4c59d9
|
@ -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": {
|
||||||
|
"BlackIP": {
|
||||||
|
"projectType": "library",
|
||||||
|
"root": "projects/BlackIP",
|
||||||
|
"sourceRoot": "projects/BlackIP/src",
|
||||||
|
"prefix": "lib",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "projects/BlackIP/tsconfig.lib.json",
|
||||||
|
"project": "projects/BlackIP/ng-package.json"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"tsConfig": "projects/BlackIP/tsconfig.lib.prod.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "projects/BlackIP/src/test.ts",
|
||||||
|
"tsConfig": "projects/BlackIP/tsconfig.spec.json",
|
||||||
|
"karmaConfig": "projects/BlackIP/karma.conf.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"projects/BlackIP/tsconfig.lib.json",
|
||||||
|
"projects/BlackIP/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
"defaultProject": "BlackIP"
|
||||||
|
}
|
|
@ -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": "BlackIP",
|
||||||
|
"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/BlackIP",
|
||||||
|
"lib": {
|
||||||
|
"entryFile": "src/public-api.ts"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "BlackIP",
|
||||||
|
"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,27 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
import { BlackIPComponent } from './components/BlackIP.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: BlackIPComponent }
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [BlackIPComponent],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
RouterModule.forChild(routes),
|
||||||
|
MaterialModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
FormsModule,
|
||||||
|
],
|
||||||
|
exports: [BlackIPComponent]
|
||||||
|
})
|
||||||
|
export class BlackIPModule { }
|
|
@ -0,0 +1,60 @@
|
||||||
|
<div style="display: flex; justify-content: center; align-items: center;">
|
||||||
|
<span *ngIf="!hasInit" style="display: flex; justify-content: center; align-items: center; height: 10vh;">
|
||||||
|
<mat-spinner diameter="25"></mat-spinner>
|
||||||
|
</span>
|
||||||
|
<mat-card *ngIf="hasInit" style="width: 40%;">
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-card-title style="text-align: center;">BlackIP</mat-card-title>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<br>
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<div style="width: 45%;">
|
||||||
|
<i style="color: grey;"><small>IPv4 Blacklist</small></i>
|
||||||
|
<textarea style="width: 100%; height: 150px; background-color: #efefef; border-color: #cecece; border-radius: 2px; resize: vertical;" disabled>{{ addresses4 }}</textarea>
|
||||||
|
</div>
|
||||||
|
<div style="width: 45%;">
|
||||||
|
<i style="color: grey;"><small>IPv6 Blacklist</small></i>
|
||||||
|
<textarea style="width: 100%; height: 150px; background-color: #efefef; border-color: #cecece; border-radius: 2px; resize: vertical;" disabled>{{ addresses6 }}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<mat-form-field style="width: 75%;">
|
||||||
|
<mat-label>IP Address (Local Or Public)</mat-label>
|
||||||
|
<input class="control-input" matInput [(ngModel)]="userIP"/>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field style="width: 15%">
|
||||||
|
<mat-label>IPv4/IPv6</mat-label>
|
||||||
|
<mat-select [(ngModel)]="userType">
|
||||||
|
<mat-option value="">--</mat-option>
|
||||||
|
<mat-option value="4">IPv4</mat-option>
|
||||||
|
<mat-option value="6">IPv6</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<button style="width: 45%; height: 5vh;" mat-flat-button color="accent" (click)="add();">
|
||||||
|
<span *ngIf="!isAdding">Add</span>
|
||||||
|
<span *ngIf="isAdding" style="display: flex; justify-content: center; align-items: center; height: 5vh;">
|
||||||
|
<mat-spinner diameter="20"></mat-spinner>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button style="width: 45%; height: 5vh; background-color: red;" mat-flat-button color="accent" (click)="clear();">
|
||||||
|
<span *ngIf="!isResetting">Clear</span>
|
||||||
|
<span *ngIf="isResetting" style="display: flex; justify-content: center; align-items: center; height: 5vh;">
|
||||||
|
<mat-spinner diameter="20"></mat-spinner>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div style="display: flex; justify-content: space-evenly; align-items: center;">
|
||||||
|
<button style="width: 100%; height: 5vh;" mat-flat-button color="accent" (click)="update();">
|
||||||
|
<span *ngIf="!isUpdating">Update Firewall</span>
|
||||||
|
<span *ngIf="isUpdating" style="display: flex; justify-content: center; align-items: center; height: 5vh;">
|
||||||
|
<mat-spinner diameter="20"></mat-spinner>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<span style="display: flex; justify-content: center; align-items: center;"><small>{{ error }}</small></span>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
|
@ -0,0 +1,107 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ApiService } from '../services/api.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'lib-BlackIP',
|
||||||
|
templateUrl: './BlackIP.component.html',
|
||||||
|
styleUrls: ['./BlackIP.component.css']
|
||||||
|
})
|
||||||
|
export class BlackIPComponent implements OnInit {
|
||||||
|
constructor(private API: ApiService) { }
|
||||||
|
|
||||||
|
error = "";
|
||||||
|
addresses4 = "";
|
||||||
|
addresses6 = "";
|
||||||
|
|
||||||
|
userIP = "";
|
||||||
|
userType = "";
|
||||||
|
hasInit: boolean = false;
|
||||||
|
isAdding: boolean = false;
|
||||||
|
isResetting: boolean = false;
|
||||||
|
isUpdating: boolean = false;
|
||||||
|
|
||||||
|
init(): void {
|
||||||
|
this.API.request({
|
||||||
|
module: 'BlackIP',
|
||||||
|
action: "init"
|
||||||
|
}, (response) => {
|
||||||
|
if (response != "ok") {
|
||||||
|
this.error = response;
|
||||||
|
} else {
|
||||||
|
this.hasInit = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
get4(): void {
|
||||||
|
this.API.request({
|
||||||
|
module: 'BlackIP',
|
||||||
|
action: "get4"
|
||||||
|
}, (response) => {
|
||||||
|
this.addresses4 = response;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
get6(): void {
|
||||||
|
this.API.request({
|
||||||
|
module: 'BlackIP',
|
||||||
|
action: "get6"
|
||||||
|
}, (response) => {
|
||||||
|
this.addresses6 = response;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
add(): void {
|
||||||
|
this.isAdding = true;
|
||||||
|
this.API.request({
|
||||||
|
module: 'BlackIP',
|
||||||
|
action: "add",
|
||||||
|
user_ip: this.userIP,
|
||||||
|
user_type: this.userType
|
||||||
|
}, (response) => {
|
||||||
|
if (response != "ok") {
|
||||||
|
this.error = response;
|
||||||
|
} else {
|
||||||
|
this.userIP = "";
|
||||||
|
this.get4();
|
||||||
|
this.get6();
|
||||||
|
}
|
||||||
|
this.isAdding = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(): void {
|
||||||
|
this.isResetting = true;
|
||||||
|
this.API.request({
|
||||||
|
module: 'BlackIP',
|
||||||
|
action: "clear"
|
||||||
|
}, (response) => {
|
||||||
|
if (response != "ok") {
|
||||||
|
this.error = response;
|
||||||
|
} else {
|
||||||
|
this.get4();
|
||||||
|
this.get6();
|
||||||
|
}
|
||||||
|
this.isResetting = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
update(): void {
|
||||||
|
this.isUpdating = true;
|
||||||
|
this.API.request({
|
||||||
|
module: 'BlackIP',
|
||||||
|
action: "update"
|
||||||
|
}, (response) => {
|
||||||
|
if (response != "ok") {
|
||||||
|
this.error = response;
|
||||||
|
}
|
||||||
|
this.isUpdating = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.init();
|
||||||
|
this.get4();
|
||||||
|
this.get6();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,8 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class BlackIPService {
|
||||||
|
constructor() {}
|
||||||
|
}
|
|
@ -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,10 @@
|
||||||
|
{
|
||||||
|
"name": "BlackIP",
|
||||||
|
"title": "BlackIP",
|
||||||
|
"description": "Blacklist IP addresses and refuse their traffic",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": "90N45",
|
||||||
|
"firmware_required": "1.0.0",
|
||||||
|
"devices": ["wifipineapplemk7"]
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from pineapple.modules import Module, Request
|
||||||
|
|
||||||
|
module = Module('BlackIP', logging.DEBUG)
|
||||||
|
|
||||||
|
addresses_4 = []
|
||||||
|
addresses_6 = []
|
||||||
|
|
||||||
|
@module.handles_action("init")
|
||||||
|
def init(request):
|
||||||
|
try:
|
||||||
|
blacklist = str(os.popen("ipset list").read())
|
||||||
|
if not "Name: blacklist" in blacklist:
|
||||||
|
subprocess.run(["ipset", "create", "blacklist", "hash:ip", "hashsize", "4096"])
|
||||||
|
subprocess.run(["ipset", "create", "blacklist6", "hash:net", "hashsize", "4096", "family", "inet6"])
|
||||||
|
subprocess.run(["iptables", "-I", "FORWARD", "-m", "set", "--match-set", "blacklist", "src", "-j", "DROP",])
|
||||||
|
subprocess.run(["iptables", "-I", "FORWARD", "-m", "set", "--match-set", "blacklist6", "src", "-j", "DROP",])
|
||||||
|
return "ok"
|
||||||
|
except Exception as e:
|
||||||
|
return "Error: " + str(e)
|
||||||
|
|
||||||
|
@module.handles_action("add")
|
||||||
|
def add_ip(request):
|
||||||
|
if request.user_ip == "":
|
||||||
|
return "Please specify an IP address"
|
||||||
|
elif request.user_type == "":
|
||||||
|
return "Please specify IPv4 or IPv6"
|
||||||
|
elif request.user_ip == "" and request.user_type == "":
|
||||||
|
return "Please specify an IP address and IPv4 or IPv6"
|
||||||
|
elif request.user_type == "4":
|
||||||
|
addresses_4.append(request.user_ip)
|
||||||
|
return "ok"
|
||||||
|
elif request.user_type == "6":
|
||||||
|
addresses_6.append(request.user_ip)
|
||||||
|
return "ok"
|
||||||
|
|
||||||
|
@module.handles_action("get4")
|
||||||
|
def fetch_blacklist4(request):
|
||||||
|
try:
|
||||||
|
blacklist = ""
|
||||||
|
for address in addresses_4:
|
||||||
|
blacklist = blacklist + address + "\n"
|
||||||
|
return blacklist
|
||||||
|
except Exception as e:
|
||||||
|
return "Error: " + str(e)
|
||||||
|
|
||||||
|
@module.handles_action("get6")
|
||||||
|
def fetch_blacklist6(request):
|
||||||
|
try:
|
||||||
|
blacklist = ""
|
||||||
|
for address in addresses_6:
|
||||||
|
blacklist = blacklist + address + "\n"
|
||||||
|
return blacklist
|
||||||
|
except Exception as e:
|
||||||
|
return "Error: " + str(e)
|
||||||
|
|
||||||
|
@module.handles_action("clear")
|
||||||
|
def clear_blacklist(request):
|
||||||
|
addresses_4.clear()
|
||||||
|
addresses_6.clear()
|
||||||
|
return "ok"
|
||||||
|
|
||||||
|
@module.handles_action("update")
|
||||||
|
def update(request):
|
||||||
|
try:
|
||||||
|
blacklist = ""
|
||||||
|
subprocess.run(["ipset", "flush", "blacklist"])
|
||||||
|
subprocess.run(["ipset", "flush", "blacklist6"])
|
||||||
|
|
||||||
|
for address in addresses_4:
|
||||||
|
subprocess.run(["ipset", "add", "blacklist", address])
|
||||||
|
for address in addresses_6:
|
||||||
|
subprocess.run(["ipset", "add", "blacklist6", address])
|
||||||
|
return "ok"
|
||||||
|
except Exception as e:
|
||||||
|
return "Error: " + str(e)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
module.start()
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg height="100%" stroke-miterlimit="10" style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;" version="1.1" viewBox="0 0 1024 1024" width="100%" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<defs/>
|
||||||
|
<g id="Ebene-1">
|
||||||
|
<path d="M512 49.5C256.568 49.5 49.5 256.568 49.5 512C49.5 767.432 256.568 974.5 512 974.5C767.432 974.5 974.5 767.432 974.5 512C974.5 256.568 767.432 49.5 512 49.5ZM512 162C588.122 162 658.502 186.388 715.938 227.656L227.656 715.938C186.388 658.502 162 588.122 162 512C162 318.7 318.7 162 512 162ZM797.375 309.5C838.018 366.671 862 436.513 862 512C862 705.3 705.3 862 512 862C436.513 862 366.671 838.018 309.5 797.375L797.375 309.5Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="none"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 970 B |
|
@ -0,0 +1,7 @@
|
||||||
|
/*
|
||||||
|
* Public API Surface of BlackIP
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './lib/services/BlackIP.service';
|
||||||
|
export * from './lib/components/BlackIP.component';
|
||||||
|
export * from './lib/BlackIP.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": {
|
||||||
|
"BlackIP": [
|
||||||
|
"dist/BlackIP"
|
||||||
|
],
|
||||||
|
"BlackIP/*": [
|
||||||
|
"dist/BlackIP/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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