Initial ApplicationInspector check-in
|
@ -0,0 +1,63 @@
|
|||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
|
@ -1,7 +1,5 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
|
@ -24,14 +22,11 @@ bld/
|
|||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
@ -45,29 +40,19 @@ TestResult.xml
|
|||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
# DNX
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
|
@ -105,9 +90,6 @@ ipch/
|
|||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
|
@ -128,14 +110,6 @@ _TeamCity*
|
|||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
|
@ -167,9 +141,9 @@ publish/
|
|||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
#*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
|
@ -180,12 +154,12 @@ PublishScripts/
|
|||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
|
@ -202,7 +176,6 @@ AppPackages/
|
|||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
|
@ -219,12 +192,9 @@ ClientBin/
|
|||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
@ -239,19 +209,15 @@ _UpgradeReport_Files/
|
|||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
@ -261,7 +227,6 @@ FakesAssemblies/
|
|||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
@ -269,9 +234,6 @@ node_modules/
|
|||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
|
@ -297,34 +259,10 @@ paket-files/
|
|||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
/AppInspector/htmlReport
|
||||
/AppInspectorLog.txt
|
||||
/AppInspector/Log.txt
|
||||
/AppInspector/LogB4.txt
|
||||
/AppInspector/wip.txt
|
||||
/AppInspector/linux/ApplicationInspector
|
||||
/Microsoft.DevSkim/linux/ApplicationInspector
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28307.645
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppInspector.CLI", "AppInspector\AppInspector.CLI.csproj", "{C6D58D43-481F-456F-90E8-FAC3779E6CC6}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{876245F3-D7C5-4AA3-A288-2CE94BF63B8E}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DevSkim", "Microsoft.DevSkim\Microsoft.DevSkim.csproj", "{C19A98D2-629D-4F4D-87E4-3154416970BA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C6D58D43-481F-456F-90E8-FAC3779E6CC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C6D58D43-481F-456F-90E8-FAC3779E6CC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C6D58D43-481F-456F-90E8-FAC3779E6CC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C6D58D43-481F-456F-90E8-FAC3779E6CC6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C19A98D2-629D-4F4D-87E4-3154416970BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C19A98D2-629D-4F4D-87E4-3154416970BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C19A98D2-629D-4F4D-87E4-3154416970BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C19A98D2-629D-4F4D-87E4-3154416970BA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1D8F88F7-47D4-475A-B1AF-713132222341}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,127 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<PackageProjectUrl>https://github.com/microsoft/ApplicationInspector</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/microsoft/ApplicationInspector</RepositoryUrl>
|
||||
<RepositoryType></RepositoryType>
|
||||
<PackageTags>Static Linter</PackageTags>
|
||||
<PackageReleaseNotes>Pre-release version</PackageReleaseNotes>
|
||||
<Description>Characterizes software content</Description>
|
||||
<Copyright>(c) Microsoft Corporation. All rights reserved</Copyright>
|
||||
<HighEntropyVA>true</HighEntropyVA>
|
||||
<PackageId>ApplicationInspector</PackageId>
|
||||
<Product>ApplicationInspector</Product>
|
||||
<Authors>ApplicationInspector</Authors>
|
||||
<Version>1.0.0</Version>
|
||||
<AssemblyName>ApplicationInspector</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DefineConstants />
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="htmlreport\**" />
|
||||
<Compile Remove="linux\**" />
|
||||
<EmbeddedResource Remove="htmlreport\**" />
|
||||
<EmbeddedResource Remove="linux\**" />
|
||||
<None Remove="htmlreport\**" />
|
||||
<None Remove="linux\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="html\partials\_file_listing.liquid" />
|
||||
<None Remove="html\partials\_report_overview.liquid" />
|
||||
<None Remove="html\partials\_report_profile.liquid" />
|
||||
<None Remove="html\partials\_report_summary.liquid" />
|
||||
<None Remove="log.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="html\partials\_file_listing.liquid" />
|
||||
<EmbeddedResource Include="html\partials\_report_overview.liquid">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="html\partials\_report_profile.liquid" />
|
||||
<EmbeddedResource Include="html\partials\_report_summary.liquid" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.6.0" />
|
||||
<PackageReference Include="DotLiquid" Version="2.0.314" />
|
||||
<PackageReference Include="Handlebars.Net" Version="1.10.1" />
|
||||
<PackageReference Include="MediaTypeMap.Core" Version="2.3.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
<PackageReference Include="NLog" Version="4.6.7" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.DevSkim\Microsoft.DevSkim.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="htmltemplates\**">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="preferences\**">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="rules\**">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="html\index.html">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="html\resources\appinspector.css">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="html\resources\appinspector.js">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="C:\temp\authorization.json" Link="authorization.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="preferences\" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ProjectExtensions><VisualStudio><UserProperties /></VisualStudio></ProjectExtensions>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,751 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.DevSkim;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Dynamic;
|
||||
using System.Runtime.Serialization.Json;
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Writers
|
||||
{
|
||||
/// <summary>
|
||||
/// Parent wrapper class for representing source characterization parts
|
||||
/// Contains data elements that represent post processing options
|
||||
/// Contains data elements that are related to organization and presentation of tagGroups
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class AppProfile
|
||||
{
|
||||
[JsonProperty(PropertyName = "appInspectorVer")]
|
||||
public string Version { get; set; }
|
||||
[JsonProperty(PropertyName = "sourcePath")]
|
||||
public string SourcePath { get; set; }
|
||||
[JsonProperty(PropertyName = "appInspectorArgs")]
|
||||
public string Args { get; set; }
|
||||
[JsonProperty(PropertyName = "dateScanned")]
|
||||
public string DateScanned { get; set; }
|
||||
[JsonProperty(PropertyName = "rulePaths")]
|
||||
public HashSet<string> RulePaths { get { return MetaData.RulePaths; } }
|
||||
public AppMetaData MetaData { get; set; }
|
||||
//has to be public to be visible to htmlwriter
|
||||
[JsonProperty(PropertyName = "TagReportGroupLists")]
|
||||
public Dictionary<string, List<TagInfo>> KeyedTagInfoLists { get; }//dynamic lists for grouping tag properties in reporting
|
||||
[JsonIgnore]
|
||||
public Dictionary<string, List<TagInfo>> KeyedSortedTagInfoLists { get; } //split to avoid json serialization with others
|
||||
[JsonIgnore]
|
||||
public List<MatchRecord> MatchList { get; set; }//results list of rulesprocessing
|
||||
[JsonIgnore]
|
||||
public List<TagCategory> TagGroupPreferences { get; set; }//read preferred list of groups and tags for profile page
|
||||
|
||||
|
||||
//Report properties
|
||||
[JsonIgnore]
|
||||
public bool ExcludeRollup { get; set; }
|
||||
[JsonIgnore]
|
||||
public bool SimpleTagsOnly { get; set; }
|
||||
[JsonIgnore]
|
||||
public bool UniqueTagsOnly { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor initializes several internal lists not populated by rules processing
|
||||
/// </summary>
|
||||
/// <param name="sourcePath">code</param>
|
||||
/// <param name="rulePaths">rules</param>
|
||||
/// <param name="excludeRollup">omit aggregated rollup e.g. simple output with matches</param>
|
||||
/// <param name="simpleTagsOnly">simple output override</param>
|
||||
/// <param name="uniqueTagsOnly">avoid duplicate tag reporting</param>
|
||||
public AppProfile(string sourcePath, List<string> rulePaths, bool excludeRollup, bool simpleTagsOnly, bool uniqueTagsOnly)
|
||||
{
|
||||
SourcePath = sourcePath;
|
||||
Version = Program.GetVersion();
|
||||
MatchList = new List<MatchRecord>();
|
||||
KeyedTagInfoLists = new Dictionary<string, List<TagInfo>>();
|
||||
KeyedSortedTagInfoLists = new Dictionary<string, List<TagInfo>>();
|
||||
|
||||
//read default/user preferences on what tags to report presence on and groupings
|
||||
TagGroupPreferences = JsonConvert.DeserializeObject<List<TagCategory>>(File.ReadAllText(Helper.GetPath(Helper.AppPath.tagGroupPref)));
|
||||
|
||||
ExcludeRollup = excludeRollup;
|
||||
SimpleTagsOnly = simpleTagsOnly;
|
||||
UniqueTagsOnly = uniqueTagsOnly;
|
||||
|
||||
MetaData = new AppMetaData(sourcePath, rulePaths)
|
||||
{
|
||||
RulePaths = rulePaths.ToHashSet<string>()
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregate tags found into lists by organizing into customer preferred
|
||||
/// groups of taginfo objects
|
||||
/// TagGroupPreferences are organized by category i.e. profile or composition pages then by groups within
|
||||
/// file to be read
|
||||
/// </summary>
|
||||
public void PrepareReport()
|
||||
{
|
||||
//start with all unique tags to initialize which is then used to sort into groups of tagInfo lists
|
||||
MetaData.UniqueTags = GetUniqueTags();
|
||||
|
||||
foreach (TagCategory CategoryTagGroup in TagGroupPreferences)
|
||||
{
|
||||
foreach (TagGroup tagGroup in CategoryTagGroup.Groups)
|
||||
{
|
||||
foreach (TagSearchPattern pattern in tagGroup.Patterns)
|
||||
pattern.Detected = MetaData.UniqueTags.Any(v => v.Contains(pattern.SearchPattern));
|
||||
}
|
||||
}
|
||||
|
||||
//create simple ranked page lists for sorted display for app defined report page
|
||||
KeyedSortedTagInfoLists["tagGrpAllTagsByConfidence"] = GetTagInfoListByConfidence();
|
||||
KeyedSortedTagInfoLists["tagGrpAllTagsBySeverity"] = GetTagInfoListBySeverity();
|
||||
KeyedSortedTagInfoLists["tagGrpAllTagsByName"] = GetTagInfoListByName();
|
||||
|
||||
//create dynamic "category" groups of tags with pattern relationship established from TagReportGroups.json
|
||||
//that can be used to populate reports with various attributes for each tag detected
|
||||
foreach (TagCategory tagCategory in TagGroupPreferences)
|
||||
{
|
||||
foreach (TagGroup group in tagCategory.Groups)
|
||||
{
|
||||
if (tagCategory.Type == TagCategory.tagInfoType.uniqueTags)
|
||||
KeyedTagInfoLists["tagGrp" + group.DataRef] = GetUniqueMatchingTagInfoList(group);
|
||||
else if (tagCategory.Type == TagCategory.tagInfoType.allTags)
|
||||
KeyedTagInfoLists["tagGrp" + group.DataRef] = GetAllMatchingTagInfoList(group);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//TBD: Alternative to use here instead of AnalyzeCommand
|
||||
//What is missed if called here instead of Analyze which may not add duplicates?
|
||||
//allow each record to be tested for presence of customizable preferred tags
|
||||
/*foreach (MatchRecord matchRecord in MatchList)
|
||||
{
|
||||
MetaData.AddStandardProperties(matchRecord);
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region TagListGroupingMethods
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the set of groups of tags for specified file section in TagReportGroups.json read previously i.e. in PrepareReport
|
||||
/// </summary>
|
||||
/// <param name="category"></param>
|
||||
/// <returns></returns>
|
||||
public List<TagInfo> GetTagInfoList(string category)
|
||||
{
|
||||
List<TagInfo> result = new List<TagInfo>();
|
||||
List<TagGroup> tagGroups = GetCategoryTagGroups(category);
|
||||
foreach (TagGroup group in tagGroups)
|
||||
{
|
||||
result.AddRange(KeyedTagInfoLists["tagGrp" + group.DataRef]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of taggroups for a given file name e.g. profile or composition
|
||||
/// </summary>
|
||||
/// <param name="category"></param>
|
||||
/// <returns></returns>
|
||||
public List<TagGroup> GetCategoryTagGroups(string category)
|
||||
{
|
||||
List<TagGroup> result = new List<TagGroup>();
|
||||
foreach (TagCategory categoryTagGroup in TagGroupPreferences)
|
||||
{
|
||||
if (categoryTagGroup.Name == category)
|
||||
{
|
||||
result = categoryTagGroup.Groups;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private HashSet<string> GetUniqueTags()
|
||||
{
|
||||
HashSet<string> results = new HashSet<string>();
|
||||
|
||||
foreach (MatchRecord match in MatchList)
|
||||
{
|
||||
foreach (string tag in match.Issue.Rule.Tags)
|
||||
results.Add(tag);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Builds list of matching tags by profile pattern
|
||||
/// Ensures only one instance of a given tag in results unlike GetAllMatchingTags method
|
||||
/// </summary>
|
||||
/// <param name="tagPattern"></param>
|
||||
/// <returns></returns>
|
||||
private List<TagInfo> GetUniqueMatchingTagInfoList(TagGroup tagGroup, bool addNotFound=true)
|
||||
{
|
||||
List<TagInfo> result = new List<TagInfo>();
|
||||
HashSet<string> hashSet = new HashSet<string>();
|
||||
|
||||
foreach (TagSearchPattern pattern in tagGroup.Patterns)
|
||||
{
|
||||
if (pattern.Detected)//set at program.RollUp already so don't search for again
|
||||
{
|
||||
var tagPatternRegex = new Regex(pattern.SearchPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
foreach (var match in MatchList)
|
||||
{
|
||||
foreach (var tagItem in match.Issue.Rule.Tags)
|
||||
{
|
||||
if (tagPatternRegex.IsMatch(tagItem))
|
||||
{
|
||||
if (!hashSet.Contains(pattern.SearchPattern))
|
||||
{
|
||||
result.Add(new TagInfo
|
||||
{
|
||||
Tag = tagItem,
|
||||
Confidence = match.Issue.Confidence.ToString(),
|
||||
Severity = match.Issue.Rule.Severity.ToString(),
|
||||
ShortTag = pattern.DisplayName,
|
||||
StatusIcon = pattern.DetectedIcon,
|
||||
Detected = true
|
||||
}) ;
|
||||
|
||||
hashSet.Add(pattern.SearchPattern);
|
||||
}
|
||||
else //already have in results but...
|
||||
{//ensure we have highest confidence, severity as there are likly multiple matches for this tag pattern
|
||||
foreach (TagInfo updateItem in result)
|
||||
{
|
||||
if (updateItem.Tag == tagItem)
|
||||
{
|
||||
DevSkim.Confidence oldConfidence;
|
||||
Enum.TryParse(updateItem.Confidence, out oldConfidence);
|
||||
if (match.Issue.Confidence > oldConfidence)
|
||||
{
|
||||
updateItem.Confidence = match.Issue.Confidence.ToString();
|
||||
}
|
||||
|
||||
DevSkim.Severity oldSeverity;
|
||||
Enum.TryParse(updateItem.Severity, out oldSeverity);
|
||||
if (match.Issue.Rule.Severity > oldSeverity)
|
||||
{
|
||||
updateItem.Severity = match.Issue.Rule.Severity.ToString();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (addNotFound) //allow page to report on false presense items
|
||||
{
|
||||
TagInfo tagInfo = new TagInfo
|
||||
{
|
||||
Tag = pattern.SearchPattern,
|
||||
Detected = false,
|
||||
ShortTag = pattern.DisplayName,
|
||||
StatusIcon = pattern.NotDetectedIcon,
|
||||
Confidence = "",
|
||||
Severity = ""
|
||||
};
|
||||
result.Add(tagInfo);
|
||||
hashSet.Add(tagInfo.Tag);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a set of matching tags for a set of patterns returning for all matches
|
||||
/// </summary>
|
||||
/// <param name="patterns"></param>
|
||||
/// <param name="addNotFound"></param>
|
||||
/// <returns></returns>
|
||||
private List<TagInfo> GetAllMatchingTagInfoList(TagGroup tagGroup, bool addNotFound = true)
|
||||
{
|
||||
List<TagInfo> result = new List<TagInfo>();
|
||||
HashSet<string> hashSet = new HashSet<string>();
|
||||
|
||||
foreach (TagSearchPattern pattern in tagGroup.Patterns)
|
||||
{
|
||||
if (pattern.Detected)
|
||||
{
|
||||
var tagPatternRegex = new Regex(pattern.SearchPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
foreach (var match in MatchList)
|
||||
{
|
||||
foreach (var tagItem in match.Issue.Rule.Tags)
|
||||
{
|
||||
if (tagPatternRegex.IsMatch(tagItem))
|
||||
{
|
||||
if (!hashSet.Contains(tagItem))
|
||||
{
|
||||
result.Add(new TagInfo
|
||||
{
|
||||
Tag = tagItem,
|
||||
Confidence = match.Issue.PatternMatch.Confidence.ToString(),
|
||||
Severity = match.Issue.Rule.Severity.ToString(),
|
||||
ShortTag = tagItem.Substring(tagItem.LastIndexOf('.') + 1),
|
||||
StatusIcon = pattern.DetectedIcon,
|
||||
Detected = true
|
||||
});
|
||||
|
||||
hashSet.Add(tagItem);
|
||||
}
|
||||
else
|
||||
{//ensure we have highest confidence, severity as there are likly multiple matches for this tag pattern
|
||||
foreach (TagInfo updateItem in result)
|
||||
{
|
||||
if (updateItem.Tag == tagItem)
|
||||
{
|
||||
DevSkim.Confidence oldConfidence;
|
||||
Enum.TryParse(updateItem.Confidence, out oldConfidence);
|
||||
if (match.Issue.PatternMatch.Confidence > oldConfidence)
|
||||
{
|
||||
updateItem.Confidence = match.Issue.PatternMatch.Confidence.ToString();
|
||||
}
|
||||
|
||||
DevSkim.Severity oldSeverity;
|
||||
Enum.TryParse(updateItem.Severity, out oldSeverity);
|
||||
if (match.Issue.Rule.Severity > oldSeverity)
|
||||
{
|
||||
updateItem.Severity = match.Issue.Rule.Severity.ToString();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region SortTagsMethods
|
||||
|
||||
/// <summary>
|
||||
/// List of taginfo items ordered by name
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private List<TagInfo> GetTagInfoListByName()
|
||||
{
|
||||
List<string> orderedTags = MetaData.UniqueTags.ToList<string>();
|
||||
orderedTags.Sort();
|
||||
HashSet<string> dupCheck = new HashSet<string>();
|
||||
List<TagInfo> result = new List<TagInfo>();
|
||||
|
||||
foreach (string tag in orderedTags)
|
||||
{
|
||||
var searchPattern = new Regex(tag, RegexOptions.IgnoreCase);
|
||||
foreach (var match in MatchList)
|
||||
{
|
||||
foreach (string testTag in match.Issue.Rule.Tags)
|
||||
{
|
||||
if (searchPattern.IsMatch(tag) && dupCheck.Add(testTag))
|
||||
{
|
||||
result.Add(new TagInfo
|
||||
{
|
||||
Tag = testTag,
|
||||
Confidence = match.Issue.PatternMatch.Confidence.ToString(),
|
||||
Severity = match.Issue.Rule.Severity.ToString(),
|
||||
ShortTag = testTag.Substring(testTag.LastIndexOf('.') + 1),
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tags sorted by confidence
|
||||
/// Todo: address array of tags in rule
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private List<TagInfo> GetTagInfoListByConfidence()
|
||||
{
|
||||
List<TagInfo> result = new List<TagInfo>();
|
||||
HashSet<string> dupCheck = new HashSet<string>();
|
||||
DevSkim.Confidence[] confidences = { Confidence.High, Confidence.Medium, Confidence.Low };
|
||||
|
||||
foreach (Confidence test in confidences)
|
||||
{
|
||||
foreach (string tag in MetaData.UniqueTags)
|
||||
{
|
||||
var searchPattern = new Regex(tag, RegexOptions.IgnoreCase);
|
||||
foreach (var match in MatchList)
|
||||
{
|
||||
foreach (string testTag in match.Issue.Rule.Tags)
|
||||
{
|
||||
if (searchPattern.IsMatch(testTag))
|
||||
{
|
||||
if (match.Issue.PatternMatch.Confidence == test && dupCheck.Add(tag))
|
||||
result.Add(new TagInfo
|
||||
{
|
||||
Tag = testTag,
|
||||
Confidence = test.ToString(),
|
||||
Severity = match.Issue.Rule.Severity.ToString(),
|
||||
ShortTag = testTag.Substring(testTag.LastIndexOf('.') + 1),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sorted by Severity
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
||||
private List<TagInfo> GetTagInfoListBySeverity()
|
||||
{
|
||||
List<TagInfo> result = new List<TagInfo>();
|
||||
HashSet<string> dupCheck = new HashSet<string>();
|
||||
DevSkim.Severity[] severities = { Severity.Critical, Severity.Important, Severity.Moderate, Severity.BestPractice, Severity.ManualReview };
|
||||
|
||||
foreach (Severity test in severities)
|
||||
{
|
||||
foreach (string tag in MetaData.UniqueTags)
|
||||
{
|
||||
var searchPattern = new Regex(tag, RegexOptions.IgnoreCase);
|
||||
foreach (var match in MatchList)
|
||||
{
|
||||
foreach (string testTag in match.Issue.Rule.Tags)
|
||||
{
|
||||
if (searchPattern.IsMatch(testTag))
|
||||
{
|
||||
if (match.Issue.Rule.Severity == test && dupCheck.Add(tag))
|
||||
result.Add(new TagInfo
|
||||
{
|
||||
Tag = testTag,
|
||||
Confidence = match.Issue.PatternMatch.Confidence.ToString(),
|
||||
Severity = test.ToString(),
|
||||
ShortTag = testTag.Substring(testTag.LastIndexOf('.') + 1),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contains meta data elements around the source scanned
|
||||
/// Contains rollup data for reporting purposes
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class AppMetaData
|
||||
{
|
||||
//Multi-list of elements makes it easier to pass to HTML template engine -direct getters also work
|
||||
[JsonIgnore]
|
||||
private Dictionary<string, string> _propertyTagSearchPatterns;
|
||||
|
||||
[JsonIgnore] //named properties below will handle for serialization
|
||||
public Dictionary<string, HashSet<string>> KeyedPropertyLists { get; }
|
||||
|
||||
|
||||
public AppMetaData(string sourcePath, List<string> rulePaths)
|
||||
{
|
||||
//Initial value for ApplicationName may be replaced if rule pattern match found later
|
||||
if (Directory.Exists(sourcePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
ApplicationName = sourcePath.Substring(sourcePath.LastIndexOf(Path.DirectorySeparatorChar)).Replace(Path.DirectorySeparatorChar, ' ').Trim();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
ApplicationName = Path.GetFileNameWithoutExtension(sourcePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplicationName = Path.GetFileNameWithoutExtension(sourcePath);
|
||||
}
|
||||
//initialize set groups of dynamic lists variables that may have more than one value; some are filled
|
||||
//using tag tests and others by different means like file type examination
|
||||
KeyedPropertyLists = new Dictionary<string, HashSet<string>>
|
||||
{
|
||||
["strGrpRulePaths"] = rulePaths.ToHashSet(),
|
||||
["strGrpPackageTypes"] = new HashSet<string>(),
|
||||
["strGrpAppTypes"] = new HashSet<string>(),
|
||||
["strGrpFileTypes"] = new HashSet<string>(),
|
||||
["strGrpUniqueTags"] = new HashSet<string>(),
|
||||
["strGrpOutputs"] = new HashSet<string>(),
|
||||
["strGrpTargets"] = new HashSet<string>(),
|
||||
["strGrpOSTargets"] = new HashSet<string>(),
|
||||
["strGrpFileExtensions"] = new HashSet<string>(),
|
||||
["strGrpFileNames"] = new HashSet<string>(),
|
||||
["strGrpCPUTargets"] = new HashSet<string>(),
|
||||
["strGrpCloudTargets"] = new HashSet<string>(),
|
||||
["strGrpUniqueDependencies"] = new HashSet<string>()
|
||||
};
|
||||
|
||||
//predefined standard tags to track; only some are propertygrouplist are tag based
|
||||
_propertyTagSearchPatterns = new Dictionary<string, string>();
|
||||
_propertyTagSearchPatterns.Add("strGrpOSTargets", ".OS.Targets");
|
||||
_propertyTagSearchPatterns.Add("strGrpCloudTargets", ".Cloud");
|
||||
_propertyTagSearchPatterns.Add("strGrpOutputs", ".Outputs");
|
||||
_propertyTagSearchPatterns.Add("strGrpCPUTargets", ".CPU");
|
||||
|
||||
//read default/user preferences on what tags to count
|
||||
TagCounters = JsonConvert.DeserializeObject<List<TagCounter>>(File.ReadAllText(Helper.GetPath(Helper.AppPath.tagCounterPref)));
|
||||
HashSet<string> dupCountersCheck = new HashSet<string>();
|
||||
foreach (TagCounter counter in TagCounters)
|
||||
if (!dupCountersCheck.Add(counter.Tag))
|
||||
throw new Exception("Duplicate tagCounter found in TagCounters.json preferences file");
|
||||
|
||||
Languages = new Dictionary<string, int>();
|
||||
|
||||
}
|
||||
|
||||
public void AddLanguage(string language)
|
||||
{
|
||||
if (Languages.ContainsKey(language))
|
||||
Languages[language]++;
|
||||
else
|
||||
Languages.Add(language, 1);
|
||||
}
|
||||
|
||||
|
||||
//simple properties
|
||||
[JsonProperty(PropertyName = "applicationName")]
|
||||
public string ApplicationName { get; set; }
|
||||
[JsonProperty(PropertyName = "sourceVersion")]
|
||||
public string SourceVersion { get; set; }
|
||||
[JsonProperty(PropertyName = "authors")]
|
||||
public string Authors { get; set; }
|
||||
[JsonProperty(PropertyName = "description")]
|
||||
public string Description { get; set; }
|
||||
|
||||
private DateTime _lastUpdated = DateTime.MinValue;
|
||||
[JsonProperty(PropertyName = "lastUpdated")]
|
||||
public string LastUpdated { get; set; }
|
||||
|
||||
//stats
|
||||
[JsonProperty(PropertyName = "filesAnalyzed")]
|
||||
public int FilesAnalyzed { get; set; }
|
||||
[JsonProperty(PropertyName = "totalFiles")]
|
||||
public int TotalFiles { get; set; }
|
||||
[JsonProperty(PropertyName = "filesSkipped")]
|
||||
public int FilesSkipped { get; set; }
|
||||
[JsonProperty(PropertyName = "filesAffected")]
|
||||
public int FilesAffected { get; set; }
|
||||
//following "counter" methods can not use enumeration on matches list which are unique by default
|
||||
[JsonProperty(PropertyName = "totalMatchesCount")]
|
||||
public int TotalMatchesCount { get; set; }
|
||||
[JsonProperty(PropertyName = "uniqueMatchesCount")]
|
||||
public int UniqueMatchesCount { get { return UniqueTags.Count; } }
|
||||
[JsonIgnore]
|
||||
public Dictionary<string, TagCounter> KeyedPropertyCounters { get; }
|
||||
[JsonProperty("selectTagCounters")]
|
||||
public List<TagCounter> TagCounters { get; }
|
||||
//predefined lists in KeyedPropertyLists for easy retrieval and loose coupling
|
||||
[JsonProperty(PropertyName = "packageTypes")]
|
||||
public HashSet<string> PackageTypes { get { return KeyedPropertyLists["strGrpPackageTypes"]; } }
|
||||
[JsonProperty(PropertyName = "appTypes")]
|
||||
public HashSet<string> AppTypes { get { return KeyedPropertyLists["strGrpAppTypes"]; } }
|
||||
[JsonIgnore]
|
||||
public HashSet<string> RulePaths { get { return KeyedPropertyLists["strGrpRulePaths"]; } set { KeyedPropertyLists["strGrpRulePaths"] = value; } }
|
||||
[JsonIgnore]
|
||||
public HashSet<string> FileNames { get { return KeyedPropertyLists["strGrpFileNames"]; } }
|
||||
[JsonProperty(PropertyName = "uniqueTags")]
|
||||
public HashSet<string> UniqueTags
|
||||
{
|
||||
get
|
||||
{
|
||||
return KeyedPropertyLists["strGrpUniqueTags"];
|
||||
}
|
||||
set
|
||||
{
|
||||
KeyedPropertyLists["strGrpUniqueTags"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
//convenience getters for standard lists of values
|
||||
[JsonProperty(PropertyName = "uniqueDependencies")]
|
||||
public HashSet<string> UniqueDependencies { get { return KeyedPropertyLists["strGrpUniqueDependencies"]; } }
|
||||
[JsonProperty(PropertyName = "outputs")]
|
||||
public HashSet<string> Outputs { get { return KeyedPropertyLists["strGrpOutputs"]; } }
|
||||
[JsonProperty(PropertyName = "targets")]
|
||||
public HashSet<string> Targets { get { return KeyedPropertyLists["strGrpTargets"]; } }
|
||||
[JsonProperty(PropertyName = "languages")]
|
||||
public Dictionary<string, int> Languages;
|
||||
[JsonProperty(PropertyName = "OSTargets")]
|
||||
public HashSet<string> OSTargets { get { return KeyedPropertyLists["strGrpOSTargets"]; } }
|
||||
[JsonProperty(PropertyName = "fileExtensions")]
|
||||
public HashSet<string> FileExtensions
|
||||
{ get { return KeyedPropertyLists["strGrpFileExtensions"]; } }
|
||||
[JsonProperty(PropertyName = "cloudTargets")]
|
||||
public HashSet<string> CloudTargets { get { return KeyedPropertyLists["strGrpCloudTargets"]; } }
|
||||
[JsonProperty(PropertyName = "CPUTargets")]
|
||||
public HashSet<string> CPUTargets { get { return KeyedPropertyLists["strGrpCPUTargets"]; } }
|
||||
|
||||
private string ExtractJSONValue(string s)
|
||||
{
|
||||
try
|
||||
{
|
||||
var parts = s.Split(':');
|
||||
var value = parts[1];
|
||||
value = value.Replace("\"", "");
|
||||
value = value.Trim();
|
||||
return value;
|
||||
} catch(Exception)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Part of post processing to test for matches against app defined properties
|
||||
/// defined in MetaData class
|
||||
/// TODO: decide if we can just call from AppProfile PrepareReport instead
|
||||
/// </summary>
|
||||
/// <param name="matchRecord"></param>
|
||||
public bool AddStandardProperties(MatchRecord matchRecord)
|
||||
{
|
||||
bool includeAsMatch = true;
|
||||
|
||||
//standard testing for presence of a tag against the preffered set of tags
|
||||
foreach (string key in _propertyTagSearchPatterns.Keys)
|
||||
{
|
||||
var tagPatternRegex = new Regex(_propertyTagSearchPatterns[key], RegexOptions.IgnoreCase);
|
||||
if (matchRecord.Issue.Rule.Tags.Any(v => tagPatternRegex.IsMatch(v)))
|
||||
{
|
||||
KeyedPropertyLists[key].Add(matchRecord.TextSample);
|
||||
}
|
||||
}
|
||||
|
||||
//update counts for default or user specified tags
|
||||
|
||||
foreach (TagCounter counter in TagCounters)
|
||||
{
|
||||
if (matchRecord.Issue.Rule.Tags.Any(v => v.Contains(counter.Tag)))
|
||||
{
|
||||
counter.Count++;
|
||||
includeAsMatch = counter.IncludeAsMatch;
|
||||
}
|
||||
}
|
||||
|
||||
// Author
|
||||
if (matchRecord.Issue.Rule.Tags.Contains("Metadata.Application.Author"))
|
||||
this.Authors = ExtractJSONValue(matchRecord.TextSample);
|
||||
if (matchRecord.Issue.Rule.Tags.Contains("Metadata.Application.Description"))
|
||||
this.Description = ExtractJSONValue(matchRecord.TextSample);
|
||||
if (matchRecord.Issue.Rule.Tags.Contains("Metadata.Application.Name"))
|
||||
this.ApplicationName = ExtractJSONValue(matchRecord.TextSample);
|
||||
if (matchRecord.Issue.Rule.Tags.Contains("Metadata.Application.Version"))
|
||||
this.SourceVersion = ExtractJSONValue(matchRecord.TextSample);
|
||||
|
||||
//special handling; attempt to detect app types...review for multiple tag limiation
|
||||
String solutionType = Helper.DetectSolutionType(matchRecord.Filename, matchRecord.Language, matchRecord.Issue.Rule.Tags[0], matchRecord.TextSample);
|
||||
if (!string.IsNullOrEmpty(solutionType) && !AppTypes.Contains(solutionType))
|
||||
AppTypes.Add(solutionType);
|
||||
|
||||
#region wip
|
||||
//special handling solution name; for efficency (?) use separate tests; note Tags is not an ienumerable
|
||||
//TODO this needs work as the text sample of PY projects is not compatible; check Rule accuracy
|
||||
/*
|
||||
foreach (string tag in matchRecord.Issue.Rule.Tags)
|
||||
{
|
||||
if (tag.Contains("Solution.Name"))
|
||||
{
|
||||
int index = matchRecord.TextSample.IndexOf("\"");
|
||||
if (-1 != index)
|
||||
{
|
||||
ApplicationName = matchRecord.TextSample.Substring(index + 1);
|
||||
ApplicationName = ApplicationName.Replace("\"", "");
|
||||
ApplicationName = ApplicationName.Trim();
|
||||
}
|
||||
else
|
||||
ApplicationName = matchRecord.TextSample;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//special handling for version possible format of textMatch i.e. <version="1.0"...
|
||||
foreach (string tag in matchRecord.Issue.Rule.Tags)
|
||||
{
|
||||
if (tag.Contains("Solution.Version"))
|
||||
{
|
||||
int index = matchRecord.TextSample.IndexOf("\"");
|
||||
if (-1 != index)
|
||||
{
|
||||
SourceVersion = matchRecord.TextSample.Substring(index + 1);
|
||||
index = SourceVersion.IndexOf("\"");
|
||||
if (-1 != index)
|
||||
SourceVersion = SourceVersion.Substring(0, index);
|
||||
|
||||
SourceVersion = SourceVersion.Trim();
|
||||
}
|
||||
else
|
||||
SourceVersion = System.Net.WebUtility.HtmlEncode(matchRecord.TextSample);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
#endregion
|
||||
|
||||
return includeAsMatch;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,686 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using ICSharpCode.SharpZipLib.GZip;
|
||||
using ICSharpCode.SharpZipLib.Tar;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using MimeTypes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ICSharpCode.SharpZipLib.Core;
|
||||
using Microsoft.AppInspector.CLI.Writers;
|
||||
using Microsoft.DevSkim;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using System.Diagnostics;
|
||||
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Commands
|
||||
{
|
||||
public class AnalyzeCommand : ICommand
|
||||
{
|
||||
readonly int MAX_FILESIZE = 1024 * 1000 * 5; // Do not analyze files larger than 5 MB
|
||||
|
||||
// Enable processing compressed files
|
||||
readonly string[] COMPRESSED_EXTENSIONS = "zip,gz,gzip,gem,tar,tgz,tar.gz,xz,7z".Split(",");
|
||||
Regex IgnoreMimeRegex;
|
||||
|
||||
public enum ExitCode
|
||||
{
|
||||
NoMatches = 0,
|
||||
MatchesFound = 1,
|
||||
CriticalError = 2
|
||||
}
|
||||
|
||||
AppProfile _appProfile;
|
||||
RuleProcessor _rulesProcessor;
|
||||
Writer _outputWriter;
|
||||
|
||||
DateTime DateScanned { get; set; }
|
||||
DateTime _lastUpdated;
|
||||
|
||||
public DateTime LastUpdated
|
||||
{
|
||||
get { return _lastUpdated; }
|
||||
set
|
||||
{
|
||||
//find last updated file in solution
|
||||
if (_lastUpdated < value)
|
||||
_lastUpdated = value;
|
||||
}
|
||||
}
|
||||
|
||||
//cmdline arguments
|
||||
private string _arg_sourcePath;
|
||||
private string _arg_outputFile;
|
||||
private string _arg_fileFormat;
|
||||
private string _arg_outputTextFormat;
|
||||
private string _arg_customRulePath;
|
||||
private bool _arg_ignoreDefaultRules;
|
||||
private bool _arg_outputUniqueTagsOnly;
|
||||
private string _arg_confidenceFilters;
|
||||
private bool _arg_simpleTagsOnly;
|
||||
private Confidence _arg_confidence;
|
||||
private WriteOnce.ConsoleVerbosityLevel _arg_consoleVerbosityLevel;
|
||||
|
||||
public AnalyzeCommand(AnalyzeCommandOptions opts)
|
||||
{
|
||||
_arg_sourcePath = opts.SourcePath;
|
||||
_arg_outputFile = opts.OutputFilePath;
|
||||
_arg_fileFormat = opts.OutputFileFormat;
|
||||
_arg_outputTextFormat = opts.TextOutputFormat;
|
||||
_arg_outputUniqueTagsOnly = opts.UniqueTagsOnly;
|
||||
_arg_customRulePath = opts.CustomRulesPath;
|
||||
_arg_confidenceFilters = opts.ConfidenceFilters;
|
||||
_arg_ignoreDefaultRules = opts.IgnoreDefaultRules;
|
||||
_arg_simpleTagsOnly = opts.SimpleTagsOnly;
|
||||
Enum.TryParse(opts.ConsoleVerbosityLevel, true, out _arg_consoleVerbosityLevel);
|
||||
WriteOnce.Verbosity = _arg_consoleVerbosityLevel;
|
||||
|
||||
IgnoreMimeRegex = new Regex(@"^(audio|video)/.*$");
|
||||
|
||||
//quick validations and setup
|
||||
if (!Directory.Exists(_arg_sourcePath) && !File.Exists(_arg_sourcePath))
|
||||
{
|
||||
string errorMsg = string.Format("Invalid source file or directory{0}", _arg_sourcePath);
|
||||
WriteOnce.Error(errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
|
||||
LastUpdated = DateTime.MinValue;
|
||||
DateScanned = DateTime.Now;
|
||||
|
||||
ConfigureConfidenceFilters();
|
||||
ConfigRules();
|
||||
ConfigOutput();
|
||||
}
|
||||
|
||||
|
||||
#region configureMethods
|
||||
|
||||
/// <summary>
|
||||
/// Expects user to supply all that apply
|
||||
/// </summary>
|
||||
void ConfigureConfidenceFilters()
|
||||
{
|
||||
//parse and verify confidence values
|
||||
if (String.IsNullOrEmpty(_arg_confidenceFilters))
|
||||
_arg_confidence = Confidence.High | Confidence.Medium; //excludes low by default
|
||||
else
|
||||
{
|
||||
string[] confidences = _arg_confidenceFilters.Split(',');
|
||||
foreach (string confidence in confidences)
|
||||
{
|
||||
Confidence single;
|
||||
if (Enum.TryParse(confidence, true, out single))
|
||||
_arg_confidence |= single;
|
||||
else
|
||||
throw new Exception("Invalid run argument value for -x");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Add default and/or custom rules paths
|
||||
/// Iterate paths and add to ruleset
|
||||
/// </summary>
|
||||
void ConfigRules()
|
||||
{
|
||||
RuleSet rulesSet = new RuleSet(Program.Logger);
|
||||
List<string> rulePaths = new List<string>();
|
||||
if (!_arg_ignoreDefaultRules)
|
||||
rulePaths.Add(Helper.GetPath(Helper.AppPath.defaultRules));
|
||||
|
||||
if (!string.IsNullOrEmpty(_arg_customRulePath))
|
||||
rulePaths.Add(_arg_customRulePath);
|
||||
|
||||
foreach (string rulePath in rulePaths)
|
||||
{
|
||||
if (Directory.Exists(rulePath))
|
||||
rulesSet.AddDirectory(rulePath);
|
||||
else
|
||||
rulesSet.AddFile(rulePath);
|
||||
}
|
||||
|
||||
//error check based on ruleset not path enumeration
|
||||
if (rulesSet.Count() == 0)
|
||||
{
|
||||
WriteOnce.Error("No rules specified");
|
||||
throw new Exception("No rules specified");
|
||||
}
|
||||
|
||||
//instantiate a RuleProcessor with the added rules and exception for dependency
|
||||
_rulesProcessor = new RuleProcessor(rulesSet, _arg_confidence, _arg_outputUniqueTagsOnly, _arg_simpleTagsOnly, Program.Logger);
|
||||
|
||||
if (_arg_outputUniqueTagsOnly)
|
||||
{
|
||||
List<TagException> tagExceptions = JsonConvert.DeserializeObject<List<TagException>>(File.ReadAllText(Helper.GetPath(Helper.AppPath.tagCounterPref)));
|
||||
string[] exceptions = new string[tagExceptions.Count];
|
||||
for (int i=0;i<tagExceptions.Count;i++)
|
||||
exceptions[i] = tagExceptions[i].Tag;
|
||||
_rulesProcessor.UniqueTagExceptions = exceptions;
|
||||
}
|
||||
|
||||
_appProfile = new AppProfile(_arg_sourcePath, rulePaths, false, _arg_simpleTagsOnly, _arg_outputUniqueTagsOnly);
|
||||
_appProfile.Args = "analyze -f " + _arg_fileFormat + " -u " + _arg_outputUniqueTagsOnly.ToString().ToLower() + " -v " +
|
||||
WriteOnce.Verbosity.ToString() + " -x " + _arg_confidence + " -i " + _arg_ignoreDefaultRules.ToString().ToLower();
|
||||
}
|
||||
|
||||
|
||||
void ConfigOutput()
|
||||
{
|
||||
//Set output type, format and outstream
|
||||
_outputWriter = WriterFactory.GetWriter(_arg_fileFormat ?? "text", (string.IsNullOrEmpty(_arg_outputFile)) ? null : "text", _arg_outputTextFormat);
|
||||
if (!string.IsNullOrEmpty(_arg_outputFile))
|
||||
{
|
||||
if (_arg_fileFormat != "html")
|
||||
_outputWriter.TextWriter = File.CreateText(_arg_outputFile);//not needed if html output since application controlled
|
||||
}
|
||||
else
|
||||
_outputWriter.TextWriter = Console.Out;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Main entry point to start analysis; handles setting up rules, directory enumeration
|
||||
/// file type detection and handoff
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int Run()
|
||||
{
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
WriteOnce.Write("Analyze command running\n", ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
|
||||
|
||||
//if it's a file, make an IEnumerable out of it.
|
||||
IEnumerable<string> fileList;
|
||||
if (!Directory.Exists(_arg_sourcePath))
|
||||
fileList = new List<string>() { _arg_sourcePath };
|
||||
else
|
||||
fileList = Directory.EnumerateFiles(_arg_sourcePath, "*.*", SearchOption.AllDirectories);
|
||||
|
||||
_appProfile.MetaData.TotalFiles = fileList.Count();
|
||||
|
||||
// Iterate through all files and process against rules
|
||||
foreach (string filename in fileList)
|
||||
{
|
||||
var fileExtension = new FileInfo(filename).Extension;
|
||||
if (COMPRESSED_EXTENSIONS.Any(fileExtension.Contains))
|
||||
ExpandAndProcess(filename);
|
||||
else
|
||||
ProcessAsFile(filename);
|
||||
|
||||
//progress report
|
||||
int totalFilesReviewed = _appProfile.MetaData.FilesAnalyzed + _appProfile.MetaData.FilesSkipped;
|
||||
int percentCompleted = (int)((float)totalFilesReviewed / (float)_appProfile.MetaData.TotalFiles * 100);
|
||||
WriteOnce.Write(string.Format("\r{0}% source files processed", percentCompleted), ConsoleColor.Gray, WriteOnce.ConsoleVerbosityLevel.Medium);
|
||||
}
|
||||
|
||||
//prepare summary report
|
||||
WriteOnce.Write(string.Format("\r100% applicable files processed\t\t\t\t"), ConsoleColor.Gray, WriteOnce.ConsoleVerbosityLevel.Medium);
|
||||
WriteOnce.NewLine();
|
||||
WriteOnce.Info("Preparing report...");
|
||||
|
||||
_appProfile.MetaData.LastUpdated = LastUpdated.ToString();
|
||||
_appProfile.DateScanned = DateScanned.ToString();
|
||||
_appProfile.PrepareReport();
|
||||
//close output files
|
||||
FlushAll();
|
||||
|
||||
if (_appProfile.MetaData.TotalFiles == _appProfile.MetaData.FilesSkipped)
|
||||
WriteOnce.Error("No file types found in source path that are supported.");
|
||||
else if (_appProfile.MatchList.Count == 0)
|
||||
WriteOnce.Error("No pattern matches were detected for files in source path.");
|
||||
else
|
||||
WriteOnce.Any("Report complete.", ConsoleColor.Cyan);
|
||||
|
||||
TimeSpan timeSpan = start - DateTime.Now;
|
||||
Program.Logger.Trace(String.Format("Processing time: seconds:{0}", timeSpan.TotalSeconds*-1));
|
||||
|
||||
return _appProfile.MatchList.Count() == 0 ? (int)ExitCode.NoMatches :
|
||||
(int)ExitCode.MatchesFound;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper for files that are on disk and ready to read
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
void ProcessAsFile(string filename)
|
||||
{
|
||||
_appProfile.MetaData.FileNames.Add(filename);
|
||||
_appProfile.MetaData.PackageTypes.Add("uncompressed");
|
||||
|
||||
if (new System.IO.FileInfo(filename).Length > MAX_FILESIZE)
|
||||
{
|
||||
Program.Logger.Error(filename + " is too large. File skipped");
|
||||
_appProfile.MetaData.FilesSkipped++;
|
||||
return;
|
||||
}
|
||||
|
||||
string fileText = File.ReadAllText(filename);
|
||||
ProcessInMemory(filename, fileText);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Main WORKHORSE for analyzing file; called directly from decompression functions
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <param name="fileText"></param>
|
||||
void ProcessInMemory(string filePath, string fileText)
|
||||
{
|
||||
if (fileText.Length > MAX_FILESIZE)
|
||||
{
|
||||
Program.Logger.Error(filePath + " is too large. File skipped");
|
||||
_appProfile.MetaData.FilesSkipped++;
|
||||
return;
|
||||
}
|
||||
|
||||
//determine if file is a compressed item to unpackage for processing
|
||||
string language = Language.FromFileName(filePath);
|
||||
|
||||
// Skip files written in unknown language
|
||||
if (string.IsNullOrEmpty(language))
|
||||
{
|
||||
Program.Logger.Trace("Language not found for file: " + filePath);
|
||||
Program.Logger.Trace("But processing anyway: " + filePath);
|
||||
language = Path.GetFileName(filePath);
|
||||
_appProfile.MetaData.FilesSkipped++;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.Logger.Trace("Preparing to process file: " + filePath);
|
||||
}
|
||||
|
||||
#region minorRollupTracking
|
||||
|
||||
_appProfile.MetaData.FilesAnalyzed++;
|
||||
_appProfile.MetaData.AddLanguage(language);
|
||||
_appProfile.MetaData.FileExtensions.Add(Path.GetExtension(filePath).Replace('.', ' ').TrimStart());
|
||||
LastUpdated = File.GetLastWriteTime(filePath);
|
||||
|
||||
#endregion
|
||||
|
||||
//process file against rules
|
||||
Issue[] matches = _rulesProcessor.Analyze(fileText, language);
|
||||
|
||||
//if any matches found for this file...
|
||||
if (matches.Count() > 0)
|
||||
{
|
||||
_appProfile.MetaData.FilesAffected++;
|
||||
_appProfile.MetaData.TotalMatchesCount += matches.Count();
|
||||
|
||||
HashSet<string> uniqueTagsControl = new HashSet<string>();
|
||||
|
||||
// Iterate through each match issue
|
||||
foreach (Issue match in matches)
|
||||
{
|
||||
Program.Logger.Trace("Processing pattern matches for ruleId {0}, ruleName {1} file {2}", match.Rule.Id, match.Rule.Name, filePath);
|
||||
|
||||
//maintain a list of unique tags; multi-purpose but primarily for filtering -u option
|
||||
bool dupTagFound = false;
|
||||
foreach (string t in match.Rule.Tags)
|
||||
dupTagFound = !uniqueTagsControl.Add(t);
|
||||
|
||||
//all unique dependendencies saved even if this tag pattern is not-unique
|
||||
var tagPatternRegex = new Regex("Dependency.SourceInclude", RegexOptions.IgnoreCase);
|
||||
String textMatch;
|
||||
if (match.Rule.Tags.Any(v => tagPatternRegex.IsMatch(v)))
|
||||
textMatch = ExtractDependency(fileText, match.Boundary.Index, match.PatternMatch, language);
|
||||
else
|
||||
textMatch = ExtractTextSample(fileText, match.Boundary.Index, match.Boundary.Length);
|
||||
|
||||
//TODO put all this in Issue class and avoid new wrapper type
|
||||
MatchRecord record = new MatchRecord()
|
||||
{
|
||||
Filename = filePath,
|
||||
Language = language,
|
||||
Filesize = fileText.Length,
|
||||
TextSample = textMatch,
|
||||
Excerpt = ExtractExcerpt(fileText, match.StartLocation.Line),
|
||||
Issue = match
|
||||
};
|
||||
|
||||
//preserve issue level characteristics as rolled up meta data of interest
|
||||
bool valid = _appProfile.MetaData.AddStandardProperties(record);
|
||||
|
||||
//bail after extracting any dependency unique items IF user requested
|
||||
if (_arg_outputUniqueTagsOnly && dupTagFound)
|
||||
continue;
|
||||
else if (valid)
|
||||
_appProfile.MatchList.Add(record);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.Logger.Trace("No pattern matches detected for file: " + filePath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#region PostRulesMatchProcessingAssist
|
||||
|
||||
/// <summary>
|
||||
/// Simple but keeps calling code consistent
|
||||
/// </summary>
|
||||
/// <param name="fileText"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
string ExtractTextSample(string fileText, int index, int length)
|
||||
{
|
||||
string result = "";
|
||||
try
|
||||
{
|
||||
result = fileText.Substring(index, length).Trim();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//control the error description and continue; error in devskim possible
|
||||
Program.Logger.Error("Unexpected indexing issue in ExtractTextSample");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to special case additional processing to just get the values without the import keywords etc.
|
||||
/// and encode for html output
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="language"></param>
|
||||
/// <returns></returns>
|
||||
string ExtractDependency(string text, int startIndex, SearchPattern pattern, string language)
|
||||
{
|
||||
// import value; load value; include value;
|
||||
string rawResult = "";
|
||||
int endIndex = text.IndexOf('\n', startIndex);
|
||||
if (-1 != startIndex && -1 != endIndex)
|
||||
{
|
||||
rawResult = text.Substring(startIndex, endIndex - startIndex).Trim();
|
||||
|
||||
//recreate regex used to find entire value
|
||||
Regex regex = new Regex(pattern.Pattern);
|
||||
MatchCollection matches = regex.Matches(rawResult);
|
||||
|
||||
//remove surrounding import or trailing comments
|
||||
if (matches.Count > 0)
|
||||
{
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
if (match.Groups.Count == 1)//handles cases like "using Newtonsoft.Json"
|
||||
{
|
||||
string[] parseValues = match.Groups[0].Value.Split(' ');
|
||||
if (parseValues.Length == 1)
|
||||
rawResult = parseValues[0].Trim();
|
||||
else if (parseValues.Length > 1)
|
||||
rawResult = parseValues[1].Trim(); //should be value; time will tell if fullproof
|
||||
}
|
||||
else if (match.Groups.Count > 1)//handles cases like include <stdio.h>
|
||||
rawResult = match.Groups[1].Value.Trim();
|
||||
//else if > 2 too hard to match; do nothing
|
||||
|
||||
break;//only designed to expect one match per line i.e. not include value include value
|
||||
}
|
||||
}
|
||||
|
||||
String finalResult = rawResult.Replace(";", "");
|
||||
_appProfile.MetaData.UniqueDependencies.Add(finalResult);
|
||||
|
||||
return System.Net.WebUtility.HtmlEncode(finalResult);
|
||||
}
|
||||
|
||||
return rawResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Located here to include during Match creation to avoid a call later or putting in constructor
|
||||
/// Needed in match ensuring value exists at time of report writing rather than expecting a callback
|
||||
/// from the template
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="startLineNumber"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
private string ExtractExcerpt(string text, int startLineNumber, int length = 10)
|
||||
{
|
||||
if (String.IsNullOrEmpty(text))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
var lines = text.Split('\n');
|
||||
var distance = (int)((length - 1.0) / 2.0);
|
||||
|
||||
// Sanity check
|
||||
if (startLineNumber < 0) startLineNumber = 0;
|
||||
if (startLineNumber >= lines.Length) startLineNumber = lines.Length - 1;
|
||||
|
||||
var excerptStartLine = Math.Max(0, startLineNumber - distance);
|
||||
var excerptEndLine = Math.Min(lines.Length - 1, startLineNumber + distance);
|
||||
|
||||
/* This is a little wacky, but if the code snippet we're viewing is already
|
||||
* indented 16 characters minimum, we don't want to show all that extra white-
|
||||
* space, so we'll find the smallest number of spaces at the beginning of
|
||||
* each line and use that.
|
||||
*/
|
||||
var n = (int)Math.Floor(Math.Log10(excerptEndLine) + 1);
|
||||
var minSpaces = -1;
|
||||
for (var i = excerptStartLine; i <= excerptEndLine; i++)
|
||||
{
|
||||
var numPrefixSpaces = lines[i].TakeWhile(c => c == ' ').Count();
|
||||
minSpaces = (minSpaces == -1 || numPrefixSpaces < minSpaces) ? numPrefixSpaces : minSpaces;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
// We want to go from (start - 5) to (start + 5) (off by one?)
|
||||
// LINE=10, len=5, we want 8..12, so N-(L-1)/2 to N+(L-1)/2
|
||||
// But cap those values at 0/end
|
||||
for (var i = excerptStartLine; i <= excerptEndLine; i++)
|
||||
{
|
||||
string line = lines[i].Substring(minSpaces).TrimEnd();
|
||||
sb.AppendLine(line);
|
||||
//string line = System.Net.WebUtility.HtmlEncode(lines[i].Substring(minSpaces).TrimEnd());
|
||||
//sb.AppendFormat("{0} {1}\n", (i + 1).ToString().PadLeft(n, ' '), line);
|
||||
}
|
||||
|
||||
return System.Convert.ToBase64String(Encoding.UTF8.GetBytes(sb.ToString()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void FlushAll()
|
||||
{
|
||||
if (_outputWriter != null)
|
||||
{
|
||||
_outputWriter.WriteApp(_appProfile);
|
||||
|
||||
if (_outputWriter.TextWriter != null && _arg_fileFormat != "html")
|
||||
{
|
||||
_outputWriter.FlushAndClose();//not required for html formal i.e. multiple files already closed
|
||||
_outputWriter = null;
|
||||
if (!String.IsNullOrEmpty(_arg_outputFile))
|
||||
WriteOnce.WriteLine(String.Format("See {0}.", _arg_outputFile));
|
||||
else
|
||||
WriteOnce.WriteLine("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region ZipDecompression
|
||||
|
||||
void ExpandAndProcess(string filename)
|
||||
{
|
||||
// Ignore images and other junk like that
|
||||
var fileExtension = new FileInfo(filename).Extension;
|
||||
var mimeType = MimeTypeMap.GetMimeType(fileExtension);
|
||||
bool mimeMatch = false;
|
||||
if (!IgnoreMimeRegex.IsMatch(mimeType))
|
||||
{
|
||||
var isValidExtension = COMPRESSED_EXTENSIONS.Any(fileExtension.Contains);
|
||||
if (isValidExtension || fileExtension == "ts")
|
||||
mimeMatch = true;
|
||||
else if (mimeType.Contains("zip", StringComparison.CurrentCultureIgnoreCase) || // Should have been caught in file extensions above, but still OK.
|
||||
mimeType.Contains("tar", StringComparison.CurrentCultureIgnoreCase) ||
|
||||
mimeType.Contains("compressed", StringComparison.CurrentCultureIgnoreCase))
|
||||
mimeMatch = true;
|
||||
|
||||
if (mimeMatch)
|
||||
{
|
||||
// Now process the file
|
||||
switch (fileExtension)
|
||||
{
|
||||
case ".tgz":
|
||||
ProcessTarGzFile(filename);
|
||||
break;
|
||||
case ".gz":
|
||||
if (filename.Contains(".tar.gz"))
|
||||
{
|
||||
ProcessTarGzFile(filename);
|
||||
}
|
||||
break;
|
||||
case ".jar":
|
||||
case ".zip":
|
||||
ProcessZipFile(filename);
|
||||
break;
|
||||
case ".gem":
|
||||
case ".tar":
|
||||
case ".nupkg":
|
||||
Program.Logger.Warn($"Processing of {fileExtension} not implemented yet.");
|
||||
break;
|
||||
default:
|
||||
Program.Logger.Warn("no support for compressed type: " + fileExtension);
|
||||
break;
|
||||
}
|
||||
|
||||
_appProfile.MetaData.PackageTypes.Add("compressed");
|
||||
|
||||
}
|
||||
else
|
||||
_appProfile.MetaData.PackageTypes.Add("compressed-unsupported");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessZipFile(string filename)
|
||||
{
|
||||
Program.Logger.Trace("Analyzing .zip file: [{0}])", filename);
|
||||
|
||||
ZipFile zipFile;
|
||||
int filesCount = 0;
|
||||
using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
zipFile = new ZipFile(fileStream);
|
||||
_appProfile.MetaData.TotalFiles = (int)zipFile.Count;
|
||||
foreach (ZipEntry zipEntry in zipFile)
|
||||
{
|
||||
if (zipEntry.IsDirectory)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
filesCount++;
|
||||
byte[] buffer = new byte[4096];
|
||||
var zipStream = zipFile.GetInputStream(zipEntry);
|
||||
if (zipEntry.Size > MAX_FILESIZE)
|
||||
{
|
||||
_appProfile.MetaData.FilesSkipped++;
|
||||
Program.Logger.Error(string.Format("{0} in {1} is too large. File skipped", zipEntry.Name, filename));
|
||||
zipFile.Close();
|
||||
continue;
|
||||
}
|
||||
|
||||
StreamUtils.Copy(zipStream, memoryStream, buffer);
|
||||
var mimeType = MimeTypeMap.GetMimeType(Path.GetExtension(zipEntry.Name));
|
||||
if (IgnoreMimeRegex.IsMatch(mimeType) && new FileInfo(filename).Extension != "ts")
|
||||
{
|
||||
_appProfile.MetaData.FilesSkipped++;
|
||||
Program.Logger.Error("Ignoring zip entry [{0}]", zipEntry.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] streamByteArray = memoryStream.ToArray();
|
||||
ProcessInMemory(Path.GetFileName(zipEntry.Name), Encoding.UTF8.GetString(streamByteArray, 0, streamByteArray.Length));
|
||||
}
|
||||
memoryStream.SetLength(0); // Clear out the stream
|
||||
}
|
||||
|
||||
_appProfile.MetaData.TotalFiles += filesCount;
|
||||
zipFile.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ProcessTarGzFile(string filename)
|
||||
{
|
||||
Program.Logger.Trace("Analyzing .tar.gz file: [{0}])", filename);
|
||||
|
||||
using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
|
||||
using (var gzipStream = new GZipInputStream(fileStream))
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
var tarStream = new TarInputStream(gzipStream);
|
||||
TarEntry tarEntry;
|
||||
int filesCount = 0;
|
||||
while ((tarEntry = tarStream.GetNextEntry()) != null)
|
||||
{
|
||||
if (tarEntry.IsDirectory)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
filesCount++;
|
||||
tarStream.CopyEntryContents(memoryStream);
|
||||
if (tarEntry.Size > MAX_FILESIZE)
|
||||
{
|
||||
_appProfile.MetaData.FilesSkipped++;
|
||||
Program.Logger.Error(string.Format("{0} in {1} is too large. File skipped", tarEntry.Name, filename));
|
||||
tarStream.Close();
|
||||
continue;
|
||||
}
|
||||
|
||||
var mimeType = MimeTypeMap.GetMimeType(Path.GetExtension(tarEntry.Name));
|
||||
if (IgnoreMimeRegex.IsMatch(mimeType) && new FileInfo(filename).Extension != "ts")
|
||||
{
|
||||
_appProfile.MetaData.FilesSkipped++;
|
||||
Program.Logger.Error("Ignoring tar entry [{0}]", tarEntry.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
//file name may contain slashes; remove prior to call
|
||||
byte[] streamByteArray = memoryStream.ToArray();
|
||||
ProcessInMemory(Path.GetFileName(tarEntry.Name), Encoding.UTF8.GetString(streamByteArray, 0, streamByteArray.Length));
|
||||
}
|
||||
|
||||
memoryStream.SetLength(0); // Clear out the stream
|
||||
}
|
||||
_appProfile.MetaData.TotalFiles+= filesCount;
|
||||
tarStream.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.DevSkim;
|
||||
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Commands
|
||||
{
|
||||
public class ExportTagsCommand : ICommand
|
||||
{
|
||||
public enum ExitCode
|
||||
{
|
||||
Success = 0,
|
||||
Error = 1,
|
||||
CriticalError = 2
|
||||
}
|
||||
|
||||
private string _arg_RulesPath;
|
||||
private string _arg_outputFile;
|
||||
|
||||
public ExportTagsCommand(ExportTagsCommandOptions opt)
|
||||
{
|
||||
_arg_RulesPath = opt.CustomRulesPath;
|
||||
_arg_outputFile = opt.OutputFilePath;
|
||||
}
|
||||
|
||||
public int Run()
|
||||
{
|
||||
WriteOnce.Write("Export unique tags command running\n", ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
|
||||
|
||||
|
||||
if (String.IsNullOrEmpty(_arg_RulesPath))
|
||||
{
|
||||
_arg_RulesPath = Helper.GetPath(Helper.AppPath.defaultRules);
|
||||
}
|
||||
else if (!Directory.Exists(_arg_RulesPath) && !File.Exists(_arg_RulesPath))
|
||||
{
|
||||
WriteOnce.Error(String.Format("Not a valid rule file or directory {0}", _arg_RulesPath));
|
||||
|
||||
return (int)ExitCode.CriticalError;
|
||||
}
|
||||
|
||||
|
||||
//setup output
|
||||
TextWriter outputWriter;
|
||||
|
||||
if (!string.IsNullOrEmpty(_arg_outputFile))
|
||||
{
|
||||
outputWriter = File.CreateText(_arg_outputFile);
|
||||
outputWriter.WriteLine(Program.GetVersionString());
|
||||
WriteOnce.Writer = outputWriter;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//override user if no output file so output to console appears
|
||||
WriteOnce.Verbosity = WriteOnce.ConsoleVerbosityLevel.High;
|
||||
}
|
||||
|
||||
//initialize rules
|
||||
RuleSet rules = new RuleSet();
|
||||
rules.AddDirectory(_arg_RulesPath);
|
||||
|
||||
SortedDictionary<string, string> uniqueTags = new SortedDictionary<string, string>();
|
||||
|
||||
foreach (Rule r in rules)
|
||||
{
|
||||
//builds a list of unique tags
|
||||
foreach (string t in r.Tags)
|
||||
{
|
||||
if (uniqueTags.ContainsKey(t))
|
||||
continue;
|
||||
else
|
||||
uniqueTags.Add(t, t);
|
||||
}
|
||||
}
|
||||
|
||||
//separate loop so results are sorted (Sorted type)
|
||||
foreach (string s in uniqueTags.Values)
|
||||
WriteOnce.Any(s, WriteOnce.ConsoleVerbosityLevel.High);
|
||||
|
||||
WriteOnce.Any("Export rule tags completed.", ConsoleColor.Cyan);
|
||||
WriteOnce.FlushAll();
|
||||
|
||||
return (int)ExitCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Commands
|
||||
{
|
||||
public interface ICommand
|
||||
{
|
||||
int Run();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Commands
|
||||
{
|
||||
[Serializable]
|
||||
public class TagsFile
|
||||
{
|
||||
[JsonProperty(PropertyName = "tags")]
|
||||
public string[] Tags { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to compare two source paths and report tag differences
|
||||
/// </summary>
|
||||
public class TagDiffCommand : ICommand
|
||||
{
|
||||
private string _arg_src1, _arg_src2;
|
||||
private string _arg_rulesPath;
|
||||
private string _arg_outputFile;
|
||||
private bool _arg_ignoreDefault;
|
||||
private TagTestType _arg_tagTestType;
|
||||
|
||||
public enum ExitCode
|
||||
{
|
||||
NoDiff = 0,
|
||||
DiffFound = 1,
|
||||
CriticalError = 2
|
||||
}
|
||||
|
||||
enum TagTestType { Equality, Inequality }
|
||||
|
||||
public TagDiffCommand(TagDiffCommandOptions opt)
|
||||
{
|
||||
_arg_src1 = opt.SourcePath1;
|
||||
_arg_src2 = opt.SourcePath2;
|
||||
_arg_rulesPath = opt.CustomRulesPath;
|
||||
_arg_outputFile = opt.OutputFilePath;
|
||||
WriteOnce.ConsoleVerbosityLevel arg_consoleVerbosityLevel;
|
||||
Enum.TryParse(opt.ConsoleVerbosityLevel, true, out arg_consoleVerbosityLevel);
|
||||
WriteOnce.Verbosity = arg_consoleVerbosityLevel;
|
||||
|
||||
if (!Enum.TryParse(opt.TestType, true, out _arg_tagTestType))
|
||||
throw new ArgumentException("Invalid -t argument value", opt.TestType);
|
||||
|
||||
_arg_ignoreDefault = opt.IgnoreDefaultRules;
|
||||
|
||||
}
|
||||
|
||||
public int Run()
|
||||
{
|
||||
WriteOnce.Write("TagDiff command running\n", ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
|
||||
|
||||
|
||||
//setup output
|
||||
TextWriter outputWriter;
|
||||
if (!string.IsNullOrEmpty(_arg_outputFile))
|
||||
{
|
||||
outputWriter = File.CreateText(_arg_outputFile);
|
||||
outputWriter.WriteLine(Program.GetVersionString());
|
||||
WriteOnce.Writer = outputWriter;
|
||||
}
|
||||
|
||||
if (_arg_src1 == _arg_src2)
|
||||
{
|
||||
WriteOnce.Error("Same file passed in for both sources. Test terminated.");
|
||||
return (int)ExitCode.CriticalError;
|
||||
}
|
||||
else if (string.IsNullOrEmpty(_arg_src1) || string.IsNullOrEmpty(_arg_src2))
|
||||
{
|
||||
WriteOnce.Error("Required [path1] or [path2] argument missing.");
|
||||
return (int)ExitCode.CriticalError;
|
||||
}
|
||||
|
||||
//save to quiet analyze cmd
|
||||
WriteOnce.ConsoleVerbosityLevel saveVerbosity = WriteOnce.Verbosity;
|
||||
|
||||
string tmp1 = Path.GetTempFileName();
|
||||
string tmp2 = Path.GetTempFileName();
|
||||
AnalyzeCommand cmd1 = new AnalyzeCommand(new AnalyzeCommandOptions { SourcePath = _arg_src1,
|
||||
OutputFilePath = tmp1,
|
||||
OutputFileFormat = "json",
|
||||
CustomRulesPath = _arg_rulesPath,
|
||||
IgnoreDefaultRules = _arg_ignoreDefault,
|
||||
SimpleTagsOnly = true,
|
||||
UniqueTagsOnly = true,
|
||||
ConsoleVerbosityLevel = "Low" });
|
||||
AnalyzeCommand cmd2 = new AnalyzeCommand(new AnalyzeCommandOptions
|
||||
{
|
||||
SourcePath = _arg_src2,
|
||||
OutputFilePath = tmp2,
|
||||
OutputFileFormat = "json",
|
||||
CustomRulesPath = _arg_rulesPath,
|
||||
IgnoreDefaultRules = _arg_ignoreDefault,
|
||||
SimpleTagsOnly = true,
|
||||
UniqueTagsOnly = true,
|
||||
ConsoleVerbosityLevel = "Low"
|
||||
});
|
||||
|
||||
//quiet analysis commands
|
||||
WriteOnce.Verbosity = WriteOnce.ConsoleVerbosityLevel.Low;
|
||||
AnalyzeCommand.ExitCode result1 = AnalyzeCommand.ExitCode.CriticalError;
|
||||
AnalyzeCommand.ExitCode result2 = AnalyzeCommand.ExitCode.CriticalError;
|
||||
result1 = (AnalyzeCommand.ExitCode)cmd1.Run();
|
||||
result2 = (AnalyzeCommand.ExitCode)cmd2.Run();
|
||||
WriteOnce.Verbosity = saveVerbosity;
|
||||
|
||||
|
||||
bool equal1 = true;
|
||||
bool equal2 = true;
|
||||
|
||||
if (result1 == AnalyzeCommand.ExitCode.CriticalError)
|
||||
{
|
||||
WriteOnce.Error("Critical error processing file " + _arg_src1 + ". Check path.");
|
||||
return (int)ExitCode.CriticalError;
|
||||
}
|
||||
else if (result2 == AnalyzeCommand.ExitCode.CriticalError)
|
||||
{
|
||||
WriteOnce.Error("Critical error processing file " + _arg_src2 + ". Check path.");
|
||||
return (int)ExitCode.CriticalError;
|
||||
}
|
||||
else if (result1 == AnalyzeCommand.ExitCode.NoMatches || result2 == AnalyzeCommand.ExitCode.NoMatches)
|
||||
{
|
||||
WriteOnce.Error("No tags found in one or both source paths");
|
||||
return (int)ExitCode.CriticalError;
|
||||
}
|
||||
else //assumed (result1&2 == AnalyzeCommand.ExitCode.MatchesFound)
|
||||
{
|
||||
string file1TagsJson = File.ReadAllText(tmp1);
|
||||
string file2TagsJson = File.ReadAllText(tmp2);
|
||||
|
||||
var file1Tags = JsonConvert.DeserializeObject<TagsFile[]>(file1TagsJson).First();
|
||||
var file2Tags = JsonConvert.DeserializeObject<TagsFile[]>(file2TagsJson).First();
|
||||
|
||||
WriteOnce.Info("TagDiff Report");
|
||||
|
||||
//can't simply compare counts as content may differ; must compare both in directions
|
||||
|
||||
//first pass
|
||||
WriteOnce.Any("[Tags in " + Path.GetFileName(_arg_src1) + " not detected in " + Path.GetFileName(_arg_src2) + "]",
|
||||
ConsoleColor.White, WriteOnce.ConsoleVerbosityLevel.High);
|
||||
equal1 = CompareTags(file1Tags.Tags, file2Tags.Tags);
|
||||
|
||||
//reverse order for second pass
|
||||
WriteOnce.Any("[Tags in " + Path.GetFileName(_arg_src2) + " not detected in " + Path.GetFileName(_arg_src1) + "]",
|
||||
ConsoleColor.White, WriteOnce.ConsoleVerbosityLevel.High);
|
||||
equal2 = CompareTags(file2Tags.Tags, file1Tags.Tags);
|
||||
|
||||
//final
|
||||
WriteOnce.Any(string.Format("Files were {0} to contain differences.",
|
||||
equal1 && equal2 ? "not found" : "found"), ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
|
||||
|
||||
if (_arg_tagTestType == TagTestType.Inequality)
|
||||
{
|
||||
WriteOnce.Any(string.Format("Test for all [{0}] in source: {1}", _arg_tagTestType.ToString(),
|
||||
equal1 && equal2 ? "failed" : "passed"), (equal1 && equal2) ? ConsoleColor.Red : ConsoleColor.Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteOnce.Any(string.Format("Test for all [{0}] in source: {1}", _arg_tagTestType.ToString(),
|
||||
equal1 && equal2 ? "passed" : "failed"), (equal1 && equal2) ? ConsoleColor.Green : ConsoleColor.Red);
|
||||
}
|
||||
|
||||
WriteOnce.Info("Report completed");
|
||||
|
||||
}
|
||||
|
||||
//cleanup
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(tmp1);
|
||||
File.Delete(tmp2);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//no action needed;
|
||||
}
|
||||
|
||||
WriteOnce.FlushAll();
|
||||
|
||||
return equal1 && equal2 ? (int)ExitCode.NoDiff : (int)ExitCode.DiffFound;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CompareTags(string[] fileTags1, string[] fileTags2)
|
||||
{
|
||||
bool found = true;
|
||||
//are all tags in file1 found in file2
|
||||
foreach (string s1 in fileTags1)
|
||||
{
|
||||
if (!fileTags2.Contains(s1))
|
||||
{
|
||||
found = false;
|
||||
WriteOnce.Any(s1, ConsoleColor.Yellow, WriteOnce.ConsoleVerbosityLevel.High);
|
||||
}
|
||||
}
|
||||
|
||||
//none missing
|
||||
if (found)
|
||||
WriteOnce.Any("None", ConsoleColor.Yellow, WriteOnce.ConsoleVerbosityLevel.High);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.DevSkim;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Commands
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Used to test a specific set of rules were all found in target source; Pass/Fail as well as inverse option to test if a set of rules is not
|
||||
/// found in source code
|
||||
/// </summary>
|
||||
public class TagTestCommand : ICommand
|
||||
{
|
||||
enum TagTestType { RulesPresent, RulesNotPresent}
|
||||
|
||||
private string _arg_srcPath;
|
||||
private string _arg_customRulesPath;
|
||||
private string _arg_outputFile;
|
||||
private bool _arg_ignoreDefault;
|
||||
private TagTestType _arg_tagTestType;
|
||||
|
||||
public enum ExitCode
|
||||
{
|
||||
NoDiff = 0,
|
||||
DiffFound = 1,
|
||||
CriticalError = 2
|
||||
}
|
||||
|
||||
|
||||
/// Compares a set of rules against a source path...
|
||||
/// Used for both RulesPresent and RulesNotePresent options
|
||||
/// Focus is pass/fail not detailed comparison output -see Tagdiff for more
|
||||
public TagTestCommand(TagTestCommandOptions opt)
|
||||
{
|
||||
_arg_srcPath = opt.SourcePath;
|
||||
_arg_customRulesPath = opt.CustomRulesPath;
|
||||
_arg_outputFile = opt.OutputFilePath;
|
||||
WriteOnce.ConsoleVerbosityLevel arg_consoleVerbosityLevel;
|
||||
Enum.TryParse(opt.ConsoleVerbosityLevel, true, out arg_consoleVerbosityLevel);
|
||||
WriteOnce.Verbosity = arg_consoleVerbosityLevel;
|
||||
|
||||
if (string.IsNullOrEmpty(opt.TestType))
|
||||
_arg_tagTestType = TagTestType.RulesPresent;
|
||||
else if (!Enum.TryParse(opt.TestType, true, out _arg_tagTestType))
|
||||
throw new ArgumentException("Invalid -t argument value", opt.TestType);
|
||||
|
||||
_arg_ignoreDefault = opt.IgnoreDefaultRules;
|
||||
|
||||
if (string.IsNullOrEmpty(opt.CustomRulesPath) && _arg_ignoreDefault)
|
||||
throw new ArgumentException("--ignore-default-rules enabled, --custom-rules-path required");
|
||||
}
|
||||
|
||||
|
||||
public int Run()
|
||||
{
|
||||
WriteOnce.Write("TagTest command running", ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
|
||||
WriteOnce.NewLine(WriteOnce.ConsoleVerbosityLevel.Low);
|
||||
|
||||
//setup output
|
||||
TextWriter outputWriter;
|
||||
if (!string.IsNullOrEmpty(_arg_outputFile))
|
||||
{
|
||||
outputWriter = File.CreateText(_arg_outputFile);
|
||||
outputWriter.WriteLine(Program.GetVersionString());
|
||||
WriteOnce.Writer = outputWriter;
|
||||
}
|
||||
|
||||
//init based on true or false present argument value
|
||||
bool testSuccess = false;
|
||||
|
||||
RuleSet rules = new RuleSet();
|
||||
|
||||
#region addrules
|
||||
//get rules from Rules subfolder to avoid having to pack into one file as a resource
|
||||
//review if want to change later...
|
||||
if (!_arg_ignoreDefault)
|
||||
{
|
||||
rules.AddDirectory(Helper.GetPath(Helper.AppPath.defaultRules));
|
||||
}
|
||||
|
||||
//add custom rules paths if any specified by caller
|
||||
if (_arg_customRulesPath != null)
|
||||
{
|
||||
if (Directory.Exists(_arg_customRulesPath))
|
||||
rules.AddDirectory(_arg_customRulesPath);
|
||||
else
|
||||
rules.AddFile(_arg_customRulesPath);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
//one file vs ruleset
|
||||
string tmp1 = Path.GetTempFileName();
|
||||
WriteOnce.ConsoleVerbosityLevel saveVerbosity = WriteOnce.Verbosity;
|
||||
WriteOnce.Verbosity = saveVerbosity;
|
||||
|
||||
AnalyzeCommand cmd1 = new AnalyzeCommand(new AnalyzeCommandOptions
|
||||
{
|
||||
SourcePath = _arg_srcPath,
|
||||
OutputFilePath = tmp1,
|
||||
OutputFileFormat = "json",
|
||||
CustomRulesPath = _arg_customRulesPath,
|
||||
IgnoreDefaultRules = _arg_ignoreDefault,
|
||||
SimpleTagsOnly = true,
|
||||
UniqueTagsOnly = true,
|
||||
ConsoleVerbosityLevel = "Low"
|
||||
});
|
||||
|
||||
AnalyzeCommand.ExitCode result = AnalyzeCommand.ExitCode.CriticalError;
|
||||
|
||||
//quiet analysis commands
|
||||
WriteOnce.Verbosity = WriteOnce.ConsoleVerbosityLevel.Low;
|
||||
result = (AnalyzeCommand.ExitCode)cmd1.Run();
|
||||
WriteOnce.Verbosity = saveVerbosity;
|
||||
|
||||
if (result == AnalyzeCommand.ExitCode.CriticalError)
|
||||
{
|
||||
WriteOnce.Error("Critical error analyzing source path. Check logs for more.");
|
||||
return (int)result;
|
||||
}
|
||||
else if (result == AnalyzeCommand.ExitCode.NoMatches)
|
||||
{
|
||||
WriteOnce.Any(string.Format("Tagtest for [{0}] in source: {1}", _arg_tagTestType.ToString(),
|
||||
_arg_tagTestType == TagTestType.RulesNotPresent ? "success" : "failed"));
|
||||
|
||||
return (int)result;
|
||||
}
|
||||
else //assumed (result == AnalyzeCommand.ExitCode.MatchesFound)
|
||||
{
|
||||
string file1TagsJson = File.ReadAllText(tmp1);
|
||||
var file1TagsObj = JsonConvert.DeserializeObject<TagsFile[]>(file1TagsJson);
|
||||
var file1Tags = file1TagsObj.First(); // here we have a single FileList object
|
||||
File.Delete(tmp1);
|
||||
|
||||
WriteOnce.Info("TestTest Report", WriteOnce.ConsoleVerbosityLevel.High);
|
||||
|
||||
bool cancel = false;
|
||||
foreach (Rule r in rules)
|
||||
{
|
||||
//supports both directions by generalizing
|
||||
string[] testList1 = _arg_tagTestType == TagTestType.RulesNotPresent ?
|
||||
r.Tags : file1Tags.Tags;
|
||||
|
||||
string[] testList2 = _arg_tagTestType == TagTestType.RulesNotPresent ?
|
||||
file1Tags.Tags : r.Tags;
|
||||
|
||||
foreach (string t in testList2)
|
||||
{
|
||||
if (TagTest(testList1, t))
|
||||
{
|
||||
testSuccess = true;
|
||||
WriteOnce.Any("Found " + t + " in source.", WriteOnce.ConsoleVerbosityLevel.High);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
testSuccess = false;
|
||||
cancel = true;
|
||||
WriteOnce.Any("Missing " + t + " in source.", WriteOnce.ConsoleVerbosityLevel.High);
|
||||
}
|
||||
}
|
||||
|
||||
if (cancel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WriteOnce.Any(string.Format("Test for all [{0}] in source: {1}", _arg_tagTestType.ToString(),
|
||||
testSuccess ? "passed" : "failed"), ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
|
||||
|
||||
|
||||
WriteOnce.FlushAll();
|
||||
|
||||
return testSuccess ? (int)ExitCode.NoDiff : (int)ExitCode.DiffFound;
|
||||
}
|
||||
|
||||
bool TagTest(string[] list, string test)
|
||||
{
|
||||
if (_arg_tagTestType == TagTestType.RulesNotPresent)
|
||||
return (!list.Any(v => v.Equals(test)));
|
||||
else
|
||||
return (list.Any(v => v.Equals(test)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.AppInspector.CLI.Writers;
|
||||
using Microsoft.DevSkim;
|
||||
using Microsoft.AppInspector;
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps DevSkim verify for ruleset
|
||||
/// </summary>
|
||||
public class VerifyRulesCommand : ICommand
|
||||
{
|
||||
public enum ExitCode
|
||||
{
|
||||
Verified = 0,
|
||||
NotVerified = 1,
|
||||
CriticalError = 2
|
||||
}
|
||||
|
||||
|
||||
public VerifyRulesCommand(VerifyRulesCommandOptions opt)
|
||||
{
|
||||
_arg_RulesPath = opt.CustomRulesPath;
|
||||
_ignoreDefault = opt.IgnoreDefaultRules;
|
||||
}
|
||||
|
||||
public int Run()
|
||||
{
|
||||
WriteOnce.Write("Verify rules command running\n", ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
|
||||
|
||||
|
||||
if (String.IsNullOrEmpty(_arg_RulesPath) && !_ignoreDefault)
|
||||
_arg_RulesPath = Helper.GetPath(Helper.AppPath.defaultRules);
|
||||
else if (!Directory.Exists(_arg_RulesPath) && !File.Exists(_arg_RulesPath))
|
||||
{
|
||||
WriteOnce.Error(string.Format("Error: Not a valid file or directory {0}", _arg_RulesPath));
|
||||
return (int)ExitCode.CriticalError;
|
||||
}
|
||||
|
||||
//load [each] rules file separately to report out where a failure is happening
|
||||
IEnumerable<string> fileListing;
|
||||
fileListing = Directory.EnumerateFiles(_arg_RulesPath, "*.json", SearchOption.AllDirectories);
|
||||
|
||||
bool bIssues = false;
|
||||
foreach (string filename in fileListing)
|
||||
{
|
||||
if (Path.GetExtension(filename) == ".json")
|
||||
{
|
||||
RuleSet rules = new RuleSet(Program.Logger);
|
||||
|
||||
try
|
||||
{
|
||||
rules.AddFile(filename);
|
||||
RuleProcessor processor = new RuleProcessor(false, false, Program.Logger);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
WriteOnce.Any("Rule parsing failed for file: " + filename);
|
||||
Program.Logger.Debug(e.Message);
|
||||
bIssues = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WriteOnce.Any(string.Format("Verify rules completed {0}", !bIssues ? "successfully" : "with errors."),
|
||||
ConsoleColor.Cyan);
|
||||
|
||||
return bIssues ? (int)ExitCode.NotVerified : (int)ExitCode.Verified;
|
||||
}
|
||||
|
||||
private string _arg_RulesPath;
|
||||
private bool _ignoreDefault;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AppInspector.CLI
|
||||
{
|
||||
class ErrorMessage
|
||||
{
|
||||
public string File { get; set; }
|
||||
public string Path { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string RuleID { get; set; }
|
||||
public bool Warning { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.AppInspector.CLI
|
||||
{
|
||||
public class ExceptionLogger
|
||||
{
|
||||
|
||||
public ExceptionLogger()
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
|
||||
}
|
||||
|
||||
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
LogException((Exception)e.ExceptionObject);
|
||||
}
|
||||
|
||||
private void LogException(Exception e)
|
||||
{
|
||||
string fileName = Write(e);
|
||||
|
||||
Console.Error.WriteLine("Critical exception happend. Details dumped into {0}", fileName);
|
||||
Environment.Exit((int)-1);
|
||||
}
|
||||
|
||||
public string WriteRaw(string rawData)
|
||||
{
|
||||
string fileName = "source.ident.log";
|
||||
FileStream fs = null;
|
||||
try
|
||||
{
|
||||
fs = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
|
||||
using (StreamWriter sw = new StreamWriter(fs))
|
||||
{
|
||||
fs = null;
|
||||
sw.WriteLine("Date: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
|
||||
sw.WriteLine("Platform: " + Environment.OSVersion.VersionString);
|
||||
sw.WriteLine("Processor count: " + Environment.ProcessorCount);
|
||||
sw.WriteLine("Memory: " + Environment.WorkingSet);
|
||||
sw.WriteLine("Culture: " + CultureInfo.CurrentCulture.Name);
|
||||
if (rawData != null)
|
||||
sw.WriteLine(rawData);
|
||||
else
|
||||
sw.WriteLine("NULL argument was passed to exception logger");
|
||||
sw.WriteLine(new string('-', 70));
|
||||
sw.Flush();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
fileName = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (fs != null)
|
||||
fs.Dispose();
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public string Write(Exception ex)
|
||||
{
|
||||
string message = "Message: " + ex.Message + "\r\n";
|
||||
message += "StackTrace: " + ex.StackTrace;
|
||||
|
||||
return WriteRaw(message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
|
||||
static public class Helper
|
||||
{
|
||||
static string _basePath;
|
||||
public enum AppPath { basePath, defaultRules, defaultLog, htmlTemplates, htmlReport, tagGroupPref, tagCounterPref };
|
||||
|
||||
static public string GetPath(AppPath pathType)
|
||||
{
|
||||
string result = "";
|
||||
switch (pathType)
|
||||
{
|
||||
case AppPath.basePath:
|
||||
result = GetBaseAppPath();
|
||||
break;
|
||||
case AppPath.defaultLog:
|
||||
result = Path.Combine(GetBaseAppPath(), "log.txt");
|
||||
break;
|
||||
case AppPath.defaultRules:
|
||||
result = Path.Combine(GetBaseAppPath(), "rules", "default");
|
||||
break;
|
||||
case AppPath.htmlTemplates:
|
||||
result = Path.Combine(GetBaseAppPath(), "htmltemplates");
|
||||
break;
|
||||
case AppPath.htmlReport:
|
||||
result = Path.Combine(GetBaseAppPath(), "htmlreport");
|
||||
break;
|
||||
case AppPath.tagGroupPref:
|
||||
result = Path.Combine(GetBaseAppPath(), "preferences", "tagreportgroups.json");
|
||||
break;
|
||||
case AppPath.tagCounterPref:
|
||||
result = Path.Combine(GetBaseAppPath(), "preferences", "tagcounters.json");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static private string GetBaseAppPath()
|
||||
{
|
||||
if (!String.IsNullOrEmpty(_basePath))
|
||||
return _basePath;
|
||||
|
||||
_basePath = Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory);
|
||||
return _basePath;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to map application type tags or file type or language to identify
|
||||
/// WebApplications, Windows Services, Client Apps, WebServices, Azure Functions etc.
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="language"></param>
|
||||
/// <param name="tag"></param>
|
||||
/// <param name="sample"></param>
|
||||
static public String DetectSolutionType(string fileName, string language, string tag, string sample)
|
||||
{
|
||||
string result = "";
|
||||
|
||||
if (tag.Contains("Application.Type"))
|
||||
{
|
||||
int lastDot = sample.LastIndexOf(".");
|
||||
if (-1 != lastDot)
|
||||
result = sample.Substring(lastDot + 1);
|
||||
}
|
||||
else if (tag.Contains("Microsoft.MVC"))
|
||||
{
|
||||
result = "WebApplication";
|
||||
}
|
||||
else if (tag.Contains("Microsoft.MFC") || tag.Contains(".WinSDK"))
|
||||
{
|
||||
result = "WinClient";
|
||||
}
|
||||
else
|
||||
{
|
||||
///////////first chance
|
||||
switch (fileName)
|
||||
{
|
||||
case "web.config":
|
||||
result = "WebApplication";
|
||||
break;
|
||||
case "app.config":
|
||||
result = ".NETClient";
|
||||
break;
|
||||
case "pom.xml":
|
||||
case "build.make.xml":
|
||||
case "build.gradle":
|
||||
result = "Java";
|
||||
break;
|
||||
case "package.json":
|
||||
result = "Node";
|
||||
break;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(result))
|
||||
{
|
||||
////////////second chance
|
||||
switch (Path.GetExtension(fileName))
|
||||
{
|
||||
case ".cshtml":
|
||||
result = "ASP.NET";
|
||||
break;
|
||||
case ".htm":
|
||||
case ".html":
|
||||
case ".js":
|
||||
result = "WebApplication";
|
||||
break;
|
||||
case "powershell":
|
||||
result = "Script";
|
||||
break;
|
||||
case "shellscript":
|
||||
result = "Script";
|
||||
break;
|
||||
case "wincmdscript":
|
||||
result = "Script";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(result))
|
||||
{
|
||||
///////////third chance
|
||||
switch (language)
|
||||
{
|
||||
case "ruby":
|
||||
case "perl":
|
||||
case "php":
|
||||
result = "WebApplication";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void OpenBrowser(string url)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}"));
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("BROWSER")))
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start("xdg-open", url);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
WriteOnce.Error("Unable to open browser. Open output file directly.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
Process.Start("open", url);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.DevSkim;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Writers
|
||||
{
|
||||
public class MatchRecord
|
||||
{
|
||||
public string Language { get; set; }
|
||||
public string Filename { get; set; }
|
||||
public int Filesize { get; set; }
|
||||
public string TextSample { get; set; }
|
||||
public Issue Issue { get; set; }
|
||||
public string Excerpt { get; set; }
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,325 @@
|
|||
//Copyright(c) Microsoft Corporation.All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using CommandLine;
|
||||
using System.Reflection;
|
||||
using Microsoft.AppInspector.CLI.Commands;
|
||||
using NLog;
|
||||
using NLog.Targets;
|
||||
using NLog.Config;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
|
||||
namespace Microsoft.AppInspector.CLI
|
||||
{
|
||||
#region CommandLineArgOptions
|
||||
|
||||
/// <summary>
|
||||
/// Command option classes for each command verb
|
||||
/// </summary>
|
||||
|
||||
[Verb("analyze", HelpText = "Inspect source directory/file against defined characteristics")]
|
||||
public class AnalyzeCommandOptions
|
||||
{
|
||||
private bool uniqueTagsOnly;
|
||||
|
||||
[Option('s', "source-path", Required = true, HelpText = "Path to source code to inspect (required)")]
|
||||
public string SourcePath { get; set; }
|
||||
|
||||
[Option('o', "output-file-path", Required = false, HelpText = "Path to output file")]
|
||||
public string OutputFilePath { get; set; }
|
||||
|
||||
[Option('f', "output-file-format", Required = false, HelpText = "Output format [html|json|text]", Default = "html")]
|
||||
public string OutputFileFormat { get; set; }
|
||||
|
||||
[Option('e', "text-format", Required = false, HelpText = "Text format specifiers", Default = "Tag:%T,Rule:%N,Ruleid:%R,Confidence:%X,File:%F,Sourcetype:%t,Line:%L,Sample:%m")]
|
||||
public string TextOutputFormat { get; set; }
|
||||
|
||||
[Option('r', "custom-rules-path", Required = false, HelpText = "Custom rules path")]
|
||||
public string CustomRulesPath { get; set; }
|
||||
|
||||
[Option('t', "tag-output-only", Required = false, HelpText = "Output only contains identified tags", Default = false)]
|
||||
public bool SimpleTagsOnly { get; set; }
|
||||
|
||||
[Option('i', "ignore-default-rules", Required = false, HelpText = "Ignore default rules bundled with application", Default = false)]
|
||||
public bool IgnoreDefaultRules { get; set; }
|
||||
|
||||
[Option('u', "unique-tags-only", Required = false, HelpText = "Output only contains unique tag matches", Default = true)]
|
||||
public bool UniqueTagsOnly
|
||||
{
|
||||
get { return uniqueTagsOnly; }
|
||||
set
|
||||
{
|
||||
uniqueTagsOnly = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Option('c', "confidence-filters", Required = false, HelpText = "Outout only if matching confidence <value>,<value> [high|medium|low]", Default = "high,medium")]
|
||||
public string ConfidenceFilters { get; set; }
|
||||
|
||||
[Option('x', "console-verbosity", Required = false, HelpText = "Console verbosity [high|medium|low]", Default = "medium")]
|
||||
public string ConsoleVerbosityLevel { get; set; }
|
||||
|
||||
#region logoptions
|
||||
|
||||
[Option('l', "log-file-path", Required = false, HelpText = "Log file path")]
|
||||
public string LogFilePath { get; set; }
|
||||
[Option('v', "log-file-level", Required = false, HelpText = "Log file level")]
|
||||
public string LogFileLevel { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Verb("tagdiff", HelpText = "Compares unique tag values between two source paths")]
|
||||
public class TagDiffCommandOptions
|
||||
{
|
||||
[Option("src1", Required = true, HelpText = "Source 1 to compare (required)")]
|
||||
public string SourcePath1 { get; set; }
|
||||
|
||||
[Option("src2", Required = true, HelpText = "Source 2 to compare (required")]
|
||||
public string SourcePath2 { get; set; }
|
||||
|
||||
[Option('t', "test-type", Required = false, HelpText = "Type of test to run [equality|inequality]", Default = "equality")]
|
||||
public string TestType { get; set; }
|
||||
|
||||
[Option('r', "custom-rules-path", Required = false, HelpText = "Custom rules path")]
|
||||
public string CustomRulesPath { get; set; }
|
||||
|
||||
[Option('i', "ignore-default-rules", Required = false, HelpText = "Ignore default rules bundled with application", Default = false)]
|
||||
public bool IgnoreDefaultRules { get; set; }
|
||||
|
||||
[Option('o', "output-file-path", Required = false, HelpText = "Path to output file")]
|
||||
public string OutputFilePath { get; set; }
|
||||
|
||||
[Option('x', "console-verbosity", Required = false, HelpText = "Console verbosity [high|medium|low", Default = "medium")]
|
||||
public string ConsoleVerbosityLevel { get; set; }
|
||||
|
||||
|
||||
#region logoptions
|
||||
|
||||
[Option('l', "log-file-path", Required = false, HelpText = "Log file path")]
|
||||
public string LogFilePath { get; set; }
|
||||
[Option('v', "log-file-level", Required = false, HelpText = "Log file level")]
|
||||
public string LogFileLevel { get; set; }
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Verb("tagtest", HelpText = "Test presence of tags in source (compare or verify modes)")]
|
||||
public class TagTestCommandOptions
|
||||
{
|
||||
[Option('s', "source-path", Required = true, HelpText = "Source to test (required)")]
|
||||
public string SourcePath { get; set; }
|
||||
|
||||
[Option('t', "test-type", Required = false, HelpText = "Test to perform [rulespresent|rulesnotpresent] ", Default = "rulespresent")]
|
||||
public string TestType { get; set; }
|
||||
|
||||
[Option('r', "custom-rules-path", Required = false, HelpText = "Custom rules path")]
|
||||
public string CustomRulesPath { get; set; }
|
||||
|
||||
[Option('i', "ignore-default-rules", Required = false, HelpText = "Ignore default rules bundled with application", Default = true)]
|
||||
public bool IgnoreDefaultRules { get; set; }
|
||||
|
||||
[Option('o', "output-file-path", Required = false, HelpText = "Path to output file")]
|
||||
public string OutputFilePath { get; set; }
|
||||
|
||||
[Option('x', "console-verbosity", Required = false, HelpText = "Console verbosity [high|medium|low", Default = "medium")]
|
||||
public string ConsoleVerbosityLevel { get; set; }
|
||||
|
||||
|
||||
#region logoptions
|
||||
|
||||
[Option('l', "log-file-path", Required = false, HelpText = "Log file path")]
|
||||
public string LogFilePath { get; set; }
|
||||
[Option('v', "log-file-level", Required = false, HelpText = "Log file level")]
|
||||
public string LogFileLevel { get; set; }
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Verb("exporttags", HelpText = "Export unique rule tags")]
|
||||
public class ExportTagsCommandOptions
|
||||
{
|
||||
[Option('r', "custom-rules-path", Required = false, HelpText = "Custom rules path")]
|
||||
public string CustomRulesPath { get; set; }
|
||||
|
||||
[Option('i', "ignore-default-rules", Required = false, HelpText = "Ignore default rules bundled with application", Default = false)]
|
||||
public bool IgnoreDefaultRules { get; set; }
|
||||
|
||||
[Option('o', "output-file-path", Required = false, HelpText = "Path to output file")]
|
||||
public string OutputFilePath { get; set; }
|
||||
|
||||
#region logoptions
|
||||
|
||||
[Option('l', "log-file-path", Required = false, HelpText = "Log file path")]
|
||||
public string LogFilePath { get; set; }
|
||||
[Option('v', "log-file-level", Required = false, HelpText = "Log file level")]
|
||||
public string LogFileLevel { get; set; }
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
[Verb("verifyrules", HelpText = "Verify rules syntax is valid")]
|
||||
public class VerifyRulesCommandOptions
|
||||
{
|
||||
[Option('r', "custom-rules-path", Required = false, HelpText = "Custom rules path")]
|
||||
public string CustomRulesPath { get; set; }
|
||||
|
||||
[Option('i', "ignore-default-rules", Required = false, HelpText = "Ignore default rules bundled with application", Default = false)]
|
||||
public bool IgnoreDefaultRules { get; set; }
|
||||
|
||||
#region logoptions
|
||||
|
||||
[Option('l', "log-file-path", Required = false, HelpText = "Log file path")]
|
||||
public string LogFilePath { get; set; }
|
||||
[Option('v', "log-file-level", Required = false, HelpText = "Log file level")]
|
||||
public string LogFileLevel { get; set; }
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
class Program
|
||||
{
|
||||
static bool _uniqueOverRide = true;
|
||||
|
||||
public static string GetVersionString()
|
||||
{
|
||||
return String.Format("Microsoft Application Inspector {0}", GetVersion());
|
||||
}
|
||||
|
||||
public static string GetVersion()
|
||||
{
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
|
||||
return fileVersionInfo.ProductVersion;
|
||||
}
|
||||
|
||||
static public Logger Logger { get; set; }
|
||||
|
||||
static bool ConsoleNoWait { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Program entry point which defines command verbs and options to running
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
static void Main(string[] args)
|
||||
{
|
||||
WriteOnce.Verbosity = WriteOnce.ConsoleVerbosityLevel.Medium;
|
||||
//TODO had to add work around for very strange behavior from cmdlineparser that will not accept a false from
|
||||
//the command line; several attempts to force, rename etc. to no avail. This works for now.
|
||||
if (args.Length > 0 && args[0] == "analyze")
|
||||
{
|
||||
for (int i=0;i<args.Length;i++)
|
||||
{
|
||||
if (args[i] == "-u" || args[i] == "--unique-tags-only")
|
||||
_uniqueOverRide = args[i + 1] == "true";
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
WriteOnce.Info(GetVersionString());
|
||||
var argsResult = Parser.Default.ParseArguments<AnalyzeCommandOptions,
|
||||
TagDiffCommandOptions,
|
||||
TagTestCommandOptions,
|
||||
ExportTagsCommandOptions,
|
||||
VerifyRulesCommandOptions>(args)
|
||||
.MapResult(
|
||||
(AnalyzeCommandOptions opts) => RunAnalyzeCommand(opts),
|
||||
(TagDiffCommandOptions opts) => RunTagDiffCommand(opts),
|
||||
(TagTestCommandOptions opts) => RunTagTestCommand(opts),
|
||||
(ExportTagsCommandOptions opts) => RunExportTagsCommand(opts),
|
||||
(VerifyRulesCommandOptions opts) => RunVerifyRulesCommand(opts),
|
||||
errs => 1
|
||||
);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
WriteOnce.Error("Runtime error encountered. Check log or log filtering options for more.");
|
||||
WriteOnce.Error($"Runtime error: {e.Message}\n{e.StackTrace}");//no sensitive data expected in output
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static int RunAnalyzeCommand(AnalyzeCommandOptions opts)
|
||||
{
|
||||
opts.UniqueTagsOnly = _uniqueOverRide;
|
||||
SetupLogging(opts.LogFilePath, opts.LogFileLevel);
|
||||
return new AnalyzeCommand(opts).Run();
|
||||
}
|
||||
|
||||
private static int RunTagDiffCommand(TagDiffCommandOptions opts)
|
||||
{
|
||||
SetupLogging(opts.LogFilePath, opts.LogFileLevel);
|
||||
return new TagDiffCommand(opts).Run();
|
||||
}
|
||||
|
||||
private static int RunTagTestCommand(TagTestCommandOptions opts)
|
||||
{
|
||||
SetupLogging(opts.LogFilePath, opts.LogFileLevel);
|
||||
return new TagTestCommand(opts).Run();
|
||||
}
|
||||
|
||||
private static int RunExportTagsCommand(ExportTagsCommandOptions opts)
|
||||
{
|
||||
SetupLogging(opts.LogFilePath, opts.LogFileLevel);
|
||||
return new ExportTagsCommand(opts).Run();
|
||||
}
|
||||
|
||||
private static int RunVerifyRulesCommand(VerifyRulesCommandOptions opts)
|
||||
{
|
||||
SetupLogging(opts.LogFilePath, opts.LogFileLevel);
|
||||
return new VerifyRulesCommand(opts).Run();
|
||||
}
|
||||
|
||||
|
||||
static void SetupLogging(string logFilePath, string logFileLevel)
|
||||
{
|
||||
var config = new NLog.Config.LoggingConfiguration();
|
||||
|
||||
if (String.IsNullOrEmpty(logFilePath))
|
||||
{
|
||||
logFilePath = Helper.GetPath(Helper.AppPath.defaultLog);
|
||||
//if using default app log path clean up previous for convenience in reading
|
||||
if (File.Exists(logFilePath))
|
||||
File.Delete(logFilePath);
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(logFileLevel))
|
||||
logFileLevel = "ERROR";
|
||||
|
||||
using (var fileTarget = new FileTarget()
|
||||
{
|
||||
Name = "LogFile",
|
||||
FileName = logFilePath,
|
||||
Layout = @"${date:universalTime=true:format=s} ${threadid} ${level:uppercase=true} - ${message}",
|
||||
ForceMutexConcurrentWrites = true
|
||||
|
||||
})
|
||||
{
|
||||
config.AddTarget(fileTarget);
|
||||
config.LoggingRules.Add(new LoggingRule("*", LogLevel.FromString(logFileLevel), fileTarget));
|
||||
}
|
||||
|
||||
LogManager.Configuration = config;
|
||||
Logger = LogManager.GetCurrentClassLogger();
|
||||
Logger.Info("["+ DateTime.Now.ToLocalTime() + "] //////////////////////////////////////////////////////////");
|
||||
WriteOnce.Log = Logger;//allows log to be written to as well as console or output file
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Any CPU</Platform>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<PublishDir>bin\Release\netcoreapp3.0\publish\</PublishDir>
|
||||
<SelfContained>false</SelfContained>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -0,0 +1,83 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace AppInspector.CLI.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AppInspector.CLI.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] comments {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("comments", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] languages {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("languages", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="comments" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\..\Microsoft.DevSkim\Resources\comments.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="languages" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\..\Microsoft.DevSkim\Resources\languages.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"profiles": {
|
||||
"AppInspect..CLI": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.DevSkim;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Dynamic;
|
||||
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Writers
|
||||
{
|
||||
/// <summary>
|
||||
/// Root parent for tag group preferences file
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class TagCategory
|
||||
{
|
||||
public enum tagInfoType { uniqueTags, allTags };
|
||||
[JsonProperty(PropertyName = "type")]
|
||||
public tagInfoType Type;
|
||||
[JsonProperty(PropertyName = "categoryName")]
|
||||
public String Name { get; set; }
|
||||
[JsonProperty(PropertyName = "groups")]
|
||||
public List<TagGroup> Groups { get; set; }
|
||||
|
||||
public TagCategory()
|
||||
{
|
||||
Groups = new List<TagGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to read customizable preference for Profile page e.g. rules\profile\profile.json
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class TagGroup
|
||||
{
|
||||
[JsonProperty(PropertyName = "title")]
|
||||
public string Title { get; set; }
|
||||
[JsonIgnore]
|
||||
public string IconURL { get; set; }
|
||||
[JsonProperty(PropertyName = "dataRef")]
|
||||
public string DataRef { get; set; }
|
||||
[JsonProperty(PropertyName = "patterns")]
|
||||
public List<TagSearchPattern> Patterns { get; set; }
|
||||
|
||||
public TagGroup()
|
||||
{
|
||||
Patterns = new List<TagSearchPattern>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public class TagSearchPattern
|
||||
{
|
||||
[JsonProperty(PropertyName = "searchPattern")]
|
||||
public string SearchPattern { get; set; }
|
||||
[JsonProperty(PropertyName = "displayName")]
|
||||
public string DisplayName { get; set; }
|
||||
[JsonProperty(PropertyName = "detectedIcon")]
|
||||
public string DetectedIcon { get; set; }
|
||||
[JsonProperty(PropertyName = "notDetectedIcon")]
|
||||
public string NotDetectedIcon { get; set; }
|
||||
[JsonProperty(PropertyName = "detected")]
|
||||
public bool Detected { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Primary use is development of lists of tags with specific group or pattern properties in reporting
|
||||
/// </summary>
|
||||
public class TagInfo
|
||||
{
|
||||
public string Tag { get; set; }
|
||||
public string ShortTag { get; set; }
|
||||
[JsonIgnore]
|
||||
public string StatusIcon { get; set; }
|
||||
private string _confidence;
|
||||
public string Confidence
|
||||
{
|
||||
get { return _confidence; }
|
||||
set
|
||||
{
|
||||
DevSkim.Confidence test;
|
||||
try
|
||||
{
|
||||
if (Enum.TryParse(value, true, out test))
|
||||
this._confidence = value;
|
||||
}
|
||||
catch (Exception)//control error description
|
||||
{
|
||||
throw new Exception("Invalid argument value set attempt for Confidence");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public string Severity { get; set; }
|
||||
public bool Detected { get; set; }
|
||||
[JsonIgnore]
|
||||
public string Msg
|
||||
{ get { return Detected ? "Not found" : "Confidence"; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public class TagCounter
|
||||
{
|
||||
[JsonProperty(PropertyName = "tag")]
|
||||
public string Tag { get; set; }
|
||||
[JsonProperty(PropertyName = "displayName")]
|
||||
public string ShortTag { get; set; }
|
||||
[JsonProperty(PropertyName = "count")]
|
||||
public int Count { get; set; }
|
||||
[JsonProperty(PropertyName = "includeAsMatch")]
|
||||
public bool IncludeAsMatch { get; set; }
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public class TagException
|
||||
{
|
||||
[JsonProperty(PropertyName = "tag")]
|
||||
public string Tag { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
// Copyright(C) Microsoft.All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using NLog;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Wraps Console, Output and Log Writes for convenience to write once from calling
|
||||
/// code to increase readability and for allowing replacement of console print
|
||||
/// functionality in conjunction logger which may have console configuration enabled
|
||||
/// Allows a Write once feature and protects code from console/log changes to standard out
|
||||
/// Use: call to write to console, file output and log in one call OR for log file only
|
||||
/// output call logger directly
|
||||
///
|
||||
/// Note: NLOG is not consistent writing to standard out console making it impossible
|
||||
/// to predict when it will be visible thus it is largely used for file log output only
|
||||
/// </summary>
|
||||
public class WriteOnce
|
||||
{
|
||||
public enum ConsoleVerbosityLevel { High, Medium, Low, None }
|
||||
|
||||
private static ConsoleColor _infoForeColor = ConsoleColor.Magenta;
|
||||
private static ConsoleColor _errorForeColor = ConsoleColor.Red;
|
||||
private static ConsoleColor _generalForeColor = ConsoleColor.Gray;
|
||||
public static ConsoleVerbosityLevel Verbosity { get; set; }
|
||||
|
||||
public static Logger Log {get; set;}
|
||||
public static TextWriter Writer { get; set; }
|
||||
public ConsoleColor InfoForeColor { set { _infoForeColor = value; } }
|
||||
public ConsoleColor ErrorForeColor { set { _errorForeColor = value; } }
|
||||
|
||||
public static void Info(string s, ConsoleVerbosityLevel verbosityLevel=ConsoleVerbosityLevel.Medium)
|
||||
{
|
||||
if (Log != null && Log.Name != "Console")
|
||||
Log.Info(s);
|
||||
|
||||
if (Writer != null && Writer != Console.Out)
|
||||
Writer.WriteLine(s);
|
||||
|
||||
WriteLine(s, _infoForeColor, verbosityLevel);
|
||||
}
|
||||
|
||||
|
||||
public static void Any(string s, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
|
||||
{
|
||||
Any(s, _generalForeColor, verbosityLevel);
|
||||
}
|
||||
|
||||
|
||||
public static void Any(string s, ConsoleColor foreColor, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
|
||||
{
|
||||
if (Log != null && Log.Name != "Console")
|
||||
Log.Info(s);
|
||||
|
||||
if (Writer != null && Writer != Console.Out)
|
||||
Writer.WriteLine(s);
|
||||
|
||||
WriteLine(s, foreColor, verbosityLevel);
|
||||
}
|
||||
|
||||
public static void Error(string s, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
|
||||
{
|
||||
if (Log != null && Log.Name != "Console")
|
||||
Log.Error(s);
|
||||
|
||||
WriteLine(s, _errorForeColor, verbosityLevel);
|
||||
}
|
||||
|
||||
|
||||
public static void NewLine(ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
|
||||
{
|
||||
if (verbosityLevel >= Verbosity)
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
public static void Write(string s, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
|
||||
{
|
||||
Write(s, _infoForeColor,verbosityLevel);
|
||||
}
|
||||
|
||||
|
||||
public static void WriteLine(string s, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
|
||||
{
|
||||
WriteLine(s, _infoForeColor, verbosityLevel);
|
||||
}
|
||||
|
||||
|
||||
public static void Write(string s, ConsoleColor foreground, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
|
||||
{
|
||||
if (verbosityLevel >= Verbosity)
|
||||
{
|
||||
ConsoleColor lastForecolor = Console.ForegroundColor;
|
||||
Console.ForegroundColor = foreground;
|
||||
Console.Write(s);
|
||||
Console.ForegroundColor = lastForecolor;
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteLine(string s, ConsoleColor foreground, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
|
||||
{
|
||||
if (verbosityLevel >= Verbosity)
|
||||
{
|
||||
ConsoleColor lastForecolor = Console.ForegroundColor;
|
||||
Console.ForegroundColor = foreground;
|
||||
Console.WriteLine(s);
|
||||
Console.ForegroundColor = lastForecolor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void FlushAll()
|
||||
{
|
||||
if (Writer != null)
|
||||
{
|
||||
//cleanup
|
||||
Writer.Flush();
|
||||
Writer.Close();
|
||||
Writer = null;
|
||||
|
||||
WriteOnce.WriteLine("See output file if specified. For HTML format option, please see the HTMLOutput folder created.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Writers
|
||||
{
|
||||
public class DummyWriter : Writer
|
||||
{
|
||||
|
||||
public override void WriteApp(AppProfile appCharacteriation)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override void FlushAndClose()
|
||||
{
|
||||
// This is intentionaly empty
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,213 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using HandlebarsDotNet;
|
||||
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Writers
|
||||
{
|
||||
|
||||
public class HTMLWriter : Writer
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// WriteApp dynamically pulls from the template folder and copies all files to the target report folder
|
||||
/// making sure to process any "template" named files as needed before compilation by the templating framework
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
public override void WriteApp(AppProfile app)
|
||||
{
|
||||
string templatesPath = Helper.GetPath(Helper.AppPath.htmlTemplates);
|
||||
string htmlReportsPath = Helper.GetPath(Helper.AppPath.htmlReport);
|
||||
IEnumerable<string> files = Directory.EnumerateFiles(templatesPath, "*.*");
|
||||
|
||||
//report too unwieldy for single file so place in named directory; create if new
|
||||
if (!Directory.Exists(htmlReportsPath))
|
||||
Directory.CreateDirectory(htmlReportsPath);
|
||||
|
||||
foreach (string filePath in files)
|
||||
{
|
||||
if (!filePath.Contains("template-"))
|
||||
File.Copy(filePath, Path.Combine(htmlReportsPath, Path.GetFileName(filePath)), true);
|
||||
else
|
||||
{
|
||||
string finalPath = filePath.Replace("template-", "");
|
||||
ProcessTemplate(filePath, Path.Combine(htmlReportsPath, Path.GetFileName(finalPath)), app);
|
||||
}
|
||||
}
|
||||
|
||||
//writes out json report for convenience and linking to from report page(s)
|
||||
String jsonReportPath = Path.Combine(htmlReportsPath, "jsonreport.json");
|
||||
Writer jsonWriter = WriterFactory.GetWriter("json", jsonReportPath);
|
||||
jsonWriter.TextWriter = File.CreateText(jsonReportPath);
|
||||
jsonWriter.WriteApp(app);
|
||||
jsonWriter.FlushAndClose();
|
||||
|
||||
OpenBrowser(Path.Combine(htmlReportsPath, "index.html"));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ProcessTemplate will match files with tagcategories to locate the right set of data to replace before
|
||||
/// final template compilation by the templating framework used
|
||||
/// </summary>
|
||||
/// <param name="templateFilePath"></param>
|
||||
/// <param name="finalFilePath"></param>
|
||||
/// <param name="app"></param>
|
||||
private void ProcessTemplate(string templateFilePath, string finalFilePath, AppProfile app)
|
||||
{
|
||||
string categoryName = null;
|
||||
foreach (TagCategory tagCategory in app.TagGroupPreferences)
|
||||
{
|
||||
if (templateFilePath.Contains(tagCategory.Name))
|
||||
{
|
||||
categoryName = tagCategory.Name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string processedTemplate = GetTemplate(templateFilePath, categoryName, app);
|
||||
CompileTemplate(processedTemplate, finalFilePath, app);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Provides feature to allow dynamic creation of tag groups in template before final template compilation
|
||||
/// Used in profile and composition html pages. If no special processing is required, returns the raw
|
||||
/// template which is assumed to contain simple template framework compatible keywords or none at all.
|
||||
/// </summary>
|
||||
/// <param name="templateFileName"></param>
|
||||
/// <param name="category"></param>
|
||||
/// <param name="app"></param>
|
||||
/// <returns></returns>
|
||||
string GetTemplate(string templateFileName, string category, AppProfile app)
|
||||
{
|
||||
string result = "";
|
||||
|
||||
string templateText = File.ReadAllText(templateFileName);
|
||||
List<TagGroup> tagGroupList = string.IsNullOrEmpty(category) ? null : app.GetCategoryTagGroups(category);
|
||||
|
||||
string subSectionStartPattern = "[[subSectionStart]]";
|
||||
string subSectionEndPattern = "[[subSectionEnd]]";
|
||||
int istartSection = templateText.IndexOf(subSectionStartPattern);
|
||||
int iendSection = templateText.IndexOf(subSectionEndPattern);
|
||||
|
||||
if (tagGroupList == null || istartSection == -1 || iendSection == -1)
|
||||
return templateText;
|
||||
|
||||
string subSectionTemplate = templateText.Substring(istartSection, iendSection-istartSection+subSectionEndPattern.Length+1);
|
||||
subSectionTemplate = subSectionTemplate.Replace(subSectionStartPattern, "");
|
||||
subSectionTemplate = subSectionTemplate.Replace(subSectionEndPattern, "");
|
||||
|
||||
//loop through optional sections for group to replace with actual variable names, titles etc.
|
||||
foreach (TagGroup tagGroup in tagGroupList)
|
||||
{
|
||||
result += subSectionTemplate;
|
||||
int isectionName= result.IndexOf("[[subSectionName]]");
|
||||
if (-1 != isectionName)
|
||||
{
|
||||
result = result.Replace("[[subSectionName]]", tagGroup.Title);
|
||||
}
|
||||
|
||||
int isectionVarRef = result.IndexOf("[[subSectionVarRef]]");
|
||||
if (-1 != isectionVarRef)
|
||||
{
|
||||
result = result.Replace("[[subSectionVarRef]]", "tagGrp" + tagGroup.DataRef);
|
||||
result = result.Replace("tagGrptagGrp", "tagGrp"); //in case someone thinks to add in profile.json etc.
|
||||
}
|
||||
}
|
||||
|
||||
//create dup sub template section with start/end and use as revised template the continue compilation
|
||||
string leftSide = templateText.Substring(0, istartSection);
|
||||
string rightSide = templateText.Substring(iendSection + subSectionEndPattern.Length);
|
||||
string finalResult = leftSide + result + rightSide;
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void CompileTemplateSimple(string templateFileName, string outputFileName, AppProfile app)
|
||||
{
|
||||
string templateText = File.ReadAllText(templateFileName);
|
||||
CompileTemplate(templateText, outputFileName, app);
|
||||
}
|
||||
|
||||
|
||||
private void CompileTemplate(string templateText, string outputFileName, AppProfile app)
|
||||
{
|
||||
//add app object for access to various items (TBD if needed in future)
|
||||
var data = new Dictionary<string, object>()
|
||||
{
|
||||
{ "app", app }
|
||||
};
|
||||
|
||||
//now add all list groups
|
||||
foreach (string outerKey in app.KeyedTagInfoLists.Keys)
|
||||
data.Add(outerKey, app.KeyedTagInfoLists[outerKey]);
|
||||
|
||||
foreach (string outerKey in app.KeyedSortedTagInfoLists.Keys)
|
||||
data.Add(outerKey, app.KeyedSortedTagInfoLists[outerKey]);
|
||||
|
||||
data.Add("selectTagCounters", app.MetaData.TagCounters);
|
||||
|
||||
foreach (string outerKey in app.MetaData.KeyedPropertyLists.Keys)
|
||||
data.Add(outerKey, app.MetaData.KeyedPropertyLists[outerKey]);
|
||||
|
||||
TextWriter textWriter = null;
|
||||
|
||||
try
|
||||
{
|
||||
var template = Handlebars.Compile(templateText);
|
||||
textWriter = File.CreateText(outputFileName);
|
||||
textWriter.Write(template(data));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteOnce.Error("Error creating HTML report");
|
||||
throw new Exception(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (textWriter != null)
|
||||
{
|
||||
textWriter.Flush();
|
||||
textWriter.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void OpenBrowser(string url)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}"));
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
Process.Start("xdg-open", url);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
Process.Start("open", url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void FlushAndClose()
|
||||
{
|
||||
TextWriter.Flush();
|
||||
TextWriter.Close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Microsoft.DevSkim;
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Writers
|
||||
{
|
||||
/// <summary>
|
||||
/// Subset of MatchRecord and Issue properties for json output
|
||||
/// TODO: look at possible consolidation with MatchRecord...do we need Issue.Rule etc. which are not
|
||||
/// wanted for json output in their entirety
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class MatchItems
|
||||
{
|
||||
public MatchItems(MatchRecord matchRecord)
|
||||
{
|
||||
FileName = matchRecord.Filename;
|
||||
SourceType = matchRecord.Language;
|
||||
StartLocationLine = matchRecord.Issue.StartLocation.Line;
|
||||
StartLocationColumn = matchRecord.Issue.StartLocation.Column;
|
||||
EndLocationLine = matchRecord.Issue.EndLocation.Line;
|
||||
EndLocationColumn = matchRecord.Issue.EndLocation.Column;
|
||||
BoundaryIndex = matchRecord.Issue.Boundary.Index;
|
||||
BoundaryLength = matchRecord.Issue.Boundary.Length;
|
||||
RuleId = matchRecord.Issue.Rule.Id;
|
||||
Severity = matchRecord.Issue.Rule.Severity.ToString();
|
||||
RuleName = matchRecord.Issue.Rule.Name;
|
||||
RuleDescription = matchRecord.Issue.Rule.Description;
|
||||
PatternConfidence = matchRecord.Issue.Confidence.ToString();
|
||||
PatternType = matchRecord.Issue.PatternMatch.PatternType.ToString();
|
||||
MatchingPattern = matchRecord.Issue.PatternMatch.Pattern;
|
||||
Sample = matchRecord.TextSample;
|
||||
Excerpt = matchRecord.Excerpt;
|
||||
Tags = matchRecord.Issue.Rule.Tags;
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "fileName")]
|
||||
public string FileName { get; set; }
|
||||
[JsonProperty(PropertyName = "ruleId")]
|
||||
public string RuleId { get; set; }
|
||||
[JsonProperty(PropertyName = "ruleName")]
|
||||
public string RuleName { get; set; }
|
||||
[JsonProperty(PropertyName = "ruleDescription")]
|
||||
public string RuleDescription { get; set; }
|
||||
[JsonProperty(PropertyName = "pattern")]
|
||||
public string MatchingPattern { get; set; }
|
||||
[JsonProperty(PropertyName = "type")]
|
||||
public string PatternType { get; set; }
|
||||
[JsonProperty(PropertyName = "confidence")]
|
||||
public string PatternConfidence { get; set; }
|
||||
[JsonProperty(PropertyName = "severity")]
|
||||
public string Severity { get; set; }
|
||||
[JsonProperty(PropertyName = "tags")]
|
||||
public string[] Tags { get; set; }
|
||||
[JsonProperty(PropertyName = "sourceType")]
|
||||
public string SourceType { get; set; }
|
||||
[JsonProperty(PropertyName = "sample")]
|
||||
public string Sample { get; set; }
|
||||
[JsonProperty(PropertyName = "excerpt")]
|
||||
public string Excerpt { get; set; }
|
||||
[JsonProperty(PropertyName = "startLocationLine")]
|
||||
public int StartLocationLine { get; set; }
|
||||
[JsonProperty(PropertyName = "startLocationColumn")]
|
||||
public int StartLocationColumn { get; set; }
|
||||
[JsonProperty(PropertyName = "endLocationLine")]
|
||||
public int EndLocationLine { get; set; }
|
||||
[JsonProperty(PropertyName = "endLocationColumn")]
|
||||
public int EndLocationColumn { get; set; }
|
||||
[JsonProperty(PropertyName = "boundaryIndex")]
|
||||
public int BoundaryIndex { get; set; }
|
||||
[JsonProperty(PropertyName = "boundaryLength")]
|
||||
public int BoundaryLength { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Writes in json format
|
||||
/// Users can select arguments to filter output to 1. only simple tags 2. only matchlist without rollup metadata etc. 3. everything
|
||||
/// Lists of tagreportgroups are written as well as match list details so users have chose to present the same
|
||||
/// UI as shown in the HTML report to the level of detail desired...
|
||||
/// </summary>
|
||||
public class JsonWriter : Writer
|
||||
{
|
||||
List<Dictionary<string, object>> jsonResult = new List<Dictionary<string, object>>();
|
||||
|
||||
public override void WriteApp(AppProfile app)
|
||||
{
|
||||
// Store the results here temporarily building up a list of items in the desired order etc.
|
||||
Dictionary<string, object> itemList = new Dictionary<string, object>(); ;
|
||||
|
||||
if (app.SimpleTagsOnly)
|
||||
{
|
||||
List<string> keys = new List<string>(app.MetaData.UniqueTags);
|
||||
itemList.Add("tags", keys);
|
||||
keys.Sort();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!app.ExcludeRollup)
|
||||
itemList.Add("AppProfile", app);
|
||||
|
||||
//matches are added this way to avoid output of entire set of MatchItem properties which include full rule/patterns/cond.
|
||||
List<MatchItems> matches = new List<MatchItems>();
|
||||
|
||||
foreach (MatchRecord match in app.MatchList)
|
||||
{
|
||||
MatchItems matchItem = new MatchItems(match);
|
||||
matches.Add(matchItem);
|
||||
}
|
||||
|
||||
itemList.Add("matchDetails", matches);
|
||||
}
|
||||
|
||||
jsonResult.Add(itemList);
|
||||
}
|
||||
|
||||
|
||||
public override void FlushAndClose()
|
||||
{
|
||||
TextWriter.Write(JsonConvert.SerializeObject(jsonResult, Formatting.Indented));
|
||||
TextWriter.Flush();
|
||||
TextWriter.Close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DotLiquid;
|
||||
using DotLiquid.FileSystems;
|
||||
using Newtonsoft.Json;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Writers
|
||||
{
|
||||
public class Random : DotLiquid.Tag
|
||||
{
|
||||
private int _max;
|
||||
|
||||
public override void Initialize(string tagName, string markup, List<string> tokens)
|
||||
{
|
||||
base.Initialize(tagName, markup, tokens);
|
||||
_max = Convert.ToInt32(markup);
|
||||
}
|
||||
}
|
||||
|
||||
public class LiquidWriter : Writer
|
||||
{
|
||||
/**
|
||||
* Writes data (defined in `app`) to the HTML template.
|
||||
*/
|
||||
public override void WriteApp(AppProfile app)
|
||||
{
|
||||
var htmlTemplateText = File.ReadAllText("html/index.html");
|
||||
Template.FileSystem = new EmbeddedFileSystem(Assembly.GetEntryAssembly(), "AppInspector.CLI.html.partials");
|
||||
Template.RegisterTag<Random>("random");
|
||||
|
||||
RegisterSafeType(typeof(AppProfile));
|
||||
RegisterSafeType(typeof(AppMetaData));
|
||||
|
||||
var htmlTemplate = Template.Parse(htmlTemplateText);
|
||||
|
||||
var data = new Dictionary<string, object>();
|
||||
data["AppProfile"] = app;
|
||||
|
||||
//matches are added this way to avoid output of entire set of MatchItem properties which include full rule/patterns/cond.
|
||||
List<MatchItems> matches = new List<MatchItems>();
|
||||
|
||||
foreach (MatchRecord match in app.MatchList)
|
||||
{
|
||||
MatchItems matchItem = new MatchItems(match);
|
||||
matches.Add(matchItem);
|
||||
}
|
||||
data["matchDetails"] = matches;
|
||||
var hashData = new Hash();
|
||||
hashData["profile"] = app;
|
||||
hashData["match_details"] = matches;
|
||||
hashData["json"] = JsonConvert.SerializeObject(data, Formatting.Indented);
|
||||
hashData["application_version"] = Program.GetVersionString();
|
||||
|
||||
var htmlResult = htmlTemplate.Render(hashData);
|
||||
File.WriteAllText("output.html", htmlResult);
|
||||
//this.TextWriter.Write(htmlResult);
|
||||
|
||||
//writes out json report for convenience and linking to from report page(s)
|
||||
String jsonReportPath = Path.Combine("output.json");
|
||||
Writer jsonWriter = WriterFactory.GetWriter("json", jsonReportPath);
|
||||
jsonWriter.TextWriter = File.CreateText(jsonReportPath);
|
||||
jsonWriter.WriteApp(app);
|
||||
jsonWriter.FlushAndClose();
|
||||
|
||||
Helper.OpenBrowser("output.html");
|
||||
}
|
||||
|
||||
public override void FlushAndClose()
|
||||
{
|
||||
TextWriter.Flush();
|
||||
TextWriter.Close();
|
||||
}
|
||||
|
||||
private void RegisterSafeType(Type type)
|
||||
{
|
||||
Template.RegisterSafeType(type, (t) => t.ToString());
|
||||
Template.RegisterSafeType(type, type.GetMembers(BindingFlags.Instance).Select((e) => e.Name).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Writers
|
||||
{
|
||||
public class SimpleTextWriter : Writer
|
||||
{
|
||||
readonly int COLUMN_MAX = 80;
|
||||
|
||||
public SimpleTextWriter(string formatString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(formatString))
|
||||
_formatString = "Tag:%T,Rule:%N,Ruleid:%R,Confidence:%X,File:%F,Sourcetype:%t,Line:%L,Sample:%m";
|
||||
else
|
||||
_formatString = formatString;
|
||||
}
|
||||
|
||||
public override void WriteApp(AppProfile app)
|
||||
{
|
||||
//option for tags only vs full match record structure; used tagdiff and tagtest commands
|
||||
if (app.SimpleTagsOnly)
|
||||
{
|
||||
List<string> tags = new List<string>();
|
||||
foreach (MatchRecord match in app.MatchList)
|
||||
foreach (string tag in match.Issue.Rule.Tags)
|
||||
tags.Add(tag);
|
||||
|
||||
tags.Sort();
|
||||
foreach (string tag in tags)
|
||||
TextWriter.WriteLine(tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!app.ExcludeRollup)
|
||||
WriteAppMeta(app);
|
||||
|
||||
TextWriter.WriteLine(MakeHeading("Dependencies"));
|
||||
WriteDependencies(app);
|
||||
|
||||
TextWriter.WriteLine(MakeHeading("Match Details"));
|
||||
foreach (MatchRecord match in app.MatchList)
|
||||
WriteMatch(match);
|
||||
}
|
||||
|
||||
TextWriter.WriteLine("\nEnd of report");
|
||||
}
|
||||
|
||||
|
||||
private string StringList (HashSet<string> data)
|
||||
{
|
||||
string results="";
|
||||
|
||||
foreach (string s in data)
|
||||
results += s + " ";
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
private string StringList(SortedDictionary<string,string> data)
|
||||
{
|
||||
string results = "";
|
||||
|
||||
foreach (string s in data.Values)
|
||||
results += s + " ";
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// even out delineator for headings
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <returns></returns>
|
||||
private string MakeHeading(string header)
|
||||
{
|
||||
string result = header;
|
||||
for (int i = header.Length; i < COLUMN_MAX; i++)
|
||||
result += "-";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public void WriteAppMeta(AppProfile app)
|
||||
{
|
||||
//write predefined characteristics
|
||||
TextWriter.WriteLine(MakeHeading("Project Info"));
|
||||
TextWriter.WriteLine("Name: {0}", app.MetaData.ApplicationName + " " + app.MetaData.SourceVersion);
|
||||
TextWriter.WriteLine("Description: {0}", app.MetaData.Description);
|
||||
TextWriter.WriteLine("Source path: {0}", app.SourcePath);
|
||||
TextWriter.WriteLine("Authors: {0}", app.MetaData.Authors);
|
||||
TextWriter.WriteLine("Last Updated: {0}", app.MetaData.LastUpdated);
|
||||
TextWriter.WriteLine(MakeHeading("Scan Settings"));
|
||||
TextWriter.WriteLine("AppInspector version: {0}", app.Version);
|
||||
TextWriter.WriteLine("Rules path: {0}", StringList(app.MetaData.RulePaths));
|
||||
TextWriter.WriteLine("Run Arguments: {0}", app.Args);
|
||||
TextWriter.WriteLine("Date scanned: {0}", app.DateScanned);
|
||||
TextWriter.WriteLine(MakeHeading("Source Info"));
|
||||
TextWriter.WriteLine("Application type: {0}", StringList(app.MetaData.AppTypes));
|
||||
TextWriter.WriteLine("Package types: {0}", StringList(app.MetaData.PackageTypes));
|
||||
TextWriter.WriteLine("File extensions: {0}", StringList(app.MetaData.FileExtensions));
|
||||
TextWriter.WriteLine(MakeHeading("Detetected Targets"));
|
||||
TextWriter.WriteLine("Output types: {0}", StringList(app.MetaData.Outputs));
|
||||
TextWriter.WriteLine("OS Targets: {0}", StringList(app.MetaData.OSTargets));
|
||||
TextWriter.WriteLine("CPU Targets: {0}", StringList(app.MetaData.CPUTargets));
|
||||
TextWriter.WriteLine("Cloud targets: {0}", StringList(app.MetaData.CloudTargets));
|
||||
TextWriter.WriteLine(MakeHeading("Stats"));
|
||||
TextWriter.WriteLine("Files analyzed: {0}", app.MetaData.FilesAnalyzed);
|
||||
TextWriter.WriteLine("Files skipped: {0}", app.MetaData.FilesSkipped);
|
||||
TextWriter.WriteLine("Total files: {0}", app.MetaData.TotalFiles);
|
||||
TextWriter.WriteLine("Detections: {0} in {1} file(s)", app.MetaData.TotalMatchesCount, app.MetaData.FilesAffected);
|
||||
TextWriter.WriteLine("Unique detections: {0}", app.MetaData.UniqueMatchesCount);
|
||||
TextWriter.WriteLine(MakeHeading("Select Counters"));
|
||||
foreach (TagCounter counter in app.MetaData.TagCounters)
|
||||
TextWriter.WriteLine("{0} count: {1}", counter.ShortTag, counter.Count);
|
||||
|
||||
TextWriter.WriteLine(MakeHeading("Customizable tag groups"));
|
||||
//iterate through customizable tag group lists
|
||||
foreach (string tagGroupCategory in app.KeyedTagInfoLists.Keys)
|
||||
{
|
||||
List<TagInfo> list = app.KeyedTagInfoLists[tagGroupCategory];
|
||||
TextWriter.WriteLine(string.Format("[{0}]", tagGroupCategory));
|
||||
foreach (TagInfo tagInfo in list)
|
||||
TextWriter.WriteLine("Tag:{0},Detected:{1},Confidence:{2}", tagInfo.Tag, tagInfo.Detected, tagInfo.Confidence);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteMatch(MatchRecord match)
|
||||
{
|
||||
string output = _formatString.Replace("%F", match.Filename);
|
||||
output = output.Replace("%t", match.Language);
|
||||
output = output.Replace("%L", match.Issue.StartLocation.Line.ToString());
|
||||
output = output.Replace("%C", match.Issue.StartLocation.Column.ToString());
|
||||
output = output.Replace("%l", match.Issue.EndLocation.Line.ToString());
|
||||
output = output.Replace("%c", match.Issue.EndLocation.Column.ToString());
|
||||
output = output.Replace("%I", match.Issue.Boundary.Index.ToString());
|
||||
output = output.Replace("%i", match.Issue.Boundary.Length.ToString());
|
||||
output = output.Replace("%R", match.Issue.Rule.Id);
|
||||
output = output.Replace("%N", match.Issue.Rule.Name);
|
||||
output = output.Replace("%S", match.Issue.Rule.Severity.ToString());
|
||||
output = output.Replace("%X", match.Issue.Confidence.ToString());//override rule confidence because of unstructured text vs source
|
||||
output = output.Replace("%D", match.Issue.Rule.Description);
|
||||
output = output.Replace("%m", match.TextSample);
|
||||
output = output.Replace("%T", string.Join(',',match.Issue.Rule.Tags));
|
||||
|
||||
TextWriter.WriteLine(output);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void WriteDependencies(AppProfile app)
|
||||
{
|
||||
foreach (string s in app.MetaData.UniqueDependencies)
|
||||
TextWriter.WriteLine(s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override void FlushAndClose()
|
||||
{
|
||||
TextWriter.Flush();
|
||||
TextWriter.Close();
|
||||
}
|
||||
|
||||
string _formatString;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,307 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.DevSkim;
|
||||
|
||||
namespace Microsoft.AppInspector
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to handle text as a searchable container
|
||||
/// </summary>
|
||||
class TextContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates new instance
|
||||
/// </summary>
|
||||
/// <param name="content">Text to work with</param>
|
||||
public TextContainer(string content, string language)
|
||||
{
|
||||
_language = language;
|
||||
_content = content;
|
||||
_lineEnds = new List<int>(){ 0 };
|
||||
|
||||
// Find line end in the text
|
||||
int pos = 0;
|
||||
while(pos > -1 && pos < _content.Length)
|
||||
{
|
||||
if (++pos < _content.Length)
|
||||
{
|
||||
pos = _content.IndexOf('\n', pos);
|
||||
_lineEnds.Add(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Text can end with \n or not
|
||||
if (_lineEnds[_lineEnds.Count - 1] == -1)
|
||||
_lineEnds[_lineEnds.Count - 1] = (_content.Length > 0) ? content.Length - 1 : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all boundaries matching the pattern
|
||||
/// </summary>
|
||||
/// <param name="pattern">Search pattern</param>
|
||||
/// <returns>List of boundaries</returns>
|
||||
public List<Boundary> MatchPattern(SearchPattern pattern)
|
||||
{
|
||||
return MatchPattern(pattern, _content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all boundaries matching the pattern
|
||||
/// </summary>
|
||||
/// <param name="pattern">Search pattern</param>
|
||||
/// <param name="boundary">Content boundary</param>
|
||||
/// <param name="searchIn">Search in command</param>
|
||||
/// <returns></returns>
|
||||
public bool MatchPattern(SearchPattern pattern, Boundary boundary, SearchCondition condition)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
Boundary scope = ParseSearchBoundary(boundary, condition.SearchIn);
|
||||
|
||||
string text = _content.Substring(scope.Index, scope.Length);
|
||||
List<Boundary> macthes = MatchPattern(pattern, text);
|
||||
if (macthes.Count > 0)
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns location (Line, Column) for given index in text
|
||||
/// </summary>
|
||||
/// <param name="index">Position in text</param>
|
||||
/// <returns>Location</returns>
|
||||
public Location GetLocation(int index)
|
||||
{
|
||||
Location result = new Location();
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
result.Line = 1;
|
||||
result.Column = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < _lineEnds.Count; i++)
|
||||
{
|
||||
if (_lineEnds[i] >= index)
|
||||
{
|
||||
result.Line = i;
|
||||
result.Column = index - _lineEnds[i - 1];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns boundary for a given index in text
|
||||
/// </summary>
|
||||
/// <param name="index">Position in text</param>
|
||||
/// <returns>Boundary</returns>
|
||||
public Boundary GetLineBoundary(int index)
|
||||
{
|
||||
Boundary result = new Boundary();
|
||||
|
||||
for(int i=0; i < _lineEnds.Count; i++)
|
||||
{
|
||||
if (_lineEnds[i] >= index)
|
||||
{
|
||||
result.Index = (i > 0 && _lineEnds[i - 1] > 0) ? _lineEnds[i - 1] + 1 : 0;
|
||||
result.Length = _lineEnds[i] - result.Index + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return content of the line
|
||||
/// </summary>
|
||||
/// <param name="line">Line number</param>
|
||||
/// <returns>Text</returns>
|
||||
public string GetLineContent(int line)
|
||||
{
|
||||
int index = _lineEnds[line];
|
||||
Boundary bound = GetLineBoundary(index);
|
||||
return _content.Substring(bound.Index, bound.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all boundaries matching the pattern in a text
|
||||
/// </summary>
|
||||
/// <param name="pattern">Search pattern</param>
|
||||
/// <param name="text">Text</param>
|
||||
/// <returns>List of boundaries</returns>
|
||||
private List<Boundary> MatchPattern(SearchPattern pattern, string text)
|
||||
{
|
||||
List<Boundary> matchList = new List<Boundary>();
|
||||
|
||||
RegexOptions reopt = RegexOptions.None;
|
||||
if (pattern.Modifiers != null && pattern.Modifiers.Length > 0)
|
||||
{
|
||||
reopt |= (pattern.Modifiers.Contains("i")) ? RegexOptions.IgnoreCase : RegexOptions.None;
|
||||
reopt |= (pattern.Modifiers.Contains("m")) ? RegexOptions.Multiline : RegexOptions.None;
|
||||
}
|
||||
|
||||
Regex patRegx = new Regex(pattern.Pattern, reopt);
|
||||
MatchCollection matches = patRegx.Matches(text);
|
||||
if (matches.Count > 0)
|
||||
{
|
||||
foreach (Match m in matches)
|
||||
{
|
||||
Boundary bound = new Boundary() { Index = m.Index, Length = m.Length };
|
||||
if (ScopeMatch(pattern, bound, text))
|
||||
matchList.Add(bound);
|
||||
}
|
||||
}
|
||||
|
||||
return matchList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check whether the boundary in a text matches the scope of a search pattern (code, comment etc.)
|
||||
/// </summary>
|
||||
/// <param name="pattern">Pattern with scope</param>
|
||||
/// <param name="boundary">Boundary in a text</param>
|
||||
/// <param name="text">Text</param>
|
||||
/// <returns>True if boundary is matching the pattern scope</returns>
|
||||
private bool ScopeMatch(SearchPattern pattern, Boundary boundary, string text)
|
||||
{
|
||||
string prefix = Language.GetCommentPrefix(_language);
|
||||
string suffix = Language.GetCommentSuffix(_language);
|
||||
string inline = Language.GetCommentInline(_language);
|
||||
|
||||
if (pattern.Scopes.Contains(PatternScope.All) || string.IsNullOrEmpty(prefix))
|
||||
return true;
|
||||
|
||||
bool isInComment = ( IsBetween(text, boundary.Index, prefix, suffix)
|
||||
|| IsBetween(text, boundary.Index, inline, "\n"));
|
||||
|
||||
return !(isInComment && !pattern.Scopes.Contains(PatternScope.Comment));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the index in the string lies between preffix and suffix
|
||||
/// </summary>
|
||||
/// <param name="text">Text</param>
|
||||
/// <param name="index">Index to check</param>
|
||||
/// <param name="prefix">Prefix</param>
|
||||
/// <param name="suffix">Suffix</param>
|
||||
/// <returns>True if the index is between prefix and suffix</returns>
|
||||
private bool IsBetween(string text, int index, string prefix, string suffix)
|
||||
{
|
||||
bool result = false;
|
||||
string preText = string.Concat(text.Substring(0, index));
|
||||
int lastPreffix = preText.LastIndexOf(prefix, StringComparison.Ordinal);
|
||||
if (lastPreffix >= 0)
|
||||
{
|
||||
preText = preText.Substring(lastPreffix);
|
||||
int lastSuffix = preText.IndexOf(suffix, StringComparison.Ordinal);
|
||||
if (lastSuffix < 0)
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return boundary defined by line and its offset
|
||||
/// </summary>
|
||||
/// <param name="line">Line number</param>
|
||||
/// <param name="offset">Offset from line number</param>
|
||||
/// <returns>Boundary</returns>
|
||||
private int BoundaryByLine(int line, int offset)
|
||||
{
|
||||
int index = line + offset;
|
||||
|
||||
// We need the begining of the line when going up
|
||||
if (offset < 0)
|
||||
index--;
|
||||
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
if (index >= _lineEnds.Count)
|
||||
index = _lineEnds.Count - 1;
|
||||
|
||||
return _lineEnds[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return boundary based on searchIn command and given boundary
|
||||
/// </summary>
|
||||
/// <param name="boundary">Relative boundary</param>
|
||||
/// <param name="searchIn">Search in command</param>
|
||||
/// <returns>Boundary</returns>
|
||||
private Boundary ParseSearchBoundary(Boundary boundary, string searchIn)
|
||||
{
|
||||
// Default baundary is the fidning line
|
||||
Boundary result = GetLineBoundary(boundary.Index);
|
||||
string srch = (string.IsNullOrEmpty(searchIn)) ? string.Empty : searchIn.ToLower();
|
||||
|
||||
if (srch == "finding-only")
|
||||
{
|
||||
result.Index = boundary.Index;
|
||||
result.Length = boundary.Length;
|
||||
}
|
||||
else if (srch.StartsWith("finding-region"))
|
||||
{
|
||||
if (ParseSearchIn(srch, out int[] args))
|
||||
{
|
||||
Location loc = GetLocation(boundary.Index);
|
||||
result.Index = BoundaryByLine(loc.Line, args[0]);
|
||||
result.Length = BoundaryByLine(loc.Line, args[1]) - result.Index;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse search in command and return arguments
|
||||
/// </summary>
|
||||
/// <param name="searchIn">text to ba parsed</param>
|
||||
/// <param name="args">arguments</param>
|
||||
/// <returns>True if parsing was succsessful</returns>
|
||||
private bool ParseSearchIn(string searchIn, out int[] args)
|
||||
{
|
||||
bool result = false;
|
||||
List<int> arglist = new List<int>();
|
||||
|
||||
Regex reg = new Regex(".*\\((.*),(.*)\\)");
|
||||
Match m = reg.Match(searchIn);
|
||||
if (m.Success)
|
||||
{
|
||||
result = true;
|
||||
for (int i=1; i < m.Groups.Count; i++)
|
||||
{
|
||||
if (int.TryParse(m.Groups[i].Value, out int value))
|
||||
{
|
||||
arglist.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
args = arglist.ToArray();
|
||||
return result;
|
||||
}
|
||||
|
||||
private string _content;
|
||||
private List<int> _lineEnds;
|
||||
private string _language;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Writers
|
||||
{
|
||||
public abstract class Writer
|
||||
{
|
||||
public TextWriter TextWriter { get; set; }
|
||||
public abstract void WriteApp(AppProfile appCharacteriation);
|
||||
public abstract void FlushAndClose();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AppInspector.CLI.Writers
|
||||
{
|
||||
public class WriterFactory
|
||||
{
|
||||
public static Writer GetWriter(string writerName, string defaultWritter, string format = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(writerName))
|
||||
writerName = defaultWritter;
|
||||
|
||||
if (string.IsNullOrEmpty(writerName))
|
||||
writerName = "text";
|
||||
|
||||
switch (writerName.ToLowerInvariant())
|
||||
{
|
||||
case "_dummy":
|
||||
return new DummyWriter();
|
||||
case "json":
|
||||
return new JsonWriter();
|
||||
case "text":
|
||||
return new SimpleTextWriter(format);
|
||||
case "html":
|
||||
return new LiquidWriter();
|
||||
//case "sarif":
|
||||
// return new SarifWriter();
|
||||
default:
|
||||
throw new Exception("wrong output");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha256-YLGeXaapI0/5IgZopewRJcFXomhRMlYYjugPLSyNjTY=" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css" integrity="sha256-zmfNZmXoNWBMemUOo1XUGFfc0ihGGLYdgtJS3KCr/l0=" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.8/c3.min.css" integrity="sha256-loJlaQZlNV5TexzLFHJ6fGO6PCjUQk4isWOG/7YffC4=" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" type="text/css" href="html/resources/appinspector.css" />
|
||||
|
||||
<title>{{ application_version }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-light navbar-lg">
|
||||
<span class="navbar-brand">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/4/44/Microsoft_logo.svg" width="32" height="32" class="d-inline-block align-top" alt="">
|
||||
Application Inspector
|
||||
</span>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li><a class="nav-button" href="#" data-target="#page__report_overview">Overview</a></li>
|
||||
<li><a class="nav-button" href="#" data-target="#page__report_summary">Summary</a></li>
|
||||
<li><a class="nav-button" href="#" data-target="#page__report_profile">Profile</a></li>
|
||||
<li><a class="nav-button" href="https://github.com/microsoft/AppInspector/wiki" data-target="#page__report_profile" target="_blank" rel="noopener">About</a></li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ml-auto" style="margin-right: 80px">
|
||||
<li>
|
||||
<a class="nav-button" href="https://github.com/Microsoft/AppInspector" rel="noopener noreferrer">
|
||||
<i class="fab fa-github" style="font-size: 1.8em; color: #888"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main role="main" class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col col-lg-2"></div>
|
||||
<div class="col" id="page__report_overview">
|
||||
{% include "report_overview" %}
|
||||
</div>
|
||||
<div class="col d-none" id="page__report_summary">
|
||||
{% include "report_summary" %}
|
||||
</div>
|
||||
<div class="col d-none" id="page__report_profile">
|
||||
{% include "report_profile" %}
|
||||
</div>
|
||||
<div class="col col-lg-2"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{% include "file_listing" %}
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.15.0/umd/popper.min.js" integrity="sha256-fTuUgtT7O2rqoImwjrhDgbXTKUwyxxujIMRIK7TbuNU=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha256-CjSoeELFOcH0/uxWu6mC/Vlrc1AARqbm/jiiImDGV3s=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.6/ace.js" integrity="sha256-CVkji/u32aj2TeC+D13f7scFSIfphw2pmu4LaKWMSY8=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.6/ext-settings_menu.js" integrity="sha256-SL34Lgdp8DbjL/8WzrKeQVoEgfsYV05j2LulsDyWEpI=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.6/ext-modelist.js" integrity="sha256-Eq83mfVraqpouXYtwjYSEvTt6JM7k1VrhsebwRs06AM=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.6/ext-beautify.js" integrity="sha256-XURxU9F6YJl7wYVNfD4/aztOdXJyQ9vZ/03hyUknaOU=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.12.0/d3.min.js" integrity="sha256-+9Mf3cAVmxxudDsr1XwXUeRZFtvdWVYdq5/vcgiYyNU=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.8/c3.min.js" integrity="sha256-N10MWEM8r2dC0bw4GafCShV+f23skko9fL5mIGcGd4A=" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="html/resources/appinspector.js"></script>
|
||||
<script type="text/javascript">
|
||||
let data = {{ json }};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
<div id="file_listing_modal" class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">File Listing</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div style="max-height: 150px; overflow-y:auto; border-bottom: 1px solid #ccc">
|
||||
<ul style="list-style-type:none; padding-left: 0">
|
||||
</ul>
|
||||
</div>
|
||||
<div style="height: 360px; overflow-y:auto;">
|
||||
<div id="editor-container" style="margin-top: 5px;">
|
||||
<div id="editor" style="width: 100%; height: 350px; max-height: 350px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,71 @@
|
|||
<div class="section">
|
||||
<h2>Application Inspector Report</h2>
|
||||
|
||||
<strong>Welcome to the Microsoft Application Inspector Report.</strong>
|
||||
This report represents the output for the specified source code for
|
||||
identified makeup and characteristics. The report can help in validating
|
||||
purported component objectives by examining source code against identifying
|
||||
patterns for the detected change, including identifying applicable
|
||||
security and privacy features. It also facilitates comparing key changes
|
||||
across versions of components or scanning for specific features.
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h5>Why it's different</h5>
|
||||
Knowing what is in your software is the first step to making choices about
|
||||
what actions are appropriate for allowing it to be deployed in your or your
|
||||
customer environment. Unlike a typical source code static analyzer,
|
||||
AppInspector is judgement free, focusing instead on helping inform security
|
||||
and other scenarios by surfacing details that might otherwise go unnoticed.
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h5>AppInspector Functions</h5>
|
||||
<table class="table" style="width: auto !important;">
|
||||
<tr>
|
||||
<td><i class="fas fa-play"></i></td>
|
||||
<td>Analyze</td>
|
||||
<td>Scan source files for characteristics</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="fas fa-tag"></i></td>
|
||||
<td>Tag Test</td>
|
||||
<td>Test source files for the presence of a specific tag identifier</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="far fa-copy"></i></td>
|
||||
<td>Tag Diff</td>
|
||||
<td>Compare identified tags between versions</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="fas fa-tags"></i></td>
|
||||
<td style="text-align:left">Tags</td>
|
||||
<td>Export Tags</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="far fa-check-square"></i></td>
|
||||
<td style="text-align:left">Verify</td>
|
||||
<td>Verify rules structure</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h4>Report Contents</h4>
|
||||
A set of customizable "Profile" traits of interest are available. Additional tools
|
||||
include a complete list of all traits detect and the full set of matching records
|
||||
to pinpoint which rule patterns were triggered located just under the Inspect
|
||||
menu. Traits are identified as "tags" found in the rule definitions which are
|
||||
customizable JSON files found under the 'Rules' folder.
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<a class="btn btn-primary nav-button" role="button" href="#" data-target="#page__report_summary">View Report</a>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<small>
|
||||
For more information, please visit our <a href="https://github.com/Microsoft/AppInspector">GitHub</a> page to review
|
||||
the AppInspector user guide, documentation, and source code.
|
||||
</small>
|
||||
</div>
|
|
@ -0,0 +1,292 @@
|
|||
<div class="section">
|
||||
<h2>Application Profile</h2>
|
||||
|
||||
<div>
|
||||
This section describes the main characteristics of the appliation
|
||||
analyzed. Begin exploring by clicking any of the highlighted icons
|
||||
below. You can also drill into specific characteristics by clicking
|
||||
on the link shown on the right.
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="section">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<table class="table table-sm" style="width:600px">
|
||||
<tr>
|
||||
<td>Select Features</td>
|
||||
<td>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" title="Authentication" data-target="Authentication">
|
||||
<i class="fas fa-sign-in-alt"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" title="Authorization" data-target="Authorization">
|
||||
<i class="fas fa-passport"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" title="Cryptography" data-target="Cryptography">
|
||||
<i class="fas fa-key"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" title="Media File Parsing" data-target="MediaFileParsing">
|
||||
<i class="fas fa-photo-video"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" title="Object Deserialization" data-target="Deserialization">
|
||||
<i class="far fa-object-ungroup"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>General Features</td>
|
||||
<td>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="\.FileOperation" title="File Operations">
|
||||
<i class="far fa-edit"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="\.Network" title="Network Communication">
|
||||
<i class="fas fa-network-wired"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" title="Application Type" data-target="Application\.Type">
|
||||
<i class="fas fa-dot-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" title="Logging" data-target="Logging">
|
||||
<i class="fas fa-file"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" title="HTML Forms" data-target="HTMLForm">
|
||||
<i class="far fa-address-card"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Development Frameworks</td>
|
||||
<td>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Development\.Build" title="Build Tools">
|
||||
<i class="fas fa-building"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Development\.Framework" title="Development Framework">
|
||||
<i class="fab fa-dev"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Testing\.Framework" title="Test Framework">
|
||||
<i class="fas fa-vial"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" title="Content Mngt System" data-target="Framework.\CMS">
|
||||
<i class="fab fa-wpforms"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Reference\.SocialMedia" title="Social Media">
|
||||
<i class="fab fa-facebook-square"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Miscellaneous\.OpenSourceLicense" title="Open Source License">
|
||||
<i class="fas fa-file-contract"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Dependency\.SourceInclude" title="Source Code Inclusion">
|
||||
<i class="far fa-plus-square"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Data</td>
|
||||
<td>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Data\.DataAccess\.SQL" title="SQL Commands">
|
||||
<i class="fas fa-table"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Data\.DataAccess\.ORM" title="Object Relational Mapper">
|
||||
<i class="fab fa-connectdevelop"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Data\.DataAccess\.ODBC" title="Object Database Connectivity">
|
||||
<i class="fas fa-plug"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Data\.DataAccess\.DBMS" title="Database Mngt System">
|
||||
<i class="fas fa-database"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Data\.DataAccess\..*Azure" title="Azure Data Services">
|
||||
<i class="fab fa-microsoft"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Data\.(XML|JSON)" title="JSON/XML">
|
||||
<i class="far fa-file-code"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Data\.Sensitive\.Personal" title="Sensitive/Personal Data">
|
||||
<i class="fas fa-user-shield"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Data\.Sensitive\.Medical" title="Sensitive/Medical Data">
|
||||
<i class="fas fa-stethoscope"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Data\.Finance" title="Financial Data">
|
||||
<i class="fas fa-money-bill"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Data\.Serialization" title="Serialization">
|
||||
<i class="fas fa-project-diagram"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>OS Integration</td>
|
||||
<td>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Platform\.OS" title="OS Identification">
|
||||
<i class="fab fa-linux"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="OS\.ACL" title="Access Control">
|
||||
<i class="fas fa-user-alt-slash"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="OS\.Environment" title="Environment Variables">
|
||||
<i class="fas fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="OS\.Process" title="Process Management">
|
||||
<i class="fas fa-stream"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="OS\.SystemRegistry" title="System Registry">
|
||||
<i class="fas fa-tree"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="OS\.UserAccount" title="System Accounts">
|
||||
<i class="fas fa-running"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cloud Services</td>
|
||||
<td>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.Microsoft\.Azure" title="Microsoft Azure">
|
||||
<i class="fab fa-microsoft"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.Amazon\.AWS" title="Amazon Web Services">
|
||||
<i class="fab fa-aws"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.Google\.Cloud" title="Google Cloud Platform">
|
||||
<i class="fab fa-google"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.Microsoft\.Office" title="Microsoft Office">
|
||||
<i class="far fa-file-word"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.Repository" title="Source Code Repository">
|
||||
<i class="fab fa-github"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.PackageManager" title="Package Manager">
|
||||
<i class="fas fa-box-open"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.CI" title="Continuous Integration">
|
||||
<i class="fas fa-vials"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Other</td>
|
||||
<td>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Miscellaneous\.Analytics" title="Analytics Services">
|
||||
<i class="fas fa-diagnoses"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Miscellaneous\.AdvertisingNetwork" title="Advertising Network">
|
||||
<i class="fas fa-ad"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="ObfuscatedCode" title="Obfuscated Strings">
|
||||
<i class="far fa-eye-slash"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid-1">
|
||||
<a href="#" class="feature_icon" data-target="Comment\.(Suspicious|Todo)" title="Incomplete Code (TODO)">
|
||||
<i class="far fa-clock"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div id="features">
|
||||
<table class="table table-sm table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Characteristics</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,90 @@
|
|||
<div class="section">
|
||||
<h2>Report Summary</h2>
|
||||
|
||||
<div class="small font-weight-bold">
|
||||
View as
|
||||
|
||||
<a class="btn-link disabled font-weight-bold" href="#">HTML</a>
|
||||
|
|
||||
<a href="output.json">JSON</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#project_info" role="tab" data-toggle="tab">Project Info</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#scan_metadata" role="tab" data-toggle="tab">Scan Metadata</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane active show" id="project_info">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div id="s_pi_analysis_chart"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div id="s_pi_patterns_chart"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div id="s_pi_languages_chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="table table-sm">
|
||||
<tr>
|
||||
<td class="font-weight-bold">Name</td>
|
||||
<td id="s_pi_application_name"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-weight-bold">Version</td>
|
||||
<td id="s_pi_version"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-weight-bold">Description</td>
|
||||
<td id="s_pi_description"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-weight-bold">Folder</td>
|
||||
<td id="s_pi_source_path"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-weight-bold">Author(s)</td>
|
||||
<td id="s_pi_author"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-weight-bold">Analyzed</td>
|
||||
<td id="s_pi_date_scanned"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div role="tabpanel" class="tab-pane" id="scan_metadata">
|
||||
<table class="table table-sm">
|
||||
<tr>
|
||||
<td class="font-weight-bold">Total Files</td>
|
||||
<td id="s_mt_total_files"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-weight-bold">Files Analyzed</td>
|
||||
<td id="s_mt_analyzed_files"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-weight-bold">Files Skipped</td>
|
||||
<td id="s_mt_skipped_files"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="profile">ccc</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,105 @@
|
|||
body {
|
||||
background-color: #fcfefd !important;
|
||||
font-family: 'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',sans-serif;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background-color: #F3F3F3 !important;
|
||||
}
|
||||
.navbar-brand:focus, .navbar-brand:hover {
|
||||
text-decoration: none !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.navbar-lg {
|
||||
min-height: 80px;
|
||||
border-radius: 0;
|
||||
padding-top: 0;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.navbar-lg .navbar-brand {
|
||||
margin-left: 80px;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.navbar-lg .navbar-nav > li {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
font-size: 0.90em;
|
||||
}
|
||||
|
||||
.navbar-lg .navbar-nav > li > a {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#file_listing_modal div.modal-dialog {
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
/* Report Overview */
|
||||
div.section {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#page__report_overview table tr:first-child td {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
#page__report_overview table td {
|
||||
padding: 0.10rem 0.55rem 0.10rem 0.55rem;
|
||||
}
|
||||
|
||||
#page__report_overview table td:first-child {
|
||||
text-align: center;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
#page__report_overview table td:nth-child(2) {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#page__report_overview table td:nth-child(3) {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
/* Report Summary */
|
||||
.c3-chart-arcs-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Report Profile */
|
||||
#page__report_profile div.accordion {
|
||||
padding-bottom: 6px;
|
||||
border-bottom: 1px solid #0078d4;
|
||||
}
|
||||
#page__report_profile div.grid-1 {
|
||||
width: 32px !important;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
margin-left: 6px;
|
||||
margin-right: 6px;
|
||||
color: #7FBA00;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
#page__report_profile table td:nth-child(1) {
|
||||
font-weight: normal;
|
||||
font-size: 0.9rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#page__report_profile a.disabled {
|
||||
color: #ccc;
|
||||
cursor: default;
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
$(document).ready(() => {
|
||||
// Initialize Bootstrap
|
||||
$('[data-toggle="popover"]').popover();
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
|
||||
|
||||
/* Main Navigation Links: These are links that change the
|
||||
* visible section to something else, specified by the
|
||||
* `data-target` attribute of the link, which should usually
|
||||
* be the #div-identifier to be shown.
|
||||
*/
|
||||
$('a.nav-button').on('click', (e) => {
|
||||
let current = $('body').data('visible_section') || '#page__report_overview';
|
||||
let target = $(e.target).data('target');
|
||||
if (!!target) {
|
||||
if (!!current) {
|
||||
$(current).addClass('d-none');
|
||||
}
|
||||
|
||||
$(target).removeClass('d-none');
|
||||
$('body').data('visible_section', target);
|
||||
}
|
||||
});
|
||||
|
||||
$('a.file_listing').on('click', (e) => {
|
||||
$('#editor-container').addClass('d-none');
|
||||
$('#file_listing_modal').modal();
|
||||
alert(1);
|
||||
})
|
||||
|
||||
/*
|
||||
* When a user clicks on a file listing filename, load the data
|
||||
* to show into the Ace editor in the popup dialog.
|
||||
*/
|
||||
$('#file_listing_modal').on('click', 'a.content-link', (e) => {
|
||||
const content = $(e.target).data('excerpt');
|
||||
const startLocationLine = $(e.target).data('startLocationLine');
|
||||
const editor = ace.edit("editor");
|
||||
|
||||
editor.setOption('firstLineNumber', startLocationLine);
|
||||
editor.getSession().setValue(content);
|
||||
editor.resize();
|
||||
editor.scrollToLine(0);
|
||||
$('editor-container').removeClass('d-none');
|
||||
});
|
||||
|
||||
const templateInsertion = new TemplateInsertion(data);
|
||||
templateInsertion.processSummaryPage();
|
||||
templateInsertion.processProfilePage();
|
||||
});
|
||||
|
||||
class TemplateInsertion {
|
||||
constructor(data) {
|
||||
this.ap = data.AppProfile;
|
||||
this.mt = this.ap.MetaData;
|
||||
this.md = data.matchDetails;
|
||||
}
|
||||
|
||||
processSummaryPage() {
|
||||
c3.generate({
|
||||
bindto: '#s_pi_analysis_chart',
|
||||
size: {
|
||||
width: 200
|
||||
},
|
||||
data: {
|
||||
columns: [
|
||||
['Analyzed', this.mt.filesAnalyzed],
|
||||
['Skipped', this.mt.filesSkipped],
|
||||
],
|
||||
type: 'donut'
|
||||
},
|
||||
donut: {
|
||||
title: "Analyzed Files",
|
||||
label: {
|
||||
format: function(value) { return value; }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
c3.generate({
|
||||
bindto: '#s_pi_patterns_chart',
|
||||
size: {
|
||||
width: 200
|
||||
},
|
||||
data: {
|
||||
columns: [
|
||||
['Unique Matches', this.mt.uniqueMatchesCount],
|
||||
['Repeats', this.mt.totalMatchesCount - this.mt.uniqueMatchesCount],
|
||||
],
|
||||
type: 'donut'
|
||||
},
|
||||
donut: {
|
||||
title: "Results",
|
||||
label: {
|
||||
format: function(value) { return value; }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
c3.generate({
|
||||
bindto: '#s_pi_languages_chart',
|
||||
size: {
|
||||
width: 200
|
||||
},
|
||||
data: {
|
||||
columns: Object.entries(this.mt.languages),
|
||||
type: 'donut'
|
||||
},
|
||||
donut: {
|
||||
title: "Languages",
|
||||
label: {
|
||||
format: function(value) { return value; }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('#s_pi_application_name').html(this.mt.applicationName);
|
||||
$('#s_pi_version').html(this.mt.sourceVersion);
|
||||
$('#s_pi_description').html(this.mt.description || 'No description available.');
|
||||
$('#s_pi_source_path').html(this.ap.sourcePath);
|
||||
$('#s_pi_author').html(this.mt.authors || 'No author found.');
|
||||
$('#s_pi_date_scanned').html(this.ap.dateScanned);
|
||||
|
||||
|
||||
}
|
||||
|
||||
combineConfidence(a, b) {
|
||||
if (a && !b) return a;
|
||||
if (b && !a) return b;
|
||||
if (!a && !b) return 'Low';
|
||||
|
||||
const _a = a.toLowerCase();
|
||||
const _b = b.toLowerCase();
|
||||
const map = { 'low': 1, 'medium': 2, 'high': 4 };
|
||||
if (map[_a] > map[_b]) { return a; }
|
||||
return b;
|
||||
}
|
||||
|
||||
show_file_listing(e) {
|
||||
let $_tr = e.target.nodeName == 'TR' ? $(e.target) : $(e.target).closest('tr');
|
||||
let ruleid = $_tr.find('a').data('ruleid');
|
||||
let $this = e.data.obj;
|
||||
|
||||
$('#file_listing_modal ul').empty();
|
||||
$('editor-container').addClass('d-none');
|
||||
|
||||
const removePrefix = (fn) => {
|
||||
if (!fn.startsWith($this.ap.sourcePath)) {
|
||||
return fn;
|
||||
}
|
||||
return fn.slice($this.ap.sourcePath.length);
|
||||
}
|
||||
|
||||
for (let match of $this.md) {
|
||||
let excerpt = atob(match.excerpt || '') || match.sample;
|
||||
if (match.ruleId === ruleid || match.ruleName === ruleid) {
|
||||
let $li = $('<li>');
|
||||
let $a = $('<a>');
|
||||
$a.addClass('content-link')
|
||||
.attr('href', '#')
|
||||
.data('excerpt', excerpt)
|
||||
.data('startLocationLine', match.startLocationLine - 3)
|
||||
.text(removePrefix(match.fileName));
|
||||
$li.append($a);
|
||||
$('#file_listing_modal ul').append($li);
|
||||
}
|
||||
}
|
||||
$('#file_listing_modal').on('shown.bs.modal', function (e) {
|
||||
$('a.content-link').first().trigger('click');
|
||||
});
|
||||
|
||||
$('#file_listing_modal').modal();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Builds the Profile page, including event handlers.
|
||||
*/
|
||||
processProfilePage() {
|
||||
|
||||
// Process each icon with the 'feature_icon' class.
|
||||
$('a.feature_icon').each((idx, elt) => {
|
||||
const targetRegexValue = $(elt).data('target');
|
||||
if (!targetRegexValue) {
|
||||
$(elt).addClass('disabled'); // Disable icon if no target exists
|
||||
return;
|
||||
}
|
||||
let foundTag = false;
|
||||
const targetRegex = new RegExp(targetRegexValue, 'i');
|
||||
|
||||
// We have a target, treated as a regular expression.
|
||||
// We're goint to go through all results (this.md) and if it contains
|
||||
// a tag that matches what we're looking for, we'll keep that icon visible.
|
||||
search_loop:
|
||||
for (let match of this.md) {
|
||||
for (let tag of match.tags) {
|
||||
if (targetRegex.exec(tag)) {
|
||||
foundTag = true; // We have at least one match for this icon
|
||||
break search_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!foundTag) {
|
||||
$(elt).addClass('disabled');
|
||||
}
|
||||
});
|
||||
|
||||
// Event handler for visible icons
|
||||
$('a.feature_icon').on('click', (e) => {
|
||||
const targetRegexValue = $(e.target).closest('a').data('target');
|
||||
if (!targetRegexValue) {
|
||||
console.log('Error: No target regular expression. This probably indicates a bug.');
|
||||
return;
|
||||
}
|
||||
const targetRegex = new RegExp(targetRegexValue, 'i');
|
||||
let identifiedRules = {};
|
||||
for (let match of this.md) {
|
||||
for (let tag of match.tags) {
|
||||
if (targetRegex.exec(tag)) {
|
||||
identifiedRules[match.ruleName] = this.combineConfidence(identifiedRules[match.ruleName], match.confidence);
|
||||
break; // Only break out of inner loop, we only need one match per tag set
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const $tbody = $('#features table tbody');
|
||||
$tbody.empty();
|
||||
|
||||
// Now we iterate through all of the rules that relate to this icon
|
||||
for (let [rule, confidence] of Object.entries(identifiedRules)) {
|
||||
|
||||
// I'm sorry, this is pretty ugly. If you'd like to clean this up, I'd be
|
||||
// happy to take a pull request.
|
||||
|
||||
let $tr = $('<tr>');
|
||||
$tr.on('click', 'td', { 'obj': this }, this.show_file_listing);
|
||||
let $td0 = $('<td>');
|
||||
let $td0a = $('<a>');
|
||||
$td0a.attr('href', '#');
|
||||
$td0a.data('ruleid', rule); // BUG: This should be the rule id, not the name
|
||||
$td0a.text(rule);
|
||||
//$td0a.on('click', {'obj': this }, this.show_file_listing);
|
||||
$td0.append($td0a);
|
||||
|
||||
//let $td1 = $('<td>');
|
||||
//let $td1d = $('<div>');
|
||||
//$td1d.addClass('progress');
|
||||
//$td1d.css('width', '120px');
|
||||
//let $td1dp = $('<div>');
|
||||
//$td1dp.addClass('progress-bar')
|
||||
// .addClass('bg-info')
|
||||
// .attr('role', 'progressbar')
|
||||
// .css('width', '100%')
|
||||
// .attr('aria-valuenow', 100)
|
||||
// .attr('aria-valuemin', 0)
|
||||
// .attr('aria-valuemax', 100)
|
||||
// .text('High');
|
||||
//$td1d.append($td1dp);
|
||||
//$td1.append($td1d);
|
||||
$tr.append($td0)
|
||||
//$tr.append($td1);
|
||||
$tbody.append($tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
После Ширина: | Высота: | Размер: 477 B |
После Ширина: | Высота: | Размер: 527 B |
После Ширина: | Высота: | Размер: 776 B |
После Ширина: | Высота: | Размер: 940 B |
После Ширина: | Высота: | Размер: 1007 B |
После Ширина: | Высота: | Размер: 827 B |
После Ширина: | Высота: | Размер: 680 B |
После Ширина: | Высота: | Размер: 370 B |
После Ширина: | Высота: | Размер: 339 B |
После Ширина: | Высота: | Размер: 664 B |
После Ширина: | Высота: | Размер: 723 B |
После Ширина: | Высота: | Размер: 598 B |
После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 895 B |
После Ширина: | Высота: | Размер: 788 B |
После Ширина: | Высота: | Размер: 543 B |
После Ширина: | Высота: | Размер: 864 B |
|
@ -0,0 +1,124 @@
|
|||
<!doctype html>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<title>AppInpector</title>
|
||||
|
||||
<link rel="stylesheet" href="bootstrap.css">
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
|
||||
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />
|
||||
<a class="navbar-brand" href="index.html">AppInspector</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="projecthome.html">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="profile.html">Profile</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown01">
|
||||
<a class="dropdown-item" href="composition.html">Composition</a>
|
||||
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
|
||||
<a class="dropdown-item" href="alltags.html">All Tags</a>
|
||||
<a class="dropdown-item" href="allmatches.html">All Matches</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
<form class="form-inline my-2 my-lg-0">
|
||||
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
|
||||
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main role="main" class="container" style="max-width: 100%">
|
||||
|
||||
|
||||
<!-- All features -->
|
||||
<h4>All Match Details</h4>
|
||||
count={{ app.matchList.Count }} <a href="jsonreport.json">Json Report</a>
|
||||
<div class="card-columns">
|
||||
{{ #each app.matchList }}
|
||||
|
||||
<div class="card" style="height:400px;overflow-y:scroll;border: 1px solid #6c757d;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Match</h5>
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed">
|
||||
<tr>
|
||||
<td>Rule ID:</td>
|
||||
<td>{{ this.Issue.Rule.Id }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rule name:</td>
|
||||
<td>{{ this.Issue.Rule.Name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rule description:</td>
|
||||
<td>{{ this.Issue.Rule.Description }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>File</td>
|
||||
<td><a href="file:///{{ this.Filename }}" rel="noopener" target="_blank">{{ this.Filename }}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Source type</td>
|
||||
<td>{{ this.Language }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Line number</td>
|
||||
<td>{{ this.Issue.StartLocation.Line }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ this.Issue.Rule.Tags.[0] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Confidence</td>
|
||||
<td>{{ this.Issue.PatternMatch.Confidence }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pattern Type</td>
|
||||
<td>{{ this.Issue.PatternMatch.PatternType }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pattern</td>
|
||||
<td>{{ this.Issue.PatternMatch.Pattern }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Text sample</td>
|
||||
<td>{{ this.TextSample }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#unless @last}} {{/unless}}
|
||||
{{ /each }}
|
||||
</div>
|
||||
</main><!-- /.container -->
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,128 @@
|
|||
<!doctype html>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<title>AppInpector</title>
|
||||
|
||||
<link rel="stylesheet" href="bootstrap.css">
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
|
||||
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />
|
||||
<a class="navbar-brand" href="index.html">AppInspector</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="projecthome.html">Home <span class="sr-only">(current)</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="profile.html">Profile</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown01">
|
||||
<a class="dropdown-item" href="composition.html">Composition</a>
|
||||
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
|
||||
<a class="dropdown-item" href="alltags.html">All Tags</a>
|
||||
<a class="dropdown-item" href="allmatches.html">All Matches</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
<form class="form-inline my-2 my-lg-0">
|
||||
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
|
||||
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
<main role="main" class="container" style="max-width: 100%">
|
||||
<h4 class="card-title">All Tags Found</h4>
|
||||
<div>count={{ app.MetaData.UniqueTags.Count }}</div>
|
||||
<!-- Design Extraction -->
|
||||
<div class="row section section-design-extraction">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-primary">
|
||||
The tags shown represent patterns detected in the inspected source code. <strong>Click</strong>
|
||||
any of the values for a list of which files the tags were detected in.
|
||||
<br />
|
||||
<br />
|
||||
<div class="panel-body">
|
||||
{{ #each tagGrpAllTagsByName }}
|
||||
<a href="#" data-action="popup" data-tag="{{ this.Tag }}"><span class="badge-info">{{ this.Tag }}</span></a>
|
||||
{{ /each }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main><!-- /.container -->
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
$('a[data-action="popup"]').on('click', function () {
|
||||
var tag = $(this).data('tag');
|
||||
var html = '';
|
||||
$('div[data-tag="' + tag + '"]').each(function (idx, elt) {
|
||||
var $row = $('<tr data-id="' + $(elt).data('id') + '" style="cursor:pointer;"/>')
|
||||
.append($('<td>' + $(elt).data('filename') + '</td>'))
|
||||
.append($('<td>' + $(elt).data('line') + '</td>'));
|
||||
$('table#detail-summary tbody').append($row);
|
||||
});
|
||||
|
||||
|
||||
$('#detail_popup div.details').html('');
|
||||
$('#detail_popup').modal();
|
||||
});
|
||||
$('#detail_popup table#detail-summary tbody').on('click', 'tr', function () {
|
||||
var id = $(this).data('id');
|
||||
var excerpt = atob($('div[data-id="' + id + '"]').data('excerpt'));
|
||||
$('#detail_popup div.details').html(excerpt);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="d-none">
|
||||
{{ #each app.matchList }}
|
||||
<div data-id="{{ this.Issue.Rule.Id }}" data-filename="{{ this.Filename }}" data-line="{{ this.Issue.StartLocation.Line }}" data-excerpt="{{ this.Excerpt }}" data-tag="{{ this.Issue.Rule.Tags.[0] }}"></div>
|
||||
{{ /each }}
|
||||
</div>
|
||||
<div class="modal fade" id="detail_popup" tabindex="-1" role="dialog" aria-labelledby="detail_popup_label" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="detail_popup_label">Details</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" style="height: 450px">
|
||||
<div class="summary" style="overflow-y:auto;height:35%;font-size:0.8em;">
|
||||
<table class="table table-sm" id="detail-summary">
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="details" style="white-space:pre;overflow-y:auto;height:65%;font-size:0.75em;font-family:monospace; border-top: 2px solid #444; margin-top: 6px;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">Open File</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,149 @@
|
|||
<!doctype html>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<title>AppInpector</title>
|
||||
|
||||
<link rel="stylesheet" href="bootstrap.css">
|
||||
|
||||
|
||||
</head>
|
||||
<body style=" background-color: cornflowerblue">
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
|
||||
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />
|
||||
<a class="navbar-brand" href="index.html">AppInspector</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="projecthome.html">Home <span class="sr-only">(current)</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="profile.html">Profile</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown01">
|
||||
<a class="dropdown-item" href="composition.html">Composition</a>
|
||||
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
|
||||
<a class="dropdown-item" href="alltags.html">All Tags</a>
|
||||
<a class="dropdown-item" href="allmatches.html">All Matches</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
<form class="form-inline my-2 my-lg-0">
|
||||
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
|
||||
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
<main role="main" class="container" style="max-width: 100%">
|
||||
<h4 style="color:whitesmoke">Composition</h4>
|
||||
<div class="card-columns">
|
||||
|
||||
<div class="card" style="max-height:500px;overflow-y:scroll;border: 1px solid #6c757d;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Dependencies</h5>
|
||||
<div class="card-text">
|
||||
<ul>
|
||||
{{ #each strGrpUniqueDependencies }}
|
||||
<li>{{ this }}</li>
|
||||
{{ else }}
|
||||
No items found
|
||||
{{ /each }}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
[[subSectionStart]]
|
||||
<div class="card" style="max-height:400px; overflow-y:scroll; border: 1px solid #6c757d">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">[[subSectionName]]</h5>
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed">
|
||||
{{ #each [[subSectionVarRef]] }}
|
||||
<tr>
|
||||
<td><a href="#" data-action="popup" data-tag="{{ this.Tag }}">{{ this.ShortTag }}</a></td>
|
||||
</tr>
|
||||
{{ else }}
|
||||
No items found
|
||||
{{ /each }}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
[[subSectionEnd]]
|
||||
|
||||
</div>
|
||||
</main><!-- /.container -->
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
$('a[data-action="popup"]').on('click', function () {
|
||||
var tag = $(this).data('tag');
|
||||
var html = '';
|
||||
$('div[data-tag="' + tag + '"]').each(function (idx, elt) {
|
||||
var $row = $('<tr data-id="' + $(elt).data('id') + '" style="cursor:pointer;"/>')
|
||||
.append($('<td>' + $(elt).data('filename') + '</td>'))
|
||||
.append($('<td>' + $(elt).data('line') + '</td>'));
|
||||
$('table#detail-summary tbody').append($row);
|
||||
});
|
||||
|
||||
|
||||
$('#detail_popup div.details').html('');
|
||||
$('#detail_popup').modal();
|
||||
});
|
||||
$('#detail_popup table#detail-summary tbody').on('click', 'tr', function () {
|
||||
var id = $(this).data('id');
|
||||
var excerpt = atob($('div[data-id="' + id + '"]').data('excerpt'));
|
||||
$('#detail_popup div.details').html(excerpt);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="d-none">
|
||||
{{ #each app.matchList }}
|
||||
<div data-id="{{ this.Issue.Rule.Id }}" data-filename="{{ this.Filename }}" data-line="{{ this.Issue.StartLocation.Line }}" data-excerpt="{{ this.Excerpt }}" data-tag="{{ this.Issue.Rule.Tags.[0] }}"></div>
|
||||
{{ /each }}
|
||||
</div>
|
||||
<div class="modal fade" id="detail_popup" tabindex="-1" role="dialog" aria-labelledby="detail_popup_label" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="detail_popup_label">Details</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" style="height: 450px">
|
||||
<div class="summary" style="overflow-y:auto;height:35%;font-size:0.8em;">
|
||||
<table class="table table-sm" id="detail-summary">
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="details" style="white-space:pre;overflow-y:auto;height:65%;font-size:0.75em;font-family:monospace; border-top: 2px solid #444; margin-top: 6px;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">Open File</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,123 @@
|
|||
<!doctype html>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<title>AppInpector-Home</title>
|
||||
|
||||
<link rel="stylesheet" href="bootstrap.css">
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
|
||||
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />
|
||||
<a class="navbar-brand" href="index.html">AppInspector</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="projecthome.html">Home <span class="sr-only">(current)</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="profile.html">Profile</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown01">
|
||||
<a class="dropdown-item" href="composition.html">Composition</a>
|
||||
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
|
||||
<a class="dropdown-item" href="alltags.html">All Tags</a>
|
||||
<a class="dropdown-item" href="allmatches.html">All Matches</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<form class="form-inline my-2 my-lg-0">
|
||||
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
|
||||
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main role="main" class="container" style="max-width: 100%">
|
||||
|
||||
|
||||
<div class="card" style="border:none">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">AppInspector Report</h5>
|
||||
<div class="card-text">
|
||||
Welcome to the Microsoft AppInspector <strong>ver. <{{app.Version}}></strong> Report. This report represents the output for the
|
||||
specified source code for identified makeup and characteristics. The report can help in validating purported component
|
||||
objectives by examining sourcecode against identifying patterns for the detected language, including identifying applicable
|
||||
security and privacy features. It also facilitates comparing key changes across versions of components or scanning for specific features.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="border:none">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Why It's Different</h5>
|
||||
<div class="card-text">
|
||||
Knowing what is in your software is the first step to making choices about what actions are appropriate for allowing it to be deployed in
|
||||
your or your customer environment. Unlike a typical source code static analyzer, AppInspector is judgement free, focusing instead on
|
||||
helping inform security and other scenarios by surfacing details that might otherwise go unnoticed.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="border:none">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">AppInspector Functions</h5>
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed" style="width:620px;">
|
||||
<tr><td><image src="scan.png" style="width:25px;height:25px;"></td><td style="width:80px;"><strong>Analyze</strong></td><td>Scan source files for characteristics.</td></tr>
|
||||
<tr><td><image src="tagtest.png" style="width:25px;height:25px;"></td><td style="width:80px;"><strong>TagTest</strong></td><td>Test source for presence of specified tag subset.</td></tr>
|
||||
<tr><td><image src="tagdiff.png" style="width:25px;height:25px;"></td><td style="width:80px;"><strong>TagDiff</strong></td><td>Compare tags between differing source code.</td></tr>
|
||||
<tr><td><image src="export.png" style="width:25px;height:25px;"></td><td style="width:80px;"><strong>Tags</strong></td><td>Export tags.<td></tr>
|
||||
<tr><td><image src="rulesverified.png" style="width:25px;height:25px;"></td><td style="width:80px;"><strong>Verify</strong></td><td>Verify tag rules structure.<td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="border:none">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Report Contents</h5>
|
||||
<div class="card-text">
|
||||
A set of customizable "Profile" traits of interest are available. Additional tools include a complete list of all traits detected
|
||||
and the full set of matching records to pinpoint which rule patterns were triggered located just under the
|
||||
Inspect menu. Traits are identified as "tags" found in the rule definitions which are customizable json files found under the 'Rules' folder.
|
||||
|
||||
<button type="button" style="background-color:dodgerblue;color:white" onclick="window.location='projecthome.html'">View Report</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="border:none">
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
See the project site for more at <a href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">https://github.com/Microsoft/AppInspector</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</main><!-- /.container -->
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,165 @@
|
|||
<!doctype html>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
|
||||
<title>AppInpector</title>
|
||||
<link rel="stylesheet" href="bootstrap.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
|
||||
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />
|
||||
<a class="navbar-brand" href="index.html">AppInspector</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="projecthome.html">Home <span class="sr-only">(current)</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="profile.html">Profile</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown01">
|
||||
<a class="dropdown-item" href="composition.html">Composition</a>
|
||||
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
|
||||
<a class="dropdown-item" href="alltags.html">All Tags</a>
|
||||
<a class="dropdown-item" href="allmatches.html">All Matches</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<form class="form-inline my-2 my-lg-0">
|
||||
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
|
||||
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main role="main" class="container" style="max-width: 100%">
|
||||
<div class="card-columns">
|
||||
|
||||
[[subSectionStart]]
|
||||
<div class="card" style="height:400px; overflow-y:scroll; border: 1px solid #6c757d">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">[[subSectionName]]</h5>
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed">
|
||||
<tr><td style="width:300px;color:dimgray;"><strong>Tag</strong></td><td style="color:dimgray;"><strong>Detected</strong></td><td style="color:dimgray;text-align:right"><strong>Confidence</strong></td></tr>
|
||||
{{ #each [[subSectionVarRef]] }}
|
||||
<tr>
|
||||
<td style="width:300px;"><img src="{{this.StatusIcon}}" />{{this.ShortTag}}</td>
|
||||
<td>{{ this.Detected }}</td>
|
||||
<td style="text-align:right"><a href="#" data-action="popup" data-tag="{{ this.Tag }}">{{ this.Confidence }}</a></td>
|
||||
</tr>
|
||||
{{ else }}
|
||||
No items found
|
||||
{{ /each }}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
[[subSectionEnd]]
|
||||
|
||||
<div class="card" style="height:400px; overflow-y:scroll; border: 1px solid #6c757d">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Selected Counters</h5>
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed" style="width:auto;">
|
||||
<tr><td style="width:375px;color:dimgray;"><strong>Tag</strong></td><td style="color:dimgray;"><strong>Count</strong></td></tr>
|
||||
{{ #each selectTagCounters }}
|
||||
<tr>
|
||||
<td style="width:465px;">{{ this.ShortTag }}</td>
|
||||
<td style="text-align:right">{{ this.Count }}</td>
|
||||
</tr>
|
||||
{{ else }}
|
||||
No items found
|
||||
{{ /each }}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div style="text-align:right">
|
||||
<button type="button" style="background-color:dodgerblue;color:white" onclick="window.location='composition.html'">See Composition</button>
|
||||
</div>
|
||||
|
||||
</main><!-- /.container -->
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
$('a[data-action="popup"]').on('click', function () {
|
||||
var tag = $(this).data('tag');
|
||||
var html = '';
|
||||
$('div[data-tag="' + tag + '"]').each(function (idx, elt) {
|
||||
var $row = $('<tr data-id="' + $(elt).data('id') + '" style="cursor:pointer;"/>')
|
||||
.append($('<td>' + $(elt).data('filename') + '</td>'))
|
||||
.append($('<td>' + $(elt).data('line') + '</td>'));
|
||||
$('table#detail-summary tbody').append($row);
|
||||
});
|
||||
|
||||
$('#detail_popup div.details').html('');
|
||||
$('#detail_popup').modal();
|
||||
});
|
||||
$('#detail_popup table#detail-summary tbody').on('click', 'tr', function () {
|
||||
var id = $(this).data('id');
|
||||
var excerpt = atob($('div[data-id="' + id + '"]').data('excerpt'));
|
||||
$('#detail_popup div.details').html(excerpt);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="d-none">
|
||||
{{ #each app.matchList }}
|
||||
<div data-id="{{ this.Issue.Rule.Id }}" data-filename="{{ this.Filename }}" data-line="{{ this.Issue.StartLocation.Line }}" data-excerpt="{{ this.Excerpt }}" data-tag="{{ this.Issue.Rule.Tags.[0] }}"></div>
|
||||
{{ /each }}
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="detail_popup" tabindex="-1" role="dialog" aria-labelledby="detail_popup_label" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="detail_popup_label">Details</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" style="height: 450px">
|
||||
<div class="summary" style="overflow-y:auto;height:35%;font-size:0.8em;">
|
||||
<table class="table table-sm" id="detail-summary">
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="details" style="white-space:pre;overflow-y:auto;height:65%;font-size:0.75em;font-family:monospace; border-top: 2px solid #444; margin-top: 6px;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">Open File</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,239 @@
|
|||
<!doctype html>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<title>AppInpector-Home</title>
|
||||
|
||||
<link rel="stylesheet" href="bootstrap.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
|
||||
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />
|
||||
<a class="navbar-brand" href="index.html">AppInspector</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="projecthome.html">Home <span class="sr-only">(current)</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="profile.html">Profile</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown01">
|
||||
<a class="dropdown-item" href="composition.html">Composition</a>
|
||||
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
|
||||
<a class="dropdown-item" href="alltags.html">All Tags</a>
|
||||
<a class="dropdown-item" href="allmatches.html">All Matches</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<form class="form-inline my-2 my-lg-0">
|
||||
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
|
||||
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main role="main" class="container" style="max-width: 100%">
|
||||
<div><img src="bar1.png" style="width:100%;height:30px;" /></div>
|
||||
<div style="height:3px;"></div>
|
||||
|
||||
<div class="card-columns">
|
||||
|
||||
<div class="card text-white" style="border: 1px solid gray;scrollbar-face-color:darkseagreen;height:400px;max-height:400px;overflow-y:scroll; background-color: cornflowerblue">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><strong>Project Info</strong></h5>
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed" style="table-layout: fixed; width: 100%">
|
||||
<tr><td style="width:123px;">Name</td><td>{{ app.MetaData.ApplicationName }} {{ app.MetaData.SourceVersion }}</td></tr>
|
||||
<tr><td style="width:123px;">Description</td><td style="word-wrap: break-word">{{ app.MetaData.Description }}</td></tr>
|
||||
<tr><td style="width:123px;">Directory</td><td style="word-wrap: break-word">{{ app.SourcePath }}</td></tr>
|
||||
<tr><td style="width:123px;">Author(s)</td><td>{{ app.MetaData.Authors }}</td></tr>
|
||||
<tr><td style="width:123px;">Last Modified</td><td>{{ app.MetaData.LastUpdated }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="height:400px;border: 1px solid #6c757d;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Source Info</h5>
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed">
|
||||
<tr>
|
||||
<td style="width:123px;">Programming Language(s)</td>
|
||||
<td>
|
||||
{{ #each app.MetaData.Languages }}
|
||||
{{ this }}
|
||||
{{#unless @last}}, {{/unless}}
|
||||
{{ /each }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:123px;">Type(s)</td>
|
||||
<td>
|
||||
{{ #each app.MetaData.Outputs }}
|
||||
{{ this }}
|
||||
{{#unless @last}}, {{/unless}}
|
||||
{{ /each }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:123px;">Extensions</td>
|
||||
<td>
|
||||
{{ #each app.MetaData.FileExtensions }}
|
||||
<a href="http://fileinfo.com/extension/{{ this }}" target="_blank" rel="noopener">{{ this }}</a>
|
||||
{{#unless @last}}, {{/unless}}
|
||||
{{ /each }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:123px;">Package Types</td>
|
||||
<td>
|
||||
{{ #each strGrpPackageTypes }}
|
||||
{{ this }}
|
||||
{{#unless @last}}, {{/unless}}
|
||||
{{ /each }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card" style="height:400px;border: 1px solid #6c757d;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Stats</h5>
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed">
|
||||
<tr><td>Files Analyzed</td><td style="text-align:right">{{ app.MetaData.FilesAnalyzed }}</td></tr>
|
||||
<tr><td>Files Skipped</td><td style="text-align:right">{{ app.MetaData.FilesSkipped }}</td></tr>
|
||||
<tr><td>Total Files</td><td style="text-align:right">{{ app.MetaData.TotalFiles }}</td></tr>
|
||||
<tr><td>Total Pattern Matches</td><td style="text-align:right">{{ app.MetaData.TotalMatchesCount }}</td></tr>
|
||||
<tr><td>Unique Pattern Matches</td><td style="text-align:right">{{ app.MetaData.UniqueTags.Count }}</td></tr>
|
||||
<tr><td>Dependencies</td><td style="text-align:right">{{ app.MetaData.UniqueDependencies.Count }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="height:400px;border: 1px solid #6c757d;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Detected Targets</h5>
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed">
|
||||
<tr>
|
||||
<td>Cloud Platform</td>
|
||||
<td style="text-align:right">
|
||||
{{ #each app.MetaData.CloudTargets }}
|
||||
{{ this }}
|
||||
{{#unless @last}}, {{/unless}}
|
||||
{{ /each }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Operating System</td>
|
||||
<td style="text-align:right">
|
||||
{{ #each app.MetaData.OSTargets }}
|
||||
{{ this }}
|
||||
{{#unless @last}}, {{/unless}}
|
||||
{{ /each }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CPU Targets</td>
|
||||
<td style="text-align:right">
|
||||
{{ #each app.MetaData.CPUTargets }}
|
||||
{{ this }}
|
||||
{{#unless @last}}, {{/unless}}
|
||||
{{ /each }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="height:400px;border: 1px solid #6c757d;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Scan Settings</h5>
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed" style="table-layout: fixed; width: 100%">
|
||||
<tr><td style="width:123px;">AppInspector</td><td>{{ app.Version }}</td></tr>
|
||||
<tr>
|
||||
<td style="width:123px;">Rules Path</td>
|
||||
<td style="max-width:200px;">
|
||||
{{ #each strGrpRulePaths }}
|
||||
{{ this }}
|
||||
{{#unless @last}}, {{/unless}}
|
||||
{{ /each }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:123px;">Scan Arguments</td>
|
||||
<td style="word-wrap: break-word">{{ app.Args }}</td>
|
||||
</tr>
|
||||
<tr><td style="width:123px;">Date Scanned</td><td>{{ app.DateScanned }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="height:400px;border: 1px solid #6c757d;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Build Info</h5>
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed">
|
||||
<tr>
|
||||
<td>Build Tools</td>
|
||||
<td style="text-align:right">
|
||||
{{ #each tagGrpBuildTools }}
|
||||
{{ this.shortTag }}
|
||||
{{#unless @last}}, {{/unless}}
|
||||
{{ /each }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Testing Tools</td>
|
||||
<td style="text-align:right">
|
||||
{{ #each tagGrpTstFrm }}
|
||||
{{ this.shortTag }}
|
||||
{{#unless @last}}, {{/unless}}
|
||||
{{ /each }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align:right">
|
||||
<button type="button" style="background-color:dodgerblue;color:white" onclick="window.location='profile.html'">Continue to Profile</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</main><!-- /.container -->
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,196 @@
|
|||
<!doctype html>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<title>AppInpector</title>
|
||||
|
||||
<link rel="stylesheet" href="bootstrap.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
|
||||
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />
|
||||
<a class="navbar-brand" href="index.html">AppInspector</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="projecthome.html">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="profile.html">Profile</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown01">
|
||||
<a class="dropdown-item" href="composition.html">Composition</a>
|
||||
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
|
||||
<a class="dropdown-item" href="alltags.html">All Tags</a>
|
||||
<a class="dropdown-item" href="allmatches.html">All Matches</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
<form class="form-inline my-2 my-lg-0">
|
||||
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
|
||||
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main role="main" class="container" style="max-width: 100%">
|
||||
<h4 class="card-title">Unique Sortable Tags</h4>
|
||||
<div>count={{ app.MetaData.UniqueTags.Count }}</div>
|
||||
<div class="card-columns">
|
||||
<div id="divtag" class="card" style="border:none;display:normal">
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed" style="border:none; width:500px;">
|
||||
<tr>
|
||||
<td><a href="#" onclick="SortbyTags();"><strong>Tag</strong></a></td>
|
||||
<td><a href="#" onclick="SortbyConfidence();"><strong>Confidence</strong></a> </td>
|
||||
<td><a href="#" onclick="SortbySeverity();"><strong>Severity</strong></a> </td>
|
||||
</tr>
|
||||
<tr></tr>
|
||||
{{ #each tagGrpAllTagsByName }}
|
||||
<tr>
|
||||
<td><a href="#" data-action="popup" data-tag="{{ this.Tag }}">{{ this.Tag }}</a></td>
|
||||
<td>{{ this.Confidence }}</td>
|
||||
<td>{{ this.Severity }}</td>
|
||||
</tr>
|
||||
{{ /each }}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="divconf" class="card" style="border:none; width:500px;display:none">
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed">
|
||||
<tr>
|
||||
<td><a href="#" onclick="SortbyTags();"><strong>Tag</strong></a></td>
|
||||
<td><a href="#" onclick="SortbyConfidence();"><strong>Confidence</strong></a> </td>
|
||||
<td><a href="#" onclick="SortbySeverity();"><strong>Severity</strong></a> </td>
|
||||
</tr>
|
||||
{{ #each tagGrpAllTagsByConfidence }}
|
||||
<tr>
|
||||
<td><a href="#" data-action="popup" data-tag="{{ this.Tag }}">{{ this.Tag }}</a></td>
|
||||
<td>{{ this.Confidence }}</td>
|
||||
<td>{{ this.Severity }}</td>
|
||||
</tr>
|
||||
{{ /each }}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="divsev" class="card" style="border:none; width:500px;display:none">
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
<table class="table table-condensed">
|
||||
<tr>
|
||||
<td><a href="#" onclick="SortbyTags();"><strong>Tag</strong></a></td>
|
||||
<td><a href="#" onclick="SortbyConfidence();"><strong>Confidence</strong></a> </td>
|
||||
<td><a href="#" onclick="SortbySeverity();"><strong>Severity</strong></a> </td>
|
||||
</tr>
|
||||
{{ #each tagGrpAllTagsBySeverity }}
|
||||
<tr>
|
||||
<td><a href="#" data-action="popup" data-tag="{{ this.Tag }}">{{ this.Tag }}</a></td>
|
||||
<td>{{ this.Confidence }}</td>
|
||||
<td>{{ this.Severity }}</td>
|
||||
</tr>
|
||||
{{ /each }}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main><!-- /.container -->
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
function SortbyConfidence() {
|
||||
$('#divconf').attr('style', 'display:normal;border:none');
|
||||
$('#divsev').attr('style', 'display:none');
|
||||
$('#divtag').attr('style', 'display:none');
|
||||
}
|
||||
|
||||
function SortbySeverity() {
|
||||
$('#divsev').attr('style', 'display:normal;border:none');
|
||||
$('#divconf').attr('style', 'display:none');
|
||||
$('#divtag').attr('style', 'display:none');
|
||||
}
|
||||
|
||||
function SortbyTags() {
|
||||
$('#divtag').attr('style', 'display:normal;border:none');
|
||||
$('#divsev').attr('style', 'display:none');
|
||||
$('#divconf').attr('style', 'display:none');
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
$('a[data-action="popup"]').on('click', function () {
|
||||
var tag = btoa($(this).data('tag'));
|
||||
var html = '';
|
||||
$('div[data-tag="' + tag + '"]').each(function (idx, elt) {
|
||||
var $row = $('<tr data-id="' + $(elt).data('id') + '"/>')
|
||||
.append($('<td>' + atob($(elt).data('filename')) + '</td>'))
|
||||
.append($('<td>' + $(elt).data('line') + '</td>'));
|
||||
$('table#detail-summary tbody').append($row);
|
||||
});
|
||||
|
||||
var snippets = $('div').find('[data-tag="' + tag + '"]').each(function (idx, elt) {
|
||||
html += atob(elt.innerText);
|
||||
});
|
||||
$('#detail_popup div.details').html('');
|
||||
$('#detail_popup').modal();
|
||||
});
|
||||
$('#detail_popup table#detail-summary tbody').on('click', 'tr', function () {
|
||||
var id = $(this).data('id');
|
||||
var excerpt = atob($('div[data-id="' + id + '"]').data('excerpt'));
|
||||
$('#detail_popup div.details').html(excerpt);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="d-none">
|
||||
{{ #each app.matchList }}
|
||||
<div data-id="{{ this.Issue.Rule.Id }}" data-filename="{{ this.Filename }}" data-line="{{ this.Issue.StartLocation.Line }}" data-excerpt="{{ this.Excerpt }}" data-tag="{{ this.Issue.Rule.Tags[0] }}"></div>
|
||||
{{ /each }}
|
||||
</div>
|
||||
<div class="modal fade" id="detail_popup" tabindex="-1" role="dialog" aria-labelledby="detail_popup_label" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="detail_popup_label">Details</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" style="height: 450px">
|
||||
<div class="summary" style="overflow-y:auto;height:35%;font-size:0.8em;">
|
||||
<table class="table table-sm" id="detail-summary">
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="details" style="white-space:pre;overflow-y:auto;height:65%;font-size:0.75em;font-family:monospace; border-top: 2px solid #444; margin-top: 6px;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">Open File</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
[
|
||||
{
|
||||
"tag": "Metric.Classes.Defined",
|
||||
"displayName": "Classes",
|
||||
"includeAsMatch": false
|
||||
},
|
||||
{
|
||||
"tag": "Metric.Functions.Defined",
|
||||
"displayName": "Functions",
|
||||
"includeAsMatch": false
|
||||
},
|
||||
{
|
||||
"tag": "Metric.Exception.Caught",
|
||||
"displayName": "Exceptions",
|
||||
"includeAsMatch": true
|
||||
},
|
||||
{
|
||||
"tag": "Metric.HTMLForm.Defined",
|
||||
"displayName": "Forms",
|
||||
"includeAsMatch": true
|
||||
},
|
||||
{
|
||||
"tag": "Dependency.SourceInclude",
|
||||
"displayName": "Dependencies",
|
||||
"includeAsMatch": true
|
||||
},
|
||||
{
|
||||
"tag": "Miscellaneous.CodeHygiene.Comment",
|
||||
"displayName": "Comments",
|
||||
"includeAsMatch": true
|
||||
},
|
||||
{
|
||||
"tag": "Metric.Logging.Call",
|
||||
"displayName": "Logging Calls",
|
||||
"includeAsMatch": true
|
||||
}
|
||||
]
|
|
@ -0,0 +1,284 @@
|
|||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
|
||||
[
|
||||
{
|
||||
"categoryName": "profile",
|
||||
"type": "uniqueTags",
|
||||
"groups": [
|
||||
{
|
||||
"title": "Security Basics",
|
||||
"dataRef": "SDLBasic",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "Authentication",
|
||||
"displayName": "Authentication",
|
||||
"detectedIcon": "authN-d.png",
|
||||
"notDetectedIcon": "authN-n.png"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Authorization",
|
||||
"displayName": "Authorization",
|
||||
"detectedIcon": "authZ-d.png",
|
||||
"notDetectedIcon": "authZ-n.png"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Cryptography",
|
||||
"displayName": "Cryptography",
|
||||
"detectedIcon": "crypto-d.png",
|
||||
"notDetectedIcon": "crypto-n.png"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Data.Serialization.Deserialization",
|
||||
"displayName": "ObjectDeserialization",
|
||||
"detectedIcon": "desz-d.png",
|
||||
"notDetectedIcon": "desz-n.png"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Data.Media",
|
||||
"displayName": "MediaParsing",
|
||||
"detectedIcon": "medparse-d.png",
|
||||
"notDetectedIcon": "medparse-n.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Extended Security",
|
||||
"dataRef": "ExtendedSDL",
|
||||
"patterns": [
|
||||
{
|
||||
|
||||
"searchPattern": "Network.Connect",
|
||||
"displayName": "ExternalNetComms"
|
||||
},
|
||||
{
|
||||
"searchPattern": "FileOperation.Write",
|
||||
"displayName": "FileWrite"
|
||||
},
|
||||
{
|
||||
"searchPattern": "FileOperation.Delete",
|
||||
"displayName": "FileDelete"
|
||||
},
|
||||
{
|
||||
"searchPattern": "DynamicExecution",
|
||||
"displayName": "DynamicExecution"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Data.SensitiveAccount",
|
||||
"displayName": "Accounts"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Data.Sensitive.Personal",
|
||||
"displayName": "Personal Data"
|
||||
},
|
||||
{
|
||||
"searchPattern": "OS.ACL.Write",
|
||||
"displayName": "OSACLWrite"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Features",
|
||||
"dataRef": "Features",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "Data.Finance",
|
||||
"displayName": "FinancialData"
|
||||
},
|
||||
{
|
||||
"searchPattern": "SystemRegistry.Write",
|
||||
"displayName": "WindowsRegistryWrite"
|
||||
},
|
||||
{
|
||||
"searchPattern": "DataAccess",
|
||||
"displayName": "DataAccess"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Multiprocessing",
|
||||
"displayName": "Multi-Threading"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Misc",
|
||||
"dataRef": "Misc",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "OSS",
|
||||
"displayName": "OSS"
|
||||
},
|
||||
{
|
||||
"searchPattern": "SocialMedia",
|
||||
"displayName": "SocialMediaUse"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Process.Access.Read",
|
||||
"displayName": "OS Process Scan"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"title": "System Access Changes",
|
||||
"dataRef": "SysAccess",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "ACL.AppContainer",
|
||||
"displayName": "ACLImpersonationAppContainer"
|
||||
},
|
||||
{
|
||||
"searchPattern": "ACL.Write",
|
||||
"displayName": "ACLWrite"
|
||||
},
|
||||
{
|
||||
"searchPattern": "OS.ACL.Permission.Elevated",
|
||||
"displayName": "ACLElevatedPermission"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Windows.Registry.Security",
|
||||
"displayName": "WindowsRegistrySecurity"
|
||||
},
|
||||
{
|
||||
"searchPattern": "TokenImpersonation",
|
||||
"displayName": "ACLImpersonationToken"
|
||||
},
|
||||
{
|
||||
"searchPattern": "System.Userorname.Add",
|
||||
"displayName": "SystemUserAdded"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Environment.Write",
|
||||
"displayName": "EnvironmentVarsWrite"
|
||||
},
|
||||
{
|
||||
"searchPattern": "SecurityEventSource",
|
||||
"displayName": "SecurityEventSource"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Audit.Write",
|
||||
"displayName": "AuditPermissionsWrite"
|
||||
},
|
||||
{
|
||||
"searchPattern": "System.Token.Write",
|
||||
"displayName": "SystemTokenWrite"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"categoryName": "composition",
|
||||
"type": "allTags",
|
||||
"groups": [
|
||||
{
|
||||
"title": "Cryptography",
|
||||
"dataRef": "Cryptography",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "Cryptography",
|
||||
"displayName": "Cryptography"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Content",
|
||||
"dataRef": "Content",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "Data.XML",
|
||||
"displayName": "ProcessesXML"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Data.JSON",
|
||||
"displayName": "ProcessesJSON"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Data.Media",
|
||||
"displayName": "ProcessesMedia"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Binary Objects",
|
||||
"dataRef": "Objects",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "Component.Adobe.Flash",
|
||||
"displayName": "FlashObjectUse"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Component.ActiveX",
|
||||
"displayName": "ActiveXUse"
|
||||
},
|
||||
{
|
||||
"searchPattern": "Component.PDF",
|
||||
"displayName": "PDFObjectUse"
|
||||
},
|
||||
{
|
||||
"searchPattern": "ObjectType.Media",
|
||||
"displayName": "MediaObjectUse"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Development Frameworks",
|
||||
"dataRef": "DevFrameWrks",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "Development.Framework",
|
||||
"displayName": "DevelopmentFramework"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Testing Frameworks",
|
||||
"dataRef": "TestFrameWrks",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "Testing.Framework",
|
||||
"displayName": "TestFramework"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Personal Data",
|
||||
"dataRef": "PII",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "Data.Sensitive.Personal",
|
||||
"displayName": "Personal Data"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Social Media",
|
||||
"dataRef": "SocMedia",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "SocialMedia",
|
||||
"displayName": "SocialMedia"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Data Access",
|
||||
"dataRef": "DataAccess",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "DataAccess",
|
||||
"displayName": "DataAccess"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "OSS License Types",
|
||||
"dataRef": "DataAccess",
|
||||
"patterns": [
|
||||
{
|
||||
"searchPattern": "OpenSourceLicense",
|
||||
"displayName": "OSSLicenseTypes"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,203 @@
|
|||
[
|
||||
{
|
||||
"name": "OS: Dynamic Execution",
|
||||
"id": "AI034510",
|
||||
"description": "OS: Dynamic Execution",
|
||||
"applies_to": [
|
||||
"objective-c",
|
||||
"swift"
|
||||
],
|
||||
"tags": [
|
||||
"OS.Process.DynamicExecution"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "stringByEvaluatingJavaScriptFromString",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high",
|
||||
"_comment": "https://developer.apple.com/documentation/uikit/uiwebview/1617963-stringbyevaluatingjavascriptfrom?language=objc"
|
||||
},
|
||||
{
|
||||
"pattern": "evaluateJavaScript",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high",
|
||||
"_comment": "https://developer.apple.com/documentation/webkit/wkwebview/1415017-evaluatejavascript?language=objc"
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OS: Dynamic Execution",
|
||||
"id": "AI034511",
|
||||
"description": "OS: Dynamic Execution",
|
||||
"applies_to": [
|
||||
"javascript",
|
||||
"ruby",
|
||||
"javascriptreact"
|
||||
],
|
||||
"tags": [
|
||||
"OS.Process.DynamicExecution"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "\\beval\\(",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "exec(Sync)?\\(",
|
||||
"type": "substring",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "\\bspawn\\(",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "\\bsystem\\(",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OS: Dynamic Execution",
|
||||
"id": "AI034512",
|
||||
"description": "OS: Dynamic Execution",
|
||||
"recommendation": "",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"OS.Process.DynamicExecution"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "process.start",
|
||||
"type": "substring",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "xp_cmdshell",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OS: Dynamic Execution",
|
||||
"id": "AI034513",
|
||||
"description": "OS: Dynamic Execution",
|
||||
"applies_to": [
|
||||
"powershell"
|
||||
],
|
||||
"tags": [
|
||||
"OS.Process.DynamicExecution"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(iex|invoke-expression).*[.]*webclient",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "(iex|invoke-expression).*[.]*downloadstring",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OS: Dynamic Execution",
|
||||
"id": "AI034513",
|
||||
"description": "OS: Dynamic Execution",
|
||||
"applies_to": [
|
||||
"c",
|
||||
"cpp"
|
||||
],
|
||||
"tags": [
|
||||
"OS.Process.DynamicExecution"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "ksh|bash|csh|sh",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "system(",
|
||||
"type": "substring",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "createprocess|execl|execlp|execlp|execv|execve|execvp|execvpe|execle|fork",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OS: Dynamic Execution",
|
||||
"id": "AI034514",
|
||||
"description": "OS: Dynamic Execution",
|
||||
"applies_to": [
|
||||
"java"
|
||||
],
|
||||
"tags": [
|
||||
"OS.Process.DynamicExecution"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Runtime.getRuntime().exec",
|
||||
"type": "substring",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,3 @@
|
|||
line: 1
|
||||
====
|
||||
NSString *string1 = [NSString stringWithFormat:@"A string: %@, a float: %1.2f", @"string", 31415.9265];
|
|
@ -0,0 +1,93 @@
|
|||
[
|
||||
{
|
||||
"name": "Cryptography: Algorithm Implementation",
|
||||
"id": "AI053010",
|
||||
"description": "Cryptography: Algorithm Implementation",
|
||||
"tags": [
|
||||
"Cryptography.Implementation"
|
||||
],
|
||||
"severity": "important",
|
||||
"_comment": "Implementing a standard cryptographic algorithm",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "5a827999",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Algorithm Implementation (SHA1)",
|
||||
"id": "AI053020",
|
||||
"description": "Cryptography: Algorithm Implementation (SHA1)",
|
||||
"tags": [
|
||||
"Cryptography.Implementation.SHA1"
|
||||
],
|
||||
"severity": "important",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "5a827999",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Algorithm Implementation (MD5)",
|
||||
"id": "AI053030",
|
||||
"description": "Cryptography: Algorithm Implementation (MD5)",
|
||||
"tags": [
|
||||
"Cryptography.Implementation.MD5"
|
||||
],
|
||||
"severity": "important",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "242070db",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Algorithm Implementation (SHA-256)",
|
||||
"id": "AI053040",
|
||||
"description": "Cryptography: Algorithm Implementation (SHA-256)",
|
||||
"tags": [
|
||||
"Cryptography.Implementation.SHA256"
|
||||
],
|
||||
"severity": "important",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "d807aa98",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Algorithm Implementation (Keccak)",
|
||||
"id": "AI053050",
|
||||
"description": "Cryptography: Algorithm Implementation (Keccak)",
|
||||
"tags": [
|
||||
"Cryptography.Implementation.SHA256"
|
||||
],
|
||||
"severity": "important",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "800000000000808A",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,54 @@
|
|||
[
|
||||
{
|
||||
"name": "Cryptography: x.509 Certificate",
|
||||
"id": "AI057510",
|
||||
"description": "Cryptography: x.509 Certificate",
|
||||
"tags": [
|
||||
"Cryptography.x509"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "x509|\\.(crt|pem|cer|pfx|csr)|certificate",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "genrsa|-keyout|-x509toreq|signkey",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ ],
|
||||
"confidence": "high",
|
||||
"_comment": "Common OpenSSL commands"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: x.509 Certificate",
|
||||
"id": "AI057520",
|
||||
"description": "Cryptography: x.509 Certificate",
|
||||
"tags": [
|
||||
"Cryptography.x509"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "x509|\\.(crt|pem|cer)",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,115 @@
|
|||
[
|
||||
{
|
||||
"name": "Cryptography: Encryption",
|
||||
"id": "AI555500",
|
||||
"description": "Cryptography: Encryption",
|
||||
"tags": [
|
||||
"Cryptography.Encryption"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "encrypt|decrypt|cipher|crypt",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Encryption (AES)",
|
||||
"id": "AI555510",
|
||||
"description": "Cryptography: Encryption (AES)",
|
||||
"tags": [
|
||||
"Cryptography.Encryption.AES"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "AES",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "AES-?(128|192|256)",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Encryption (3DES)",
|
||||
"id": "AI555520",
|
||||
"description": "Cryptography: Encryption (3DES)",
|
||||
"tags": [
|
||||
"Cryptography.Encryption.3DES"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "3DES|TripleDES",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Encryption (RC)",
|
||||
"id": "AI555530",
|
||||
"description": "Cryptography: Encryption (RC)",
|
||||
"tags": [
|
||||
"Cryptography.Encryption.RC"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "RC([2456])",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "arc4random",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Encryption: Cipher Mode",
|
||||
"id": "AP003100",
|
||||
"description": "Encryption: Cipher Mode",
|
||||
"tags": [
|
||||
"Cryptography.Encryption.CipherMode"
|
||||
],
|
||||
"severity": "critical",
|
||||
"_comment": "",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "CBC|CTR|ECB|OFB|CFB|CTS|PCBC|GMAC|XCBC|IACBC|IAPM|EAX|OCB|CWC|AEAD|LRW|XEX|XTS|CMC|EME|CBCMAC|OMAC|PMAC",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,34 @@
|
|||
[
|
||||
{
|
||||
"name": "CryptoCurrency",
|
||||
"id": "AI054500",
|
||||
"description": "CryptoCurrency",
|
||||
"tags": [
|
||||
"Cryptography.Currency"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "cardano|ethereum|cryptocurrency",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "miner|ripple|nxt|zcash|tether|ether|btc|monero|markleroot|xmr|eth|p2pool",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "medium"
|
||||
},
|
||||
{
|
||||
"pattern": "(bit|lite|name|peer|doge|grid|prim|vert|tit|pot)coin",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
{
|
||||
"name": "Cryptography: Encoding (Base-64)",
|
||||
"id": "AI054010",
|
||||
"description": "Cryptography: Encoding (Base-64)",
|
||||
"applies_to": [
|
||||
],
|
||||
"tags": [
|
||||
"Cryptography.Encoding.Base64"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "base64",
|
||||
"type": "substring",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,161 @@
|
|||
[
|
||||
{
|
||||
"name": "Crypographic Library: BouncyCastle",
|
||||
"id": "AI051000",
|
||||
"description": "Crypographic Library: BouncyCastle",
|
||||
"applies_to": [
|
||||
"csharp",
|
||||
"java",
|
||||
"kotlin",
|
||||
"scala"
|
||||
],
|
||||
"tags": [
|
||||
"Cryptography.Library.BouncyCastle"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "bouncycastle|spongycastle",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Crypographic Library: mbed TLS",
|
||||
"id": "AI051010",
|
||||
"description": "Crypographic Library: mbed TLS",
|
||||
"applies_to": [
|
||||
],
|
||||
"tags": [
|
||||
"Cryptography.Library.mbedTLS"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "mbedtls",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Crypographic Library: OpenSSL",
|
||||
"id": "AI051020",
|
||||
"description": "Crypographic Library: OpenSSL",
|
||||
"applies_to": [
|
||||
],
|
||||
"tags": [
|
||||
"Cryptography.Library.OpenSSL"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "openssl",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Crypographic Library: BoringSSL",
|
||||
"id": "AI051030",
|
||||
"description": "Crypographic Library: BoringSSL",
|
||||
"applies_to": [
|
||||
],
|
||||
"tags": [
|
||||
"Cryptography.Library.BoringSSL"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "boringssl",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Crypographic Library: LibreSSL",
|
||||
"id": "AI051040",
|
||||
"description": "Crypographic Library: LibreSSL",
|
||||
"applies_to": [
|
||||
],
|
||||
"tags": [
|
||||
"Cryptography.Library.LibreSSL"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "libressl",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Crypographic Library: Win32",
|
||||
"id": "AI051100",
|
||||
"description": "Crypographic Library: Win32",
|
||||
"applies_to": [
|
||||
],
|
||||
"tags": [
|
||||
"Cryptography.Library.Win32"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "\\b(wincrypt|cryptxml|wintrust|dpapi|bcrypt|cryptdlg|ncrypt|cryptxml|ncryptprotect)\\.h",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Crypographic Library: .NET",
|
||||
"id": "AI051110",
|
||||
"description": "Crypographic Library: .NET",
|
||||
"applies_to": [
|
||||
"c",
|
||||
"cpp",
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Cryptography.Library.NET"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "ProtectedData",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modified": [ "i" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "DPAPI",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modified": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,102 @@
|
|||
[
|
||||
{
|
||||
"name": "Cryptography: Hash Algorithm Usage",
|
||||
"id": "AI052000",
|
||||
"description": "Cryptography: Hash Algorithm Usage",
|
||||
"tags": [
|
||||
"Cryptography.HashAlgorithm"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "HashAlgorithm|MessageDigest|DigestUtils",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Hash Algorithm Usage (SHA-256)",
|
||||
"id": "AI052010",
|
||||
"description": "Cryptography: Hash Algorithm Usage (SHA-256)",
|
||||
"tags": [
|
||||
"Cryptography.HashAlgorithm.SHA2"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "SHA-?(2|224|256|384|512)",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Hash Algorithm Usage (Legacy)",
|
||||
"id": "AI052020",
|
||||
"description": "Cryptography: Hash Algorithm Usage (Legacy)",
|
||||
"tags": [
|
||||
"Cryptography.HashAlgorithm.Legacy"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "MD2|MD4|MD5|SHA-?0",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Hash Algorithm Usage (SHA-3)",
|
||||
"id": "AI052030",
|
||||
"description": "Cryptography: Hash Algorithm Usage (SHA-3)",
|
||||
"tags": [
|
||||
"Cryptography.HashAlgorithm.SHA3"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "SHA-?3|Keccak",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Hash Algorithm Usage (Misc)",
|
||||
"id": "AI052040",
|
||||
"description": "Cryptography: Hash Algorithm Usage (Misc)",
|
||||
"tags": [
|
||||
"Cryptography.HashAlgorithm.Misc"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "RIPEMD|Blowfish|Twofish|Threefish|Serpent",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,712 @@
|
|||
[
|
||||
{
|
||||
"name": "Detect Cryptography",
|
||||
"id": "AP003900",
|
||||
"description": "Detect use of cryptography",
|
||||
"recommendation": "",
|
||||
"tags": [
|
||||
"Inspect.Threatmodel.Cryptography.Infrastructure"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"_comment": "",
|
||||
"rule_info": "",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "SSLCACertificateFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCACertificatePath",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCADNRequestFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCADNRequestPath",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCARevocationCheck",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCARevocationFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCARevocationPath",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCertificateChainFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCertificateFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCertificateKeyFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCipherSuite",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCompression",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLCryptoDevice",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLEngine",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLFIPS",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLHonorCipherOrder",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLInsecureRenegotiation",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLOCSPDefaultResponder",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLOCSPEnable",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLOCSPOverrideResponder",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLOCSPProxyURL",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLOCSPResponderTimeout",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLOCSPResponseMaxAge",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLOCSPResponseTimeSkew",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLOCSPUseRequestNonce",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLOpenSSLConfCmd",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLOptions",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLPassPhraseDialog",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProtocol",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyCACertificateFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyCACertificatePath",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyCARevocationCheck",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyCARevocationFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyCARevocationPath",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyCheckPeerCN",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyCheckPeerExpire",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyCheckPeerName",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyCipherSuite",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyEngine",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyMachineCertificateChainFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyMachineCertificateFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyMachineCertificatePath",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyProtocol",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyVerify",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLProxyVerifyDepth",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLRandomSeed",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLRenegBufferSize",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLRequire",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLRequireSSL",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLSessionCache",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLSessionCacheTimeout",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLSessionTicketKeyFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLSessionTickets",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLSRPUnknownUserSeed",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLSRPVerifierFile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLStaplingCache",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLStaplingErrorCacheTimeout",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLStaplingFakeTryLater",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLStaplingForceURL",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLStaplingResponderTimeout",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLStaplingResponseMaxAge",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLStaplingResponseTimeSkew",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLStaplingReturnResponderErrors",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLStaplingStandardCacheTimeout",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLStrictSNIVHostCheck",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLUserName",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLUseStapling",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLVerifyClient",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "SSLVerifyDepth",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_buffer_size",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_crl",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_dhparam",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_ecdh_curve",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_password_file",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_prefer_server_ciphers",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_protocols",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_session_cache",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_session_ticket_key",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_session_tickets",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_session_timeout",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_stapling",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_stapling_file",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_stapling_responder",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_stapling_verify",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_trusted_certificate",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_verify_client",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "ssl_verify_depth",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"modifiers": [ "" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,49 @@
|
|||
[
|
||||
{
|
||||
"name": "Cryptography: Key Derivation",
|
||||
"id": "AI056010",
|
||||
"description": "Cryptography: Key Derivation",
|
||||
"tags": [
|
||||
"Cryptography.KeyDerivation"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Key Derivation (PBKDF1)",
|
||||
"id": "AI056020",
|
||||
"description": "Cryptography: Key Derivation (PBKDF1)",
|
||||
"tags": [
|
||||
"Cryptography.KeyDerivation.PBKDF1"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "pbkdf1|PasswordDeriveBytes",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: Key Derivation (PBKDF2)",
|
||||
"id": "AI056030",
|
||||
"description": "Cryptography: Key Derivation (PBKDF2)",
|
||||
"tags": [
|
||||
"Cryptography.KeyDerivation.PBKDF2"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "pbkdf2",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,76 @@
|
|||
[
|
||||
{
|
||||
"name": "Cryptography: SSL/TLS Protocol",
|
||||
"id": "AI057000",
|
||||
"description": "Cryptography: SSL/TLS Protocol",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Cryptography.Protocol.TLS"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(SSL|TLS)(v)?([123]{1,2})",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: SSL/TLS Protocol",
|
||||
"id": "AI057010",
|
||||
"description": "Cryptography: SSL/TLS Protocol",
|
||||
"applies_to": [
|
||||
"c",
|
||||
"objective-c",
|
||||
"swift"
|
||||
],
|
||||
"tags": [
|
||||
"Cryptography.Protocol.TLS"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(kCF|NS)StreamSocketSecurityLevel(None|SSLv2|SSLv3|TLSv1|NegotiatedSSL)",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "kSSLProtocol(2|3Only|All|Unknown)",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "k(D)?(SSL|TLS)Protocol(1|1Only|2|3Only|All)",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cryptography: SSH Protocol",
|
||||
"id": "AI057110",
|
||||
"description": "Cryptography: SSH Protocol",
|
||||
"tags": [
|
||||
"Cryptography.Protocol.SSH"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "ssh",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,80 @@
|
|||
[
|
||||
{
|
||||
"name": "Crypgraphy: PRNG",
|
||||
"id": "AI055020",
|
||||
"description": "Crypgraphy: PRNG",
|
||||
"tags": [
|
||||
"Cryptography.Randomness.PRNG"
|
||||
],
|
||||
"applies_to": [
|
||||
"c",
|
||||
"cpp"
|
||||
],
|
||||
"severity": "critical",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "DUAL_EC_DRBG",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "pseudoRandomBytes",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Crypgraphy: PRNG",
|
||||
"id": "AI055030",
|
||||
"description": "Crypgraphy: PRNG",
|
||||
"tags": [
|
||||
"Cryptography.Randomness.PRNG"
|
||||
],
|
||||
"applies_to": [
|
||||
"javascript"
|
||||
],
|
||||
"severity": "critical",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(pseudo)?randombytes",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Crypgraphy: PRNG",
|
||||
"id": "AI055040",
|
||||
"description": "Crypgraphy: PRNG",
|
||||
"tags": [
|
||||
"Cryptography.Randomness.PRNG"
|
||||
],
|
||||
"applies_to": [
|
||||
"java"
|
||||
],
|
||||
"severity": "critical",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "SecureRandom",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,260 @@
|
|||
[
|
||||
{
|
||||
"name": "Data: Access (Azure Storage Account)",
|
||||
"id": "AI068610",
|
||||
"description": "Data: Access (Azure Storage Account)",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Data.DataAccess.Microsoft.Azure.Storage"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "CloudStorageAccount",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Access (Azure Storage Account: Blob)",
|
||||
"id": "AI068611",
|
||||
"description": "Data: Access (Azure Storage Account: Blob)",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Data.DataAccess.Microsoft.Azure.Storage.Blob"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "CreateCloudBlobClient|BlobRequestOptions|GetBlockBlobReference|CloudBlockBlob|CloudBlobContainer|BlobContinuationToken|CloudPageBlob",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Access (Azure Storage Account: Blob)",
|
||||
"id": "AI068612",
|
||||
"description": "Data: Access (Azure Storage Account: Blob)",
|
||||
"applies_to": [
|
||||
"python"
|
||||
],
|
||||
"tags": [
|
||||
"Data.DataAccess.Microsoft.Azure.Storage.Blob"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(BlockBlobService|azure)\\.storage\\.blob",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Access (Azure Storage Account: Blob)",
|
||||
"id": "AI068613",
|
||||
"description": "Data: Access (Azure Storage Account: Blob)",
|
||||
"applies_to": [
|
||||
"javascript"
|
||||
],
|
||||
"tags": [
|
||||
"Data.DataAccess.Microsoft.Azure.Storage.Blob"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": ".createBlobService",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: ORM (SQL Alchemy)",
|
||||
"id": "AI068614",
|
||||
"description": "Data: ORM (SQL Alchemy)",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [
|
||||
"Data.DataAccess.ORM.SQLAlchemy"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "sqlalchemy",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: ORM (Django)",
|
||||
"id": "AI068615",
|
||||
"description": "Data: ORM (Django)",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [
|
||||
"Data.DataAccess.ORM.Django"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "django",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: DBMS (SQLite)",
|
||||
"id": "AI068616",
|
||||
"description": "Data: DBMS (SQLite)",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [
|
||||
"Data.DataAccess.DBMS.SQLite"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "sqlite",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: DBMS (PostgreSQL)",
|
||||
"id": "AI068617",
|
||||
"description": "Data: DBMS (PostgreSQL)",
|
||||
"applies_to": [],
|
||||
"tags": [
|
||||
"Data.DataAccess.DBMS.SQLite"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(pgsql|PG)\\.connect|PG::Connection",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: DBMS (PostgreSQL)",
|
||||
"id": "AI068618",
|
||||
"description": "Data: DBMS (PostgreSQL)",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [
|
||||
"Data.DataAccess.DBMS.SQLite"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "psycopg2",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: DBMS (PostgreSQL)",
|
||||
"id": "AI068619",
|
||||
"description": "Data: DBMS (PostgreSQL)",
|
||||
"applies_to": [ "csharp" ],
|
||||
"tags": [
|
||||
"Data.DataAccess.DBMS.SQLite"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "npgsql",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: ODBC",
|
||||
"id": "AI068620",
|
||||
"description": "Data: ODBC",
|
||||
"applies_to": [ "csharp" ],
|
||||
"tags": [
|
||||
"Data.DataAccess.ODBC"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Odbc|OdbcConnection|OdbcCommand|OdbcDataReader",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: SQL",
|
||||
"id": "AI068621",
|
||||
"description": "Data: SQL",
|
||||
"applies_to": [],
|
||||
"tags": [
|
||||
"Data.DataAccess.SQL"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "['\\\"](select|insert|delete)\\s.*",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
],
|
||||
"conditions": [
|
||||
{
|
||||
"pattern": {
|
||||
"pattern": "from|where",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
},
|
||||
"search_in": "finding-region(-5,5)",
|
||||
"negate_finding": false,
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,109 @@
|
|||
[
|
||||
{
|
||||
"name": "Data: Commerce",
|
||||
"id": "AI068510",
|
||||
"description": "Data: Commerce",
|
||||
"tags": [
|
||||
"Data.Finance"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "pci|wallet|fips-140",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "medium"
|
||||
},
|
||||
{
|
||||
"pattern": "paypal|google pay|ebay|google\\.com/pay/api",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "price|shopping chart|payment",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ]
|
||||
},
|
||||
{
|
||||
"pattern": "bigcommerce|shopify|bigcartel|woocommerce|wc_api_client|weebly|3dcart|squarespace|connect\\.squareup\\.com",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "demandware|yocart|opencart|magento|magentohost/api|volusion|vtex|x-vtex-api-appkey|alibaba",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Financial",
|
||||
"id": "AI068511",
|
||||
"description": "Data: Financial",
|
||||
"tags": [
|
||||
"Data.Finance"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "bank\\s*(acct|account)",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "(checking|savings|chk)\\s*(account|acct)",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "income|salary|salaries|financial",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "currency|usd|money|dollar|euro|peso",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "medium",
|
||||
"_comment": "Currencies"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Financial (Credit Card)",
|
||||
"id": "AI068512",
|
||||
"description": "Data: Financial (Credit Card)",
|
||||
"tags": [
|
||||
"Data.Finance.CreditCard"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "visa|americanexpress|amex|(master|discover|credit|debit)\\s*card",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,39 @@
|
|||
[
|
||||
{
|
||||
"name": "Data: JSON",
|
||||
"id": "AI068010",
|
||||
"description": "Data: JSON",
|
||||
"tags": [
|
||||
"Data.JSON"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "json",
|
||||
"type": "substring",
|
||||
"scopes": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: JSON",
|
||||
"id": "AI068020",
|
||||
"description": "Data: JSON",
|
||||
"tags": [
|
||||
"Data.JSON"
|
||||
],
|
||||
"applies_to": [ "csharp" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "JavaScriptSerializer",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,61 @@
|
|||
[
|
||||
{
|
||||
"name": "Data: XML",
|
||||
"id": "AI068110",
|
||||
"description": "Data: XML",
|
||||
"tags": [
|
||||
"Data.XML"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "xml|dom|sax|xpath|xmldom|xelement|xmldocument",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: XML",
|
||||
"id": "AI068120",
|
||||
"description": "Data: XML",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [
|
||||
"Data.XML"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "lxml|etree|ElementTree|minidom|pulldom|xmlrpc",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: XML",
|
||||
"id": "AI068130",
|
||||
"description": "Data: XML",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Data.XML"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "jdom2|SAXBuilder",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
[
|
||||
{
|
||||
"name": "Data: Embedded Secret (Access Token)",
|
||||
"id": "AI068310",
|
||||
"description": "Data: Embedded Secret",
|
||||
"tags": [
|
||||
"Data.Sensitive.SensitiveKey"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(secret|pass).*[a-f0-9]{30,}",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "low"
|
||||
},
|
||||
{
|
||||
"pattern": "[\"'][a-f0-9]{30,}[\"']",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "low"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Embedded Secret (Access Token)",
|
||||
"id": "AI068311",
|
||||
"description": "Data: Embedded Secret",
|
||||
"tags": [
|
||||
"Data.Sensitive"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(secret|password|credential|credentials|access_token)\\s*[=:]",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,206 @@
|
|||
[
|
||||
{
|
||||
"name": "Data: Sensitive (Personal Information)",
|
||||
"id": "AI068400",
|
||||
"description": "Data: Sensitive (Personal Information)",
|
||||
"tags": [
|
||||
"Data.Sensitive.Personal"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(first|last|sur)name",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "medium"
|
||||
},
|
||||
{
|
||||
"pattern": "birthdate|ethnicity|gender|citizenship|nationality|martial|marriage|married|spouce|mother|father|kid|kids",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "medium"
|
||||
},
|
||||
{
|
||||
"pattern": "race|avatar|photo",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "low"
|
||||
},
|
||||
{
|
||||
"pattern": "ssnumber|socialsecurity|nationalid|passport|drvlic|studentID",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "phone|mobilenumber|email|emailaddress|emailaddr",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "ipaddress|ipaddr",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "geotracking",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "medium"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Sensitive (Personal Information)",
|
||||
"id": "AI068401",
|
||||
"description": "Data: Sensitive (Personal Information)",
|
||||
"tags": [
|
||||
"Data.Sensitive.Personal"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "mobile",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "medium"
|
||||
}
|
||||
],
|
||||
"conditions": [
|
||||
{
|
||||
"pattern": {
|
||||
"pattern": "user|phone|cell|number",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
},
|
||||
"search_in": "finding-region(-30,30)",
|
||||
"negate_finding": false,
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Sensitive (Medical Information)",
|
||||
"id": "AI068402",
|
||||
"description": "Data: Sensitive (Medical Information)",
|
||||
"tags": [
|
||||
"Data.Sensitive.Personal"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "ssn",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "medium"
|
||||
}
|
||||
],
|
||||
"conditions": [
|
||||
{
|
||||
"pattern": {
|
||||
"pattern": "user",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
},
|
||||
"search_in": "finding-region(-40,40)",
|
||||
"negate_finding": false,
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Sensitive (Medical Information)",
|
||||
"id": "AI068403",
|
||||
"description": "Data: Sensitive (Medical Information)",
|
||||
"tags": [
|
||||
"Data.Sensitive.Medical"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "medical|insurance|doctor",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "low"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Sensitive",
|
||||
"id": "AI068404",
|
||||
"description": "Data: Sensitive",
|
||||
"tags": [
|
||||
"Data.Sensitive"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(strictly|highly) confidential",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "secret",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Sensitive (Account Information)",
|
||||
"id": "AI068405",
|
||||
"description": "Data: Sensitive (Account Information)",
|
||||
"tags": [
|
||||
"Data.Sensitive.Account"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "account|registration|membership|acct|acctnum|accountnum|accountnumber",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
],
|
||||
"conditions": [
|
||||
{
|
||||
"pattern": {
|
||||
"pattern": "user",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
},
|
||||
"search_in": "finding-region(-40,40)",
|
||||
"negate_finding": false,
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,254 @@
|
|||
[
|
||||
{
|
||||
"name": "Data: Serialization",
|
||||
"id": "AI068210",
|
||||
"description": "Data: Serialization",
|
||||
"applies_to": [
|
||||
"python"
|
||||
],
|
||||
"tags": [
|
||||
"Data.Serialization"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(de)?serialize",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "medium"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Serialization",
|
||||
"id": "AI068211",
|
||||
"description": "Data: Serialization",
|
||||
"applies_to": [
|
||||
"python"
|
||||
],
|
||||
"tags": [
|
||||
"Data.Serialization"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "import .*c?pickle",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Serialization",
|
||||
"id": "AI068212",
|
||||
"description": "Data: Serialization",
|
||||
"applies_to": [
|
||||
"python"
|
||||
],
|
||||
"tags": [
|
||||
"Data.Serialization.Serialization"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "c?pickle\\.dump",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Deserialization",
|
||||
"id": "AI068213",
|
||||
"description": "Data: Deserialization",
|
||||
"applies_to": [
|
||||
"python"
|
||||
],
|
||||
"tags": [
|
||||
"Data.Serialization.Deserialization"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "c?pickle\\.load",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Deserialization",
|
||||
"id": "AI068214",
|
||||
"description": "Data: Deserialization",
|
||||
"applies_to": [
|
||||
"java"
|
||||
],
|
||||
"tags": [
|
||||
"Data.Serialization.Deserialization"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": ".readObject",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Deserialization",
|
||||
"id": "AI068215",
|
||||
"description": "Data: Deserialization",
|
||||
"applies_to": [
|
||||
"php"
|
||||
],
|
||||
"tags": [
|
||||
"Data.Serialization.Deserialization"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "unserialize(",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Deserialization",
|
||||
"id": "AI068216",
|
||||
"description": "Data: Deserialization",
|
||||
"applies_to": [
|
||||
"ruby"
|
||||
],
|
||||
"tags": [
|
||||
"Data.Serialization.Deserialization"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "(YAML|Syck|Marshal)\\.load",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Serialization",
|
||||
"id": "AI068217",
|
||||
"description": "Data: Serialization",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Data.Serialization.Serialization"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "SerializeObject",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Deserialization",
|
||||
"id": "AI068218",
|
||||
"description": "Data: Deserialization",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Data.Serialization.Deserialization"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "DeserializeObject",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "PopulateObject",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "TypeNameHandling",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Data: Deserialization",
|
||||
"id": "AI068219",
|
||||
"description": "Data: Deserialization",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Data.Serialization.Deserialization"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "System.Runtime.Serialization",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "BinaryFormatter",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
},
|
||||
{
|
||||
"pattern": "TypeNameHandling",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,95 @@
|
|||
[
|
||||
{
|
||||
"name": "Detect Frameworks",
|
||||
"id": "AP012000",
|
||||
"description": "Detect well-known frameworks used",
|
||||
"recommendation": "",
|
||||
"applies_to": [ "php" ],
|
||||
"tags": [ "Development.Framework.PHP" ],
|
||||
"severity": "moderate",
|
||||
"_comment": "",
|
||||
"rule_info": "",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Laravel",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "Symfony",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "CodeIgniter",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "Zend",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "Fuelphp",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "Slim",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "Phalcon",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "Aura",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "Yii",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
},
|
||||
{
|
||||
"pattern": "Cakephp",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,190 @@
|
|||
[
|
||||
{
|
||||
"name": "Development: Build Tool (Maven)",
|
||||
"id": "AI063010",
|
||||
"description": "Development: Build Tool (Maven)",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [ "Development.Build.Maven" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Maven",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development: Build Tool (Ant)",
|
||||
"id": "AI063011",
|
||||
"description": "Development: Build Tool (Ant)",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [ "Development.Build.Ant" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Ant",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development: Build Tool (Gradle)",
|
||||
"id": "AI063012",
|
||||
"description": "Development: Build Tool (Gradle)",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [ "Development.Build.Gradle" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Gradle",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development: Build Tool (Jenkins)",
|
||||
"id": "AI063013",
|
||||
"description": "Development: Build Tool (Jenkins)",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [ "Development.Build.Jenkins" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "jenkins",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development: Build Tool (SBT)",
|
||||
"id": "AI063014",
|
||||
"description": "Development: Build Tool (SBT)",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [ "Development.Build.SBT" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "sbt",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development: Build Tool (Bamboo)",
|
||||
"id": "AI063015",
|
||||
"description": "Development: Build Tool (Bamboo)",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [ "Development.Build.Bamboo" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "atlassian bamboo",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development: Build Tool (TeamCity)",
|
||||
"id": "AI063016",
|
||||
"description": "Development: Build Tool (TeamCity)",
|
||||
"recommendation": "",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [ "Development.Build.TeamCity" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "teamcity",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development: Build Tool (Grape)",
|
||||
"id": "AI063017",
|
||||
"description": "Development: Build Tool (Grape)",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [ "Development.Build.Grape" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "grape",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development: Build Tool (Ivy)",
|
||||
"id": "AI063018",
|
||||
"description": "Development: Build Tool (Ivy)",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [ "Development.Build.Ivy" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "ivy",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development: Build Tool (Leiningen)",
|
||||
"id": "AI063019",
|
||||
"description": "Development: Build Tool (Leiningen)",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [ "Development.Build.Leiningen" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "leiningen",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development: Build Tool (Visual Studio)",
|
||||
"id": "AI063020",
|
||||
"description": "Development: Build Tool (Studio)",
|
||||
"applies_to": [ "VSSolution", "VSProject" ],
|
||||
"tags": [ "Development.Build.VisualStudio" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "VisualStudio|Visual Studio",
|
||||
"type": "regex",
|
||||
"scopes": [ "code", "comment" ],
|
||||
"modifiers": [ "i" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,42 @@
|
|||
[
|
||||
{
|
||||
"name": "Development Framework: Standard C Library",
|
||||
"id": "AI061010",
|
||||
"description": "Development Framework: Standard C Library",
|
||||
"recommendation": "",
|
||||
"applies_to": [ "c" ],
|
||||
"tags": [ "Development.Framework.StandardCLibrary" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "std::",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Boost",
|
||||
"id": "AI061020",
|
||||
"description": "Development Framework: Boost",
|
||||
"recommendation": "",
|
||||
"applies_to": [ "c" ],
|
||||
"tags": [ "Development.Framework.StandardCLibrary" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "boost::",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ]
|
||||
},
|
||||
{
|
||||
"pattern": "#include <boost/.*>",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,120 @@
|
|||
[
|
||||
{
|
||||
"name": "Component: Adobe Flash",
|
||||
"id": "AI066010",
|
||||
"description": "Component: Adobe Flash",
|
||||
"applies_to": [
|
||||
"actionscript"
|
||||
],
|
||||
"tags": [
|
||||
"Development.Framework.Component.AdobeFlash"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "import flash",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Component: Adobe Flash",
|
||||
"id": "AI066011",
|
||||
"description": "Component: Adobe Flash",
|
||||
"applies_to": [
|
||||
],
|
||||
"tags": [
|
||||
"Development.Framework.Component.AdobeFlash"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": ".swf",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Component: Active-X",
|
||||
"id": "AI066012",
|
||||
"description": "Component: Active-X",
|
||||
"applies_to": [
|
||||
"c",
|
||||
"cpp",
|
||||
"csharp",
|
||||
"html"
|
||||
],
|
||||
"tags": [
|
||||
"Development.Framework.Component.ActiveX"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "active-?x",
|
||||
"type": "regex",
|
||||
"scopes": [
|
||||
"code",
|
||||
"comment"
|
||||
],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Component: COM",
|
||||
"id": "AI066013",
|
||||
"description": "Component: COM",
|
||||
"applies_to": [
|
||||
"c",
|
||||
"cpp",
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Development.Framework.Component.ActiveX"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER|CoCreateInstance",
|
||||
"type": "regex-word",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Component: PDF",
|
||||
"id": "AI066014",
|
||||
"description": "Component: PDF",
|
||||
"applies_to": [
|
||||
"c",
|
||||
"cpp",
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Development.Framework.Component.PDF"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "pdf",
|
||||
"type": "string",
|
||||
"scopes": [
|
||||
"code"
|
||||
],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,306 @@
|
|||
[
|
||||
{
|
||||
"name": "Development Framework: Spring",
|
||||
"id": "AI062010",
|
||||
"description": "Development Framework: Spring",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.Spring"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "springframework",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Hibernate",
|
||||
"id": "AI062020",
|
||||
"description": "Development Framework: Hibernate",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.Hibernate"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "hibernate",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Blade",
|
||||
"id": "AI062030",
|
||||
"description": "Development Framework: Blade",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.Blade"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "blade",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: DropWizard",
|
||||
"id": "AI062040",
|
||||
"description": "Development Framework: DropWizard",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.DropWizard"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "dropwizard",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: GWT",
|
||||
"id": "AI062050",
|
||||
"description": "Development Framework: GWT",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.GWT"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "gwt",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: JSF",
|
||||
"id": "AI062060",
|
||||
"description": "Development Framework: JSF",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.JSF"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "jsf",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: JHipster",
|
||||
"id": "AI062070",
|
||||
"description": "Development Framework: JHipster",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.JHipster"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "jhipster",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: MyBatis",
|
||||
"id": "AI062080",
|
||||
"description": "Development Framework: MyBatis",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.MyBatis"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "mybatis",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Play Framework",
|
||||
"id": "AI062090",
|
||||
"description": "Development Framework: Play Framework",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.PlayFramework"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "import play.",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: PrimeFaces",
|
||||
"id": "AI062100",
|
||||
"description": "Development Framework: PrimeFaces",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.PrimeFaces"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "primefaces",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Spark",
|
||||
"id": "AI062110",
|
||||
"description": "Development Framework: Spark",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.Spark"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "import spark.",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Apache Struts",
|
||||
"id": "AI062120",
|
||||
"description": "Development Framework: Apache Struts",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.ApacheStruts"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "struts",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Apache Tapestry",
|
||||
"id": "AI062130",
|
||||
"description": "Development Framework: Apache Tapestry",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.ApacheTapestry"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "tapestry",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Vaadin",
|
||||
"id": "AI062140",
|
||||
"description": "Development Framework: Vaadin",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.Vaadin"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "vaadin",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Vert.x",
|
||||
"id": "AI062150",
|
||||
"description": "Development Framework: Vert.x",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.Vertx"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "vert.x",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Wicket",
|
||||
"id": "AI062160",
|
||||
"description": "Development Framework: Wicket",
|
||||
"applies_to": [ "java" ],
|
||||
"tags": [
|
||||
"Development.Framework.Wicket"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "wicket",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,238 @@
|
|||
[
|
||||
{
|
||||
"name": "Development Framework: Angular.JS",
|
||||
"id": "AI061510",
|
||||
"description": "Development Framework: Angular.JS",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.AngularJS" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Angular",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Vue",
|
||||
"id": "AI061511",
|
||||
"description": "Development Framework: Vue",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.Vue" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Vue",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: EmberJS",
|
||||
"id": "AI061512",
|
||||
"description": "Development Framework: EmberJS",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.EmberJS" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "Ember",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Backbone",
|
||||
"id": "AI061513",
|
||||
"description": "Development Framework: Backbone",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.Backbone" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "backbone",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: jQuery",
|
||||
"id": "AI061514",
|
||||
"description": "Development Framework: jQuery",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.jQuery" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "jquery",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Redux",
|
||||
"id": "AI061515",
|
||||
"description": "Development Framework: Redux",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.Redux" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "redux",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Redux-Saga",
|
||||
"id": "AI061516",
|
||||
"description": "Development Framework: Redux-Saga",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.Redux-Saga" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "redux-saga",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: React",
|
||||
"id": "AI061517",
|
||||
"description": "Development Framework: React",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.React" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "react",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: RITEWay",
|
||||
"id": "AI061518",
|
||||
"description": "Development Framework: RITEWay",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.RITEWay" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "riteway",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Meteor",
|
||||
"id": "AI061519",
|
||||
"description": "Development Framework: Meteor",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.Meteor" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "meteor",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Mithril",
|
||||
"id": "AI061520",
|
||||
"description": "Development Framework: Mithril",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.Mithril" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "mithril",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Polymer",
|
||||
"id": "AI061521",
|
||||
"description": "Development Framework: Polymer",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.Polymer" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "polymer",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Aurelia",
|
||||
"id": "AI061522",
|
||||
"description": "Development Framework: Aurelia",
|
||||
"applies_to": [ "javascript" ],
|
||||
"tags": [ "Development.Framework.Aurelia" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "aurelia",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Content Management Framework: Wordpress",
|
||||
"id": "AI061522",
|
||||
"description": "Development Framework: Wordpress",
|
||||
"applies_to": [ "javascript", "html"],
|
||||
"tags": [ "Development.Framework.CMS.Wordpress" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "wordpress",
|
||||
"type": "string",
|
||||
"scopes": [ "code", "comment"],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,128 @@
|
|||
[
|
||||
{
|
||||
"name": "Framework: Logging (Log4J)",
|
||||
"id": "AI068010",
|
||||
"description": "Framework: Logging (Log4J)",
|
||||
"applies_to": [
|
||||
"java"
|
||||
],
|
||||
"tags": [
|
||||
"Development.Framework.Logging.Log4j"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "log4j",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Framework: Logging (NLog)",
|
||||
"id": "AI068011",
|
||||
"description": "Framework: Logging (NLog)",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Development.Framework.Logging.NLog"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "nlog",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Framework: Logging (Serilog)",
|
||||
"id": "AI068012",
|
||||
"description": "Framework: Logging (Serilog)",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Development.Framework.Logging.Serilog"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "serilog",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Framework: Logging (log4net)",
|
||||
"id": "AI068013",
|
||||
"description": "Framework: Logging (log4net)",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Development.Framework.Logging.Log4Net"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "log4net",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Framework: Logging (ulog)",
|
||||
"id": "AI068014",
|
||||
"description": "Framework: Logging (ulog)",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Development.Framework.Logging.ULog"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "ulog",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Framework: Logging (Winston)",
|
||||
"id": "AI068015",
|
||||
"description": "Framework: Logging (Winston)",
|
||||
"applies_to": [
|
||||
"csharp"
|
||||
],
|
||||
"tags": [
|
||||
"Development.Framework.Logging.Winston"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "winston",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"confidence": "high",
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,140 @@
|
|||
[
|
||||
{
|
||||
"name": "Development Framework: .NET Core",
|
||||
"id": "AI061211",
|
||||
"description": "Development Framework: .NET Core",
|
||||
"applies_to": [ "csharp" ],
|
||||
"tags": [ "Development.Framework.Microsoft.NETCore" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "netcore",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Microsoft MVC",
|
||||
"id": "AI061212",
|
||||
"description": "Development Framework: Microsoft MVC",
|
||||
"applies_to": [ "csharp" ],
|
||||
"tags": [ "Development.Framework.Microsoft.MVC" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "mvc",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ]
|
||||
},
|
||||
{
|
||||
"pattern": "aspnetcore",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Microsoft WCF",
|
||||
"id": "AI061213",
|
||||
"description": "Development Framework: Microsoft WCF",
|
||||
"applies_to": [ "csharp" ],
|
||||
"tags": [ "Development.Framework.Microsoft.WCF" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "wcf",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Microsoft MFC",
|
||||
"id": "AI061214",
|
||||
"description": "Development Framework: Microsoft MFC",
|
||||
"applies_to": [ "c", "cpp", "csharp" ],
|
||||
"tags": [ "Development.Framework.Microsoft.MFC" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "mfc",
|
||||
"type": "regex-word",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Microsoft ADO",
|
||||
"id": "AI061215",
|
||||
"description": "Development Framework: Microsoft ADO",
|
||||
"applies_to": [ "csharp" ],
|
||||
"tags": [ "Development.Framework.Microsoft.ADO" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "ado",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Microsoft Linq",
|
||||
"id": "AI061216",
|
||||
"description": "Development Framework: Microsoft Linq",
|
||||
"applies_to": [ "csharp" ],
|
||||
"tags": [ "Development.Framework.Microsoft.Linq" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "linq",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Windows SDK",
|
||||
"id": "AI061217",
|
||||
"description": "Development Framework: Windows SDK",
|
||||
"applies_to": [ "c", "cpp", "csharp" ],
|
||||
"tags": [ "Development.Framework.Microsoft.WindowsSDK" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "winsdk",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Microsoft Active Directory (ADAL)",
|
||||
"id": "AI061218",
|
||||
"description": "Development Framework: Microsoft Active Directory (ADAL)",
|
||||
"tags": [
|
||||
"Development.Framework.Authentication.Microsoft.ADAL"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "ADAL",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"_comment": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,266 @@
|
|||
[
|
||||
{
|
||||
"name": "Development Framework: Django",
|
||||
"id": "AI062210",
|
||||
"description": "Development Framework: Django",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [
|
||||
"Development.Framework.Django"
|
||||
],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "django",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Pryamid",
|
||||
"id": "AI062211",
|
||||
"description": "Development Framework: Pryamid",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [ "Development.Framework.Pryamid" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "pyramid",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Web2Py",
|
||||
"id": "AI062212",
|
||||
"description": "Development Framework: Web2Py",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [ "Development.Framework.Web2Py" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "web2py",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: CubicWeb",
|
||||
"id": "AI062213",
|
||||
"description": "Development Framework: CubicWeb",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [ "Development.Framework.CubicWeb" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "cubicweb",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: OWL",
|
||||
"id": "AI062214",
|
||||
"description": "Development Framework: OWL",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [ "Development.Framework.OWL" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "owlready",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: RDF",
|
||||
"id": "AI062215",
|
||||
"description": "Development Framework: RDF",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [ "Development.Framework.RDF" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "rdflib",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: RQL",
|
||||
"id": "AI062216",
|
||||
"description": "Development Framework: RQL",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [ "Development.Framework.RQL" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "rql",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Flask",
|
||||
"id": "AI062217",
|
||||
"description": "Development Framework: Flask",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [ "Development.Framework.Flask" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "flask",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Bottle",
|
||||
"id": "AI062218",
|
||||
"description": "Development Framework: Bottle",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [ "Development.Framework.Bottle" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "bottle",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: CherryPy",
|
||||
"id": "AI062219",
|
||||
"description": "Development Framework: CherryPy",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [ "Development.Framework.CherryPy" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "cherrypy",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Sanic",
|
||||
"id": "AI062220",
|
||||
"description": "Development Framework: Sanic",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [ "Development.Framework.Sanic" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "sanic",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Tornado",
|
||||
"id": "AI062221",
|
||||
"description": "Development Framework: Tornado",
|
||||
"applies_to": [ "python" ],
|
||||
"tags": [ "Development.Framework.Tornado" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "tornado",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: TurboGears",
|
||||
"id": "AI062222",
|
||||
"description": "Development Framework: TurboGears",
|
||||
"applies_to": [
|
||||
"python",
|
||||
"requirements.txt"
|
||||
],
|
||||
"tags": [ "Development.Framework.TurboGears" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "TGController|TurboGears2",
|
||||
"type": "regex",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Giotto",
|
||||
"id": "AI062223",
|
||||
"description": "Development Framework: Giotto",
|
||||
"applies_to": [
|
||||
"python"
|
||||
],
|
||||
"tags": [ "Development.Framework.Giotto" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "giotto",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Pylons",
|
||||
"id": "AI062224",
|
||||
"description": "Development Framework: Pylons",
|
||||
"applies_to": [
|
||||
"python"
|
||||
],
|
||||
"tags": [ "Development.Framework.Pylons" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "pylons",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,36 @@
|
|||
[
|
||||
{
|
||||
"name": "Development Framework: Grails",
|
||||
"id": "AI061250",
|
||||
"description": "Development Framework: Grails",
|
||||
"applies_to": [ "groovy" ],
|
||||
"tags": [ "Development.Framework.Grails" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "grails",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Development Framework: Rails",
|
||||
"id": "AI061251",
|
||||
"description": "Development Framework: Rails",
|
||||
"applies_to": [ "ruby" ],
|
||||
"tags": [ "Development.Framework.Rails" ],
|
||||
"severity": "moderate",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern": "rails",
|
||||
"type": "string",
|
||||
"scopes": [ "code" ],
|
||||
"modifiers": [ "i" ],
|
||||
"confidence": "high"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|