Add locate module. (#42)

* Add locate module.

* Fix version number, return error properly

* Fix handling of error in API response

* Switch lookup API

* Embed country flag image and allow domain names for lookup.

* Fix HTML

Co-authored-by: Marc <foxtrot@malloc.me>
pull/47/head
Theo 2021-07-09 23:39:08 +02:00 committed by GitHub
parent 9f00b8fe15
commit 032fb7a86c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 33117 additions and 0 deletions

13
locate/.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
locate/.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
locate/angular.json Normal file
View File

@ -0,0 +1,47 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"locate": {
"projectType": "library",
"root": "projects/locate",
"sourceRoot": "projects/locate/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/locate/tsconfig.lib.json",
"project": "projects/locate/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/locate/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/locate/src/test.ts",
"tsConfig": "projects/locate/tsconfig.spec.json",
"karmaConfig": "projects/locate/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/locate/tsconfig.lib.json",
"projects/locate/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
}},
"defaultProject": "locate"
}

90
locate/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

32121
locate/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

52
locate/package.json Normal file
View File

@ -0,0 +1,52 @@
{
"name": "locate",
"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/locate",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

@ -0,0 +1,11 @@
{
"name": "locate",
"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,42 @@
.locate-center-card {
display: flex;
justify-content: center;
align-items: center;
}
.locate-button {
display: flex;
justify-content: center;
align-items: center;
height: 4vh;
}
.locate-card {
min-width: 40%;
}
.locate-card-content {
display: flex;
flex-direction: column;
}
.locate-lookup-field {
width: 100%;
}
.locate-results {
display: flex;
justify-content: space-evenly;
}
.locate-results-left {
word-break: break-word;
padding: 1vw;
max-width: 300px;
}
.locate-results-right {
padding: 1vw;
}
.spinner {
display: flex;
justify-content: center;
align-items: center;
height: 4vh;
}

View File

@ -0,0 +1,58 @@
<div class="locate-center-card">
<mat-card class="locate-card">
<mat-card-title>Geolocate IP Address</mat-card-title>
<mat-card-content class="locate-card-content">
<mat-form-field class="locate-lookup-field">
<mat-label> IP address. </mat-label>
<input matInput [(ngModel)]="userInput" />
</mat-form-field>
<div *ngIf="!validIP">
<span><strong>Please enter a valid IP address or domain name!</strong></span>
</div>
<div *ngIf="lookup_ip" class="locate-results">
<br />
<div class="locate-results-left">
<span> <strong>IP:</strong> {{ lookup_ip }} </span>
<br />
<span> <strong>City:</strong> {{ city }} </span>
<br />
<span> <strong>Region:</strong> {{ region }} </span>
<br />
<span> <strong>Country:</strong> {{ country }} </span>
<br />
<span>
<strong>Neighbor Countries:</strong>
{{ country_neighbours }}
</span>
</div>
<div class="locate-results-right">
<span> <strong>Timezone:</strong> {{ timezone }} </span>
<br />
<span style="display: flex; align-items: center">
<strong>Country Flag:</strong>
<div>
<img width="25" height="18" style="margin-left: 0.25em" src="{{ country_flag }}" />
</div>
</span>
<span>
<strong>Coordinates:</strong> {{ coordinates }}
</span>
<br />
<span>
<strong>Calling Code:</strong> {{ country_phone }}
</span>
<br />
<span> <strong>ORG:</strong> {{ org }} </span>
<br />
</div>
</div>
<button mat-flat-button class="macinfo-lookup-button" color="accent" (click)="locate_ip()">
<span *ngIf="!isLoading">Locate IP</span>
<span class="spinner" *ngIf="isLoading">
<mat-spinner diameter="20"></mat-spinner>
</span>
</button>
</mat-card-content>
</mat-card>
</div>

View File

@ -0,0 +1,59 @@
import { Component, OnInit } from "@angular/core";
import { ApiService } from "../services/api.service";
@Component({
selector: "lib-locate",
templateUrl: "./locate.component.html",
styleUrls: ["./locate.component.css"],
})
export class locateComponent implements OnInit {
constructor(private API: ApiService) {}
userInput = "";
iplocation = "";
isLoading: boolean = false;
lookup_ip = "";
city = "";
region = "";
country = "";
country_name = "";
country_capital = "";
timezone = "";
country_neighbours = "";
country_phone = "";
country_flag = "";
org = "";
coordinates = "";
validIP: boolean = true;
locate_ip(): void {
this.isLoading = true;
this.API.request(
{
module: "locate",
action: "locate_ip",
user_input: this.userInput,
},
(response) => {
this.isLoading = false;
this.iplocation = response.iplocation;
this.lookup_ip = response.lookup_ip;
this.city = response.city;
this.region = response.region;
this.country = response.country;
this.country_neighbours = response.country_neighbours;
this.country_capital = response.country_capital;
this.timezone = response.timezone;
this.country_phone = response.country_phone;
this.country_flag = response.country_flag;
this.org = response.org;
this.coordinates = response.coordinates;
if (response.error){
this.validIP = false;
}
}
);
}
ngOnInit() {}
}

View File

@ -0,0 +1,27 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { locateComponent } from './components/locate.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: locateComponent }
];
@NgModule({
declarations: [locateComponent],
imports: [
CommonModule,
RouterModule.forChild(routes),
MaterialModule,
FlexLayoutModule,
FormsModule,
],
exports: [locateComponent]
})
export class locateModule { }

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,185 @@
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';
}
request(payload: any, callback: (any) => void) {
this.setBusy();
let resp;
this.http.post('/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(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(path).toPromise();
}
APIPut(path: string, body: any, callback: (any) => void): any {
ApiService.totalRequests++;
let resp;
this.http.put(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(path, body).toPromise();
}
APIPost(path: string, body: any, callback: (any) => void): any {
ApiService.totalRequests++;
let resp;
this.http.post(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(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(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(path, body).toPromise();
}
APIDownload(fullpath: string, filename: string): void {
ApiService.totalRequests++;
const body = {
filename: fullpath
};
this.http.post('/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 locateService {
constructor() {}
}

View File

@ -0,0 +1,9 @@
{
"name": "locate",
"title": "Locate",
"description": "Geolocate IP addresses over HTTPS via ipapi.",
"version": "1.0",
"author": "KoalaV2",
"firmware_required": "1.0.0"
}

View File

@ -0,0 +1,48 @@
#!/usr/bin/env python3
import logging
from pineapple.modules import Module, Request
import json
import urllib.request
module = Module('locate', logging.DEBUG)
API_LINK = f"https://ipwhois.app/json/"
@module.handles_action('locate_ip')
def locate_ip(request: Request):
ip = request.user_input
module.logger.debug(f"{ip} address is valid.")
module.logger.debug(f"{API_LINK}{ip}")
response = urllib.request.urlopen(f"{API_LINK}/{ip}")
data = response.read()
output_json = json.loads(data)
if output_json['success'] == False:
error_code = output_json['message']
return error_code,False
module.logger.debug(output_json)
lookup_ip = output_json['ip']
city = output_json['city']
region = output_json['region']
country = output_json['country']
country_capital = output_json['country_capital']
timezone = output_json['timezone_name']
country_flag = output_json['country_flag']
country_phone = output_json['country_phone']
longitude = output_json['longitude']
latitude = output_json['latitude']
coordinates = f"{latitude} / {longitude}"
country_neighbours = output_json['country_neighbours']
org = output_json['org']
return {'lookup_ip':lookup_ip,'city':city,'region':region,
'country':country,'country_capital':country_capital,
'timezone':timezone, 'country_flag':country_flag,
'country_phone':country_phone,'coordinates':coordinates,'org':org,'country_neighbours':country_neighbours}
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"><defs><style>.cls-1{fill-rule:evenodd;}</style></defs><path class="cls-1" d="M39.78,29.53c0,.08,0,.16-.09.24-.61.77-13.08,16.26-14.15,17.58a2.14,2.14,0,0,1-3.07,0c-.79-1-13.32-16.5-14.19-17.62-.06-.08,0-.16-.08-.23a19,19,0,1,1,31.58,0ZM24,11.57A7.41,7.41,0,1,0,31.4,19,7.41,7.41,0,0,0,24,11.57Z"/></svg>

After

Width:  |  Height:  |  Size: 373 B

View File

@ -0,0 +1,7 @@
/*
* Public API Surface of locate
*/
export * from './lib/services/locate.service';
export * from './lib/components/locate.component';
export * from './lib/locate.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
locate/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": {
"locate": [
"dist/locate"
],
"locate/*": [
"dist/locate/*"
]
}
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
}

79
locate/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
}
}