Skip to content

Commit

Permalink
Merge pull request #23 from devaa-security/u/s5dev/webview-detections
Browse files Browse the repository at this point in the history
Add WebView Common weakness detections
  • Loading branch information
s5dev committed Sep 3, 2023
2 parents 77ffabf + fca67d1 commit d22e884
Show file tree
Hide file tree
Showing 25 changed files with 926 additions and 556 deletions.
8 changes: 4 additions & 4 deletions manifest-scanner/.github/workflows/ci-docs.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: ci
name: ci
on:
push:
branches:
- master
- master
- main
permissions:
contents: write
Expand All @@ -14,12 +14,12 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: 3.x
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v3
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache
restore-keys: |
mkdocs-material-
- run: pip install mkdocs-material
- run: pip install mkdocs-material
- run: mkdocs gh-deploy --force
7 changes: 4 additions & 3 deletions manifest-scanner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
Android Manifest Scanner CLI - DEVAA Security

<!-- toc -->
* [manifest-scanner](#manifest-scanner)
* [Usage](#usage)
* [Commands](#commands)

- [manifest-scanner](#manifest-scanner)
- [Usage](#usage)
- [Commands](#commands)
<!-- tocstop -->

# Usage
Expand Down
1 change: 0 additions & 1 deletion manifest-scanner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
"@oclif/core": "^2",
"@oclif/plugin-help": "^5",
"@oclif/plugin-plugins": "^2.4.4",
"java-parser": "^2.0.4",
"xml2js": "^0.5.0"
},
"devDependencies": {
Expand Down
147 changes: 72 additions & 75 deletions manifest-scanner/src/commands/scan.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
import {Args, Command, Flags} from '@oclif/core'
import {findFileInDirectory, parseXmlFileToJson} from '../utils/fileutils'
import {ManifestPlugin} from '../plugins/ManifestPlugin'
import path = require('path');
const fs = require('fs/promises')
import { Args, Command, Flags } from "@oclif/core";
import { findFileInDirectory, parseXmlFileToJson } from "../utils/fileutils";
import { ManifestPlugin } from "../plugins/ManifestPlugin";
import path = require("path");
const fs = require("fs/promises");

export default class Scan extends Command {
static description =
'DEVAA Manifest Scanner helps to scan for vulnerable configurations in Android Studio Project';
"DEVAA Manifest Scanner helps to scan for vulnerable configurations in Android Studio Project";

issues = [];

static flags = {
// flag with a value (-f, --file=VALUE)
file: Flags.string({
char: 'f',
description: 'Path to the Android Project',
char: "f",
description: "Path to the Android Project",
}),
// flag with no value (-r, --report)
report: Flags.string({
char: 'r',
description: 'Report format (json)',
char: "r",
description: "Report format (json)",
}),
output: Flags.string({
char: 'o',
description: 'Output File Path',
char: "o",
description: "Output File Path",
}),
enableAST: Flags.boolean({
char: 'a',
char: "a",
description:
'Enable AST to parse Android Studio Project Java & Kotlin source code',
"Enable AST to parse Android Studio Project Java & Kotlin source code",
}),
};

Expand All @@ -37,85 +37,82 @@ export default class Scan extends Command {
// }

public async run(): Promise<void> {
const {args, flags} = await this.parse(Scan)
const { args, flags } = await this.parse(Scan);

// throw error if required flags are not provided
if (!flags.file) {
this.error('Please provide a file path')
this.error("Please provide a file path");
}

if (!flags.report) {
this.error('Please provide a report format')
this.error("Please provide a report format");
}

const filePath = findFileInDirectory(flags.file, 'AndroidManifest.xml')
const filePath = findFileInDirectory(flags.file, "AndroidManifest.xml");

if (filePath) {
console.log(`Found file at: ${filePath}`)
console.log(`Found file at: ${filePath}`);
parseXmlFileToJson(filePath)
.then((result: any) => {
// console.log(JSON.stringify(result, null, 2));
const AndroidManifestXML = JSON.parse(
JSON.stringify(result, null, 2),
)
ManifestPlugin.updateManifest(
AndroidManifestXML,
filePath,
flags.file,
flags.enableAST,
)
.then((result: any) => {
// console.log(JSON.stringify(result, null, 2));
const AndroidManifestXML = JSON.parse(
JSON.stringify(result, null, 2)
);
ManifestPlugin.updateManifest(
AndroidManifestXML,
filePath,
flags.file,
flags.enableAST
);

const folders = [path.join(__dirname, '..', 'plugins', 'manifest')];
const folders = [
path.join(__dirname, "..", "plugins", "manifest"),
path.join(__dirname, "..", "plugins", "webview"),
];

(async () => {
for (const folder of folders) {
let files = await fs.readdir(folder)
files = files.filter(
(file: any) => file.endsWith('.js') || !file.endsWith('.d.ts'),
)
(async () => {
for (const folder of folders) {
let files = await fs.readdir(folder);
files = files.filter(
(file: any) => file.endsWith(".js") || !file.endsWith(".d.ts")
);

for (const file of files) {
// console.log(folder + "/" + file);
const fileWithoutExtension = file.split('.')[0]
const filePath = path.join(
__dirname,
'..',
'plugins',
'manifest',
fileWithoutExtension,
)
const {default: Rule} = await import(filePath)
const rule = new Rule()
rule.run()
// console.log(rule.issues);
this.issues = this.issues.concat(rule.issues)
for (const file of files) {
// console.log(folder + "/" + file);
const fileWithoutExtension = file.split(".")[0];
const filePath = path.join(folder, fileWithoutExtension);
const { default: Rule } = await import(filePath);
const rule = new Rule();
rule.run();
// console.log(rule.issues);
this.issues = this.issues.concat(rule.issues);
}
}
}
})()
.then(() => {
console.log(this.issues)
if (flags.output) {
fs.writeFile(
flags.output,
JSON.stringify(this.issues, null, 2),
function (err: any) {
if (err) throw err
console.log('Saved!')
},
)
}
})()
.then(() => {
console.log(this.issues);
if (flags.output) {
fs.writeFile(
flags.output,
JSON.stringify(this.issues, null, 2),
function (err: any) {
if (err) throw err;
console.log("Saved!");
}
);
}
})
.catch((error) => {
console.error(error);
});
})
.catch(error => {
console.error(error)
})
})
.catch((error: any) => {
console.error(error)
})
.catch((error: any) => {
console.error(error);
});
} else {
this.error(
'AndroidManifest.xml not found. Please provide a valid path to the Android Project',
)
"AndroidManifest.xml not found. Please provide a valid path to the Android Project"
);
}
}
}
2 changes: 1 addition & 1 deletion manifest-scanner/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export {run} from '@oclif/core'
export { run } from "@oclif/core";
12 changes: 6 additions & 6 deletions manifest-scanner/src/plugins/BasePlugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Severity} from './util'
import { Severity } from "./util";

export default abstract class BasePlugin {
issues: any[];
Expand All @@ -9,15 +9,15 @@ export default abstract class BasePlugin {
// add constructor accepting category, severity and description
constructor(category: string, severity: Severity, description: string) {
// console.log("BasePlugin constructor")
this.category = category
this.severity = severity
this.description = description
this.category = category;
this.severity = severity;
this.description = description;

this.issues = []
this.issues = [];
}

abstract run(): void;
}

// export both the BaseRule class and the Severity enum
export {BasePlugin}
export { BasePlugin };
34 changes: 17 additions & 17 deletions manifest-scanner/src/plugins/ManifestPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,51 @@
import {BasePlugin} from './BasePlugin'
import {Severity} from './util'
import { BasePlugin } from "./BasePlugin";
import { Severity } from "./util";

export default abstract class ManifestPlugin extends BasePlugin {
static manifestPath = '';
static manifestPath = "";
static manifestXMLObject: any = null;
static minSdk = -1;
static targetSdk = -1;
static packageName = 'PACKAGE_NOT_FOUND';
static androidProjectDirectory = '';
static packageName = "PACKAGE_NOT_FOUND";
static androidProjectDirectory = "";
static isASTEnabled = false;

// add constructor accepting category, severity and description
constructor(category: string, severity: Severity, description: string) {
// console.log("ManifestPlugin constructor")
super(category, severity, description)
super(category, severity, description);
}

static updateManifest(
manifestXMLObject: any,
ManifestPath: string,
projectDirectory: any,
isASTEnabled: boolean,
isASTEnabled: boolean
) {
// Users of this class should call this method instead of changing class attributes directly
this.manifestXMLObject = manifestXMLObject
this.manifestPath = ManifestPath
this.androidProjectDirectory = projectDirectory
this.isASTEnabled = isASTEnabled
this.manifestXMLObject = manifestXMLObject;
this.manifestPath = ManifestPath;
this.androidProjectDirectory = projectDirectory;
this.isASTEnabled = isASTEnabled;

try {
this.minSdk =
manifestXMLObject.manifest.usesSdk[0].$['android:minSdkVersion']
manifestXMLObject.manifest.usesSdk[0].$["android:minSdkVersion"];
this.targetSdk =
manifestXMLObject.manifest.usesSdk[0].$['android:targetSdkVersion']
manifestXMLObject.manifest.usesSdk[0].$["android:targetSdkVersion"];
} catch {
// manifest path is not set, assume minSdk and targetSdk
this.minSdk = this.targetSdk = 1
this.minSdk = this.targetSdk = 1;
}

try {
this.packageName = manifestXMLObject.manifest.$.package
this.packageName = manifestXMLObject.manifest.$.package;
} catch {
this.packageName = 'PACKAGE_NOT_FOUND'
this.packageName = "PACKAGE_NOT_FOUND";
}
}

abstract run(): void; // User should define how their plugin runs
}

export {ManifestPlugin}
export { ManifestPlugin };
Loading

0 comments on commit d22e884

Please sign in to comment.